Compare commits

...

527 Commits

Author SHA1 Message Date
jamesread
d3aa3b25b0 fix: doc typo
Some checks failed
Build & Release pipeline / build (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-10-24 01:24:33 +01:00
jamesread
d944b09c51 chore: Move up the saving of integrationtests 2025-10-24 01:18:14 +01:00
jamesread
b9851adfde doc: Add upgrade guide to readme 2025-10-24 01:16:48 +01:00
jamesread
45f9c18bc3 fix: enable main releases on 3k 2025-10-24 01:13:01 +01:00
jamesread
5d947f5a32 fix: enable main releases on 3k 2025-10-24 01:01:22 +01:00
jamesread
754d216827 fix: 3k version in semrel 2025-10-24 00:54:28 +01:00
jamesread
3d902295ad chore: disable semrel on inactive 2k branch 2025-10-24 00:47:49 +01:00
jamesread
5f8cd60736 chore: disable semrel on inactive 2k branch 2025-10-24 00:46:51 +01:00
jamesread
ae360100ce chore: add build service step to build and release workflow 2025-10-23 23:43:43 +01:00
jamesread
4a851355a8 chore: run pipeline on all branches 2025-10-23 23:36:38 +01:00
jamesread
54d3c65df3 chore: upgrade icons package 2025-10-23 23:34:54 +01:00
jamesread
58ba8eeeb9 chore: Simplify semrel pipeline 2025-10-23 23:34:39 +01:00
jamesread
e1e9cd9c35 feat: Begin automating 3k releases 2025-10-23 23:24:10 +01:00
jamesread
2a5fe71458 chore: wip OliveTin3k 2025-10-23 23:18:10 +01:00
jamesread
cbb163726e chore: wip OliveTin3k 2025-10-23 23:16:39 +01:00
dependabot[bot]
6836062b00 build(deps): bump vite from 7.1.9 to 7.1.11 in /frontend (#654)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-22 09:22:04 +00:00
dependabot[bot]
339dbe6dbd build(deps): bump github.com/go-viper/mapstructure/v2 from 2.3.0 to 2.4.0 in /service (#641)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-11 06:23:50 +00:00
dependabot[bot]
a24a7fbd01 build(deps): bump github.com/quic-go/quic-go from 0.53.0 to 0.54.1 in /service (#652)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2025-10-11 06:16:47 +00:00
jamesread
c9c781b197 fix: webui directory search
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Buf CI / buf (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
2025-10-11 01:16:06 +01:00
jamesread
b0f24811b2 fix: stylelint and webui cleanup 2025-10-11 01:12:07 +01:00
jamesread
3884dc6d0a fix: codestyle workflow 2025-10-11 00:59:49 +01:00
jamesread
91dfe2437e fix: increase integration test timeout 2025-10-11 00:56:56 +01:00
jamesread
60814b97e2 chore: fix gocyclo issues 2025-10-11 00:52:18 +01:00
jamesread
b330fbd1a5 fix: all broken integration tests 2025-10-11 00:45:41 +01:00
jamesread
7d5fa999e5 fix: Move Iconify to v3, and version it via npm 2025-10-01 23:28:55 +01:00
jamesread
a464e6a445 fix: broken tests after changing the way arguments are parsed
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-10-01 22:20:56 +01:00
Tim Green
a26a8bb032 chore: update the docs link for timeouts in the error message (#651)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-10-01 07:18:39 +01:00
jamesread
7345744e41 chore: frontend updates
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-09-07 01:33:46 +01:00
jamesread
570c0ba087 chore: Repair output streaming, lots of css/go lint
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Buf CI / buf (push) Has been cancelled
2025-09-06 08:42:13 +01:00
dependabot[bot]
60c0c5db27 build(deps-dev): bump tmp from 0.2.3 to 0.2.4 in /integration-tests (#638)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2025-09-02 20:56:57 +01:00
jamesread
4a847f0587 Merge branch 'main' of github.com:OliveTin/OliveTin
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-08-20 00:05:47 +01:00
jamesread
6b342cbedb chore: Port huge amount of code to OliveTin 3k 2025-08-20 00:05:40 +01:00
jamesread
f46a02fced chore: tests wip
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-08-19 17:29:40 +01:00
James Read
3dd7aaff88 Update restapi_auth_oauth2.go
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-08-15 18:26:50 +02:00
James Read
7d4edeb60a Update build-tag.yml (#640) 2025-08-15 18:23:19 +02:00
James Read
387f1d9c1a Update build-snapshot.yml 2025-08-15 18:21:36 +02:00
James Read
c526fa323e Update AI.md
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-08-08 00:07:16 +01:00
jamesread
17c716c599 chore: fix build error 2025-08-03 22:41:01 +01:00
James Read
c5b49b33ab Update README.md
Some checks failed
Buf CI / buf (push) Has been cancelled
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-08-03 22:22:17 +01:00
jamesread
2a73b58255 chore: merge main 2025-08-03 22:17:35 +01:00
jamesread
a62d58f119 chore: OliveTin 3k progress 2025-08-03 22:10:51 +01:00
James Read
e02ce2be4e Update README.md (#637)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-07-31 19:45:01 +00:00
James Read
21ad5871ce doc: Fix broken link (#636)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-31 14:02:27 +00:00
James Read
d4d3193c1d bugfix: Argument confirmations stopped working (#627) (#632)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-07-29 21:51:34 +00:00
dependabot[bot]
10e5a92cbe build(deps): bump github.com/docker/docker from 28.3.1+incompatible to 28.3.3+incompatible in /service (#635)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-29 21:19:17 +00:00
James Read
a06299bd9e feature: stylemods, for side by side buttons, and XL images (#634)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
2025-07-28 23:02:04 +00:00
James Read
2d4a3fc048 bugfix: Crash in OAuth2 userdata, and option to log user data (#631) 2025-07-28 21:46:08 +00:00
James Read
81ef166d78 bugfix #627 (#630)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-28 09:24:38 +00:00
dependabot[bot]
d4fe9eaa79 build(deps): bump form-data from 4.0.0 to 4.0.4 in /integration-tests (#626)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 06:19:32 +00:00
James Read
af75afa82f bugfix: #401 Duplicate lines in output (#623)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-19 23:34:59 +00:00
James Read
b91c0d7e45 feat: Style update for buttons, reduce style duplication (#621)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-19 11:51:19 +00:00
James Read
e922baa2e0 feat: #104 Checkboxes / booleans at last! (#620)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-19 02:10:41 +01:00
James Read
fcd1879d09 feat: Entities in icon field, and other cleanup stuff (#619)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-07-17 15:04:15 +00:00
James Read
a8ac719af7 feat kill acl (#618)
Some checks failed
Buf CI / buf (push) Has been cancelled
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-13 09:08:05 +00:00
jamesread
b99b3f4345 chore: Various codestyle fixes
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-07-12 23:46:50 +01:00
jamesread
b16ce074ea chore: Various codestyle fixes 2025-07-12 23:44:24 +01:00
James Read
54447774d1 fix: #616 - JSON parsing of ints to float64 (#617) 2025-07-12 22:02:50 +00:00
James Read
260477e5e8 Update README.md (#615)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-07-09 16:09:26 +00:00
James Read
e559c32c37 doc screenshots (#614) 2025-07-09 15:54:23 +00:00
James Read
2c7b33b730 chore: Dep update 2025-07-09 (#613)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Buf CI / buf (push) Has been cancelled
2025-07-09 10:24:59 +00:00
James Read
1970311ff5 feat: Triggered actions get previous action args #607 (#611)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-06-22 22:08:07 +00:00
James Read
433456986d fix: #603 - Dashboards that have fieldsets without entities are hidden (#609) 2025-06-22 21:09:03 +00:00
James Read
e38361f3d7 fix: gofmt/gocylo leftover from old PR (#610) 2025-06-22 20:42:57 +00:00
James Read
1ffdd93ddf fix: Redact password arguments in logs #594 (#601)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-06-06 21:00:56 +00:00
James Read
18c5599704 fix: Datetime mangling for Android phones #564 (#602) 2025-06-06 20:41:54 +00:00
James Read
224d7f40ed feat: Add unauthenticated readyz endpoint (#600) 2025-06-06 16:02:00 +00:00
James Read
1357eae9b8 fix: Empty dashboards are hidden (#599)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
2025-06-06 15:11:02 +00:00
James Read
b2e7509959 feat: use sans-serif font everywhere (#597)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-06-01 11:51:17 +00:00
James Read
cebab32514 bug: Hide password values in deeplinks #594 (#596)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-05-31 19:54:44 +00:00
James Read
7110399d41 fix: Bug that caused duplicate links (eg Diagnostics and Logs) in the nav bar (#595) 2025-05-31 19:20:37 +00:00
James Read
74f0930dcc feat: #582 ServiceMain for Windows (#593)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-05-30 08:30:58 +00:00
James Read
c20eea29cd feat: win unicode flag (#590)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-26 07:33:22 +00:00
James Read
8c073bf45f feature: Intelligent version comparison #575 (#580)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-02 15:53:56 +00:00
jamesread
fcfa007cec build: Add unit tests for regex (ref: #578)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-01 16:30:29 +01:00
dependabot[bot]
b83b7a4c42 build(deps-dev): bump base-x from 3.0.9 to 3.0.11 in /webui.dev (#577)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 06:48:12 +00:00
James Read
0a7f3f3226 bugfix: #503 Fix possible race condition in onfileindir* (#576)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-26 20:42:12 +00:00
James Read
633e513697 feature: (#568) Separator allowed in usergroup line for trusted headers (#572)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-22 14:35:49 +01:00
James Read
eb2721c023 chore: Cleanup argument handling (#571)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-21 08:50:59 +00:00
James Read
765c698a9b feature: Easier loading of custom-webui icons with simplified paths (#567)
Some checks failed
Buf CI / buf (push) Has been cancelled
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-19 23:06:17 +00:00
James Read
c19428f6b6 feature: Policy support - allow hiding daignostics and logs (#569) 2025-04-19 23:05:49 +00:00
James Read
f02982b451 docs: Add AI policy (#563)
Some checks failed
Buf CI / buf (push) Has been cancelled
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-14 23:04:34 +00:00
jamesread
6ffb0cedbc chore: Remove surious dep update 2025-04-14 17:33:24 +01:00
James Read
775b3d3ca6 feat: Smaller width buttons on mobile (#561)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
2025-04-13 18:37:58 +00:00
jamesread
6ad001619d build: feat/feature changelog prio
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-09 10:34:13 +01:00
James Read
db28e8915b feature: Include kubernetes-client (#559)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-08 21:39:21 +00:00
jamesread
bb4969c9ac build: Fix webui codestyle job
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
2025-04-08 22:27:21 +01:00
jamesread
aef70c0e1b build: Fix webui codestyle job 2025-04-08 22:19:36 +01:00
jamesread
27c287c2de build: Code format 2025-04-08 22:14:23 +01:00
Noah Perks Sloan
ec1f974f67 feat: links to argument forms (#551)
Co-authored-by: James Read <contact@jread.com>
2025-04-08 21:07:01 +00:00
James Read
4ccfd0f993 fix: 404 in docs for "big error messages" (#558) 2025-04-08 20:54:37 +00:00
jamesread
c5eaa35fb0 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2025-04-08 21:49:22 +01:00
jamesread
24ba4fb574 build: cyclo ignore "getexecutionscount 2025-04-08 21:49:10 +01:00
Noah Perks Sloan
b742bd89c4 feat: support multiple user groups (#555) 2025-04-08 20:31:55 +00:00
James Read
2fcc0a63a0 feature: #543 Rate limits are now per action-entity instead of per action (#557)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-08 00:28:32 +00:00
jamesread
ba29325c15 feature: #543 Rate limits are now per action-entity instead of per action 2025-04-08 01:18:55 +01:00
James Read
88f639d29f chore: Cleanup executor shell passing (#556)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-07 20:48:45 +00:00
James Read
fa44e958d8 chore: Big dependency update (#553)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-06 22:26:51 +00:00
David Q
182548e0dc feat: add syntax for interpolating environment variables into config file (#548)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Co-authored-by: James Read <contact@jread.com>
2025-04-05 22:36:10 +00:00
David Q
c3097e40db fix: reloading config after k8s configmap replacement (#552)
Co-authored-by: James Read <contact@jread.com>
2025-04-05 22:28:28 +00:00
jamesread
2b66414a93 build: Add missing build-snapshot job on PR 2025-04-05 23:23:47 +01:00
jamesread
7da8a5bc38 buf dep update
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Buf CI / buf (push) Has been cancelled
2025-04-05 01:02:47 +01:00
jamesread
2bc45e9a09 build: cannot set cwd with buf-action 2025-04-05 01:00:00 +01:00
jamesread
fd3c6087f0 working directory for buf 2025-04-05 00:51:32 +01:00
jamesread
c0b8dd71db Enable manual trigger for buf 2025-04-05 00:48:09 +01:00
jamesread
1164e5fae2 working directory for buf 2025-04-05 00:43:26 +01:00
jamesread
902d4ed819 build: Switch to buf2 2025-04-05 00:15:57 +01:00
James Read
2320a56dd9 build: Update cache path for go (#550)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-03 10:48:15 +00:00
James Read
2981fc4c1f doc: Point pull request template to contributors guide (#549)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-02 22:47:41 +00:00
Noah Perks Sloan
8865331da2 feat: enable JWT auth from a header (#547)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-04-02 19:14:43 +01:00
James Read
709d6ac2ad feature: Allow rendering output as HTML (#544)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-03-28 23:48:26 +00:00
jamesread
8d4e335dda fix: Invalid path to systemd file
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-03-23 01:02:22 +00:00
jamesread
44a9de080c docs: Windows was not bold. 2025-03-23 00:28:07 +00:00
jamesread
9bb17badad docs: Links and make targets 2025-03-23 00:26:52 +00:00
James Read
ff31abe66c refactor: Project directories (#541)
Some checks failed
Build Snapshot / build-snapshot (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
Buf CI / buf (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
2025-03-22 01:06:59 +00:00
James Read
b4c886d5d3 refactor: systemd file does not need to be in root dir (#538) 2025-03-22 01:06:22 +00:00
dependabot[bot]
e0bc1d86f6 build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2 (#540)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-22 00:42:53 +00:00
James Read
270f20ec75 refactor: Moved proto files into own folder (#537)
Some checks failed
Buf CI / buf (push) Waiting to run
Build Snapshot / build-snapshot (push) Waiting to run
Codestyle checks / codestyle (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-03-21 02:41:41 +00:00
James Read
486253b253 feature: Docker ce (#536) 2025-03-21 00:15:44 +00:00
James Read
6b9c6c8b9c refactor: Switch to conventional scripts, rather than custom script (#535) 2025-03-20 23:04:36 +00:00
dependabot[bot]
1275934ac1 build(deps): bump axios from 1.7.4 to 1.8.4 in /integration-tests (#534)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2025-03-20 23:00:03 +00:00
jamesread
bbc6095e36 doc: social banner 2025-03-20 22:44:25 +00:00
jamesread
7906f2d363 refactor: dep update 2025-03-20 21:55:17 +00:00
jamesread
d45bd887c2 security: dep update 2025-03-20 21:44:06 +00:00
James Read
7788f58aac feature: persist local sessions across restart (#522)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-02-21 22:26:15 +00:00
James Read
f3bc82311d feature: Allow arbitary HTML on argument form (useful for descriptions) (#519) 2025-02-21 17:57:02 +00:00
James Read
cae5d296ca bugfix: Fixed broken log message for Execution finished on websocket (#520) 2025-02-21 17:56:37 +00:00
James Read
5cd5bd2a25 bugfix: Default config now uses "triggers" instead of "trigger", and shows HTML (#521) 2025-02-21 17:53:19 +00:00
James Read
6550223ee4 fmt: code style (#518)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2025-02-19 23:18:02 +00:00
James Read
39368d511a feature: Limit log history to prevent browser lag and grpc encode failures (#507)
* feature: Limit log history to prevent browser lag and grpc encode failures

* cicd: Simplify if/else chain to switch

* cicd: Lint failure in JS because of a trailing space

* cicd: Coderabbit fixes on PR

* cicd: Move config sanitize into correct place

* cicd: Handle negative startOffset, negative endOffset and empty logs

* Update internal/executor/executor.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* cicd: Fix getLogs segfault

* cicd: Fix code rabbit nitpicks

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-02-19 23:17:06 +00:00
James Read
0a4bcc6423 cicd: Update .goreleaser.yml file to Feb 2025 syntax (#517) 2025-02-19 16:57:32 +00:00
jamesread
56ab1cec8f cicd: Textarea resizing [skip ci] 2025-02-18 17:49:54 -08:00
jamesread
12f87ca6e1 feature: Add support for raw textboxes #490 2025-02-18 17:49:54 -08:00
James Read
2fc7c23416 feature!: Trigger changed Triggers, allowing multiple actions (#515)
* feature!: Trigger changed Triggers, allowing multiple actions

* bugfix: Warning message on trigger loops, prevented NPE

* cicd: Fix cyclo complexity with triggers
2025-02-19 00:00:33 +00:00
James Read
2cf538bab1 bugfix: Systemd unit now waits for network and filesystem #495 (#514)
Some checks are pending
Build Snapshot / build-snapshot (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Codestyle checks / codestyle (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
2025-02-18 23:17:56 +00:00
dependabot[bot]
906b6c5783 build(deps): bump serialize-javascript and mocha in /integration-tests (#513)
Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `serialize-javascript` from 6.0.0 to 6.0.2
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)

Updates `mocha` from 10.4.0 to 10.8.2
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v10.4.0...v10.8.2)

---
updated-dependencies:
- dependency-name: serialize-javascript
  dependency-type: indirect
- dependency-name: mocha
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 17:14:25 +00:00
jamesread
6d43ebef44 docs: Change maturity label
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-01-23 14:58:26 +00:00
James Read
c04203e671 Update README.md (#508)
Some checks are pending
Build Snapshot / build-snapshot (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
2025-01-22 14:07:21 +00:00
dependabot[bot]
bf93707787 build(deps): bump github.com/MicahParks/jwkset from 0.5.17 to 0.7.0 (#506)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Bumps [github.com/MicahParks/jwkset](https://github.com/MicahParks/jwkset) from 0.5.17 to 0.7.0.
- [Release notes](https://github.com/MicahParks/jwkset/releases)
- [Commits](https://github.com/MicahParks/jwkset/compare/v0.5.17...v0.7.0)

---
updated-dependencies:
- dependency-name: github.com/MicahParks/jwkset
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-12 21:39:18 +00:00
Bjorn Lammers
f0d70f0c15 Migrate dashboard-icons to homarr-labs
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-01-06 22:21:35 +00:00
jamesread
17d9e29f19 cicd: Add responsibility labels to all new issues
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2024-12-30 02:05:05 +00:00
jamesread
be7168d9c5 cicd: Issue responsibility bugs 2024-12-30 01:59:27 +00:00
jamesread
d36b23832c cicd: Issue responsibility bugs 2024-12-30 01:54:36 +00:00
jamesread
b6429e9bc7 cicd: Add issue responsibility labels 2024-12-30 01:45:51 +00:00
jamesread
7ddc112b2c doc: CONTRIBUTING - add more guidelines
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2024-12-23 17:14:55 +00:00
jamesread
10a473ca1c security: Big dependency update
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2024-12-22 01:59:43 +00:00
jamesread
c7207d1ee6 security: Big dependency update 2024-12-22 01:58:19 +00:00
jamesread
c585762ba8 cicd: Standardize the automated code generation 2024-12-22 01:48:21 +00:00
James Read
476838d59a bugfix: Local users now work with a single usergroup (#486)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2024-11-24 21:22:24 +00:00
James Read
f0b1cefb72 feature: OAuth2 early support for CertBundles (#474) and Usergroups (#477) (#485)
Some checks are pending
Build Snapshot / build-snapshot (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Codestyle checks / codestyle (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
2024-11-24 10:00:25 +00:00
James Read
b4a555e3da bugfix: #481 StartActionAndWait now allows arguments. (#483) 2024-11-24 06:56:27 +00:00
James Read
79a4119351 security: Update cross-spawn vulnerable dependency (#482) 2024-11-24 06:56:16 +00:00
jamesread
851d0dac84 doc: Fix #478 - easy.cfg typo [skip ci] 2024-11-23 16:31:23 -06:00
James Read
655a7f205d feature: Improved auth log messages (#476)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2024-11-14 22:00:08 +00:00
James Read
13e48dded2 feature: Better guest handling (#472)
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
* feature: Better guest handling

* bugfix: Better handling of requiring guests to login
2024-11-09 23:27:09 +00:00
dependabot[bot]
344df3739d build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#473)
Some checks are pending
Build Snapshot / build-snapshot (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Codestyle checks / codestyle (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
Bumps [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v4.5.0...v4.5.1)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-09 00:13:32 +00:00
jamesread
0d981773b3 fmt: gofmt 2024-11-08 23:54:32 +00:00
jamesread
8d4ddd36cd cicd: Goreleaser tikeout
Some checks failed
Build Snapshot / build-snapshot (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Codestyle checks / codestyle (push) Has been cancelled
DevSkim / DevSkim (push) Has been cancelled
2024-11-02 07:35:36 +00:00
James Read
209234c09f bugfix: Still hide an empty actions section if a section is currently selected (#469) 2024-11-02 01:32:02 +00:00
James Read
9bcb2d80dc bugfix: Logs table only updating on start, not finish (#467)
Some checks are pending
Build Snapshot / build-snapshot (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Codestyle checks / codestyle (push) Waiting to run
DevSkim / DevSkim (push) Waiting to run
2024-11-02 00:47:13 +00:00
jamesread
de504f5f80 cicd: Lint issue 2024-11-01 23:23:02 +00:00
jamesread
8fe91101db feature: Log search box that is less visually offensive 2024-11-01 23:23:02 +00:00
James Read
8717997b0e feature: Hovering over the execution dialog title shows the action ID and execution ID (#468) 2024-11-01 22:49:09 +00:00
James Read
1bfb7c4b28 feature: Logs table creates an entry as soon as the execution is started (#464) 2024-11-01 21:23:22 +00:00
James Read
964dc7b48a feature: Rerun button on execution dialog, easily rerun actions! (#465) 2024-11-01 20:49:45 +00:00
James Read
ceb0a78180 bugfix: Logout cookies causing a conflict (#461) 2024-11-01 20:36:38 +00:00
James Read
9117163316 bugfix: Login form was not displayed if only OAuth2 was configured (#457)
* bugfix: Login form was not displayed if only OAuth2 was configured

* bugfix: npe in AuthOAuth2Provider

* test: Try and fix flakey tests
2024-10-27 08:56:28 +00:00
James Read
d3ad811ac5 bugfix: Removed hardcoded dependency on GitHub in OAuth2 flow (#458) 2024-10-26 22:30:08 +00:00
James Read
ee26fe6b50 ci github int tests settle (#459)
* ci: Allow more time for GitHub tests to settle

* ci: Run build-snapshot on any push, but dont dupe with PR
2024-10-26 22:10:33 +00:00
James Read
2950b59514 cicd: Devskim actions upgrade (#456) 2024-10-25 13:44:08 +00:00
James Read
be5ddda020 feature: freebsd support (#454) 2024-10-23 12:52:25 +00:00
James Read
16b07283b0 feature: Add riscv build! (#453) 2024-10-23 10:54:43 +00:00
jamesread
d7814ff6df bugfix: If a button is disabled in the API, render it disabled [skip ci] 2024-10-20 23:03:10 +01:00
James Read
be9b2a7c78 bugfix: Cookie expiry for OAuth2 & Local set to 1 year, not session (#451) 2024-10-20 21:58:12 +00:00
James Read
80e5b5b0c1 feature: Cleanup auth code (#444) 2024-10-19 19:33:27 +00:00
James Read
0283b51eca feature: Login/Logout links (#443)
* feature: Login/Logout links

* cicd: codestyle
2024-10-19 07:49:41 +00:00
jamesread
1af2e92132 feature: Local user login! 2024-10-18 01:20:04 +01:00
James Read
71ad5d2e3a feature: local auth! (#441)
* feature: local auth!

* cicd: contentLogin -> content-login

* bugfix: CSS codestyle
2024-10-17 13:23:01 +00:00
James Read
32b5fee108 bugfix: Fixed crash when requesting execution status that could not be found (NPE) (#440) 2024-10-15 10:48:55 +00:00
James Read
de81ec00fd feature: mix of bits (#439)
* feature: mix of bits

* bugfix: codestyle
2024-10-15 07:47:51 +00:00
Simon Dahlbacka
7cc07158ab bugfix: Turns out this should now be 403 instead (#438) 2024-10-14 13:53:23 +00:00
jamesread
3b8976fd51 feature: Login screen 2024-10-14 09:26:33 +01:00
jamesread
fb7e650267 feature: OAuth2 Redirect URL 2024-10-14 09:25:21 +01:00
jamesread
6a7187fb5b feature: OAuth2! :-D 2024-10-14 09:25:21 +01:00
James Read
b31cdf15a2 feature: Email argument type (#433)
* feature: Email argument type

* bugfix: Fix error if additional links is null
2024-10-13 18:40:16 +00:00
jamesread
6e0e0e8133 cicd: cleanup console log 2024-10-13 01:10:47 +01:00
jamesread
706441799f feature: Custom navigation links in the nav (sidebar/topbar) 2024-10-13 00:35:47 +01:00
jamesread
0b66bc7bbd cicd: Labels on issue templates [skip ci] 2024-10-13 00:35:28 +01:00
jamesread
86e876a9c9 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-10-12 23:18:29 +01:00
jamesread
8b33061bbb cicd: Remove unused Jenkinsfile 2024-10-12 23:15:06 +01:00
James Read
411f1bff1c feature: Style the currently selected section in nav, and few minor style improvements (#429)
* feature: Style the currently selected section in nav, and few minor style improvements

* bugfix: No unit on 0 length
2024-10-12 21:45:26 +00:00
James Read
eee4c4e404 bugfix: Auth in the wrong place (#430) 2024-10-12 21:14:09 +00:00
James Read
a187c8c8a0 feature: Slightly nicer looking logs and diagnostics pages (#427) 2024-10-11 17:40:40 +00:00
Simon Dahlbacka
35dca50863 Make it possible to redirect to a login url unless authenticated (#347)
* feature: Try to navigate to UrlOnUnauthenticated if set and not authenticated

* refactor: use better naming

* feature: default to allow guest
2024-10-11 17:36:31 +00:00
Simon Dahlbacka
00856f15a7 feature: pass ot_ args to shellAfterCompleted (#420)
* feature: pass ot_ args to shellAfterCompleted

* refactor: Implement this the right way

---------

Co-authored-by: James Read <contact@jread.com>
2024-10-11 14:59:02 +00:00
James Read
d1c67a9dd8 depbump: js micromatch 4.0.8 (#426) 2024-10-10 23:38:35 +00:00
James Read
6c289506c2 bugfix: Fixed unusual issues that slipped through with shellAfterCompleted (#425)
* bugfix: Fixed unusual issues that slipped through with shellAfterCompleted #419 #420

* cicd: Fix broken style lint
2024-10-10 23:15:03 +00:00
James Read
5d82ae7680 feature: Log username with each request #422 (#424) 2024-10-10 20:50:47 +00:00
James Read
9737886839 feature: Better websocket error message (#417) 2024-10-02 00:19:49 +00:00
James Read
1d9502d800 Feature better 404s (#416)
* feature: CSS on actions

* feature: Less crashes when things are not found
2024-10-01 23:21:37 +00:00
James Read
c0a18f82a5 feature: Link to log outputs (#415) 2024-10-01 23:17:09 +00:00
jamesread
9723a38ca1 bugfix: Crash on trying to start a non-existant action from the API 2024-10-01 21:19:17 +01:00
James Read
8258a758d2 bugfix: Dashboards with multiple spaces in the name could not be navigated properly (#408) 2024-09-16 22:36:40 +00:00
James Read
044613ae9a bugfix: Null action map, causing crash on startup actions (#407) 2024-09-11 16:19:52 +00:00
James Read
76c9171356 feature: Add OT_ vars to each execution (#406) 2024-09-10 22:52:46 +00:00
James Read
f8c330aae3 feature: Better feedback on shellAfterCommand, and mark OliveTin specific output with "OliveTin::" in logs (#403) 2024-09-02 22:59:19 +00:00
jamesread
d4bd7dd586 doc: shellAfterCompleted should use output, not stdout [skip ci] 2024-09-02 21:14:34 +01:00
Mitch Brown
fa20f6a63a Fixed typo 2024-09-01 00:22:45 +01:00
James Read
b9ce695616 feature: Nicer default colors (catpuccin/frappe (#395) 2024-08-30 20:48:17 +00:00
James Read
3f1dbf1130 bugfix: System users can now be used in ACLs (#396) 2024-08-30 20:48:07 +00:00
James Read
6413e51cf5 feature: Exec permission denied now marks the action as "blocked" and adds a log message. Timeouts also add a documentation link to the command output. Tags always set. (#398) 2024-08-30 20:36:13 +00:00
James Read
defcf6d26e fmt: Rebuilt ACL code to have less boilerplate (#397) 2024-08-30 20:30:44 +00:00
James Read
2671983c43 bugfix: Execution dialog duration no longer has issues displaying actions that were never started. (#394) 2024-08-30 20:28:27 +00:00
James Read
dc9653307b feature: Logs, column for tag, and left align status. Stop nav flash (#393) 2024-08-30 20:28:12 +00:00
jamesread
eb91eb33d5 bugfix: Log for http request mangling changed to DEBUG level 2024-08-30 21:27:56 +01:00
James Read
ddb803d9b5 feature: Sidebar hiding now pure CSS & theme reloading for devs (#391) 2024-08-25 23:47:43 +00:00
dependabot[bot]
c9095b4d67 build(deps): bump axios from 1.6.8 to 1.7.4 in /integration-tests (#387)
Bumps [axios](https://github.com/axios/axios) from 1.6.8 to 1.7.4.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.6.8...v1.7.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-14 22:14:35 +00:00
James Read
40158eda71 bugfix: Race condition on executor logs (#385) 2024-08-14 22:06:50 +00:00
dependabot[bot]
bbbbfceeb3 build(deps): bump github.com/docker/docker (#386)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.1.4+incompatible to 26.1.5+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.1.4...v26.1.5)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-14 22:06:06 +00:00
James Read
9ca1940834 feature: change all navigation to path based (#384)
* feature: change all navigation to path based

* bugfix: load default dashboard if actions is empty
2024-08-14 11:35:10 +00:00
James Read
37160a91f3 feature: take full page and display footer at bottom pf window (#383) 2024-08-14 06:56:30 +00:00
James Read
274d036f74 fmt: Cleanup terminal code (#381)
* fmt: Clean up OutputTerminal code

* fmt: Clean up OutputTerminal code
2024-08-09 19:04:57 +00:00
James Read
1fe0e49adb bugfix: #337 - Entity overwriting (#382) 2024-08-09 19:04:50 +00:00
James Read
7a7a07d9ad feature: Minor change to action timeout message to be more consistent with other logs (#380) 2024-08-09 14:53:02 +00:00
James Read
5b5fca0837 feature: enableCustomJs toggle to allow loading ./custom-webui/custom.js (#379) 2024-08-09 09:21:50 +00:00
James Read
fab0264d9b feature: Cleanup execution dialog, and log display status. (#378)
* feature: Cleanup execution dialog, and log display status.

* fmt: Remove empty block

* cicd: Use ActionStatusDisplay in test

* bugfix: missed promise

* bugfix: missed promise

* bugfix: Didnt return getText on ActionStatusDisplay
2024-08-08 20:46:46 +00:00
jamesread
8d839ee6ce bugfix: fsnotify event logs moved to DEBUG level, because info was spammy 2024-08-07 00:22:49 +01:00
jamesread
90efbf3159 fmt: #368 2024-08-07 00:21:02 +01:00
jamesread
17dd1b4158 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-08-07 00:17:42 +01:00
dependabot[bot]
e5f6d8ff50 build(deps): bump github.com/docker/docker (#372)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.0.2+incompatible to 26.1.4+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.0.2...v26.1.4)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-06 16:02:13 +00:00
jamesread
e183910b88 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-08-06 16:35:10 +01:00
James Read
8cd5b9fb46 feature: Trace log message on ExecRequest for debugging (#375) 2024-08-06 13:46:49 +00:00
wushuzh
6958445f83 Use windows compatible cmds and wait more time (#374)
* bugfix: change action request cnt type as Counter

* bugfix: fix type of act req count and typo

* bugfix: change to correct type of act req in TC

* bugfix: use Windows compatible cmds for test

* bugfix: wait more for slow test env

---------

Co-authored-by: wushuzh <wushuzh@outlook.com>
2024-08-06 13:43:16 +00:00
James Read
ef91294d5e cicd: Make grpc to fix codeql (#373) 2024-07-30 13:03:56 +00:00
jamesread
a36f286f8a cicd: Make grpc to fix codeql 2024-07-30 13:58:12 +01:00
wushuzh
d9e921950f bugfix: fix type of the prometheus metric act req as count (#370)
* bugfix: change action request cnt type as Counter

* bugfix: fix type of act req count and typo

* bugfix: change to correct type of act req in TC

---------

Co-authored-by: wushuzh <wushuzh@outlook.com>
2024-07-26 08:41:42 +00:00
wushuzh
ffcd19e748 bugfix: use cross-platform module filepath to set usedConfigDir (#369)
* bugfix: use filepath to set correct configDir in Windows

* test: improve unittest rep folder creation

---------

Co-authored-by: wushuzh <wushuzh@outlook.com>
2024-07-22 09:33:56 +00:00
jamesread
d0eb132b95 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-07-18 15:11:19 +01:00
jamesread
1cf971c092 feature: Better format for server dashboard 2024-07-18 15:11:06 +01:00
James Read
49f745be68 fmt: Set for setdir (#367) 2024-07-18 12:08:36 +00:00
wushuzh
b50824a705 feature: support basic dev tasks in Windows (#364)
* feature: support basic dev tasks in Windows

* feature: support front-end targets in Windows

---------

Co-authored-by: wushuzh <wushuzh@outlook.com>
2024-07-17 12:51:08 +00:00
James Read
69d1cc75a7 feature: css classes on displays (#363) 2024-07-16 10:01:31 +00:00
jamesread
a54ea505c9 bugfix: Allow . in enxtended variable paths 2024-07-15 22:20:49 +01:00
James Read
a1563b72ae Feature argument grid layout (#360)
* feature: Argument form now uses a grid layout, making the input boxes take up available room

* feature: Argument form now uses a grid layout, making the input boxes take up available room

* feature: Argument form now uses a grid layout, making the input boxes take up available room

* feature: Argument form now uses a grid layout, making the input boxes take up available room
2024-07-15 16:17:08 +00:00
James Read
31d7168aac feature: #350 Environment variable PORT can be used to override the default 1337, and internal services will calculate their port based on that (#358) 2024-07-15 14:28:53 +00:00
James Read
09016e1d5f feature: Entitiy data now serializes non-strings (#357) 2024-07-15 12:10:13 +00:00
James Read
652882350c cicd: Update login-action (#356) 2024-07-15 12:09:35 +00:00
James Read
20c4423799 feature: Argument labels will end with a :, unless they end with ?, : or . already (#355) 2024-07-15 08:24:54 +00:00
jamesread
bb90a5da92 feature: Use SVG icon for window maximize #343 2024-07-13 20:46:06 +01:00
jamesread
3ca3a2dd3c Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-07-13 20:43:21 +01:00
jamesread
510c48e1af bugfix: Restore default theme 2024-07-13 20:43:04 +01:00
James Read
3ac809c234 feature: Container images upgraded to Fedora 40. (#354) 2024-07-13 18:36:10 +00:00
James Read
9dd33bc3f9 bugfix: Empty environment variable names causing exec failures on Windows, thanks @sirjmann92 ! (#353) 2024-07-12 16:22:03 +00:00
James Read
897cc0e034 depbump: Upgrade Go to 1.21 (#352) 2024-07-11 22:33:36 +00:00
James Read
482ef0e5e8 feature: Helper scripts for ssh, themes, etc (#349)
* feature: Helper scripts for ssh, themes, etc

* cicd: Update goreleaser to support v2 .goreleaser.yml files
2024-07-07 22:10:33 +00:00
dependabot[bot]
e0678fc0a9 build(deps): bump github.com/rs/cors from 1.10.1 to 1.11.0 (#348)
Bumps [github.com/rs/cors](https://github.com/rs/cors) from 1.10.1 to 1.11.0.
- [Commits](https://github.com/rs/cors/compare/v1.10.1...v1.11.0)

---
updated-dependencies:
- dependency-name: github.com/rs/cors
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2024-07-07 07:01:33 +00:00
jamesread
9cb5574b99 feature: easy-ssh-docs 2024-07-07 01:06:43 +01:00
jamesread
c18b91f684 feature: Easy SSH 2024-07-07 00:55:22 +01:00
James Read
6622a6ded4 bugfix: Kill the process group, not just the parent process (#328), , thanks @ioqy, @vvrein (#346)
* bugfix: Kill the process group, not just the parent process (#328), thanks @ioqy, @vvrein

* bugfix: Kill the process group, not just the parent process (#328), thanks @ioqy, @vvrein

* bugfix: Kill the process group, not just the parent process (#328), thanks @ioqy, @vvrein
2024-07-04 00:12:28 +00:00
James Read
fb6aaa52c7 feature: New diagnostics page, showing SSH keys found. (#344) 2024-07-03 23:34:07 +00:00
James Read
a1adc2a85d bugfix: Output width in chrome (#345) 2024-07-03 23:33:58 +00:00
dependabot[bot]
3d9cb621dd build(deps-dev): bump braces from 3.0.2 to 3.0.3 in /integration-tests
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-04 00:34:34 +01:00
James Read
943b4c75aa feature: Password type (no validation) (#340) 2024-07-01 08:31:53 +00:00
James Read
fb972fae55 bugfix: Handle update failed update checks silently (#342) 2024-06-30 22:05:04 +00:00
dependabot[bot]
eb4f28dfda build(deps-dev): bump ws from 8.16.0 to 8.17.1 in /integration-tests (#335)
Bumps [ws](https://github.com/websockets/ws) from 8.16.0 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.16.0...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 05:25:03 +00:00
James Read
e36fedf4b2 Check for updates default disabled (#333)
* feature: Checking for updates is now disabled by default (#93)

* feature: Default config has checkForUpdates: false (it defaults to false anyway) to make people aware of the update checking feature
2024-06-04 18:37:59 +00:00
James Read
362a97c59e feature: No more tracking in update checking! :-) (#93) (#332) 2024-06-04 12:21:11 +00:00
James Read
c82beb61a9 feature: Vastly improved logs and tests for killing actions (#330)
* bugfix: Sleep testing

* feature: Vastly improved testing for killing actions (#328)

* cicd: Add find-flakey-tests target

* cicd: Better debugging for domStatus

* cicd: Debug flakey test

* cicd: Debug flakey test

* cicd: Is cors messing with killaction?

* cicd: Slip broken test in CI

* cicd: Skip broken test in CI

* cicd: Skip broken test in CI
2024-06-03 16:19:15 +00:00
James Read
00a8a0bf69 fmt: Center argument-wrapper #327, point 5 (#331) 2024-06-02 22:09:24 +00:00
James Read
ffc17dd73b bugfix: Terminal width fitting (#329)
* bugfix: Terminal width fitting

* bugfix: Terminal width fitting

* fmt: css codestyle issue presumably from pkg upgrade
2024-06-02 11:44:23 +00:00
James Read
238abc95ad feature: Customizable default directory, back and action icons (#326) 2024-05-31 22:43:05 +00:00
James Read
ac0f3ab6f8 feature: Live command output! (#325)
* feature: Live command output WIP

* cicd: Fix live command output build errors

* feature: Live command output WIP, remove stdout/stderr split

* feature: Live command output

* Restore output im stepExecAfter, rename so to ost for OutputStreamer

* Update executor.go

* feature: Remove output from log message, bad for long messages, binary output, and security

* feature: Live command output WIP
2024-05-31 20:56:49 +00:00
James Read
4bac315568 feature: The executor now controls the public action map - meaning actions work without the API, and pages load faster (and much more!) (#324)
* feature: The executor now controls the public action map

* bugfix: Build the action map if there are no entities!

* bugfix: Sort by title if the actions have the same config order
2024-05-27 22:52:06 +00:00
James Read
daa48b5a73 feature: OliveTin now relies on websocket, and will show a big error if it isn't available (#323)
* feature: OliveTin now relies on websocket, and will show a big error if it isnt available

* feature: OliveTin now relies on websocket, and will show a big error if it isnt available
2024-05-26 18:21:54 +00:00
James Read
c70cc864ee feature: Websocket URL is now relocatable (#322)
* feature: Websocket URL is now relocatable

* feature: Websocket URL is now relocatable
2024-05-26 17:03:12 +00:00
James Read
dc7ff40da6 bugfix: #316 Entity file change debouce timer now uses delay after initial event (#321) 2024-05-26 17:01:37 +00:00
James Read
046ffaecf4 feature: Displays now have centered text, and "fit in" a bit better (#320) 2024-05-26 16:54:11 +00:00
James Read
3904f8563d feature: Refresh dashboards when entity files change. (#319)
* feature: Refresh dashboards when entities change

* feature: Refresh dashboards when entities change

* bugfix: Concurrency, lock around websocket write
2024-05-24 22:10:38 +00:00
James Read
18423a9888 bugfix: Default load dashboard when it contains multiple spaces (#318) 2024-05-23 08:22:08 +00:00
James Read
8fbbd9b32c feature: displays have basic styling (#317) 2024-05-23 08:21:57 +00:00
guangwu
7e34efd453 chore: remove refs to deprecated io/ioutil (#309)
Signed-off-by: guoguangwu <guoguangwug@gmail.com>
Co-authored-by: James Read <contact@jread.com>
2024-05-13 15:20:58 +00:00
jamesread
9d33e62d34 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-05-13 15:39:54 +01:00
jamesread
6b2bc0adc0 cicd: run build-snapshot against prs 2024-05-13 15:39:42 +01:00
James Read
80083fedab bugfix: Race condition in stringvariables (#311) 2024-05-13 14:10:44 +00:00
James Read
1ab35fdb36 feature: #Logs and similar in the address bar to load relevant section (#306) (#310) 2024-05-13 12:12:04 +00:00
James Read
f43ece4263 feature: Better sosreports (#308) 2024-05-13 07:01:45 +00:00
jamesread
ea1ce82ded fmt: Change publicid map debug URL 2024-05-13 01:04:21 +01:00
jamesread
c24adaafcb Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-05-06 23:01:09 +01:00
jamesread
c42875b107 cicd: update package-lock.json 2024-05-06 23:00:35 +01:00
jamesread
447ad36d4d cicd: update package-lock.json 2024-05-06 23:00:05 +01:00
jamesread
71dc467b31 cicd: Quick target to run default integration tests 2024-05-06 22:59:49 +01:00
James Read
8625e1fc0a fmt: Clean REST API Testing (#307)
* fmt: Clean REST API Testing

* fmt: Clean REST API Testing
2024-05-06 21:44:12 +00:00
James Read
638e5b7fe1 doc: fix default licenses in package.json (#304) 2024-05-01 07:38:47 +00:00
James Read
f467c69e8f Argument suggestions (#301)
* feature: Suggestions for inputs

* feature: #103 Completed suggestions support
2024-04-28 08:55:40 +00:00
James Read
8fd98874e2 feature: Save logs! #174 (#300) 2024-04-28 07:58:25 +00:00
James Read
dc6f6c2896 feature: Kill support in the UI (#297)
* feature: Kill command API (wip)

* feature: Kill support in the UI
2024-04-27 21:51:45 +00:00
James Read
a783fc8cd4 feature: Arguments are now also passed as ENV variables (#296) 2024-04-26 23:03:17 +00:00
James Read
6a16a7c6c2 fmt: onfileindir (#295) 2024-04-26 23:02:40 +00:00
James Read
ceb215a6dc bugfix: #272 if the dialog is already open, close it (#294) 2024-04-26 23:02:17 +00:00
James Read
d6cb634824 feature: Extra file info using onfileindir (#293) 2024-04-26 22:05:28 +00:00
James Read
500419307b Nullable args (#292)
* feature: Argument values can be null be default. Use RejectNull to change.

* feature: Argument values can be null be default. Use RejectNull to change.
2024-04-26 17:36:33 +00:00
James Read
12cf0013e2 feature: extra args for fileindir (#291) 2024-04-25 23:32:58 +00:00
James Read
318d4fe0d0 cicd: Reduce test flake and add lots more debugging info (#290) 2024-04-24 15:22:15 +00:00
James Read
a3aee3603f More screenshots link (#289)
* More screenshots link

* bugfix: wip

* cicd: Test flakey tests

* cicd: more tests

* cicd: more tests

* cicd: Try a 10s timeout

* cicd: Better debugging of process start / stop

* cicd: Better debugging of process start / stop

* cicd: Possibly unflaky tests
2024-04-23 20:54:54 +00:00
jamesread
7c6f36c600 doc: Update images 2024-04-22 23:34:36 +01:00
James Read
dde8a9cbb6 cicd: More test coverage that would have caught recent issues (#287)
* cicd: More test coverage that would have caught recent issues

* bugfix: test flake

* bugfix: test flake

* cicd: Reduce test flake

* cicd: more test coverage

* depbump: testing packages
2024-04-22 21:40:48 +00:00
James Read
dfca712cb1 bugfix: Update icon on buttons (#288) 2024-04-22 19:02:59 +00:00
James Read
5057ba2e1c bugfix: Start filewatcher on different goroutines (#286) 2024-04-21 19:51:49 +00:00
jamesread
8f1dfffa49 fmt: Clean up log statement 2024-04-21 20:12:47 +01:00
James Read
6991724258 bugfix: Unexpected message #283 (#284) 2024-04-20 19:58:38 +00:00
James Read
09e1de06ce bugfix: Dont rename logo filenames (#282) 2024-04-19 23:27:13 +00:00
James Read
5a644b0856 bugfix: The web interface now refreshes when the config file is changed! (#281) 2024-04-19 23:11:40 +00:00
James Read
86b2187236 cicd: Increase coverage (#280) 2024-04-19 21:56:45 +00:00
James Read
fafacfeafb bugfix: Move all inotify to filehelper (#279) 2024-04-19 21:56:21 +00:00
James Read
362019738d feature: #267 add jq to containers (#278) 2024-04-19 16:16:23 +00:00
dependabot[bot]
1a0ba6c6b1 build(deps): bump golang.org/x/net from 0.22.0 to 0.23.0 (#277)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 16:16:09 +00:00
jamesread
4c2cc5da1c bugfix: Remove debug log left in the code 2024-04-19 00:58:05 +01:00
James Read
30e2aa141b feature: Rate limit for actions (#76) (#275) 2024-04-18 23:51:59 +00:00
dependabot[bot]
3768a57eaa build(deps): bump github.com/docker/docker (#274)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.0.0+incompatible to 26.0.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.0.0...v26.0.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-18 23:49:41 +00:00
James Read
db5de9be97 feature: #135 Permissions for logs (#273) 2024-04-18 20:52:04 +00:00
James Read
f60ab6ce85 feature: Show username in header (#270) 2024-04-15 00:09:55 +00:00
James Read
43c48aef17 feature: Renamed authJwtSecret to authJwtHmacSecret (#271)
* feature: Renamed authJwtSecret to authJwtHmacSecret

* feature: rename authJwtSecret
2024-04-15 00:01:30 +00:00
James Read
8341b1d6d0 feature: Huge JWT improvements for CloudFlare, etc (#269) 2024-04-14 22:59:45 +00:00
jamesread
dd11961a11 bugfix: custom-webui prefix 2024-04-12 22:07:06 +01:00
James Read
3de819a0e9 feature: add prometheus metrics (#268)
* feature: add prometheus metrics

* bugfix: ixed issue with path
2024-04-11 23:23:40 +00:00
James Read
0b546eaeb5 Improve screenshots visibility 2024-04-11 11:13:10 +01:00
jamesread
558e1819bf doc: Updated mobile screenshot 2024-04-11 10:20:03 +01:00
James Read
9d6afa2fe7 doc: typo #266 (#267) 2024-04-11 06:23:24 +00:00
James Read
5f3a967515 depbump: 2024-04 (#265)
* depbump: 2024-04

* go mod tidy
2024-04-10 23:03:25 +00:00
jamesread
179f1be19a bugfix: Null JWT verifier 2024-04-11 00:04:34 +01:00
James Read
f13a5c070a feature: JWT Validation wip for Cloudflare (#264) 2024-04-10 22:14:33 +00:00
James Read
9476d052b6 cicd: Dont build snapshot on tag (#263) 2024-04-10 20:14:18 +00:00
James Read
1d446ace04 custom-webui and faster theme loading (#262)
* feature: custom-webui and faster theme loading

* feature: custom-webui and faster theme loading
2024-04-09 08:26:18 +00:00
jamesread
3a8d8706a6 bugfix: remove underline from sidebar links 2024-04-04 20:37:25 +01:00
James Read
910418925a bugfix: dark mode headr (#261) 2024-04-02 22:57:54 +00:00
James Read
1b539df2aa bugfix: rounded buttons for folders (#260) 2024-04-02 22:41:59 +00:00
James Read
f5794e57ee bugfix: sidebar nav wont tab when hidden (#259) 2024-04-02 22:40:46 +00:00
James Read
7dd1d0a7fc Markup optimisations (#258)
* feature: Cleanup markup for accessibility

* feature: Cleanup markup for accessibility

* feature: Cleanup markup for accessibility

* feature: Cleanup markup for accessibility

* bugfix: Broken test

* feature: Cleanup markup for accessibility
2024-04-02 21:58:23 +00:00
James Read
ce670cf58c Bug ignored signals (#257)
* bugfix: Signals, like SIGKILL etc were ignored. Now we capture them and add the err to stderr

* bugfix: Signals, like SIGKILL etc were ignored. Now we capture them and add the err to stderr
2024-04-01 20:30:34 +00:00
jamesread
c4d1a2a105 cicd: Bug in dockerfile.arm64 2024-03-24 23:06:37 +00:00
James Read
709223bd46 feature: Removed unimplemented CSS rules from config, but added ID for buttons to allow for easy theming (#255) 2024-03-24 22:35:19 +00:00
jamesread
19b4340e18 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-03-24 22:20:58 +00:00
jamesread
a5a1c64dcb bugfix: Entity buttons didnt support popupOnStart 2024-03-24 22:20:39 +00:00
dependabot[bot]
2b7bdffe41 build(deps): bump follow-redirects in /integration-tests (#248)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-24 21:32:11 +00:00
dependabot[bot]
a2df96354e build(deps): bump github.com/docker/docker (#249)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 25.0.3+incompatible to 25.0.5+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v25.0.3...v25.0.5)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-24 21:31:58 +00:00
James Read
8b49eeff98 bugfix: Regex validation client side was not running (#254) 2024-03-24 21:31:23 +00:00
James Read
a8c4db197d Bug webui search order (#253)
* bugfix: Search order of webui directories was not deterministic

* bugfix: webui dir search order was not deterministic

* bugfix: webui dir search order was not deterministic

* bugfix: webui dir search order was not deterministic
2024-03-23 22:14:08 +00:00
James Read
1319f314ff Argument suggestions (#252)
* feature: Suggestions for inputs

* feature: #103 Completed suggestions support
2024-03-23 21:52:53 +00:00
James Read
781abaaf40 feature: Entitiys in dropdowns #247 (#251) 2024-03-22 23:49:41 +00:00
James Read
744debc00a feature: add apprise (#250) 2024-03-22 19:00:30 +00:00
James Read
77321c1bcd cicd: Try {configdir}/var/entities/ when looking for entity files as well (#246) 2024-03-15 10:07:51 +00:00
James Read
c97fd60c25 feature: #56 custom tegex for arguments (#244) 2024-03-08 22:17:10 +00:00
James Read
2fb40ff443 feature: Exec on Calendar file support (#243)
* feature: Exec on calendar file

* feature: support for datetime args

* feature: Schedule commands based on seconds
2024-03-08 20:31:51 +00:00
James Read
a992ef84f5 doc: YouTube Banner (#242) 2024-03-07 17:26:15 +00:00
James Read
8fce4c79b6 Update README.md 2024-03-07 17:11:33 +00:00
jamesread
7e4aa9ebbe doc: Updated demo video 2024-03-06 08:27:54 +00:00
James Read
522e5bb129 cicd: Flakey test on dropdowns (#241) 2024-03-05 17:23:17 +00:00
James Read
1a97836dc3 feature: erm, added support 200,000 icons via iconify (#240) 2024-03-05 16:59:46 +00:00
jamesread
e1bc9276bc doc: Add rounded screenshot 2024-03-05 16:10:43 +00:00
James Read
555b6929e4 feature: Rounded buttons... because apparently they look modern?! (#239)
* feature: Rounded buttons... because apparently they look modern?!

* bugfix: Logo in readme
2024-03-05 14:53:50 +00:00
jamesread
ee4d61e476 bugfix: Logo in readme 2024-03-05 14:48:48 +00:00
James Read
f15235d120 Msot recent execution output on the dashboard. (#238)
* feature: Support for most recent action output on dashboard

* feature: Support for most recent action output on dashboard
2024-03-04 23:33:50 +00:00
jamesread
471d5726f6 bugfix: Switch to first dashboard if actions page is empty 2024-03-04 23:37:53 +00:00
jamesread
e344530fc0 bugfix: Switch to first dashboard if actions page is empty 2024-03-04 22:47:45 +00:00
jamesread
29fe38eff4 bugfix: Switch to first dashboard if actions page is empty 2024-03-03 23:09:15 +00:00
jamesread
25e643371e Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-02-29 23:21:16 +00:00
jamesread
32cb8dd873 feature: entity filepaths are relative to the config dir 2024-02-29 23:20:48 +00:00
James Read
12cc61fba5 feature: Nicer container dashboard example in the default config (#235) 2024-02-29 21:27:54 +00:00
James Read
fe40731df3 bugfix: PageTitle works again (#236) 2024-02-29 21:27:34 +00:00
jamesread
7464ca5543 fmt: typo in "dashboards" 2024-02-29 16:28:04 +00:00
jamesread
ce83521429 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2024-02-28 23:18:40 +00:00
jamesread
27ab530ba6 bugfix: StartAction responds with used tracking ID, not necessarily the requested tracking ID 2024-02-28 23:18:31 +00:00
James Read
843121f5fd bugfix: #233 switch sidebar to 100dvh (#234) 2024-02-28 21:32:44 +00:00
jamesread
d26c469107 bugfix: #233 switch sidebar to 100dvh 2024-02-28 21:27:29 +00:00
James Read
97453260eb bugfix: #230 Set public-url in parcel to . (#231) 2024-02-28 17:40:43 +00:00
jamesread
06b85c5769 cicd: I am tired and cannot type it seems 2024-02-27 01:18:28 +00:00
jamesread
5bb21031ac cicd: extra files for all ghe dockers 2024-02-27 01:09:13 +00:00
jamesread
256d6139b7 cicd: Add extra files needed for docker 2024-02-27 00:24:25 +00:00
jamesread
aa342047ed cicd: Dont run the docker ps in default config 2024-02-27 00:10:07 +00:00
jamesread
ea663f8286 cicd: Vagrant, need /opt/OliveTin-configs created 2024-02-25 23:04:31 +00:00
jamesread
e953dfb017 fmt: Ansible -> Automation, robot icon 2024-02-25 22:45:12 +00:00
jamesread
54170f3da6 feature: Better default config file, restart icons 2024-02-25 22:39:29 +00:00
jamesread
77ec2fea63 feature: sosreport in the browser outputs text/plain 2024-02-25 21:10:47 +00:00
jamesread
83beab4c92 bugfix: onExecutionFinished ignores actions it cannot find 2024-02-25 00:49:17 +00:00
jamesread
29b6d12454 feature: Trigger another action after first action completes 2024-02-25 00:29:55 +00:00
jamesread
866a38f286 bugfix: All execution tracking IDs must now be unique 2024-02-25 00:11:35 +00:00
jamesread
0ec2e7069b bugfix: All previous entity files are removed when file is updated 2024-02-25 00:01:51 +00:00
jamesread
f3934b1906 bugfix: Default path for entities files 2024-02-24 22:28:52 +00:00
jamesread
fb2bb63d15 feature: comfig file provided with docker volume, upgrade to f38 2024-02-24 07:27:54 +00:00
jamesread
58cc04298f feature: Popup execution dialog from logs 2024-02-23 23:52:41 +00:00
jamesread
42535feadf feature: Hide actions in sidebar if it is empty 2024-02-23 22:43:52 +00:00
jamesread
baa690ffc2 feature: include entities in packages 2024-02-23 22:19:45 +00:00
jamesread
d13f0a7acf fmt: regex raw string 2024-02-23 21:36:28 +00:00
jamesread
b747199528 fmt: Removed uneeded assign 2024-02-23 21:35:55 +00:00
jamesread
6a1af44aa0 fmt: actionName -> actionTitle 2024-02-23 21:30:35 +00:00
jamesread
6da050e3b9 bugfix: Allow static IDs 2024-02-23 21:30:13 +00:00
jamesread
b8f23ce80c cicd: fix broken test, hopefully 2024-02-23 17:19:36 +00:00
jamesread
865bef532a bugfix: Titles on every button 2024-02-23 16:55:09 +00:00
jamesread
6fb158190d cicd: make grpc is not working 2024-02-23 16:27:31 +00:00
jamesread
0e3f9c8ceb bugfix: #192 repeating logs 2024-02-23 16:09:58 +00:00
jamesread
4dba6fd0f9 depbump: everything 2024-02-23 00:33:02 +00:00
jamesread
fbbf168e88 cicd: fix tests 2024-02-23 00:08:50 +00:00
jamesread
2cd739c3b4 cicd: make grpc for codeql 2024-02-22 23:57:50 +00:00
jamesread
a8e770726a bugfix: unittests 2024-02-22 23:42:40 +00:00
jamesread
0c5a99cc03 bugfix: Use better hash algo 2024-02-22 23:31:13 +00:00
jamesread
2dee246593 bugfix: sidebar fixed 2024-02-22 23:22:21 +00:00
jamesread
381bf59fbd feature: The mega dashboards & entities commit. 2024-02-22 23:16:43 +00:00
James Read
fddf83f27d https everywhere 2024-02-10 12:23:49 +00:00
James Read
3d3e19e26a Create devskim.yml (#229) 2024-02-10 10:44:39 +00:00
jamesread
c082a5438a cicd: wip 2024-02-09 23:47:27 +00:00
jamesread
5adab1091f cicd: Utility to get the latest snapshot 2024-02-09 23:01:24 +00:00
jamesread
290a2ec91b cicd: upgrade codeql 2024-02-09 22:38:18 +00:00
jamesread
9ebeabac51 cicd: update upload-artifact 2024-02-09 22:27:59 +00:00
jamesread
b5e2c8d6b8 cicd: Include all of webui/* in packages now it is processed by parcel 2024-02-09 22:09:13 +00:00
jamesread
a482b6a3c2 cicd: Upgrade goreleaser, fix deprecations 2024-02-09 22:08:45 +00:00
jamesread
f348de6a03 cicd: Need to build webui-dist before integration tests 2024-02-09 21:57:10 +00:00
jamesread
8df8978516 cicd: upgrade actions 2024-02-09 21:22:10 +00:00
jamesread
086d8fd21c feature: HTML/JS/CSS minifiction and cache busting 2024-02-09 17:01:39 +00:00
jamesread
7dce77adcf cicd: These are just testing certs, but they do not need to be in git 2024-02-09 16:17:42 +00:00
James Read
917a0469d8 Proxy integration tests (#228)
* cicd: Proxies included in integration testing

* cicd: proxy configs for integration testing
2024-02-09 16:12:25 +00:00
James Read
c12431d8a3 feature: popupOnStart allows for many feedback options when actions are started (#227) 2024-02-08 21:54:08 +00:00
jamesread
dc0cf33d37 feature: center align the fieldset titles 2024-02-07 10:58:49 +00:00
jamesread
15d332012f feature: Buttons are now fixed-width, so align to center 2024-02-07 10:53:46 +00:00
jamesread
99460beafd feature: box icon for containers 2024-02-07 10:52:46 +00:00
James Read
5b0cfb5c33 feature: entities wip (#226) 2024-02-07 09:36:57 +00:00
James Read
759e747f54 feature: readyz API endpoint support (#225) 2024-02-07 09:36:50 +00:00
James Read
6892a679ee feature: Dashboards, at long last (#224)
* feature: Dashboards, at long last

* fmt: action button IDs now use hypens. Removed ;
2024-02-07 08:54:22 +00:00
jamesread
1b13a2bc4b cicd: setup-go v5 2024-02-07 08:47:48 +00:00
jamesread
63e8e10a6d cicd: checkout v4 2024-02-07 08:47:00 +00:00
James Read
0615a7e353 feature: #202 Cron seconds support optional. Example in default config. (#223) 2024-02-02 21:58:30 +00:00
James Read
16acf9db91 bugfix: Execution dialog would only show first result (#222)
* bugfix: execution-dialog

* bugfix: execution-dialog
2024-02-02 21:22:29 +00:00
James Read
0c19ba59d2 Markup improvements (#220)
* bugfix: various markup improvements, accessibility

* bugfix: various markup improvements, accessibility
2024-01-27 23:43:30 +00:00
James Read
143528d919 bugfix: #216 - fix scroll in chrome (#219) 2024-01-27 22:09:12 +00:00
dependabot[bot]
07cdf378f6 build(deps): bump follow-redirects in /integration-tests (#214)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-11 08:35:50 +00:00
James Read
f559a2f9c9 feature: #69 - Add action confirmation (#208)
* feature: #69 - Add action confirmation

* fmt: style
2023-12-28 23:50:39 +00:00
James Read
6b3e9e4676 feature: clock and ashtonished emoji (#207) 2023-12-28 23:48:27 +00:00
James Read
3f72b7cc0d bugfix: Argument form on smaller screens (#209) 2023-12-28 23:47:02 +00:00
James Read
4ce5b0e645 cicd: Improve tests (#205)
* cicd: make it easier to grab snapshot builds

* cicd: Better support for running tests against VMs

* Update multipleDropdowns.js
2023-12-28 22:04:47 +00:00
James Read
e92ab8d741 #201 - startActionByAlias should be HTTP GET (#206) 2023-12-28 20:34:55 +00:00
jamesread
6b0e414932 More debug info for auth 2023-12-21 01:26:17 +00:00
jamesread
00927f3ba3 Revert "ACL check was broken, addToEveryAction should come first (#204)"
This reverts commit b0faecfa75.
2023-12-21 01:22:18 +00:00
James Read
b0faecfa75 ACL check was broken, addToEveryAction should come first (#204) 2023-12-21 00:07:40 +00:00
James Read
c15449f99a #197 Dialog has min-width, but should be max-width (#203) 2023-12-20 22:07:56 +00:00
dependabot[bot]
68f04c0912 build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#199)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 13:22:07 +00:00
James Read
c3c010443f feature: Better UI for execution buttons (#195) 2023-12-17 04:19:48 +00:00
dependabot[bot]
15c8abf3d6 build(deps): bump axios and wait-on in /integration-tests (#196)
Bumps [axios](https://github.com/axios/axios) to 1.6.2 and updates ancestor dependency [wait-on](https://github.com/jeffbski/wait-on). These dependencies need to be updated together.


Updates `axios` from 0.27.2 to 1.6.2
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.27.2...v1.6.2)

Updates `wait-on` from 7.0.1 to 7.2.0
- [Release notes](https://github.com/jeffbski/wait-on/releases)
- [Commits](https://github.com/jeffbski/wait-on/compare/v7.0.1...v7.2.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: indirect
- dependency-name: wait-on
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 11:53:11 +00:00
James Read
d0f74c1ab7 feature: Additional APIs for StartAction (#188) 2023-10-31 18:17:35 +00:00
dependabot[bot]
ca921c1890 build(deps): bump github.com/docker/docker (#186)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 24.0.5+incompatible to 24.0.7+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v24.0.5...v24.0.7)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-31 10:05:37 +00:00
jamesread
3b60bbce0a feature: Reduce websocket logging 2023-10-25 23:03:34 +01:00
James Read
8f6b384fe6 Notification support (#183)
* feature: #158 shellAfterComplete support for notifications

* fmt: reduce cyclo
2023-10-25 21:32:18 +00:00
dependabot[bot]
4d04264caa build(deps): bump google.golang.org/grpc from 1.57.0 to 1.57.1 (#181)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 21:31:31 +00:00
James Read
912fd8089e Feature search logs (#182)
* feature: search logs wip

* feature: Log search
2023-10-25 21:29:41 +00:00
James Read
5739091773 feature: Add actionTitle to blocked log messages (#179) 2023-10-25 19:38:27 +00:00
James Read
a09c278585 bugfix: #172 Recent UI changes totally broke dark mode (#180) 2023-10-25 19:37:43 +00:00
jamesread
a7fb49a11b feature: Tidy up error display, and refresh loop 2023-10-24 12:33:32 +01:00
James Read
3db8ae53b5 bugfix: #173 Websocket fixes 1) The upgrader was refusing reverse proxies, 2) The upgrader was "listening" on /, not /websocket (#177) 2023-10-24 04:48:16 +00:00
James Read
311f9a1d00 feature: Reduce debug log spam in ACL/getDashboardComponents (#176) 2023-10-24 04:43:38 +00:00
jamesread
50204f8180 feature: #175 Print verison with --version 2023-10-23 15:59:38 +01:00
jamesread
d639a802dc cicd: Fix syntax issue with setting date 2023-10-12 23:35:37 +01:00
jamesread
f41eafe3bd cicd: Fix date in artifact name 2023-10-12 23:22:42 +01:00
dependabot[bot]
8b080eb3cc build(deps): bump golang.org/x/net from 0.14.0 to 0.17.0 (#171)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2023-10-12 21:30:14 +00:00
jamesread
268d8a3a90 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2023-10-12 09:23:58 +01:00
jamesread
44d6c40c27 cicd: Try to add date to integration test artifacts - easier to sort when downloaded 2023-10-11 22:03:40 +01:00
jamesread
9522e25b1d cicd: bugfix variable name 2023-10-09 23:11:04 +01:00
jamesread
db475895ca Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2023-10-09 22:55:28 +01:00
jamesread
dc33509127 cicd: Minor tweaks in workflow, version bump 2023-10-09 22:54:02 +01:00
James Read
2ada67be04 Migrate integration-test infrastucture from Cypress to Selenium+Mocha (#170)
* cicd: Move cypress to selenium+mocha

* cicd: with is not supported unless using an a container

* cicd: relative path to mocha

* cicd: the integration-tests runner now starts/stops OliveTin

* cicd: Knowing the CWD helps debugging

* cicd: Headless chrome

* cicd: wait for integration-test server to be started

* fmt: Mostly fix isses from eslint

* cicd: #169 - Test multiple combo boxes

* fmt: let should be const

* cicd: Remove cypress entirely
2023-10-09 21:44:29 +00:00
jamesread
77b17604f3 feature: WIP - a functioning history popup 2023-10-06 09:27:44 +01:00
James Read
d169b3f2b1 feature: #146 Support for maxConcurrent (#168) 2023-10-05 01:22:08 +01:00
James Read
c8210568eb feature: #146 Support for maxConcurrent (#164) 2023-10-04 23:55:35 +00:00
James Read
2ea6430a3b cicd: Remote node_modules from integration tests upload (#167) 2023-10-04 23:50:58 +00:00
dependabot[bot]
ac5f997f85 build(deps-dev): bump postcss from 8.4.23 to 8.4.31 in /webui (#165)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.23 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.23...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2023-10-04 23:44:24 +00:00
jamesread
e1930c0899 fmt: codestyle 2023-10-05 00:21:02 +01:00
jamesread
020281c1e6 cicd: integration tests against main config 2023-10-04 23:54:34 +01:00
jamesread
9dc81a6280 cicd: . not in path 2023-10-04 22:12:39 +01:00
jamesread
a9906addff cicd: start/stop server for integration tests, update checkout action 2023-10-04 22:06:54 +01:00
jamesread
37269cef02 fmt: reduce cyclo 2023-10-04 21:42:35 +01:00
James Read
186ec00de7 cicd: cypress path to exe 2023-10-04 14:34:39 +01:00
jamesread
abd13b756c cicd: Disable a broken test for now 2023-10-04 10:33:37 +01:00
jamesread
6851683d94 cicd: Include unit tests and integration tests 2023-10-03 23:24:57 +01:00
jamesread
2b4a3ab137 bugfix: broken unit tests 2023-10-03 23:24:36 +01:00
jamesread
6d21bbe03a bugfix: style lint 2023-09-28 23:16:37 +01:00
jamesread
6f4a0e68a7 bugfix: sidebar link style 2023-09-28 23:05:12 +01:00
jamesread
3de0f38049 fmt: trailing spaces 2023-09-28 22:32:16 +01:00
jamesread
216ccbfcef bugfix: Timestamp "IDs" need to be a string 2023-09-28 22:24:35 +01:00
jamesread
66b012cd55 Merge branch 'jamesread-patch-1' 2023-09-27 22:59:03 +01:00
jamesread
8339bd3cb1 Merge branch 'exec-on-new-file' 2023-09-27 22:57:35 +01:00
dependabot[bot]
e93c62b06d build(deps): bump @cypress/request and cypress in /integration-tests (#159)
Bumps [@cypress/request](https://github.com/cypress-io/request) to 3.0.1 and updates ancestor dependency [cypress](https://github.com/cypress-io/cypress). These dependencies need to be updated together.


Updates `@cypress/request` from 2.88.12 to 3.0.1
- [Release notes](https://github.com/cypress-io/request/releases)
- [Changelog](https://github.com/cypress-io/request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/request/compare/v2.88.12...v3.0.1)

Updates `cypress` from 12.17.4 to 13.2.0
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/cypress/compare/v12.17.4...v13.2.0)

---
updated-dependencies:
- dependency-name: "@cypress/request"
  dependency-type: indirect
- dependency-name: cypress
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2023-09-26 21:30:20 +00:00
James Read
43ceb33b53 feature: onfileindir (#161)
* feature: onfileindir

* fmt: ActionButton.js
2023-09-26 21:29:11 +00:00
James Read
ae0b45c308 Merge branch 'main' into exec-on-new-file 2023-09-26 22:24:48 +01:00
James Read
bbaeff00f3 fmt: ActionButton.js (#162) 2023-09-26 21:24:28 +00:00
jamesread
75a9697586 fmt: ActionButton.js 2023-09-26 22:09:42 +01:00
jamesread
77bd37ca90 feature: onfileindir 2023-09-26 22:04:58 +01:00
James Read
3a44a6a3b4 fmt: ActionButton.js (#160) 2023-09-24 23:57:23 +01:00
James Read
604d956d0c fmt: ActionButton.js 2023-09-24 23:57:01 +01:00
jamesread
822327edfc Now works in insecure contexts 2023-09-24 23:29:51 +01:00
jamesread
3ea14f1353 Merge branch 'main' of github.com:OliveTin/OliveTin 2023-09-23 06:43:52 +01:00
jamesread
7dbc077f76 cicd: Cypress upgrade 2023-09-23 06:42:20 +01:00
James Read
e8cb661938 feature: #146 Support for maxConcurrent (#156) 2023-08-25 15:30:58 +00:00
jamesread
e5a870ed94 feature: websocket implemenation at last! 2023-08-25 15:11:29 +01:00
jamesread
6116e954ba cicd: Useful for development settings 2023-08-25 15:09:24 +01:00
jamesread
56ef7ce95c fmt: fix cyclo complexity in recent jwt key merge 2023-08-24 12:56:03 +01:00
Bernard Crnković
6e2e585175 add support for asymmetric crypto based jwt signatures (#145)
* add support for asymmetric crypto based jwt signatures

* wip: e2e test example

* wip: rsa key parse error...

* fix: test works

---------

Co-authored-by: James Read <contact@jread.com>
2023-08-24 12:33:10 +01:00
jamesread
8c1c0c6029 cicd: Ensure consistency in setup-go 2023-08-24 12:20:35 +01:00
jamesread
11dad79794 fmt: Added pre-commit, fixed a few lint errors, npn updated webui 2023-08-24 12:17:55 +01:00
jamesread
4b3485145f fmt: ws -> window.ws 2023-08-24 12:12:47 +01:00
jamesread
4b5a579b0b fmt: codestyle formatting 2023-08-24 12:11:28 +01:00
jamesread
07bd09473c Merge branch 'websocket' 2023-08-24 11:54:44 +01:00
jamesread
adba3b0d4b cicd: air config file 2023-08-24 11:54:14 +01:00
jamesread
f6162c58f2 feature: websocket progress 2023-08-24 11:52:23 +01:00
jamesread
ed949d1dd8 feature: websocket progress 2023-08-24 11:45:29 +01:00
dependabot[bot]
5d94de418b build(deps): bump tough-cookie and @cypress/request (#154)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) and [@cypress/request](https://github.com/cypress-io/request). These dependencies needed to be updated together.

Updates `tough-cookie` from 2.5.0 to 4.1.3
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v2.5.0...v4.1.3)

Updates `@cypress/request` from 2.88.10 to 2.88.12
- [Release notes](https://github.com/cypress-io/request/releases)
- [Changelog](https://github.com/cypress-io/request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/request/compare/v2.88.10...v2.88.12)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
- dependency-name: "@cypress/request"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 20:29:49 +00:00
jamesread
f7fd8af124 feature: Websocket early impl 2023-08-09 21:24:05 +01:00
jamesread
d74734972b depbump: General dependency bump 2023-08-09 21:23:25 +01:00
jamesread
8736f5e387 feature: websocket wip 2023-08-09 21:15:47 +01:00
jamesread
89f08ae6c7 feature: log-popup 2023-08-09 21:15:47 +01:00
jamesread
0b75b3847d depbump: General dependency bump 2023-08-09 21:14:14 +01:00
dependabot[bot]
6d27c3db11 build(deps-dev): bump word-wrap from 1.2.3 to 1.2.4 in /webui (#150)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 22:29:27 +00:00
jamesread
b78065e23c cicd: Goreleaser removed support for archive name replacements 2023-07-14 11:14:41 +01:00
dependabot[bot]
c611c5c749 build(deps): bump yaml, stylelint and stylelint-config-standard (#138)
Removes [yaml](https://github.com/eemeli/yaml). It's no longer used after updating ancestor dependencies [yaml](https://github.com/eemeli/yaml), [stylelint](https://github.com/stylelint/stylelint) and [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard). These dependencies need to be updated together.


Removes `yaml`

Updates `stylelint` from 14.14.0 to 15.6.0
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/14.14.0...15.6.0)

Updates `stylelint-config-standard` from 25.0.0 to 33.0.0
- [Release notes](https://github.com/stylelint/stylelint-config-standard/releases)
- [Changelog](https://github.com/stylelint/stylelint-config-standard/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint-config-standard/compare/25.0.0...33.0.0)

---
updated-dependencies:
- dependency-name: yaml
  dependency-type: indirect
- dependency-name: stylelint
  dependency-type: direct:development
- dependency-name: stylelint-config-standard
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Read <contact@jread.com>
2023-05-13 19:30:33 +00:00
jamesread
5b637154ea fmt: Fieldset media query wasnt doing anything useful 2023-05-13 20:21:20 +01:00
jamesread
0b6edb3c38 fmt: Removed unecessary CSS rules from keyframes 2023-05-13 20:15:21 +01:00
jamesread
f1ba1c55a6 fmt: Minor CSS optimization needed for stylelint 2023-05-13 19:54:32 +01:00
James Read
2940a63d09 Add upgrade warnings + breaking changes (#136)
Recommebded by bestpractices.dev
2023-04-24 13:12:32 +00:00
dependabot[bot]
cc311f88a5 build(deps): bump github.com/docker/docker (#137)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 23.0.1+incompatible to 23.0.3+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v23.0.1...v23.0.3)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-24 12:54:35 +00:00
jamesread
0911df0442 bugfix: console.log made it into a commit 2023-04-03 09:29:08 +01:00
jamesread
86e5dfe2ee cicd: copy/paaye fail 2023-03-24 23:32:48 +00:00
jamesread
34b5570563 cicd: try CONTAINER_TOKEN 2023-03-24 22:23:12 +00:00
264 changed files with 34828 additions and 12807 deletions

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env python3
import sys
commitmsg = ""
with open('.git/COMMIT_EDITMSG', mode='r') as f:
commitmsg = f.readline().strip()
print("Commit message is: " + commitmsg)
ALLOWED_COMMIT_TYPES = [
"cicd",
"test",
"refactor",
"depbump",
"typo",
"fmt",
"doc",
"bugfix",
"security",
"feature",
]
for allowedType in ALLOWED_COMMIT_TYPES:
if commitmsg.startswith(allowedType + ":"):
print("Allowing commit type: ", allowedType)
sys.exit(0)
print("Commit message should start with commit type. One of: ", ", ".join(ALLOWED_COMMIT_TYPES))
sys.exit(1)

View File

@@ -2,7 +2,9 @@
name: Bug report
about: Create a report to help us improve
title: ""
labels: bug
labels:
- "type: bug"
- "waiting-on-developer"
assignees: ''
---

View File

@@ -2,7 +2,9 @@
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
labels:
- "type: feature-request"
- "waiting-on-developer"
assignees: ''
---

View File

@@ -2,7 +2,9 @@
name: Support request
about: Need some help? Got an error message?
title: ""
labels: support
labels:
- "type: support"
- "waiting-on-developer"
assignees: ''
---
@@ -39,7 +41,7 @@ If possible, please copy and paste your OliveTin logs from when the error happen
**Screenshot of WebDeveloper console logs**
If you know how, and if you think it's relevant, a screenshot of the
WebDeveloper console from when you clicked a button is often really helpful.
WebDeveloper console from when you clicked a button is often really helpful.
**Anything else?**

View File

@@ -4,7 +4,7 @@ First of all, thank you for considering to raise a pull request!
Dont be afraid to ask for advice before working on a contribution. If youre thinking about a bigger change, especially that might affect the core working or architecture, its almost essential to talk and ask about what youre planning might affect things. Some of the larger future plans may not be documented well so its difficult to understand how your change might affect the general direction and roadmap of this project without asking.
The preferred way to communicate is probably via Discord or GitHub issues.
The preferred way to communicate is probably via Discord or GitHub issues.
Helpful information to understand the project can be found here: [CONTRIBUTING](https://github.com/OliveTin/OliveTin/blob/main/CONTRIBUTING.adoc)
@@ -13,10 +13,14 @@ Helpful information to understand the project can be found here: [CONTRIBUTING](
# Checklist
Please put a X in the boxes as evidence of reading through the checklist.
- [ ] I have forked the project, and raised this PR on a feature branch.
- [ ] `make githooks` has been run, and my git commit message was accepted by the git hook.
- [ ] `make daemon-compile` runs without any issues.
- [ ] `make daemon-codestyle` runs without any issues.
- [ ] `make daemon-unittests` runs without any issues.
- [ ] `make webui-codestyle` runs without any issues.
- [ ] I understand and accept the [AGPL-3.0 license](LICENSE) and [code of conduct](CODE_OF_CONDUCT.md), and my contributions fall under these.
- [ ] I have read the [CONTRIBUTORS](CONTRIBUTORS.adoc) guide
- [ ] I considered the "3 line" suggestion.
- [ ] I followed the "1 logical change" rule.
- [ ] I have forked the project, and raised this PR on a feature branch.
- [ ] I ran the `pre-commit` hooks, and my commit message was validated.
- [ ] `make -wC service compile` runs without any issues.
- [ ] `make -wC service codestyle` runs without any issues.
- [ ] `make -wC service unittests` runs without any issues.
- [ ] `make -wC webui codestyle` runs without any issues.
- [ ] `make -w it` runs without any issues.
- [ ] I understand and accept the [AGPL-3.0 license](LICENSE) and [code of conduct](CODE_OF_CONDUCT.md), and my contributions fall under these.

105
.github/workflows/build-and-release.yml vendored Normal file
View File

@@ -0,0 +1,105 @@
---
name: "Build & Release pipeline"
on:
pull_request:
workflow_dispatch:
push:
tags:
- '*'
branches:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:latest
platforms: arm64,arm
- name: Setup node
uses: actions/setup-node@v4
with:
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: 'service/go.mod'
cache: true
cache-dependency-path: 'service/go.mod'
- name: Print go version
run: go version
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_KEY }}
- name: Login to ghcr
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.CONTAINER_TOKEN }}
- name: make webui
run: make -w webui-dist
- name: unit tests
run: make -w service-unittests
- name: build service
run: make -w service
- name: integration tests
run: cd integration-tests && make -w
- name: Archive integration tests
uses: actions/upload-artifact@v4.3.1
if: always()
with:
name: "OliveTin-integration-tests-${{ env.DATE }}-${{ github.sha }}"
path: |
integration-tests
!integration-tests/node_modules
- name: Install goreleaser
uses: goreleaser/goreleaser-action@v6
with:
install-only: true
- name: release
if: github.ref_type != 'tag'
uses: cycjimmy/semantic-release-action@v4
with:
extra_plugins: |
@semantic-release/commit-analyzer
@semantic-release/exec
@semantic-release/git
env:
GITHUB_TOKEN: ${{ secrets.CONTAINER_TOKEN }}
GH_TOKEN: ${{ secrets.CONTAINER_TOKEN }}
- name: get date
run: |
echo "DATE=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV"
- name: Archive binaries
uses: actions/upload-artifact@v4.3.1
with:
name: "OliveTin-snapshot-${{ env.DATE }}-${{ github.sha }}"
path: dist/OliveTin*.*

34
.github/workflows/build-buf.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Buf CI
on:
workflow_dispatch:
push:
paths:
- 'proto/**'
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
delete:
permissions:
contents: read
pull-requests: write
jobs:
buf:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: 'service/go.mod'
cache: true
cache-dependency-path: 'service/go.mod'
- uses: bufbuild/buf-action@v1.1.0
with:
token: ${{ secrets.BUF_TOKEN }}
# Change setup_only to true if you only want to set up the Action and not execute other commands.
# Otherwise, you can delete this line--the default is false.
setup_only: false
# Optional GitHub token for API requests. Ensures requests aren't rate limited.
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,56 +0,0 @@
---
name: "Build Snapshot"
on:
- push
- workflow_dispatch
jobs:
build-snapshot:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v2
with:
image: tonistiigi/binfmt:latest
platforms: arm64,arm
- name: Setup node
uses: actions/setup-node@v3
with:
cache: 'npm'
cache-dependency-path: webui/package-lock.json
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '>=1.18.0'
cache: true
- name: grpc
run: make grpc
- name: goreleaser
uses: goreleaser/goreleaser-action@v4.2.0
with:
distribution: goreleaser
version: latest
args: release --snapshot --clean --parallelism 1 --skip-docker
- name: Archive binaries
uses: actions/upload-artifact@v3.1.0
with:
name: "OliveTin-snapshot-${{ github.sha }}-dist"
path: dist/OliveTin*.*
- name: Archive integration tests
uses: actions/upload-artifact@v3.1.0
with:
name: integration-tests
path: integration-tests

View File

@@ -1,72 +0,0 @@
---
name: "Build Tag"
on:
push:
tags:
- '*'
jobs:
build-tag:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v2
with:
image: tonistiigi/binfmt:latest
platforms: arm64,arm
- name: Setup node
uses: actions/setup-node@v3
with:
cache: 'npm'
cache-dependency-path: webui/package-lock.json
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '^1.18.0'
cache: true
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_KEY }}
- name: Login to ghcr
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: grpc
run: make grpc
- name: goreleaser
uses: goreleaser/goreleaser-action@v4.2.0
with:
distribution: goreleaser
version: latest
args: release --clean --parallelism 1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Archive binaries
uses: actions/upload-artifact@v2
with:
name: dist
path: dist/OliveTin*.*
- name: Archive integration tests
uses: actions/upload-artifact@v2
with:
name: integration-tests
path: integration-tests

View File

@@ -17,7 +17,7 @@ on:
paths:
- 'cmd/**'
- 'internal/**'
- 'webui/**'
- 'webui.dev/**'
- 'integration-tests/**'
- 'OliveTin.proto'
branches: [main]
@@ -42,13 +42,22 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: 'service/go.mod'
cache: true
cache-dependency-path: 'service/go.mod'
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@@ -6,7 +6,7 @@ on:
paths:
- 'cmd/**'
- 'internal/**'
- 'webui/**'
- 'webui.dev/**'
- 'integration-tests/**'
- 'OliveTin.proto'
@@ -16,18 +16,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
go-version: '^1.16.0'
go-version-file: 'service/go.mod'
cache: true
cache-dependency-path: 'service/go.mod'
- name: deps
run: make grpc
- name: Print go version
run: go version
- name: daemon
run: make daemon-codestyle
- name: service
run: make -wC service codestyle
- name: webui
run: make webui-codestyle
- name: frontend
run: make -wC frontend codestyle

34
.github/workflows/devskim.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: DevSkim
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '34 21 * * 2'
jobs:
lint:
name: DevSkim
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run DevSkim scanner
uses: microsoft/DevSkim-Action@v1
- name: Upload DevSkim scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: devskim-results.sarif

View File

@@ -0,0 +1,73 @@
---
name: Issue Responsibility
on:
issue_comment:
types: [created]
jobs:
update-responsibility-labels:
runs-on: ubuntu-latest
steps:
- name: Update responsibility labels
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const commentAuthor = context.payload.comment.user.login;
const issueNumber = context.payload.issue.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
const skipAction = context.payload.comment.body.includes("/skip-responsibility");
if (skipAction) {
core.info("Skipping responsibility label update");
return;
}
const developers = ["jamesread"]
const commenterIsDeveloper = developers.includes(commentAuthor);
const commenterIsUser = !commenterIsDeveloper;
const issueLabels = context.payload.issue.labels.map(label => label.name);
if (issueLabels.includes("waiting-on-developer")) {
if (commenterIsDeveloper) {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: issueNumber,
name: "waiting-on-developer",
});
await github.rest.issues.addLabels({
owner,
repo,
issue_number: issueNumber,
labels: ["waiting-on-requestor"],
});
core.info(`Switched responsibility to user for issue #${issueNumber}`);
}
}
if (issueLabels.includes("waiting-on-requestor")) {
if (commenterIsUser) {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: issueNumber,
name: "waiting-on-requestor",
});
await github.rest.issues.addLabels({
owner,
repo,
issue_number: issueNumber,
labels: ["waiting-on-developer"],
});
core.info(`Switched responsibility to developer for issue #${issueNumber}`);
}
}

19
.gitignore vendored
View File

@@ -1,11 +1,18 @@
webui/node_modules
**/*.swp
**/*.swo
gen/
/OliveTin
/OliveTin.armhf
/OliveTin.exe
reports
service/OliveTin
service/OliveTin.armhf
service/OliveTin.exe
service/reports
releases/
dist/
installation-id.txt
tmp/
frontend/dist/
frontend/node_modules
custom-frontend
integration-tests/screenshots/
.vscode/
webui/
server.log
OliveTin

View File

@@ -1,28 +1,32 @@
project_name: OliveTin
version: 2
before:
hooks:
- go mod download
- rm -rf webui/node_modules
- make service-prep
builds:
- env:
- CGO_ENABLED=0
binary: OliveTin
main: main.go
dir: service
goos:
- linux
- windows
- darwin
- freebsd
goarch:
- amd64
- arm64
- arm
- riscv64
goarm:
- 5 # For old RPIs
- 6
- 6
- 7
main: cmd/OliveTin/main.go
ignore:
- goos: darwin
goarch: arm # Mac does not work on [32bit] arm
@@ -39,7 +43,7 @@ builds:
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Branch }}-{{ .ShortCommit }}"
version_template: "{{ .Branch }}-{{ .ShortCommit }}"
changelog:
sort: asc
groups:
@@ -47,7 +51,7 @@ changelog:
regexp: '^.*?security(\([[:word:]]+\))??!?:.+$'
order: 0
- title: 'Features'
regexp: '^.*?feature(\([[:word:]]+\))??!?:.+$'
regexp: '^.*?feat.*?(\([[:word:]]+\))??!?:.+$'
order: 1
- title: 'Bug fixes'
regexp: '^.*?bugfix(\([[:word:]]+\))??!?:.+$'
@@ -62,29 +66,19 @@ changelog:
- '^refactor:'
archives:
-
format: tar.gz
files:
- formats: tar.gz
files:
- config.yaml
- LICENSE
- README.md
- Dockerfile
- webui
- OliveTin.service
- ./var/
replacements:
darwin: macOS
arm: arm32v
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}"
wrap_in_directory: true
format_overrides:
- goos: windows
format: zip
formats: zip
dockers:
- image_templates:
@@ -100,10 +94,13 @@ dockers:
- "--label=org.opencontainers.image.version={{.Tag}}"
extra_files:
- webui
- var/entities/
- config.yaml
- var/helper-actions/
- image_templates:
- "docker.io/jamesread/olivetin:{{ .Tag }}-arm64"
- "ghcr.io/olivetin/olivetin:{{ .Tag }}-amd64"
- "ghcr.io/olivetin/olivetin:{{ .Tag }}-arm64"
dockerfile: Dockerfile.arm64
goos: linux
goarch: arm64
@@ -114,6 +111,9 @@ dockers:
- "--label=org.opencontainers.image.version={{.Tag}}"
extra_files:
- webui
- var/entities/
- config.yaml
- var/helper-actions/
docker_manifests:
- name_template: docker.io/jamesread/olivetin:{{ .Version }}
@@ -151,31 +151,20 @@ nfpms:
file_name_template: '{{ .PackageName }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
contents:
- src: OliveTin.service
- src: var/systemd/OliveTin.service
dst: /etc/systemd/system/OliveTin.service
- src: webui/main.js
- src: webui/*
dst: /var/www/olivetin/
- src: webui/index.html
dst: /var/www/olivetin/
- src: webui/*.png
dst: /var/www/olivetin/
- src: webui/*.svg
dst: /var/www/olivetin/
- src: webui/style.css
dst: /var/www/olivetin/
- src: webui/js/
dst: /var/www/olivetin/js/
- src: config.yaml
dst: /etc/OliveTin/config.yaml
type: "config|noreplace"
- src: var/entities/*
dst: /etc/OliveTin/entities/
type: "config|noreplace"
- src: var/manpage/OliveTin.1.gz
dst: /usr/share/man/man1/OliveTin.1.gz
@@ -195,28 +184,17 @@ nfpms:
- src: var/openrc/OliveTin
dst: /etc/init.d/OliveTin
- src: webui/main.js
- src: webui/*
dst: /var/www/olivetin/
- src: webui/index.html
dst: /var/www/olivetin/
- src: webui/*.png
dst: /var/www/olivetin/
- src: webui/*.svg
dst: /var/www/olivetin/
- src: webui/style.css
dst: /var/www/olivetin/
- src: webui/js/
dst: /var/www/olivetin/js/
- src: config.yaml
dst: /etc/OliveTin/config.yaml
type: "config|noreplace"
- src: var/entities/*
dst: /etc/OliveTin/entities/
type: "config|noreplace"
- src: var/manpage/OliveTin.1.gz
dst: /usr/share/man/man1/OliveTin.1.gz
@@ -230,10 +208,13 @@ release:
- `docker pull docker.io/jamesread/olivetin:{{ .Version }}`
## Upgrade warnings, or breaking changes
- No such issues between the last release and this version.
## Useful links
- [Which download do I need?](https://docs.olivetin.app/choose-package.html)
- [Which download do I need?](https://docs.olivetin.app/install/choose_package.html)
- [Ask for help and chat with others users in the Discord community](https://discord.gg/jhYWWpNJ3v)
Thanks for your interest in OliveTin!

19
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,19 @@
---
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
# Alternative semantic commit checker
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v3.1.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test]

16
.releaserc.yaml Normal file
View File

@@ -0,0 +1,16 @@
---
branches:
- name: main
# range: '3000.x.x'
# - name: release/2k
# range: '>=2000.0.0 <3000.0.0'
plugins:
- '@semantic-release/commit-analyzer'
- '@semantic-release/git'
- - "@semantic-release/exec"
- publishCmd: |
goreleaser release --clean --timeout 60m
tagFormat: '${version}'

68
AGENTS.md Normal file
View File

@@ -0,0 +1,68 @@
## OliveTin Agent Guide
This document helps AI agents contribute effectively to OliveTin.
If you are looking for OliveTin's AI policy, you can find it in `AI.md`.
### Project Overview
- **Service (Go)**: `service/` with business logic under `service/internal/*`
- API (Connect RPC): `service/internal/api`
- Command execution: `service/internal/executor`
- HTTP frontends/proxy: `service/internal/httpservers`
- Config/types/entities: `service/internal/config`, `service/internal/entities`
- **Frontend (Vue 3)**: `frontend/` (served by the service)
- **Integration tests**: `integration-tests/`
- **Protos/Generated**: `proto/`, `service/gen/...`
### How to Run
- Run the server (dev):
- From repo root: `go run ./service`
- Unit tests (Go):
- From repo root: `cd service && make unittests`
- Integration tests (Mocha + Selenium):
- Single test: `cd integration-tests && npx --yes mocha test/general.mjs`
- All tests: `cd integration-tests && npx --yes mocha`
### Test Notes and Gotchas
- The top-level Makefile does not expose `unittests`; use `cd service && make unittests`.
- Connect RPC API must be mounted correctly; in tests, create the handler via `GetNewHandler(ex)` and serve under `/api/`.
- Frontend “ready” state: the app sets `document.body` attribute `initial-marshal-complete="true"` when loaded. Integration helpers wait for this before selecting elements.
- Modern UI uses Vue components:
- Action buttons are rendered as `.action-button button`.
- Logs and Diagnostics are Vue router links available via `/logs` and `/diagnostics`.
- Some legacy DOM ids (e.g., `contentActions`) no longer exist; prefer class-based selectors.
- Hidden UI features:
- Footer visibility is controlled by `showFooter` from Init API; tests may assert the footer is absent when config disables it.
### Coding Standards (Go)
- Prefer clear, descriptive names; avoid 12 letter identifiers.
- Use early returns and handle edge cases first.
- Do not swallow errors; propagate or log meaningfully.
- Match existing formatting; avoid unrelated reformatting.
- Be safe around nils in executor steps (e.g., guard `req.Binding` and `req.Binding.Action`).
### API and Execution Flow (High-level)
1. Client calls Connect RPC (e.g., `Init`, `GetDashboard`, `StartAction`).
2. API translates requests to `executor.ExecutionRequest` and calls `Executor.ExecRequest`.
3. Executor runs a chain of steps: request binding → concurrency/rate/ACL checks → arg parsing → exec → post-exec → logging/triggering.
4. Logs are stored and can be fetched via `ExecutionStatus`/`GetLogs`.
### Common Tasks
- Add/modify actions: update `config.yaml` and ensure `executor.RebuildActionMap()` is called when needed.
- Adjust dashboard rendering: see `service/internal/api/dashboards.go` and `apiActions.go`.
- Frontend behavior:
- Router: `frontend/resources/vue/router.js`
- Main shell/layout: `frontend/resources/vue/App.vue`
- Action button behavior: `frontend/resources/vue/ActionButton.vue`
### Contributing Checklist
- Review the contributuing guidelines at `CONTRIBUTING.adoc`.
- Review the AI guidance in `AI.md`.
- Review the pull request template at `.github/PULL_REQUEST_TEMPLATE.md`.
### Troubleshooting
- API tests failing with content-type errors: ensure Connect handler is served under `/api/` and the client targets that base URL.
- Executor panics: check for nil `Binding/Action` and add guards in step functions.
- Integration timeouts: wait for `initial-marshal-complete` and use selectors matching the Vue UI.

32
AI.md Normal file
View File

@@ -0,0 +1,32 @@
# OliveTin's AI Policy
## Runtime:
- [x] The project does not include any AI functionality at runtime.
- [x] No data, usage, or similar is sent to, or analyized by AI.
## Development - Contributions
- [x] The project **does accept** contributions that were written with AI help. **However**:
- The contribution must be attributed to a human username who takes responsibility for the code as if they wrote it themselves.
- AI often generates very unmaintainable code as it gets longer - loads of duplication, very little function re-use amd very poor at following style guides / idiomatic design. All code contributions (AI or not) are scrutinized hard for **maintainability** and **clean merging**. Please follow the CONTRIBUTORS guide.
- AI that helps with short tab completion is generally fine.
- AI that writes lots of new code across lots of files, or makes lots of superfluous changes is generally less likely to be accepted.
- Vibe coding is not a suitable way to contribute to this project.
- [x] Contributors should declare when AI has been used to help write contributions in the pull request body message.
- [x] The project uses AI as an **optional** part of the PR process (coderabbitai). Please raise any concerns about usage within the PR.
- [x] Suggestions from coderabbitai can be accepted verbaitem, but ideally it should be the PR author that uses coderabbitai as a guide, who then re-writes the contribution.
- [x] Maintainers are the only agents permitted to accept merges.
## Development - Build process
- [x] Linters, code review tools, and others which are enabled by AI are allowed, but cannot be added as part of the standard build process.
## Community
- [x] Only project admins are allowed to run bots in the community discord server (at the time of writing, the current bot, Japella, is not AI-enabled).
- [x] Support is currently not provided by AI.
## Training
- [x] You may use the OliveTin code base, documentation and repositories to train AI, but obviously usernames and personally identifiable information may not be stored.

View File

@@ -7,9 +7,17 @@ of multiple projects, your time and interest in contributing is most welcome.
If you're not sure where to get started, raise an issue in the project.
Ideas may be discussed, purely on their merits and issues. Our Code of Conduct
(CoC) is straightforward - it's important that contributors feel comfortable in
discussion throughout the whole process. This project respects the
link:https://www.kernel.org/doc/html/latest/process/code-of-conduct.html[Linux Kernel code of conduct].
(CoC) is straightforward - it's important that contributors feel comfortable in
discussion throughout the whole process. This project respects the
link:https://www.kernel.org/doc/html/latest/process/code-of-conduct.html[Linux Kernel code of conduct].
== Suggestion: More than 3 lines - talk to someone first
If you're planning on making a change that's more than a 3 lines, please talk to someone first (raising a GitHub issue is the best way to do that). This is so that you don't waste your time on something that might not be accepted. It's also a good way to get some feedback on your idea and make sure you're on the right track.
== Rule: A PR should be one logical change
Please try to keep your pull requests small and focused. It's almost impossible to review PRs that change lots of files for lots of different reasons. If you have a big change, it's probably best to break it down into smaller, more manageable chunks, otherwise it's likely to be rejected.
== If you're not sure, ask!
@@ -18,19 +26,27 @@ contribution. If you're thinking about a bigger change, especially that might
affect the core working or architecture, it's almost essential to talk and ask
about what you're planning might affect things. Some of the larger future plans may not be
documented well so it's difficult to understand how your change might affect
the general direction and roadmap of this project without asking.
the general direction and roadmap of this project without asking.
The preferred way to communicate is probably via Discord or GitHub issues.
The preferred way to communicate is probably via Discord or GitHub issues.
=== Dev environment setup and clean build - Fedora
== Dev environment setup and clean build
```
dnf install git go protobuf-compiler make -y
# Step1: setup compile env
# - Fedora
dnf install git go protobuf-compiler make -y
# - Windows with chocolatey
choco install git go protoc make python nodejs-lts -y
# Step2: clone and setup repo
git clone https://github.com/OliveTin/OliveTin.git
cd OliveTin
make githooks
# `make grpc` will also run `make go-tools`, which installs "buf". This binary
# will be put in your GOPATH/bin/, which should be on your path. buf is used to
# Step3: compile binary for current dev env (OS, ARCH)
# `make grpc` will also run `make go-tools`, which installs "buf". This binary
# will be put in your GOPATH/bin/, which should be on your path. buf is used to
# generate the protobuf / grpc stubs.
make grpc
make
@@ -39,10 +55,10 @@ make
=== Getting started to contribute;
The project layout is reasonably straightforward;
The project layout is reasonably straightforward;
* See the `Makefile` for common targets. This project was originally created on top of Fedora, but it should be usable on Debian/your faveourite distro with minor changes (if any).
* The API is defined in protobuf+grpc - you will need to `make grpc`.
* The API is defined in protobuf+grpc - you will need to `make grpc`.
* The Go daemon is built from the `cmd` and `internal` directories mostly.
* The webui is just a single page application with a bit of Javascript in the `webui` directory. This can happily be hosted on another webserver.

View File

@@ -1,24 +1,45 @@
FROM --platform=linux/amd64 registry.fedoraproject.org/fedora-minimal:36-x86_64
FROM --platform=linux/amd64 registry.fedoraproject.org/fedora-minimal:42-x86_64 AS olivetin-tmputils
RUN microdnf -y install dnf-plugins-core && \
dnf-3 config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo && \
microdnf install -y docker-ce-cli docker-compose-plugin && microdnf clean all
FROM --platform=linux/amd64 registry.fedoraproject.org/fedora-minimal:42-x86_64
LABEL org.opencontainers.image.source https://github.com/OliveTin/OliveTin
LABEL org.opencontainers.image.title=OliveTin
LABEL org.opencontainers.image.title OliveTin
RUN mkdir -p /config /var/www/olivetin \
&& microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
RUN mkdir -p /config /config/entities/ /var/www/olivetin \
&& \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
iputils \
openssh-clients \
kubernetes-client \
shadow-utils \
docker \
apprise \
jq \
git \
&& microdnf clean all
RUN useradd --system --create-home olivetin -u 1000
COPY --from=olivetin-tmputils \
/usr/bin/docker \
/usr/bin/docker
EXPOSE 1337/tcp
COPY --from=olivetin-tmputils \
/usr/libexec/docker/cli-plugins/docker-compose \
/usr/libexec/docker/cli-plugins/docker-compose
RUN useradd --system --create-home olivetin -u 1000
EXPOSE 1337/tcp
COPY config.yaml /config
COPY var/entities/* /config/entities/
VOLUME /config
COPY OliveTin /usr/bin/OliveTin
COPY webui /var/www/olivetin/
COPY var/helper-actions/* /usr/bin/
USER olivetin

View File

@@ -1,23 +1,45 @@
FROM --platform=linux/arm64 registry.fedoraproject.org/fedora-minimal:36-aarch64
FROM --platform=linux/arm64 registry.fedoraproject.org/fedora-minimal:42-aarch64 AS olivetin-tmputils
RUN microdnf -y install dnf-plugins-core && \
dnf-3 config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo && \
microdnf install -y docker-ce-cli docker-compose-plugin && microdnf clean all
FROM --platform=linux/arm64 registry.fedoraproject.org/fedora-minimal:42-aarch64
LABEL org.opencontainers.image.source https://github.com/OliveTin/OliveTin
LABEL org.opencontainers.image.title=OliveTin
LABEL org.opencontainers.image.title OliveTin
RUN mkdir -p /config /var/www/olivetin \
RUN mkdir -p /config /config/entities/ /var/www/olivetin \
&& \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
iputils \
openssh-clients \
kubernetes-client \
shadow-utils \
openssh-clients
apprise \
jq \
git \
&& microdnf clean all
RUN useradd --system --create-home olivetin -u 1000
COPY --from=olivetin-tmputils \
/usr/bin/docker \
/usr/bin/docker
EXPOSE 1337/tcp
COPY --from=olivetin-tmputils \
/usr/libexec/docker/cli-plugins/docker-compose \
/usr/libexec/docker/cli-plugins/docker-compose
RUN useradd --system --create-home olivetin -u 1000
EXPOSE 1337/tcp
COPY config.yaml /config
COPY var/entities/* /config/entities/
VOLUME /config
COPY OliveTin /usr/bin/OliveTin
COPY webui /var/www/olivetin/
COPY var/helper-actions/* /usr/bin/
USER olivetin

View File

@@ -3,21 +3,24 @@ FROM --platform=linux/armhfp registry.fedoraproject.org/fedora-minimal:36-armhfp
LABEL org.opencontainers.image.source https://github.com/OliveTin/OliveTin
LABEL org.opencontainers.image.title=OliveTin
RUN mkdir -p /config /var/www/olivetin \
RUN mkdir -p /config /config/entities /var/www/olivetin \
&& \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
iputils \
shadow-utils \
openssh-clients
shadow-utils \
openssh-clients
RUN useradd --system --create-home olivetin -u 1000
RUN useradd --system --create-home olivetin -u 1000
EXPOSE 1337/tcp
EXPOSE 1337/tcp
COPY config.yaml /config
COPY var/entities/* /config/entities/
VOLUME /config
COPY OliveTin /usr/bin/OliveTin
COPY webui /var/www/olivetin/
COPY var/helper-actions/* /usr/bin/
USER olivetin

50
Jenkinsfile vendored
View File

@@ -1,50 +0,0 @@
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
stages {
stage ('Pre-Build') {
steps {
cleanWs()
checkout scm
sh 'make go-tools'
}
}
stage('Compile') {
steps {
withEnv(["PATH+GO=/root/go/bin/"]) {
sh 'go env'
sh 'echo $PATH'
sh 'buf generate'
sh 'make daemon-compile'
}
}
}
stage ('Post-Compile') {
parallel {
stage('Codestyle') {
steps {
withEnv(["PATH+GO=/root/go/bin/"]) {
sh 'make daemon-codestyle'
sh 'make webui-codestyle'
}
}
}
stage('UnitTests') {
steps {
withEnv(["PATH+GO=/root/go/bin/"]) {
sh 'make daemon-unittests'
}
}
}
}
}
}
}

View File

@@ -1,43 +1,28 @@
compile: daemon-compile-x64-lin
define delete-files
python -c "import shutil;shutil.rmtree('$(1)', ignore_errors=True)"
endef
daemon-compile-armhf:
GOARCH=arm GOARM=6 go build -o OliveTin.armhf github.com/OliveTin/OliveTin/cmd/OliveTin
service:
$(MAKE) -wC service
daemon-compile-x64-lin:
GOOS=linux go build -o OliveTin github.com/OliveTin/OliveTin/cmd/OliveTin
service-prep:
$(MAKE) -wC service prep
daemon-compile-x64-win:
GOOS=windows GOARCH=amd64 go build -o OliveTin.exe github.com/OliveTin/OliveTin/cmd/OliveTin
service-unittests:
$(MAKE) -wC service unittests
daemon-compile: daemon-compile-armhf daemon-compile-x64-lin daemon-compile-x64-win
it:
$(MAKE) -wC integration-tests
daemon-codestyle:
go fmt ./...
go vet ./...
gocyclo -over 4 cmd internal
gocritic check ./...
daemon-unittests:
mkdir -p reports
go test ./... -coverprofile reports/unittests.out
go tool cover -html=reports/unittests.out -o reports/unittests.html
githooks:
cp -v .githooks/* .git/hooks/
go-tools:
go install "github.com/bufbuild/buf/cmd/buf"
go install "github.com/fzipp/gocyclo/cmd/gocyclo"
go install "github.com/go-critic/go-critic/cmd/gocritic"
go install "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway"
go install "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
go install "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
go install "google.golang.org/protobuf/cmd/protoc-gen-go"
$(MAKE) -wC service go-tools
proto: grpc
grpc: go-tools
buf generate
$(MAKE) -wC proto
dist: protoc
dist: protoc
protoc:
protoc --go_out=. --go-grpc_out=. --grpc-gateway_out=. -I .:/usr/include/ OliveTin.proto
@@ -54,7 +39,7 @@ podman-container:
integration-tests-docker-image:
docker rm -f olivetin && docker rmi -f olivetin
docker build -t olivetin:latest .
docker create --name olivetin -p 1337:1337 -v `pwd`/integration-tests/configs/:/config/ olivetin
docker create --name olivetin -p 1337:1337 -v `pwd`/integration-tests/configs/:/config/ olivetin
devrun: compile
killall OliveTin || true
@@ -62,12 +47,16 @@ devrun: compile
devcontainer: compile podman-image podman-container
webui-codestyle:
cd webui && npm install
cd webui && ./node_modules/.bin/eslint main.js js/*
cd webui && ./node_modules/.bin/stylelint style.css
webui-dist:
$(MAKE) -wC frontend dist
mv frontend/dist webui
clean:
rm -rf dist OliveTin OliveTin.armhf OliveTin.exe reports gen
$(call delete-files,dist)
$(call delete-files,OliveTin)
$(call delete-files,OliveTin.armhf)
$(call delete-files,OliveTin.exe)
$(call delete-files,reports)
$(call delete-files,gen)
.PHONY: grpc
.PHONY: grpc proto service

View File

@@ -1,140 +0,0 @@
syntax = "proto3";
option go_package = "gen/grpc";
import "google/api/annotations.proto";
message Action {
string id = 1;
string title = 2;
string icon = 3;
bool canExec = 4;
repeated ActionArgument arguments = 5;
}
message ActionArgument {
string name = 1;
string title = 2;
string type = 3;
string defaultValue = 4;
repeated ActionArgumentChoice choices = 5;
string description = 6;
}
message ActionArgumentChoice {
string value = 1;
string title = 2;
}
message Entity {
string title = 1;
string icon = 2;
repeated Action actions = 3;
}
message GetDashboardComponentsResponse {
string title = 1;
repeated Action actions = 2;
repeated Entity entities = 3;
}
message GetDashboardComponentsRequest {}
message StartActionRequest {
string actionName = 1;
repeated StartActionArgument arguments = 2;
}
message StartActionArgument {
string name = 1;
string value = 2;
}
message StartActionResponse {
LogEntry logEntry = 1;
}
message GetLogsRequest{};
message LogEntry {
string datetime = 1;
string actionTitle = 2;
string stdout = 3;
string stderr = 4;
bool timedOut = 5;
int32 exitCode = 6;
string user = 7;
string userClass = 8;
string actionIcon = 9;
repeated string tags = 10;
}
message GetLogsResponse {
repeated LogEntry logs = 1;
}
message ValidateArgumentTypeRequest {
string value = 1;
string type = 2;
}
message ValidateArgumentTypeResponse {
bool valid = 1;
string description = 2;
}
message WhoAmIRequest {}
message WhoAmIResponse {
string authenticatedUser = 1;
}
message SosReportRequest {}
message SosReportResponse {
string alert = 1;
}
service OliveTinApi {
rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) {
option (google.api.http) = {
get: "/api/GetDashboardComponents"
};
}
rpc StartAction(StartActionRequest) returns (StartActionResponse) {
option (google.api.http) = {
post: "/api/StartAction"
body: "*"
};
}
rpc GetLogs(GetLogsRequest) returns (GetLogsResponse) {
option (google.api.http) = {
get: "/api/GetLogs"
};
}
rpc ValidateArgumentType(ValidateArgumentTypeRequest) returns (ValidateArgumentTypeResponse) {
option (google.api.http) = {
post: "/api/ValidateArgumentType"
body: "*"
};
}
rpc WhoAmI(WhoAmIRequest) returns (WhoAmIResponse) {
option (google.api.http) = {
get: "/api/WhoAmI"
};
}
rpc SosReport(SosReportRequest) returns (SosReportResponse) {
option (google.api.http) = {
get: "/api/sosreport"
};
}
}

115
README.md
View File

@@ -1,17 +1,25 @@
# OliveTin
<div align = "center">
<img alt = "project logo" src = "https://github.com/OliveTin/OliveTin/blob/main/frontend/OliveTinLogo.png" width = "128" />
<h1>OliveTin</h1>
<img alt = "project logo" src = "https://github.com/OliveTin/OliveTin/blob/main/webui/OliveTinLogo.png" align = "right" width = "160px" />
OliveTin gives **safe** and **simple** access to predefined shell commands from a web interface.
OliveTin gives **safe** and **simple** access to predefined shell commands from a web interface.
[![Maturity Badge](https://img.shields.io/badge/maturity-Production-brightgreen)](#none)
[![Discord](https://img.shields.io/discord/846737624960860180?label=Discord%20Server)](https://discord.gg/jhYWWpNJ3v)
[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/awesome-selfhosted/awesome-selfhosted#automation)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5050/badge)](https://bestpractices.coreinfrastructure.org/projects/5050)
[![Go Report Card](https://goreportcard.com/badge/github.com/Olivetin/OliveTin)](https://goreportcard.com/report/github.com/OliveTin/OliveTin)
[![Build Snapshot](https://github.com/OliveTin/OliveTin/actions/workflows/build-snapshot.yml/badge.svg)](https://github.com/OliveTin/OliveTin/actions/workflows/build-snapshot.yml)
## Use cases
[OliveTin 2k to 3k upgrade guide](https://docs.olivetin.app/upgrade/2k3k.html)
</div>
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-laptop_framed.png" />
<a href = "#screenshots">More screenshots below</a>
All documentation can be found at [docs.olivetin.app](https://docs.olivetin.app). This includes installation and usage guide, etc.
## Use cases
**Safely** give access to commands, for less technical people;
@@ -22,23 +30,23 @@ OliveTin gives **safe** and **simple** access to predefined shell commands from
**Simplify** complex commands, make them accessible and repeatable;
* eg: Expose complex commands on touchscreen tablets stuck on walls around your house. `wake-on-lan aa:bb:cc:11:22:33`
* eg: Run long running on your servers from your cell phone. `dnf update -y`
* eg: Run long-lived commands on your servers from your cell phone. `dnf update -y`
* eg: Define complex commands with lots of preset arguments, and turn a few arguments into dropdown select boxes. `docker rm {{ container }} && docker create {{ container }} && docker start {{ container }}`
[Join the community on Discord](https://discord.gg/jhYWWpNJ3v) to talk with other users about use cases, or to ask for support in getting started.
## YouTube demo video (6 mins)
## YouTube demo video
[![6 minute demo video](https://img.youtube.com/vi/Ej6NM9rmZtk/0.jpg)](https://www.youtube.com/watch?v=Ej6NM9rmZtk)
[![YouTube demo video](https://raw.githubusercontent.com/OliveTin/OliveTin/main/var/marketing/YouTubeBanner.png)](https://www.youtube.com/watch?v=UBgOfNrzId4)
## Features
* **Responsive, touch-friendly UI** - great for tablets and mobile
* **Super simple config in YAML** - because if it's not YAML now-a-days, it's not "cloud native" :-)
* **Super simple config in YAML** - because if it's not YAML now-a-days, it's not "cloud native" :-)
* **Dark mode** - for those of you that roll that way.
* **Accessible** - passes all the accessibility checks in Firefox, and issues with accessibility are taken seriously.
* **Container** - available for quickly testing and getting it up and running, great for the selfhosted community.
* **Integrate with anything** - OliveTin just runs Linux shell commands, so theoretially you could integrate with a bunch of stuff just by using curl, ping, etc. However, writing your own shell scripts is a great way to extend OliveTin.
* **Accessible** - passes all the accessibility checks in Firefox, and issues with accessibility are taken seriously.
* **Container** - available for quickly testing and getting it up and running, great for the selfhosted community.
* **Integrate with anything** - OliveTin just runs Linux shell commands, so theoretically you could integrate with a bunch of stuff just by using curl, ping, etc. However, writing your own shell scripts is a great way to extend OliveTin.
* **Lightweight on resources** - uses only a few MB of RAM and barely any CPU. Written in Go, with a web interface written as a modern, responsive, Single Page App that uses the REST/gRPC API.
* **Good amount of unit tests and style checks** - helps potential contributors be consistent, and helps with maintainability.
@@ -46,69 +54,34 @@ OliveTin gives **safe** and **simple** access to predefined shell commands from
Desktop web browser;
![Desktop screenshot](media/screenshotDesktop.png)
<p align = "center">
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-laptop_framed.png" />
</p>
Desktop web browser (dark mode);
Desktop web browser (dark mode);
![Desktop screenshot](media/screenshotDesktopDark.png)
<p align = "center">
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-darkop_framed.png" />
</p>
Mobile screen size (responsive layout);
Mobile screen size (responsive layout);
![Mobile screenshot](media/screenshotMobile.png)
<p align = "center">
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-phone_framed.png" style = "width: 700px;" />
</p>
## No-Nonsense Software Principles
OliveTin follows these principles:
* **Open Source & Free Software**: following the [Open Source Definition](https://opensource.org/osd) and the [Free Software Definition](https://www.gnu.org/philosophy/free-sw.html). All code and assets are available under the [AGPL-3.0 License](LICENSE).
* **Independent**: No company owns the code or is responsible for the projects' governance.
* **Inclusive**: No "core", "pro", "premium" or "enterprise" version. The only version is the one you can download and run, and it has all the features.
* **Invisible**: No usage tracking, no user tracking, no ads, and no telemetry.
* **Internal**: No internet connection required for any functionality.
## Documentation
All documentation can be found at http://docs.olivetin.app . This includes installation and usage guide, etc.
### Quickstart reference for `config.yaml`
This is a quick example of `config.yaml` - but again, lots of documentation for how to write your `config.yaml` can be found at [the documentation site.](https://docs.olivetin.app)
* (Recommended) [Linux package install (.rpm/.deb)](https://docs.olivetin.app/install-linuxpackage.html) install instructions
* [Container (podman/docker)](https://docs.olivetin.app/install-container.html) install instructions
* [Docker compose](https://docs.olivetin.app/install-compose.html) install instructions
* [Helm on Kubernetes](https://docs.olivetin.app/install-helm.html) install instructions
* [Kubernetes (manual)](https://docs.olivetin.app/install-k8s.html) install instructions
* [.tar.gz (manual)](https://docs.olivetin.app/install-targz.html) install instructions
Put this `config.yaml` in `/etc/OliveTin/` if you're running a standard service, or mount it at `/config` if running in a container.
```yaml
# Listen on all addresses available, port 1337
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
# Choose from INFO (default), WARN and DEBUG
logLevel: "INFO"
# Actions (buttons) to show up on the WebUI:
actions:
# Docs: https://docs.olivetin.app/action-container-control.html
- title: Restart Plex
icon: restart
shell: docker restart plex
# This will send 1 ping
# Docs: https://docs.olivetin.app/action-ping.html
- title: Ping host
shell: ping {{ host }} -c {{ count }}
icon: ping
arguments:
- name: host
title: host
type: ascii_identifier
default: example.com
- name: count
title: Count
type: int
default: 1
# Restart http on host "webserver1"
# Docs: https://docs.olivetin.app/action-ssh.html
- title: restart httpd
icon: restart
shell: ssh root@webserver1 'service httpd restart'
```
A full example config can be found at in this repository - [config.yaml](https://github.com/OliveTin/OliveTin/blob/main/config.yaml).
All documentation can be found at [docs.olivetin.app](https://docs.olivetin.app). This includes installation and usage guide, etc.
You can find instructions in the docs on how to install as a **Linux package**, **Linux Container**, on **FreeBSD**, **Windows**, **MacOS** and other platforms, too!

View File

@@ -2,7 +2,7 @@
## Supported Versions
Currently, only the `main` branch is "supported".
Currently, only the `main` branch is "supported".
| Version | Supported |
| ------- | ------------------ |
@@ -10,4 +10,4 @@ Currently, only the `main` branch is "supported".
## Reporting a Vulnerability
Please email `contact@jread.com` for responsible disclosure. Accepted issues will be made public once patched, and you will be given credit.
Please email `contact@jread.com` for responsible disclosure. Accepted issues will be made public once patched, and you will be given credit.

View File

@@ -1,20 +0,0 @@
version: v1
plugins:
- name: go
out: gen/grpc/
opt: paths=source_relative
- name: go-grpc
out: gen/grpc/
opt: paths=source_relative,require_unimplemented_servers=false
- name: grpc-gateway
out: gen/grpc/
opt: paths=source_relative
# - name: swagger
# out: reports/swagger
# - name: openapiv2
# out: reports/openapiv2

View File

@@ -1,7 +0,0 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: googleapis
repository: googleapis
commit: e9fcfb66f77242e5b8fd4564d7a01033

View File

@@ -1,122 +0,0 @@
package main
import (
"flag"
log "github.com/sirupsen/logrus"
"github.com/OliveTin/OliveTin/internal/executor"
grpcapi "github.com/OliveTin/OliveTin/internal/grpcapi"
"github.com/OliveTin/OliveTin/internal/installationinfo"
"github.com/OliveTin/OliveTin/internal/oncron"
"github.com/OliveTin/OliveTin/internal/onstartup"
updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck"
"github.com/OliveTin/OliveTin/internal/httpservers"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"os"
"path"
)
var (
cfg *config.Config
version = "dev"
commit = "nocommit"
date = "nodate"
)
func init() {
log.SetFormatter(&log.TextFormatter{
ForceQuote: true,
DisableTimestamp: true,
})
log.WithFields(log.Fields{
"version": version,
"commit": commit,
"date": date,
}).Info("OliveTin initializing")
log.SetLevel(log.DebugLevel) // Default to debug, to catch cfg issues
var configDir string
flag.StringVar(&configDir, "configdir", ".", "Config directory path")
flag.Parse()
log.WithFields(log.Fields{
"value": configDir,
}).Debugf("Value of -configdir flag")
viper.AutomaticEnv()
viper.SetConfigName("config.yaml")
viper.SetConfigType("yaml")
viper.AddConfigPath(configDir)
viper.AddConfigPath("/config") // For containers.
viper.AddConfigPath("/etc/OliveTin/")
if err := viper.ReadInConfig(); err != nil {
log.Errorf("Config file error at startup. %s", err)
os.Exit(1)
}
cfg = config.DefaultConfig()
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
if e.Op == fsnotify.Write {
log.Info("Config file changed:", e.String())
reloadConfig()
}
})
reloadConfig()
warnIfPuidGuid()
installationinfo.Config = cfg
installationinfo.Build.Version = version
installationinfo.Build.Commit = commit
installationinfo.Build.Date = date
log.Info("Init complete")
}
func warnIfPuidGuid() {
if os.Getenv("PUID") != "" || os.Getenv("PGID") != "" {
log.Warnf("PUID or PGID seem to be set to something, but they are ignored by OliveTin. Please check https://docs.olivetin.app/no-puid-pgid.html")
}
}
func reloadConfig() {
if err := viper.UnmarshalExact(&cfg); err != nil {
log.Errorf("Config unmarshal error %+v", err)
os.Exit(1)
}
cfg.Sanitize()
}
func main() {
configDir := path.Dir(viper.ConfigFileUsed())
log.WithFields(log.Fields{
"configDir": configDir,
}).Infof("OliveTin started")
log.Debugf("Config: %+v", cfg)
executor := executor.DefaultExecutor()
go onstartup.Execute(cfg, executor)
go oncron.Schedule(cfg, executor)
go updatecheck.StartUpdateChecker(version, commit, cfg, configDir)
go grpcapi.Start(cfg, executor)
httpservers.StartServers(cfg)
}

View File

@@ -1,79 +1,324 @@
# There is a built-in micro proxy that will host the webui and REST API all on
# one port (this is called the "Single HTTP Frontend") and means you just need
# one open port in the container/firewalls/etc.
# There is a built-in micro proxy that will host the webui and REST API all on
# one port (this is called the "Single HTTP Frontend") and means you just need
# one open port in the container/firewalls/etc.
#
# Listen on all addresses available, port 1337
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
bannerMessage: "This is an early alpha version of OliveTin 3000. Many thanks are broken, many things will change."
bannerCss: "background-color: #b2e4b2; color: black; font-size: small; text-align: center; padding: .6em; border-radius: 0.5em;"
insecureAllowDumpSos: true
insecureAllowDumpVars: true
# Choose from INFO (default), WARN and DEBUG
logLevel: "INFO"
# Actions (buttons) to show up on the WebUI:
actions:
# This will run a simple script that you create.
- title: Run backup script
shell: /opt/backupScript.sh
icon: backup
# Checking for updates https://docs.olivetin.app/reference/updateChecks.html
checkForUpdates: false
# This will send 1 ping (-c 1)
# Docs: https://docs.olivetin.app/action-ping.html
- title: Ping host
shell: ping {{ host }} -c {{ count }}
icon: ping
arguments:
- name: host
title: host
type: ascii_identifier
default: example.com
description: The host that you want to ping
authLocalUsers:
enabled: true
- name: count
title: Count
type: int
default: 1
description: How many times to do you want to ping?
# Restart lightdm on host "server1"
# Docs: https://docs.olivetin.app/action-ping.html
- title: restart httpd
icon: restart
shell: ssh root@server1 'service httpd restart'
# OliveTin can run long-running jobs like Ansible playbooks.
#
# For such jobs, you will need to install ansible-playbook on the host where
# you are running OliveTin, or in the container.
# Actions are commands that are executed by OliveTin, and normally show up as
# buttons on the WebUI.
#
# Docs: https://docs.olivetin.app/action_execution/create_your_first.html
actions:
# This is the most simple action, it just runs the command and flashes the
# button to indicate status.
#
# You probably want a much longer timeout as well (so that ansible completes).
- title: "Run Ansible Playbook"
icon: "&#x1F1E6"
shell: ansible-playbook -i /etc/hosts /root/myRepo/myPlaybook.yaml
timeout: 120
# If you are running OliveTin in a container remember to pass through the
# docker socket! https://docs.olivetin.app/solutions/container-control-panel/index.html
- title: Ping the Internet
shell: ping -c 3 1.1.1.1
icon: ping
popupOnStart: execution-dialog-stdout-only
# This uses `popupOnStart: execution-dialog-stdout-only` to simply show just
# the command output.
- title: Check disk space
icon: disk
shell: df -h /media
popupOnStart: execution-dialog-stdout-only
# This uses `popupOnStart: execution-dialog` to show a dialog with more
# information about the command that was run.
- title: check dmesg logs
shell: dmesg | tail
icon: logs
popupOnStart: execution-dialog
# This uses `popupOnStart: execution-button` to display a mini button that
# links to the logs.
#
# You can also rate-limit actions too.
- title: date
shell: date
timeout: 6
icon: clock
popupOnStart: execution-button
maxRate:
- limit: 3
duration: 5m
# You are not limited to operating system commands, and of course you can run
# your own scripts. Here `maxConcurrent` stops the script running multiple
# times in parallel. There is also a timeout that will kill the command if it
# runs for too long.
- title: Run backup script
shell: /opt/backupScript.sh
shellAfterCompleted: "apprise -t 'Notification: Backup script completed' -b 'The backup script completed with code {{ exitCode}}. The log is: \n {{ output }} '"
maxConcurrent: 1
timeout: 10
icon: backup
popupOnStart: execution-dialog
# When you want to prompt users for input, that is when you should use
# `arguments` - this presents a popup dialog and asks for argument values.
#
# Docs: https://docs.olivetin.app/action_examples/ping.html
- title: Ping host
id: ping_host
shell: ping {{ host }} -c {{ count }}
icon: ping
timeout: 100
popupOnStart: execution-dialog-stdout-only
arguments:
- name: host
title: Host
type: ascii_identifier
default: example.com
description: The host that you want to ping
- name: count
title: Count
type: int
default: 3
description: How many times to do you want to ping?
# OliveTin can control containers - docker is just a command line app.
#
#
# However, if you are running in a container you will need to do some setup,
# see the docs below.
#
# Docs: https://docs.olivetin.app/action-container-control.html
- title: Restart Docker Container
icon: restart
shell: docker restart {{ container }}
arguments:
- name: container
title: Container name
choices:
- value: plex
- value: traefik
- value: grafana
# Docs: https://docs.olivetin.app/solutions/container-control-panel/index.html
- title: Restart Docker Container
icon: restart
shell: docker restart {{ .CurrentEntity }}
arguments:
- name: container
title: Container name
choices:
- value: plex
- value: traefik
- value: grafana
- title: Slow Script
shell: sleep 3
timeout: 5
icon: "&#x1F971"
# There is a special `confirmation` argument to help against accidental clicks
# on "dangerous" actions.
#
# Docs: https://docs.olivetin.app/args/input_confirmation.html
- title: Delete old backups
icon: ashtonished
shell: rm -rf /opt/oldBackups/
arguments:
- type: html
title: Description
default:
The documentation for this action can be found at <a href = "example.com">example.com</a>.
- type: confirmation
title: Are you sure?!
- title: Broken Script (timeout)
shell: sleep 5
timeout: 5
icon: "&#x1F62A"
# This is an action that runs a script included with OliveTin, that will
# download themes. You will still need to set theme "themeName" in your config.
#
# Docs: https://docs.olivetin.app/reference/reference_themes_for_users.html
- title: Get OliveTin Theme
shell: olivetin-get-theme {{ themeGitRepo }} {{ themeFolderName }}
icon: theme
arguments:
- name: themeGitRepo
title: Theme's Git Repository
description: Find new themes at https://olivetin.app/themes
type: url
- name: themeFolderName
title: Theme's Folder Name
type: ascii_identifier
# Sometimes you want to run actions on other servers - don't overcomplicate
# it, just use SSH! OliveTin includes a helper to make this easier, which is
# entirely optional. You can also setup SSH manually.
#
# Docs: https://docs.olivetin.app/action_examples/ssh-easy.html
# Docs: https://docs.olivetin.app/action_examples/ssh-manual.html
- title: "Setup easy SSH"
icon: ssh
shell: olivetin-setup-easy-ssh
popupOnStart: execution-dialog
# Here's how to use SSH with the "easy" config, to restart a service on
# another server.
#
# Docs: https://docs.olivetin.app/action_examples/ssh-easy.html
# Docs: https://docs.olivetin.app/action_examples/systemd_service.html
- title: Restart httpd on server1
id: restart_httpd
icon: restart
timeout: 1
shell: ssh -F /config/ssh/easy.cfg root@server1 'service httpd restart'
# Lots of people use OliveTin to build web interfaces for their electronics
# projects. It's best to install OliveTin as a native package (eg, .deb), and
# then you can use either a python script or the `gpio` command.
- title: Toggle GPIO light
shell: gpioset gpiochip1 9=1
icon: light
# There are several built-in shortcuts for the `icon` option, but you
# can also just specify any HTML, this includes any unicode character,
# or a <img = "..." /> link to a custom icon.
#
# Docs: https://docs.olivetin.app/action_customization/icons.html
#
# Lots of people use OliveTin to easily execute ansible-playbooks. You
# probably want a much longer timeout as well (so that ansible completes).
#
# Docs: https://docs.olivetin.app/action_examples/ansible.html
- title: "Run Automation Playbook"
icon: '&#129302;'
shell: ansible-playbook -i /etc/hosts /root/myRepo/myPlaybook.yaml
timeout: 120
# The following actions are "dummy" actions, used in a Dashboard. As long as
# you have these referenced in a dashboard, they will not show up in the
# `actions` view.
- title: Ping hypervisor1
shell: echo "hypervisor1 online"
- title: Ping hypervisor2
shell: echo "hypervisor2 online"
- title: "{{ server.name }} Wake on Lan"
shell: echo "Sending Wake on LAN to {{ server.hostname }}"
entity: server
- title: "{{ server.name }} Power Off"
shell: "echo 'Power Off Server: {{ server.hostname }}'"
entity: server
- title: Ping All Servers
shell: "echo 'Ping all servers'"
icon: ping
- title: Start {{ .CurrentEntity.Names }}
icon: box
shell: docker start {{ .CurrentEntity.Names }}
entity: container
triggers: ["Update container entity file"]
- title: Stop {{ .CurrentEntity.Names }}
icon: box
shell: docker stop {{ .CurrentEntity.Names }}
entity: container
triggers: ["Update container entity file"]
# Lastly, you can hide actions from the web UI, this is useful for creating
# background helpers that execute only on startup or a cron, for updating
# entity files.
# - title: Update container entity file
# shell: 'docker ps -a --format json > /etc/OliveTin/entities/containers.json'
# hidden: true
# execOnStartup: true
# execOnCron: '*/1 * * * *'
# An entity is something that exists - a "thing", like a VM, or a Container
# is an entity. OliveTin allows you to then dynamically generate actions based
# around these entities.
#
# This is really useful if you want to generate wake on lan or poweroff actions
# for `server` entities, for example.
#
# A very popular use case that entities were designed for was for `container`
# entities - in a similar way you could generate `start`, `stop`, and `restart`
# container actions.
#
# Entities are just loaded fome files on disk, OliveTin will also watch these
# files for updates while OliveTin is running, and update entities.
#
# Entities can have properties defined in those files, and those can be used
# in your configuration as variables. For example; `container.status`,
# or `vm.hostname`.
#
# Docs: https://docs.olivetin.app/entities/intro.html
entities:
# YAML files are the default expected format, so you can use .yml or .yaml,
# or even .txt, as long as the file contains valid a valid yaml LIST, then it
# will load properly.
#
# Docs: https://docs.olivetin.app/entities/intro.html
- file: entities/servers.yaml
name: server
- file: entities/containers.json
name: container
# Dashboards are a way of taking actions from the default "actions" view, and
# organizing them into groups - either into folders, or fieldsets.
#
# The only way to properly use entities, are to use them with a `fieldset` on
# a dashboard.
#
# Docs: https://docs.olivetin.app/dashboards/intro.html
dashboards:
# Top level items are dashboards.
- title: My Servers
contents:
- title: All Servers
type: fieldset
contents:
# The contents of a dashboard will try to look for an action with a
# matching title IF the `contents: ` property is empty.
- title: Ping All Servers
# If you create an item with some "contents:", OliveTin will show that as
# directory.
- title: Hypervisors
contents:
- title: Ping hypervisor1
- title: Ping hypervisor2
# If you specify `type: fieldset` and some `contents`, it will show your
# actions grouped together without a folder.
- type: fieldset
entity: server
title: 'Server: {{ .CurrentEntity.hostname }}'
contents:
# By default OliveTin will look for an action with a matching title
# and put it on the dashboard.
#
# Fieldsets also support `type: display`, which can display arbitary
# text. This is useful for displaying things like a container's state.
- type: display
title: |
Hostname: <strong>{{ server.name }}</strong>
IP Address: <strong>{{ server.ip }}</strong>
# These are the actions (defined above) that we want on the dashboard.
- title: '{{ server.name }} Wake on Lan'
- title: '{{ server.name }} Power Off'
# This is the second dashboard.
- title: My Containers
contents:
- title: 'Container {{ .CurrentEntity.Names }} ({{ .CurrentEntity.Image }})'
entity: container
type: fieldset
contents:
- type: display
title: |
{{ container.RunningFor }} <br /><br /><strong>{{ container.State }}</strong>
- title: 'Start {{ .CurrentEntity.Names }}'
- title: 'Stop {{ .CurrentEntity.Names }}'

View File

@@ -12,4 +12,4 @@
},
"rules": {
}
}
}

1
frontend/.npmrc Normal file
View File

@@ -0,0 +1 @@
fund=false

21
frontend/Makefile Normal file
View File

@@ -0,0 +1,21 @@
define delete-files
python -c "import shutil;shutil.rmtree('$(1)', ignore_errors=True)"
endef
codestyle:
npm install
npx eslint --fix main.js js/*
npx stylelint style.css
clean:
$(call delete-files,dist)
deps:
npm install
build:
npx vite build
dist: deps clean build
.PHONY: codestyle

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

69
frontend/index.html Normal file
View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8" />
<meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
<meta name = "description" content = "Give safe and simple access to predefined shell commands from a web interface." />
<title>OliveTin</title>
<link rel = "stylesheet" type = "text/css" href = "/theme.css" />
<link rel = "stylesheet" href = "node_modules/@xterm/xterm/css/xterm.css" />
<link rel = "shortcut icon" type = "image/png" href = "OliveTinLogo.png" />
<link rel = "apple-touch-icon" sizes="57x57" href="OliveTinLogo-57px.png" />
<link rel = "apple-touch-icon" sizes="120x120" href="OliveTinLogo-120px.png" />
<link rel = "apple-touch-icon" sizes="180x180" href="OliveTinLogo-180px.png" />
<base href = "/" />
</head>
<body>
<slot id = "app" />
<noscript>
<div class = "error">Sorry, JavaScript is required to use OliveTin.</div>
</noscript>
<dialog title = "Big Error Message" id = "big-error" class = "error padded-content">
</dialog>
<script type = "text/javascript">
const bigErrorDialog = document.getElementById('big-error')
/**
This is the bootstrap code, which relies on very simple, old javascript
to at least display a helpful error message if we can't use OliveTin.
*/
window.showBigError = function (type, friendlyType, message, isFatal) {
console.error('Error ' + type + ': ', message)
return;
bigErrorDialog.innerHTML = '<h1>Error ' + friendlyType + '</h1><p>' + message + "</p><p><a href = 'http://docs.olivetin.app/troubleshooting/err-" + type + ".html' target = 'blank'/>" + type + " error in OliveTin Documentation</a></p>"
if (isFatal) {
bigErrorDialog.innerHTML += '<p>You will need to refresh your browser to clear this message.</p>'
} else {
bigErrorDialog.innerHTML += '<p>This error message will go away automatically if the problem is solved.</p>'
}
bigErrorDialog.showModal()
console.error('Error ' + type + ': ', message)
}
window.clearBigErrors = function () {
bigErrorDialog.close()
}
</script>
<script type = "text/javascript" nomodule>
showBigError("js-modules-not-supported", "Sorry, your browser does not support JavaScript modules.", null)
</script>
<script type = "module" src = "main.js"></script>
</body>
</html>

273
frontend/js/ArgumentForm.js Normal file
View File

@@ -0,0 +1,273 @@
class ArgumentForm extends window.HTMLElement {
getQueryParams () {
return new URLSearchParams(window.location.search.substring(1))
}
setup (json, callback) {
this.setAttribute('class', 'action-arguments')
this.constructTemplate()
this.domTitle.innerText = json.title
this.domIcon.innerHTML = json.icon
this.createDomFormArguments(json.arguments)
this.domBtnStart.onclick = () => {
for (const arg of this.argInputs) {
if (!arg.validity.valid) {
return
}
}
const argvs = this.getArgumentValues()
callback(argvs)
this.remove()
}
this.domBtnCancel.onclick = () => {
this.clearBookmark()
this.remove()
}
}
getArgumentValues () {
const ret = []
for (const arg of this.argInputs) {
if (arg.type === 'checkbox') {
if (arg.checked) {
arg.value = '1'
} else {
arg.value = '0'
}
}
if (arg.name === '') {
continue
}
ret.push({
name: arg.name,
value: arg.value
})
}
return ret
}
constructTemplate () {
const tpl = document.getElementById('tplArgumentForm')
const content = tpl.content.cloneNode(true)
this.appendChild(content)
this.domTitle = this.querySelector('h2')
this.domIcon = this.querySelector('span.icon')
this.domWrapper = this.querySelector('.wrapper')
this.domArgs = this.querySelector('.arguments')
this.domBtnStart = this.querySelector('[name=start]')
this.domBtnCancel = this.querySelector('[name=cancel]')
}
createDomFormArguments (args) {
this.argInputs = []
for (const arg of args) {
this.domArgs.appendChild(this.createDomLabel(arg))
this.domArgs.appendChild(this.createDomSuggestions(arg))
this.domArgs.appendChild(this.createDomInput(arg))
this.domArgs.appendChild(this.createDomDescription(arg))
}
}
createDomLabel (arg) {
const domLbl = document.createElement('label')
const lastChar = arg.title.charAt(arg.title.length - 1)
if (lastChar === '?' || lastChar === '.' || lastChar === ':') {
domLbl.innerHTML = arg.title
} else {
domLbl.innerHTML = arg.title + ':'
}
domLbl.setAttribute('for', arg.name)
return domLbl
}
createDomSuggestions (arg) {
if (typeof arg.suggestions !== 'object' || arg.suggestions.length === 0) {
return document.createElement('span')
}
const ret = document.createElement('datalist')
ret.setAttribute('id', arg.name + '-choices')
for (const suggestion of Object.keys(arg.suggestions)) {
const opt = document.createElement('option')
opt.setAttribute('value', suggestion)
if (typeof arg.suggestions[suggestion] !== 'undefined' && arg.suggestions[suggestion].length > 0) {
opt.innerText = arg.suggestions[suggestion]
}
ret.appendChild(opt)
}
return ret
}
createDomInput (arg) {
let domEl = null
if (arg.choices.length > 0 && (arg.type === 'select' || arg.type === '')) {
domEl = document.createElement('select')
// select/choice elements don't get an onchange/validation because theoretically
// the user should only select from a dropdown of valid options. The choices are
// riggeriously checked on StartAction anyway. ValidateArgumentType is only
// meant for showing simple warnings in the UI before running.
for (const choice of arg.choices) {
domEl.appendChild(this.createSelectOption(choice))
}
} else {
switch (arg.type) {
case 'html':
domEl = document.createElement('div')
domEl.innerHTML = arg.defaultValue
return domEl
case 'confirmation':
this.domBtnStart.disabled = true
domEl = document.createElement('input')
domEl.setAttribute('type', 'checkbox')
domEl.onchange = () => {
this.domBtnStart.disabled = false
domEl.disabled = true
}
break
case 'raw_string_multiline':
domEl = document.createElement('textarea')
domEl.setAttribute('rows', '5')
domEl.style.resize = 'vertical'
break
case 'datetime':
domEl = document.createElement('input')
domEl.setAttribute('type', 'datetime-local')
domEl.setAttribute('step', '1')
break
case 'checkbox':
domEl = document.createElement('input')
domEl.setAttribute('type', 'checkbox')
domEl.setAttribute('name', arg.name)
domEl.setAttribute('value', '1')
break
case 'password':
case 'email':
domEl = document.createElement('input')
domEl.setAttribute('type', arg.type)
break
default:
domEl = document.createElement('input')
if (arg.type.startsWith('regex:')) {
domEl.setAttribute('pattern', arg.type.replace('regex:', ''))
}
domEl.onchange = () => {
this.formatValidation(domEl, arg)
}
}
}
domEl.name = arg.name
// Use query parameter value if available
const params = this.getQueryParams()
const paramValue = params.get(arg.name)
if (paramValue !== null) {
domEl.value = paramValue
} else {
domEl.value = arg.defaultValue
}
// update the URL when a parameter is changed
domEl.addEventListener('change', this.updateUrlWithArg)
if (typeof arg.suggestions === 'object' && Object.keys(arg.suggestions).length > 0) {
domEl.setAttribute('list', arg.name + '-choices')
}
this.argInputs.push(domEl)
return domEl
}
async formatValidation (domEl, arg) {
const validateArgumentTypeArgs = {
value: domEl.value,
type: arg.type
}
const validation = await window.validateArgumentType(validateArgumentTypeArgs)
if (validation.valid) {
domEl.setCustomValidity('')
} else {
domEl.setCustomValidity(validation.description)
}
}
updateUrlWithArg (ev) {
if (!ev.target.name) {
return
}
const url = new URL(window.location.href)
if (ev.target.type === 'password') {
return
}
// copy the parameter value
url.searchParams.set(ev.target.name, ev.target.value)
// Update the URL without reloading the page
window.history.replaceState({}, '', url.toString())
}
createDomDescription (arg) {
const domArgumentDescription = document.createElement('span')
domArgumentDescription.classList.add('argument-description')
domArgumentDescription.innerHTML = arg.description
return domArgumentDescription
}
createSelectOption (choice) {
const domEl = document.createElement('option')
domEl.setAttribute('value', choice.value)
domEl.innerText = choice.title
return domEl
}
clearBookmark () {
// remove the action from the URL
window.history.replaceState({
path: window.location.pathname
}, '', window.location.pathname)
}
}
window.customElements.define('argument-form', ArgumentForm)

View File

@@ -0,0 +1,29 @@
export class ExecutionFeedbackButton extends window.HTMLElement {
onExecutionFinished (LogEntry) {
if (LogEntry.timedOut) {
this.renderExecutionResult('action-timeout', 'Timed out')
} else if (LogEntry.blocked) {
this.renderExecutionResult('action-blocked', 'Blocked!')
} else if (LogEntry.exitCode !== 0) {
this.renderExecutionResult('action-nonzero-exit', 'Exit code ' + LogEntry.exitCode)
} else {
this.ellapsed = Math.ceil(new Date(LogEntry.datetimeFinished) - new Date(LogEntry.datetimeStarted)) / 1000
this.renderExecutionResult('action-success', 'Success!')
}
}
renderExecutionResult (resultCssClass, temporaryStatusMessage) {
this.updateDom(resultCssClass, '[' + temporaryStatusMessage + ']')
this.onExecStatusChanged()
}
updateDom (resultCssClass, title) {
if (resultCssClass == null) {
this.btn.className = ''
} else {
this.btn.classList.add(resultCssClass)
}
this.domTitle.innerText = title
}
}

24
frontend/js/Mutex.js Normal file
View File

@@ -0,0 +1,24 @@
export class Mutex {
constructor () {
this._locked = false
this._waiting = []
}
lock () {
const unlock = () => {
const next = this._waiting.shift()
if (next) {
next(unlock)
} else {
this._locked = false
}
}
if (this._locked) {
return new Promise(resolve => this._waiting.push(resolve)).then(() => unlock)
} else {
this._locked = true
return Promise.resolve(unlock)
}
}
}

View File

@@ -0,0 +1,76 @@
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import { Mutex } from './Mutex.js'
/**
* xterm.js based terminal output for the execution dialog.
*
* the xterm.js methods for write(), reset() and clear() appear to be async,
* but they do not return a Promise and instead use a callback. When calling
* these methods in quick succession, the output can get garbled due to race
* conditions.
*
* To avoid this, this class uses Mutex around those methods to ensure that
* only one write OR reset is executed at a time, is completed, and the calls
* occour in sequential order.
*/
export class OutputTerminal {
constructor () {
this.writeMutex = new Mutex()
this.terminal = new Terminal({
convertEol: true
})
const fitAddon = new FitAddon()
this.terminal.loadAddon(fitAddon)
this.terminal.fit = fitAddon
}
async write (out, then) {
const unlock = await this.writeMutex.lock()
try {
await new Promise(resolve => {
this.terminal.write(out, () => {
resolve()
})
})
} finally {
unlock()
if (then != null && then !== undefined) {
then()
}
}
}
async reset () {
const unlock = await this.writeMutex.lock()
try {
await new Promise(resolve => {
this.terminal.clear()
this.terminal.reset()
resolve()
})
} finally {
unlock()
}
}
fit () {
this.terminal.fit.fit()
}
open (el) {
this.terminal.open(el)
}
close () {
this.terminal.dispose()
}
resize (cols, rows) {
this.terminal.resize(cols, rows)
}
}

13
frontend/js/marshaller.js Normal file
View File

@@ -0,0 +1,13 @@
export function initMarshaller () {
window.addEventListener('EventOutputChunk', onOutputChunk)
}
function onOutputChunk (evt) {
const chunk = evt.payload
if (window.terminal) {
if (chunk.executionTrackingId === window.terminal.executionTrackingId) {
window.terminal.write(chunk.output)
}
}
}

49
frontend/js/websocket.js Normal file
View File

@@ -0,0 +1,49 @@
import { buttonResults } from '../resources/vue/stores/buttonResults.js'
export function checkWebsocketConnection () {
reconnectWebsocket()
}
window.websocketAvailable = false
async function reconnectWebsocket () {
if (window.websocketAvailable) {
return
}
try {
window.websocketAvailable = true
for await (const e of window.client.eventStream()) {
handleEvent(e)
}
} catch (err) {
console.error('Websocket connection failed: ', err)
}
window.websocketAvailable = false
console.log('Reconnecting websocket...')
}
function handleEvent (msg) {
const typeName = msg.event.value.$typeName.replace('olivetin.api.v1.', '')
const j = new Event(typeName)
j.payload = msg.event.value
switch (typeName) {
case 'EventOutputChunk':
case 'EventConfigChanged':
case 'EventEntityChanged':
window.dispatchEvent(j)
break
case 'EventExecutionFinished':
case 'EventExecutionStarted':
buttonResults[msg.event.value.logEntry.executionTrackingId] = msg.event.value.logEntry
window.dispatchEvent(j)
break
default:
console.warn('Unhandled websocket message type from server: ', typeName)
window.showBigError('ws-unhandled-message', 'handling websocket message', 'Unhandled websocket message type from server: ' + typeName, true)
}
}

53
frontend/main.js Normal file
View File

@@ -0,0 +1,53 @@
'use strict'
import 'femtocrank/style.css'
import './style.css'
import 'iconify-icon'
import { createClient } from '@connectrpc/connect'
import { createConnectTransport } from '@connectrpc/connect-web'
import { OliveTinApiService } from './resources/scripts/gen/olivetin/api/v1/olivetin_pb'
import { createApp } from 'vue'
import router from './resources/vue/router.js'
import App from './resources/vue/App.vue'
import {
initMarshaller
} from './js/marshaller.js'
import { checkWebsocketConnection } from './js/websocket.js'
function initClient () {
const transport = createConnectTransport({
baseUrl: window.location.protocol + '//' + window.location.host + '/api/'
})
window.client = createClient(OliveTinApiService, transport)
}
function setupVue () {
const app = createApp(App)
app.use(router)
app.mount('#app')
}
function main () {
initClient()
// Expose websocket connection function globally so App.vue can call it after successful init
window.checkWebsocketConnection = checkWebsocketConnection
setupVue()
initMarshaller()
// window.addEventListener('EventConfigChanged', fetchGetDashboardComponents)
// window.addEventListener('EventEntityChanged', fetchGetDashboardComponents)
}
main() // call self

3345
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

38
frontend/package.json Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "olivetin-webui",
"version": "1.0.0",
"description": "The WebUI for OliveTin",
"repository": "https://github.com/OliveTin/OliveTin",
"source": "index.html",
"devDependencies": {
"process": "^0.11.10",
"stylelint": "^16.25.0",
"stylelint-config-standard": "^39.0.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"parcelIgnore": [
"theme.css",
"OliveTinLogo.png",
"OliveTinLogo-57px.png",
"OliveTinLogo-120px.png",
"OliveTinLogo-180px.png"
],
"license": "AGPL-3.0-only",
"dependencies": {
"@connectrpc/connect": "^2.1.0",
"@connectrpc/connect-web": "^2.1.0",
"@hugeicons/core-free-icons": "^1.2.1",
"@hugeicons/vue": "^1.0.3",
"@vitejs/plugin-vue": "^6.0.1",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"iconify-icon": "^3.0.1",
"picocrank": "^1.6.2",
"unplugin-vue-components": "^30.0.0",
"vite": "^7.1.12",
"vue-router": "^4.6.3"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,296 @@
<template>
<div :id="`actionButton-${actionId}`" role="none" class="action-button">
<button :id="`actionButtonInner-${actionId}`" :title="title" :disabled="!canExec || isDisabled"
:class="buttonClasses" @click="handleClick">
<div class="navigate-on-start-container">
<div v-if="navigateOnStart == 'pop'" class="navigate-on-start" title="Opens a popup dialog on start">
<HugeiconsIcon :icon="ComputerTerminal01Icon" />
</div>
<div v-if="navigateOnStart == 'arg'" class="navigate-on-start" title="Opens an argument form on start">
<HugeiconsIcon :icon="TypeCursorIcon" />
</div>
<div v-if="navigateOnStart == ''" class="navigate-on-start" title="Run in the background">
<HugeiconsIcon :icon="WorkoutRunIcon" />
</div>
</div>
<span class="icon" v-html="unicodeIcon"></span>
<span class="title" aria-live="polite">{{ displayTitle }}
</span>
</button>
</div>
</template>
<script setup>
import ArgumentForm from './views/ArgumentForm.vue'
import { buttonResults } from './stores/buttonResults'
import { useRouter } from 'vue-router'
import { HugeiconsIcon } from '@hugeicons/vue'
import { WorkoutRunIcon, TypeCursorIcon, ComputerTerminal01Icon } from '@hugeicons/core-free-icons'
import { ref, watch, onMounted, inject } from 'vue'
const router = useRouter()
const navigateOnStart = ref('')
const props = defineProps({
actionData: {
type: Object,
required: true
}
})
const actionId = ref('')
const title = ref('')
const canExec = ref(true)
const popupOnStart = ref('')
// Display properties
const unicodeIcon = ref('&#x1f4a9;')
const displayTitle = ref('')
// State
const isDisabled = ref(false)
const showArgumentForm = ref(false)
// Animation classes
const buttonClasses = ref([])
// Timestamps
const updateIterationTimestamp = ref(0)
function getUnicodeIcon(icon) {
if (icon === '') {
console.log('icon not found ', icon)
return '&#x1f4a9;'
} else {
return unescape(icon)
}
}
function constructFromJson(json) {
updateIterationTimestamp.value = 0
updateFromJson(json)
actionId.value = json.bindingId
title.value = json.title
canExec.value = json.canExec
popupOnStart.value = json.popupOnStart
if (popupOnStart.value.includes('execution-dialog')) {
navigateOnStart.value = 'pop'
} else if (props.actionData.arguments.length > 0) {
navigateOnStart.value = 'arg'
}
isDisabled.value = !json.canExec
displayTitle.value = title.value
unicodeIcon.value = getUnicodeIcon(json.icon)
}
function updateFromJson(json) {
// Fields that should not be updated
// title - as the callback URL relies on it
unicodeIcon.value = getUnicodeIcon(json.icon)
}
async function handleClick() {
if (props.actionData.arguments && props.actionData.arguments.length > 0) {
router.push(`/actionBinding/${props.actionData.bindingId}/argumentForm`)
} else {
await startAction()
}
}
function getUniqueId() {
if (window.isSecureContext) {
return window.crypto.randomUUID()
} else {
return Date.now().toString()
}
}
async function startAction(actionArgs) {
buttonClasses.value = [] // Removes old animation classes
if (actionArgs === undefined) {
actionArgs = []
}
// UUIDs are create client side, so that we can setup a "execution-button"
// to track the execution before we send the request to the server.
const startActionArgs = {
bindingId: props.actionData.bindingId,
arguments: actionArgs,
uniqueTrackingId: getUniqueId()
}
console.log('Watching buttonResults for', startActionArgs.uniqueTrackingId)
watch(
() => buttonResults[startActionArgs.uniqueTrackingId],
(newResult, oldResult) => {
onLogEntryChanged(newResult)
}
)
try {
await window.client.startAction(startActionArgs)
} catch (err) {
console.error('Failed to start action:', err)
}
}
function onLogEntryChanged(logEntry) {
if (logEntry.executionFinished) {
onExecutionFinished(logEntry)
} else {
onExecutionStarted(logEntry)
}
}
function onExecutionStarted(logEntry) {
if (popupOnStart.value && popupOnStart.value.includes('execution-dialog')) {
router.push(`/logs/${logEntry.executionTrackingId}`)
}
isDisabled.value = true
}
function onExecutionFinished(logEntry) {
if (logEntry.timedOut) {
renderExecutionResult('action-timeout', 'Timed out')
} else if (logEntry.blocked) {
renderExecutionResult('action-blocked', 'Blocked!')
} else if (logEntry.exitCode !== 0) {
renderExecutionResult('action-nonzero-exit', 'Exit code ' + logEntry.exitCode)
} else {
const ellapsed = Math.ceil(new Date(logEntry.datetimeFinished) - new Date(logEntry.datetimeStarted)) / 1000
renderExecutionResult('action-success', 'Success!')
}
}
function renderExecutionResult(resultCssClass, temporaryStatusMessage) {
updateDom(resultCssClass, '[' + temporaryStatusMessage + ']')
onExecStatusChanged()
}
function updateDom(resultCssClass, newTitle) {
if (resultCssClass == null) {
buttonClasses.value = []
} else {
buttonClasses.value = [resultCssClass]
}
displayTitle.value = newTitle
}
function onExecStatusChanged() {
isDisabled.value = false
setTimeout(() => {
updateDom(null, title.value)
}, 2000)
}
onMounted(() => {
constructFromJson(props.actionData)
})
watch(
() => props.actionData,
(newData) => {
updateFromJson(newData)
},
{ deep: true }
)
</script>
<style scoped>
.action-button {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.action-button button {
display: flex;
flex-direction: column;
flex-grow: 1;
justify-content: center;
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 4px;
background: #fff;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 0 .6em #aaa;
font-size: .85em;
border-radius: .7em;
}
.action-button button:hover:not(:disabled) {
background: #f5f5f5;
border-color: #999;
}
.action-button button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.action-button button .icon {
font-size: 3em;
flex-grow: 1;
align-content: center;
}
.action-button button .title {
font-weight: 500;
padding: 0.2em;
}
/* Animation classes */
.action-button button.action-timeout {
background: #fff3cd;
border-color: #ffeaa7;
color: #856404;
}
.action-button button.action-blocked {
background: #f8d7da !important;
border-color: #f5c6cb;
color: #721c24;
}
.action-button button.action-nonzero-exit {
background: #f8d7da !important;
border-color: #f5c6cb;
color: #721c24;
}
.action-button button.action-success {
background: #d4edda !important;
border-color: #c3e6cb;
color: #155724;
}
.action-button-footer {
margin-top: 0.5em;
}
.navigate-on-start-container {
position: relative;
margin-left: auto;
height: 0;
right: 0;
top: 0;
}
</style>

View File

@@ -0,0 +1,168 @@
<template>
<Header title="OliveTin" :logoUrl="logoUrl" @toggleSidebar="toggleSidebar">
<template #toolbar>
<div id="banner" v-if="bannerMessage" :style="bannerCss">
<p>{{ bannerMessage }}</p>
</div>
</template>
<template #user-info>
<div class="flex-row" style="gap: .5em;">
<span id="link-login" v-if="!isLoggedIn"><router-link to="/login">Login</router-link></span>
<div v-else>
<span id="username-text" :title="'Provider: ' + userProvider">{{ username }}</span>
<span id="link-logout" v-if="isLoggedIn"><a href="/api/Logout">Logout</a></span>
</div>
<HugeiconsIcon :icon="UserCircle02Icon" width = "1.5em" height = "1.5em" />
</div>
</template>
</Header>
<div id="layout">
<Sidebar ref="sidebar" id = "mainnav" v-if="showNavigation && !initError" />
<div id="content" initial-martial-complete="{{ hasLoaded }}">
<main title="Main content">
<section v-if="initError" class="error-container error" style="text-align: center; padding: 2em;">
<h2>Failed to Initialize OliveTin</h2>
<p><strong>Error Message:</strong> {{ initErrorMessage }}</p>
<p>Please check the your browser console first, and then the server logs for more details.</p>
<button @click="retryInit" class="bad">Retry</button>
</section>
<router-view v-else :key="$route.fullPath" />
</main>
<footer title="footer" v-if="showFooter && !initError">
<p>
<img title="application icon" src="../../OliveTinLogo.png" alt="OliveTin logo" height="1em"
class="logo" />
OliveTin 3000!
</p>
<p>
<span>
<a href="https://docs.olivetin.app" target="_new">Documentation</a>
</span>
<span>
<a href="https://github.com/OliveTin/OliveTin/issues/new/choose" target="_new">Raise an issue on
GitHub</a>
</span>
<span>{{ currentVersion }}</span>
<span>{{ serverConnection }}</span>
</p>
<p>
<a id="available-version" href="http://olivetin.app" target="_blank" hidden>?</a>
</p>
</footer>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import Sidebar from 'picocrank/vue/components/Sidebar.vue';
import Header from 'picocrank/vue/components/Header.vue';
import { HugeiconsIcon } from '@hugeicons/vue'
import { Menu01Icon } from '@hugeicons/core-free-icons'
import { UserCircle02Icon } from '@hugeicons/core-free-icons'
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
import logoUrl from '../../OliveTinLogo.png';
const sidebar = ref(null);
const username = ref('guest');
const userProvider = ref('system');
const isLoggedIn = ref(false);
const serverConnection = ref('Connected');
const currentVersion = ref('?');
const bannerMessage = ref('');
const bannerCss = ref('');
const hasLoaded = ref(false);
const showFooter = ref(true)
const showNavigation = ref(true)
const showLogs = ref(true)
const showDiagnostics = ref(true)
const initError = ref(false)
const initErrorMessage = ref('')
function toggleSidebar() {
sidebar.value.toggle()
}
async function requestInit() {
try {
const initResponse = await window.client.init({})
window.initResponse = initResponse
window.initError = false
window.initErrorMessage = ''
window.initCompleted = true
username.value = initResponse.authenticatedUser
currentVersion.value = initResponse.currentVersion
bannerMessage.value = initResponse.bannerMessage || '';
bannerCss.value = initResponse.bannerCss || '';
showFooter.value = initResponse.showFooter
showNavigation.value = initResponse.showNavigation
showLogs.value = initResponse.showLogList
showDiagnostics.value = initResponse.showDiagnostics
for (const rootDashboard of initResponse.rootDashboards) {
sidebar.value.addNavigationLink({
id: rootDashboard,
name: rootDashboard,
title: rootDashboard,
path: rootDashboard === 'Actions' ? '/' : `/dashboards/${rootDashboard}`,
icon: DashboardSquare01Icon,
})
}
sidebar.value.addSeparator()
sidebar.value.addRouterLink('Entities')
if (showLogs.value) {
sidebar.value.addRouterLink('Logs')
}
if (showDiagnostics.value) {
sidebar.value.addRouterLink('Diagnostics')
}
hasLoaded.value = true;
initError.value = false;
// Only start websocket connection after successful init
if (window.checkWebsocketConnection) {
window.checkWebsocketConnection()
}
} catch (error) {
console.error("Error initializing client", error)
initError.value = true
initErrorMessage.value = error.message || 'Failed to connect to OliveTin server'
window.initError = true
window.initErrorMessage = error.message || 'Failed to connect to OliveTin server'
window.initCompleted = false
serverConnection.value = 'Disconnected'
}
}
function retryInit() {
initError.value = false
initErrorMessage.value = ''
window.initError = false
window.initErrorMessage = ''
window.initCompleted = false
requestInit()
}
onMounted(() => {
serverConnection.value = 'Connected';
// Initialize global state
window.initError = false
window.initErrorMessage = ''
window.initCompleted = false
requestInit()
})
</script>

View File

@@ -0,0 +1,174 @@
<template>
<section v-if="!dashboard && !initError" style = "text-align: center; padding: 2em;">
<HugeiconsIcon :icon="Loading03Icon" width="3em" height="3em" style="animation: spin 1s linear infinite;" />
<p>Loading dashboard...</p>
<p style="color: var(--fg2);">{{ loadingTime }}s</p>
</section>
<section v-if="initError" style="text-align: center; padding: 2em;" class = "bad">
<h2 style="color: var(--error);">Initialization Failed</h2>
<p>{{ initError }}</p>
<p style="color: var(--fg2);">Please check your configuration and try again.</p>
</section>
<div v-else-if="dashboard">
<section v-if="dashboard.contents.length == 0">
<legend>{{ dashboard.title }}</legend>
<p style = "text-align: center" class = "padding">This dashboard is empty.</p>
</section>
<section class="transparent" v-else>
<div v-for="component in dashboard.contents" :key="component.title">
<fieldset>
<legend v-if = "dashboard.title != 'Default'">{{ component.title }}</legend>
<template v-for="subcomponent in component.contents">
<DashboardComponent :component="subcomponent" />
</template>
</fieldset>
</div>
</section>
</div>
</template>
<script setup>
import DashboardComponent from './components/DashboardComponent.vue'
import { onMounted, onUnmounted, ref } from 'vue'
import { HugeiconsIcon } from '@hugeicons/vue'
import { Loading03Icon } from '@hugeicons/core-free-icons'
const props = defineProps({
title: {
type: String,
required: false
}
})
const dashboard = ref(null)
const loadingTime = ref(0)
const initError = ref(null)
let loadingTimer = null
let checkInitInterval = null
async function getDashboard() {
let title = props.title
// If no specific title was provided or it's the placeholder 'default',
// prefer the first configured root dashboard (e.g., "Test").
if ((!title || title === 'default') && window.initResponse.rootDashboards && window.initResponse.rootDashboards.length > 0) {
title = window.initResponse.rootDashboards[0]
}
try {
const ret = await window.client.getDashboard({
title: title,
})
if (!ret || !ret.dashboard) {
throw new Error('No dashboard found')
}
dashboard.value = ret.dashboard
document.title = ret.dashboard.title + ' - OliveTin'
// Clear any previous init error since we successfully loaded
initError.value = null
// Stop the loading timer once dashboard is loaded
if (loadingTimer) {
clearInterval(loadingTimer)
loadingTimer = null
}
// Set attribute to indicate dashboard is loaded successfully
document.body.setAttribute('loaded-dashboard', title || 'default')
} catch (e) {
// On error, provide a safe fallback state
console.error('Failed to load dashboard', e)
dashboard.value = { title: title || 'Default', contents: [] }
document.title = 'Error - OliveTin'
// Stop the loading timer on error
if (loadingTimer) {
clearInterval(loadingTimer)
loadingTimer = null
}
// Set attribute even on error so tests can proceed
document.body.setAttribute('loaded-dashboard', title || 'error')
}
}
function waitForInitAndLoadDashboard() {
// Start the loading timer
loadingTime.value = 0
loadingTimer = setInterval(() => {
loadingTime.value++
}, 1000)
// Check if init has completed successfully
if (window.initCompleted && window.initResponse) {
getDashboard()
} else if (window.initError) {
// Init failed, show error immediately
initError.value = window.initErrorMessage || 'Initialization failed. Please check your configuration and try again.'
// Stop the loading timer since we're showing an error
if (loadingTimer) {
clearInterval(loadingTimer)
loadingTimer = null
}
} else {
// Init hasn't completed yet, poll for completion
checkInitInterval = setInterval(() => {
if (window.initCompleted && window.initResponse) {
clearInterval(checkInitInterval)
checkInitInterval = null
getDashboard()
} else if (window.initError) {
clearInterval(checkInitInterval)
checkInitInterval = null
initError.value = window.initErrorMessage || 'Initialization failed. Please check your configuration and try again.'
// Stop the loading timer since we're showing an error
if (loadingTimer) {
clearInterval(loadingTimer)
loadingTimer = null
}
}
}, 100) // Check every 100ms
}
}
onMounted(() => {
waitForInitAndLoadDashboard()
})
onUnmounted(() => {
// Clean up the timers when component is unmounted
if (loadingTimer) {
clearInterval(loadingTimer)
loadingTimer = null
}
if (checkInitInterval) {
clearInterval(checkInitInterval)
checkInitInterval = null
}
})
</script>
<style>
fieldset {
display: grid;
grid-template-columns: repeat(auto-fit, 180px);
grid-auto-rows: 1fr;
justify-content: center;
place-items: stretch;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>

View File

@@ -0,0 +1,141 @@
<template>
<div
:id="`execution-${executionTrackingId}`"
class="execution-button"
>
<button
:title="`${ellapsed}s`"
@click="show"
>
{{ buttonText }}
</button>
</div>
</template>
<script>
//import { ExecutionFeedbackButton } from '../js/ExecutionFeedbackButton.js'
export default {
name: 'ExecutionButton',
// mixins: [ExecutionFeedbackButton],
props: {
executionTrackingId: {
type: String,
required: true
}
},
data() {
return {
ellapsed: 0,
isWaiting: true
}
},
computed: {
buttonText() {
if (this.isWaiting) {
return 'Executing...'
} else {
return `${this.ellapsed}s`
}
}
},
mounted() {
this.constructFromJson(this.executionTrackingId)
},
methods: {
constructFromJson(json) {
this.executionTrackingId = json
this.ellapsed = 0
this.isWaiting = true
},
show() {
this.$emit('show')
if (window.executionDialog) {
window.executionDialog.reset()
window.executionDialog.show()
window.executionDialog.fetchExecutionResult(this.executionTrackingId)
}
},
onExecStatusChanged() {
this.isWaiting = false
this.domTitle = this.ellapsed + 's'
},
// Override from ExecutionFeedbackButton
onExecutionFinished(logEntry) {
if (logEntry.timedOut) {
this.renderExecutionResult('action-timeout', 'Timed out')
} else if (logEntry.blocked) {
this.renderExecutionResult('action-blocked', 'Blocked!')
} else if (logEntry.exitCode !== 0) {
this.renderExecutionResult('action-nonzero-exit', 'Exit code ' + logEntry.exitCode)
} else {
this.ellapsed = Math.ceil(new Date(logEntry.datetimeFinished) - new Date(logEntry.datetimeStarted)) / 1000
this.renderExecutionResult('action-success', 'Success!')
}
},
renderExecutionResult(resultCssClass, temporaryStatusMessage) {
this.updateDom(resultCssClass, '[' + temporaryStatusMessage + ']')
this.onExecStatusChanged()
},
updateDom(resultCssClass, title) {
// For execution button, we don't need to update classes as much
// since it's a simpler component
if (resultCssClass) {
this.$el.classList.add(resultCssClass)
}
}
}
}
</script>
<style scoped>
.execution-button {
display: inline-block;
}
.execution-button button {
padding: 0.25em 0.5em;
border: 1px solid #ccc;
border-radius: 3px;
background: #fff;
cursor: pointer;
font-size: 0.9em;
transition: all 0.2s ease;
}
.execution-button button:hover {
background: #f5f5f5;
border-color: #999;
}
/* Animation classes */
.execution-button button.action-timeout {
background: #fff3cd;
border-color: #ffeaa7;
color: #856404;
}
.execution-button button.action-blocked {
background: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
}
.execution-button button.action-nonzero-exit {
background: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
}
.execution-button button.action-success {
background: #d4edda;
border-color: #c3e6cb;
color: #155724;
}
</style>

View File

@@ -0,0 +1,63 @@
<template>
<span>
<span :class="['action-status', statusClass]">{{ statusText }}</span><span>{{ exitCodeText }}</span>
</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
logEntry: {
type: Object,
required: true
}
})
const statusText = computed(() => {
const logEntry = props.logEntry
if (!logEntry) return 'unknown'
if (logEntry.executionFinished) {
if (logEntry.blocked) {
return 'Blocked'
} else if (logEntry.timedOut) {
return 'Timed out'
} else {
return 'Completed'
}
} else {
return 'Still running...'
}
})
const exitCodeText = computed(() => {
const logEntry = props.logEntry
if (!logEntry) return ''
if (logEntry.executionFinished) {
if (logEntry.blocked || logEntry.timedOut) {
return ''
}
return ' Exit code: ' + logEntry.exitCode
}
return ''
})
const statusClass = computed(() => {
const logEntry = props.logEntry
if (!logEntry) return ''
if (logEntry.executionFinished) {
if (logEntry.blocked) {
return 'action-blocked'
} else if (logEntry.timedOut) {
return 'action-timeout'
} else if (logEntry.exitCode === 0) {
return 'action-success'
} else {
return 'action-nonzero-exit'
}
}
return ''
})
</script>

View File

@@ -0,0 +1,58 @@
<template>
<div id = "breadcrumbs">
<template v-for="(link, index) in links" :key="link.name">
<router-link :to="link.href">{{ link.name }}</router-link>
<span v-if="index < links.length - 1" class="separator">
&raquo;
</span>
</template>
</div>
</template>
<style scoped>
span {
color: #bbb;
}
a {
text-decoration: none;
padding: 0.4em;
border-radius: 0.2em;
}
a:hover {
text-decoration: underline;
background-color: #000;
}
</style>
<script setup>
import { ref } from 'vue';
import { watch } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
const links = ref([]);
watch(() => route.matched, (matched) => {
links.value = [];
matched.forEach((record) => {
if (record.meta && record.meta.breadcrumb) {
record.meta.breadcrumb.forEach((item) => {
links.value.push({
name: item.name,
href: item.href || record.path || '/'
});
});
} else if (record.name) {
links.value.push({
name: record.name,
href: record.path || '/'
});
}
});
}, { immediate: true });
</script>

View File

@@ -0,0 +1,41 @@
<template>
<ActionButton v-if="component.type == 'link'" :actionData="component.action" :key="component.title" />
<div v-else-if="component.type == 'directory'">
<router-link :to="{ name: 'Dashboard', params: { title: component.title } }" class="dashboard-link">
<button>
{{ component.title }}
</button>
</router-link>
</div>
<div v-else-if="component.type == 'display'" class="display">
<div v-html="component.title" />
</div>
<template v-else-if="component.type == 'fieldset'">
<fieldset>
<legend>{{ component.title }}</legend>
<template v-for="subcomponent in component.contents" :key="subcomponent.title">
<DashboardComponent :component="subcomponent" />
</template>
</fieldset>
</template>
<div v-else>
OTHER: {{ component.type }}
{{ component }}
</div>
</template>
<script setup>
import ActionButton from '../ActionButton.vue'
const props = defineProps({
component: {
type: Object,
required: true
}
})
</script>

View File

@@ -0,0 +1,284 @@
<template>
<div class="pagination">
<div class="pagination-info">
<span class="pagination-text">
Showing {{ startItem + 1 }}-{{ endItem }} of {{ total }} {{ itemTitle }}
</span>
</div>
<div class="pagination-controls">
<button
class="pagination-btn"
:disabled="currentPage === 1"
@click="goToPage(currentPage - 1)"
title="Previous page"
>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M15.41 7.41L14 6l-6 6l6 6l1.41-1.41L10.83 12z"/>
</svg>
</button>
<div class="pagination-pages">
<!-- First page -->
<button
v-if="showFirstPage"
class="pagination-btn"
:class="{ active: currentPage === 1 }"
@click="goToPage(1)"
>
1
</button>
<!-- Ellipsis after first page -->
<span v-if="showFirstEllipsis" class="pagination-ellipsis">...</span>
<!-- Page numbers around current page -->
<button
v-for="page in visiblePages"
:key="page"
class="pagination-btn"
:class="{ active: currentPage === page }"
@click="goToPage(page)"
>
{{ page }}
</button>
<!-- Ellipsis before last page -->
<span v-if="showLastEllipsis" class="pagination-ellipsis">...</span>
<!-- Last page -->
<button
v-if="showLastPage"
class="pagination-btn"
:class="{ active: currentPage === totalPages }"
@click="goToPage(totalPages)"
>
{{ totalPages }}
</button>
</div>
<button
class="pagination-btn"
:disabled="currentPage === totalPages"
@click="goToPage(currentPage + 1)"
title="Next page"
>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M8.59 16.59L10 18l6-6l-6-6L8.59 7.41L13.17 12z"/>
</svg>
</button>
</div>
<div class="pagination-size" v-if="canChangePageSize">
<label for="page-size">Items per page:</label>
<select
id="page-size"
v-model="localPageSize"
@change="handlePageSizeChange"
class="page-size-select"
>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const props = defineProps({
pageSize: {
type: Number,
default: 25
},
total: {
type: Number,
required: true
},
currentPage: {
type: Number,
default: 1
},
canChangePageSize: {
type: Boolean,
default: false
},
itemTitle: {
type: String,
default: 'items'
}
})
const emit = defineEmits(['page-change', 'page-size-change'])
const localPageSize = ref(props.pageSize)
const localCurrentPage = ref(props.currentPage)
// Computed properties
const totalPages = computed(() => Math.ceil(props.total / localPageSize.value))
const startItem = computed(() => (localCurrentPage.value - 1) * localPageSize.value)
const endItem = computed(() => Math.min(localCurrentPage.value * localPageSize.value, props.total))
// Pagination logic
const maxVisiblePages = 5
const visiblePages = computed(() => {
const pages = []
const halfVisible = Math.floor(maxVisiblePages / 2)
let start = Math.max(1, localCurrentPage.value - halfVisible)
let end = Math.min(totalPages.value, start + maxVisiblePages - 1)
// Adjust start if we're near the end
if (end - start < maxVisiblePages - 1) {
start = Math.max(1, end - maxVisiblePages + 1)
}
for (let i = start; i <= end; i++) {
pages.push(i)
}
return pages
})
const showFirstPage = computed(() => visiblePages.value[0] > 1)
const showLastPage = computed(() => visiblePages.value[visiblePages.value.length - 1] < totalPages.value)
const showFirstEllipsis = computed(() => visiblePages.value[0] > 2)
const showLastEllipsis = computed(() => visiblePages.value[visiblePages.value.length - 1] < totalPages.value - 1)
// Methods
function goToPage(page) {
if (page >= 1 && page <= totalPages.value && page !== localCurrentPage.value) {
localCurrentPage.value = page
emit('page-change', page)
}
}
function handlePageSizeChange() {
// Reset to first page when changing page size
localCurrentPage.value = 1
emit('page-size-change', localPageSize.value)
emit('page-change', 1)
}
// Watch for prop changes
watch(() => props.currentPage, (newPage) => {
localCurrentPage.value = newPage
})
watch(() => props.pageSize, (newSize) => {
localPageSize.value = newSize
})
</script>
<style scoped>
.pagination {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 1rem;
}
.pagination-info {
flex: 1;
}
.pagination-text {
font-size: 0.875rem;
color: #6c757d;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 0.5rem;
}
.pagination-pages {
display: flex;
align-items: center;
gap: 0.25rem;
}
.pagination-btn {
display: flex;
align-items: center;
justify-content: center;
min-width: 2.5rem;
height: 2.5rem;
padding: 0.5rem;
border: 1px solid #dee2e6;
background: #fff;
color: #495057;
text-decoration: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
font-size: 0.875rem;
}
.pagination-btn:hover:not(:disabled) {
background: #e9ecef;
border-color: #adb5bd;
color: #495057;
}
.pagination-btn.active {
background: #c6d0d7;
color: #333;
}
.pagination-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination-ellipsis {
padding: 0.5rem;
color: #6c757d;
font-size: 0.875rem;
}
.pagination-size {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
color: #6c757d;
}
.page-size-select {
padding: 0.25rem 0.5rem;
border: 1px solid #dee2e6;
border-radius: 4px;
background: #fff;
font-size: 0.875rem;
}
.page-size-select:focus {
outline: none;
border-color: #5681af;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}
/* Responsive design */
@media (max-width: 768px) {
.pagination {
flex-direction: column;
gap: 1rem;
align-items: stretch;
}
.pagination-controls {
justify-content: center;
}
.pagination-size {
justify-content: center;
}
}
</style>

View File

@@ -0,0 +1,129 @@
import { createRouter, createWebHistory } from 'vue-router'
import { Wrench01Icon } from '@hugeicons/core-free-icons'
import { LeftToRightListDashIcon } from '@hugeicons/core-free-icons'
import { CellsIcon } from '@hugeicons/core-free-icons'
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
const routes = [
{
path: '/',
name: 'Actions',
component: () => import('./Dashboard.vue'),
meta: { title: 'Actions', icon: DashboardSquare01Icon }
},
{
path: '/dashboards/:title',
name: 'Dashboard',
component: () => import('./Dashboard.vue'),
props: true,
meta: { title: 'Dashboard' }
},
{
path: '/actionBinding/:bindingId/argumentForm',
name: 'ActionBinding',
component: () => import('./views/ArgumentForm.vue'),
props: true,
meta: { title: 'Action Binding' }
},
{
path: '/logs',
name: 'Logs',
component: () => import('./views/LogsListView.vue'),
meta: {
title: 'Logs',
icon: LeftToRightListDashIcon
}
},
{
path: '/entities',
name: 'Entities',
component: () => import('./views/EntitiesView.vue'),
meta: {
title: 'Entities',
icon: CellsIcon
}
},
{
path: '/entity-details/:entityType/:entityKey',
name: 'EntityDetails',
component: () => import('./views/EntityDetailsView.vue'),
props: true,
meta: {
title: 'OliveTin - Entity Details',
breadcrumb: [
{ name: "Entities", href: "/entities" },
{ name: "Entity Details" }
]
}
},
{
path: '/logs/:executionTrackingId',
name: 'Execution',
component: () => import('./views/ExecutionView.vue'),
props: true,
meta: {
title: 'Execution',
breadcrumb: [
{ name: "Logs", href: "/logs" },
{ name: "Execution" },
]
}
},
{
path: '/diagnostics',
name: 'Diagnostics',
component: () => import('./views/DiagnosticsView.vue'),
meta: {
title: 'Diagnostics',
icon: Wrench01Icon
}
},
{
path: '/login',
name: 'Login',
component: () => import('./views/LoginView.vue'),
meta: { title: 'Login' }
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('./views/NotFoundView.vue'),
meta: { title: 'Page Not Found' }
}
]
// Create router instance
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
}
})
// Navigation guard to update page title
router.beforeEach((to, from, next) => {
if (to.meta && to.meta.title) {
document.title = to.meta.title + " - OliveTin"
}
next()
})
// Navigation guard for authentication (if needed)
router.beforeEach((to, from, next) => {
// Check if user is authenticated for protected routes
const isAuthenticated = window.isAuthenticated || true // Default to true for now
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login')
} else {
next()
}
})
export default router

View File

@@ -0,0 +1,3 @@
import { reactive } from 'vue'
export const buttonResults = reactive({})

View File

@@ -0,0 +1,345 @@
<template>
<section id = "argument-popup">
<div class="section-header">
<h2>Start action: {{ title }}</h2>
</div>
<div class="section-content padding">
<form @submit.prevent="handleSubmit">
<template v-if="actionArguments.length > 0">
<template v-for="arg in actionArguments" :key="arg.name" class="argument-group">
<label :for="arg.name">
{{ formatLabel(arg.title) }}
</label>
<datalist v-if="arg.suggestions && Object.keys(arg.suggestions).length > 0" :id="`${arg.name}-choices`">
<option v-for="(suggestion, key) in arg.suggestions" :key="key" :value="key">
{{ suggestion }}
</option>
</datalist>
<select v-if="getInputComponent(arg) === 'select'" :id="arg.name" :name="arg.name" :value="getArgumentValue(arg)"
:required="arg.required" @input="handleInput(arg, $event)" @change="handleChange(arg, $event)">
<option v-for="choice in arg.choices" :key="choice.value" :value="choice.value">
{{ choice.title || choice.value }}
</option>
</select>
<component v-else :is="getInputComponent(arg)" :id="arg.name" :name="arg.name" :value="getArgumentValue(arg)"
:list="arg.suggestions ? `${arg.name}-choices` : undefined"
:type="getInputComponent(arg) !== 'select' ? getInputType(arg) : undefined"
:rows="arg.type === 'raw_string_multiline' ? 5 : undefined"
:step="arg.type === 'datetime' ? 1 : undefined" :pattern="getPattern(arg)" :required="arg.required"
@input="handleInput(arg, $event)" @change="handleChange(arg, $event)" />
<span class="argument-description" v-html="arg.description"></span>
</template>
</template>
<div v-else>
<p>No arguments required</p>
</div>
<div class="buttons">
<button name="start" type="submit" :disabled="!isFormValid || (hasConfirmation && !confirmationChecked)">
Start
</button>
<button name="cancel" type="button" @click="handleCancel">
Cancel
</button>
</div>
</form>
</div>
</section>
</template>
<script setup>
import { ref, computed, onMounted, nextTick } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const emit = defineEmits(['submit', 'cancel', 'close'])
// Reactive data
const dialog = ref(null)
const title = ref('')
const icon = ref('')
//const arguments = ref([])
const argValues = ref({})
const confirmationChecked = ref(false)
const hasConfirmation = ref(false)
const formErrors = ref({})
const actionArguments = ref([])
// Computed properties
const isFormValid = computed(() => Object.keys(formErrors.value).length === 0)
const props = defineProps({
bindingId: {
type: String,
required: true
}
})
// Methods
async function setup() {
const ret = await window.client.getActionBinding({
bindingId: props.bindingId
})
const action = ret.action
console.log('action', action)
title.value = action.title
icon.value = action.icon
actionArguments.value = action.arguments || []
argValues.value = {}
formErrors.value = {}
confirmationChecked.value = false
hasConfirmation.value = false
// Initialize values from query params or defaults
actionArguments.value.forEach(arg => {
const paramValue = getQueryParamValue(arg.name)
argValues.value[arg.name] = paramValue !== null ? paramValue : arg.defaultValue || ''
if (arg.type === 'confirmation') {
hasConfirmation.value = true
}
})
}
function getQueryParamValue(paramName) {
const params = new URLSearchParams(window.location.search.substring(1))
return params.get(paramName)
}
function formatLabel(title) {
const lastChar = title.charAt(title.length - 1)
if (lastChar === '?' || lastChar === '.' || lastChar === ':') {
return title
}
return title + ':'
}
function getInputComponent(arg) {
if (arg.type === 'html') {
return 'div'
} else if (arg.type === 'raw_string_multiline') {
return 'textarea'
} else if (arg.choices && arg.choices.length > 0 && (arg.type === 'select' || arg.type === '')) {
return 'select'
} else {
return 'input'
}
}
function getInputType(arg) {
if (arg.type === 'html' || arg.type === 'raw_string_multiline' || arg.type === 'select') {
return undefined
}
if (arg.type === 'ascii_identifier') {
return 'text'
}
return arg.type
}
function getPattern(arg) {
if (arg.type && arg.type.startsWith('regex:')) {
return arg.type.replace('regex:', '')
}
return undefined
}
function getArgumentValue(arg) {
if (arg.type === 'checkbox') {
return argValues.value[arg.name] === '1' || argValues.value[arg.name] === true
}
return argValues.value[arg.name] || ''
}
function handleInput(arg, event) {
const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value
argValues.value[arg.name] = value
updateUrlWithArg(arg.name, value)
}
function handleChange(arg, event) {
if (arg.type === 'confirmation') {
confirmationChecked.value = event.target.checked
return
}
// Validate the input
validateArgument(arg, event.target.value)
}
async function validateArgument(arg, value) {
if (!arg.type || arg.type.startsWith('regex:')) {
return
}
try {
const validateArgumentTypeArgs = {
value: value,
type: arg.type
}
const validation = await window.validateArgumentType(validateArgumentTypeArgs)
if (validation.valid) {
delete formErrors.value[arg.name]
} else {
formErrors.value[arg.name] = validation.description
}
} catch (err) {
console.warn('Validation failed:', err)
}
}
function updateUrlWithArg(name, value) {
if (name && value !== undefined) {
const url = new URL(window.location.href)
// Don't add passwords to URL
const arg = actionArguments.value.find(a => a.name === name)
if (arg && arg.type === 'password') {
return
}
url.searchParams.set(name, value)
window.history.replaceState({}, '', url.toString())
}
}
function getArgumentValues() {
const ret = []
for (const arg of actionArguments.value) {
let value = argValues.value[arg.name] || ''
if (arg.type === 'checkbox') {
value = value ? '1' : '0'
}
ret.push({
name: arg.name,
value: value
})
}
return ret
}
function handleSubmit() {
// Validate all inputs
let isValid = true
for (const arg of actionArguments.value) {
const value = argValues.value[arg.name]
if (arg.required && (!value || value === '')) {
formErrors.value[arg.name] = 'This field is required'
isValid = false
}
}
if (!isValid) {
return
}
const argvs = getArgumentValues()
emit('submit', argvs)
close()
}
function handleCancel() {
router.back()
clearBookmark()
emit('cancel')
close()
}
function handleClose() {
emit('close')
}
function clearBookmark() {
// Remove the action from the URL
window.history.replaceState({
path: window.location.pathname
}, '', window.location.pathname)
}
function show() {
if (dialog.value) {
dialog.value.showModal()
}
}
function close() {
if (dialog.value) {
dialog.value.close()
}
}
// Expose methods for parent components
defineExpose({
show,
close
})
// Lifecycle
onMounted(() => {
setup()
})
</script>
<style scoped>
form {
grid-template-columns: max-content auto auto;
}
.argument-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.argument-group label {
font-weight: 500;
color: #333;
}
.argument-group input:invalid,
.argument-group select:invalid,
.argument-group textarea:invalid {
border-color: #dc3545;
}
.argument-description {
font-size: 0.875rem;
color: #666;
margin-top: 0.25rem;
}
.buttons {
display: flex;
gap: 0.5rem;
justify-content: flex-end;
padding-top: 1rem;
border-top: 1px solid #eee;
}
/* Checkbox specific styling */
.argument-group input[type="checkbox"] {
width: auto;
margin-right: 0.5rem;
}
.argument-group input[type="checkbox"]+label {
display: inline;
font-weight: normal;
}
</style>

View File

@@ -0,0 +1,158 @@
<template>
<Section title = "Get support">
<p>If you are having problems with OliveTin and want to raise a support request, it would be very helpful to include a sosreport from this page.
</p>
<ul>
<li>
<a href="https://docs.olivetin.app/sosreport.html" target="_blank">sosreport Documentation</a>
</li>
<li>
<a href = "https://docs.olivetin.app/troubleshooting/wheretofindhelp.html" target="_blank">Where to find help</a>
</li>
</ul>
</Section>
<Section title = "SSH">
<dl>
<dt>Found Key</dt>
<dd>{{ diagnostics.sshFoundKey || '?' }}</dd>
<dt>Found Config</dt>
<dd>{{ diagnostics.sshFoundConfig || '?' }}</dd>
</dl>
</Section>
<Section title = "SOS Report">
<p>This section allows you to generate a detailed report of your configuration and environment. It is a good idea to include this when raising a support request.</p>
<div role="toolbar">
<button @click="generateSosReport" :disabled="loading" class = "good">Generate SOS Report</button>
</div>
<textarea v-model="sosReport" readonly style="flex: 1; min-height: 200px; resize: vertical;"></textarea>
</Section>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Section from 'picocrank/vue/components/Section.vue'
const diagnostics = ref({})
const loading = ref(false)
const sosReport = ref('Waiting to start...')
async function fetchDiagnostics() {
loading.value = true
try {
const response = await window.client.getDiagnostics();
diagnostics.value = {
sshFoundKey: response.SshFoundKey,
sshFoundConfig: response.SshFoundConfig
};
} catch (err) {
console.error('Failed to fetch diagnostics:', err);
diagnostics.value = {
sshFoundKey: 'Unknown',
sshFoundConfig: 'Unknown'
}
}
loading.value = false
}
function formatKey(key) {
return key
.replace(/([A-Z])/g, ' $1')
.replace(/^./, str => str.toUpperCase())
.trim()
}
async function generateSosReport() {
const response = await window.client.sosReport()
console.log("response", response)
sosReport.value = response.alert
}
onMounted(() => {
fetchDiagnostics()
})
</script>
<style scoped>
.diagnostics-view {
padding: 1rem;
}
.diagnostics-content {
max-width: 800px;
margin: 0 auto;
}
.note {
background: #f8f9fa;
border-left: 4px solid #007bff;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0 4px 4px 0;
font-size: 0.875rem;
color: #495057;
}
.note a {
color: #007bff;
text-decoration: none;
}
.note a:hover {
text-decoration: underline;
}
.diagnostics-table {
width: 100%;
border-collapse: collapse;
}
.diagnostics-table td {
padding: 0.75rem 1rem;
border-bottom: 1px solid #f1f3f4;
}
.diagnostics-table td:first-child {
font-weight: 500;
color: #495057;
background: #f8f9fa;
}
.diagnostics-table tr:last-child td {
border-bottom: none;
}
.error-list {
padding: 1rem;
}
.error-item {
background: #f8d7da;
color: #721c24;
padding: 0.75rem;
margin-bottom: 0.5rem;
border-radius: 4px;
border-left: 4px solid #dc3545;
font-family: monospace;
font-size: 0.875rem;
}
.error-item:last-child {
margin-bottom: 0;
}
.flex-col {
display: flex;
flex-direction: column;
}
.section-content {
display: flex;
flex-direction: column;
gap: 1em;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<Section class = "with-header-and-content" v-if="entityDefinitions.length === 0" title="Loading entity definitions...">
<div class = "section-header">
<h2 class="loading-message">
Loading entity definitions...
</h2>
</div>
</Section>
<template v-else>
<Section v-for="def in entityDefinitions" :key="def.name" :title="'Entity: ' + def.title ">
<div class = "section-content">
<p>{{ def.instances.length }} instances.</p>
<ul>
<li v-for="inst in def.instances" :key="inst.id">
<router-link :to="{ name: 'EntityDetails', params: { entityType: inst.type, entityKey: inst.uniqueKey } }">
{{ inst.title }}
</router-link>
</li>
</ul>
<h3>Used on Dashboards:</h3>
<ul>
<li v-for="dash in def.usedOnDashboards">
<router-link :to="{ name: 'Dashboard', params: { title: dash } }">
{{ dash }}
</router-link>
</li>
</ul>
</div>
</Section>
</template>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Section from 'picocrank/vue/components/Section.vue'
const entityDefinitions = ref([])
async function fetchEntities() {
const ret = await window.client.getEntities()
entityDefinitions.value = ret.entityDefinitions
}
onMounted(() => {
fetchEntities()
})
</script>

View File

@@ -0,0 +1,40 @@
<template>
<Section title="Entity Details">
<div>
<p v-if="!entityDetails">Loading entity details...</p>
<p v-else-if="!entityDetails.title">No details available for this entity.</p>
<p v-else>{{ entityDetails.title }}</p>
</div>
</Section>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Section from 'picocrank/vue/components/Section.vue'
const entityDetails = ref(null)
const props = defineProps({
entityType: String,
entityKey: String
})
async function fetchEntityDetails() {
try {
const response = await window.client.getEntity({
type: props.entityType,
uniqueKey: props.entityKey
})
entityDetails.value = response
} catch (err) {
console.error('Failed to fetch entity details:', err)
window.showBigError('fetch-entity-details', 'getting entity details', err, false)
}
}
onMounted(() => {
fetchEntityDetails()
})
</script>

View File

@@ -0,0 +1,310 @@
<template>
<Section :title="'Execution Results: ' + title" id = "execution-results-popup">
<template #toolbar>
<button @click="toggleSize" title="Toggle dialog size">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor"
d="M3 3h6v2H6.462l4.843 4.843l-1.415 1.414L5 6.367V9H3zm0 18h6v-2H6.376l4.929-4.928l-1.415-1.414L5 17.548V15H3zm12 0h6v-6h-2v2.524l-4.867-4.866l-1.414 1.414L17.647 19H15zm6-18h-6v2h2.562l-4.843 4.843l1.414 1.414L19 6.39V9h2z" />
</svg>
</button>
</template>
<div v-if="logEntry" class = "flex-row">
<dl class = "fg1">
<dt>Duration</dt>
<dd><span v-html="duration"></span></dd>
<dt>Status</dt>
<dd>
<ActionStatusDisplay :log-entry="logEntry" id = "execution-dialog-status" />
</dd>
</dl>
<span class="icon" role="img" v-html="icon" style = "align-self: start"></span>
</div>
<div ref="xtermOutput"></div>
<br />
<div class="flex-row g1 buttons padded-content">
<button @click="goBack" title="Go back">
<HugeiconsIcon :icon="ArrowLeftIcon" />
Back
</button>
<div class = "fg1" />
<button :disabled="!canRerun" @click="rerunAction" title="Rerun">
<HugeiconsIcon :icon="WorkoutRunIcon" />
Rerun
</button>
<button :disabled="!canKill" @click="killAction" title="Kill" id = "execution-dialog-kill-action">
<HugeiconsIcon :icon="Cancel02Icon" />
Kill
</button>
</div>
</Section>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
import Section from 'picocrank/vue/components/Section.vue'
import { OutputTerminal } from '../../../js/OutputTerminal.js'
import { HugeiconsIcon } from '@hugeicons/vue'
import { WorkoutRunIcon, Cancel02Icon, ArrowLeftIcon } from '@hugeicons/core-free-icons'
import { useRouter } from 'vue-router'
import { buttonResults } from '../stores/buttonResults'
const router = useRouter()
// Refs for DOM elements
const xtermOutput = ref(null)
const props = defineProps({
executionTrackingId: {
type: String,
required: true
}
})
const executionTrackingId = ref(props.executionTrackingId)
const hideBasics = ref(false)
const hideDetails = ref(false)
const hideDetailsOnResult = ref(false)
const executionSeconds = ref(0)
const icon = ref('')
const title = ref('Waiting for result...')
const titleTooltip = ref('')
const duration = ref('')
const logEntry = ref(null)
const canRerun = ref(false)
const canKill = ref(false)
let executionTicker = null
let terminal = null
function initializeTerminal() {
terminal = new OutputTerminal(executionTrackingId.value, this)
terminal.open(xtermOutput.value)
terminal.resize(80, 24)
window.terminal = terminal
}
function toggleSize() {
terminal.fit()
}
async function reset() {
executionSeconds.value = 0
executionTrackingId.value = 'notset'
hideBasics.value = false
hideDetails.value = false
hideDetailsOnResult.value = false
icon.value = ''
title.value = 'Waiting for result...'
titleTooltip.value = ''
duration.value = ''
canRerun.value = false
canKill.value = false
logEntry.value = null
if (terminal) {
await terminal.reset()
terminal.fit()
}
}
function show(actionButton) {
if (actionButton) {
icon.value = actionButton.domIcon.innerText
}
canKill.value = true
// Clear existing ticker
if (executionTicker) {
clearInterval(executionTicker)
}
executionSeconds.value = 0
executionTick()
executionTicker = setInterval(() => {
executionTick()
}, 1000)
}
async function rerunAction() {
let startActionArgs = {}
const res = await window.client.startAction(startActionArgs)
router.push(`/logs/${res.executionTrackingId}`)
}
async function killAction() {
if (!executionTrackingId.value || executionTrackingId.value === 'notset') {
return
}
const killActionArgs = {
executionTrackingId: executionTrackingId.value
}
try {
await window.client.killAction(killActionArgs)
} catch (err) {
console.error('Failed to kill action:', err)
}
}
function executionTick() {
executionSeconds.value++
updateDuration(null)
}
function hideEverythingApartFromOutput() {
hideDetailsOnResult.value = true
hideBasics.value = true
hideDetailsOnResult.value = true
hideBasics.value = true
}
async function fetchExecutionResult(executionTrackingIdParam) {
console.log("fetchExecutionResult", executionTrackingIdParam)
executionTrackingId.value = executionTrackingIdParam
const executionStatusArgs = {
executionTrackingId: executionTrackingId.value
}
try {
const logEntryResult = await window.client.executionStatus(executionStatusArgs)
await renderExecutionResult(logEntryResult)
} catch (err) {
renderError(err)
throw err
}
}
function updateDuration(logEntryParam) {
logEntry.value = logEntryParam
if (logEntry.value == null) {
duration.value = executionSeconds.value + ' seconds'
duration.value = duration.value
} else if (!logEntry.value.executionStarted) {
duration.value = logEntry.value.datetimeStarted + ' (request time). Not executed.'
} else if (logEntry.value.executionStarted && !logEntry.value.executionFinished) {
duration.value = logEntry.value.datetimeStarted
} else {
let delta = ''
try {
delta = (new Date(logEntry.value.datetimeStarted) - new Date(logEntry.value.datetimeStarted)) / 1000
delta = new Intl.RelativeTimeFormat().format(delta, 'seconds').replace('in ', '').replace('ago', '')
} catch (e) {
console.warn('Failed to calculate delta', e)
}
duration.value = logEntry.value.datetimeStarted + ' &rarr; ' + logEntry.value.datetimeFinished
if (delta !== '') {
duration.value += ' (' + delta + ')'
}
}
}
async function renderExecutionResult(res) {
logEntry.value = res.logEntry
// Clear ticker
if (executionTicker) {
clearInterval(executionTicker)
}
executionTicker = null
if (hideDetailsOnResult.value) {
hideDetails.value = true
}
executionTrackingId.value = res.logEntry.executionTrackingId
canRerun.value = res.logEntry.executionFinished
canKill.value = res.logEntry.canKill
icon.value = res.logEntry.actionIcon
title.value = res.logEntry.actionTitle
titleTooltip.value = 'Action ID: ' + res.logEntry.actionId + '\nExecution ID: ' + res.logEntry.executionTrackingId
updateDuration(res.logEntry)
if (terminal) {
await terminal.reset()
await terminal.write(res.logEntry.output, () => {
terminal.fit()
})
}
}
function renderError(err) {
window.showBigError('execution-dlg-err', 'in the execution dialog', 'Failed to fetch execution result. ' + err, false)
}
function handleClose() {
if (executionTicker) {
clearInterval(executionTicker)
}
executionTicker = null
}
function cleanup() {
if (executionTicker) {
clearInterval(executionTicker)
}
executionTicker = null
if (terminal != null) {
terminal.close()
}
terminal = null
}
function goBack() {
router.back()
}
onMounted(() => {
initializeTerminal()
fetchExecutionResult(props.executionTrackingId)
watch(
() => buttonResults[props.executionTrackingId],
(newResult, oldResult) => {
if (newResult) {
renderExecutionResult({
logEntry: newResult
})
}
}
)
})
onBeforeUnmount(() => {
cleanup()
})
// Expose methods for parent/imperative use
defineExpose({
reset,
show,
rerunAction,
killAction,
fetchExecutionResult,
renderExecutionResult,
hideEverythingApartFromOutput,
handleClose
})
</script>

View File

@@ -0,0 +1,131 @@
<template>
<Section title="Login to OliveTin" class="small">
<div class="login-form" style="display: grid; grid-template-columns: max-content 1fr; gap: 1em;">
<div v-if="!hasOAuth && !hasLocalLogin" class="login-disabled">
<span>This server is not configured with either OAuth, or local users, so you cannot login.</span>
</div>
<div v-if="hasOAuth" class="login-oauth2">
<h3>OAuth Login</h3>
<div class="oauth-providers">
<button v-for="provider in oauthProviders" :key="provider.name" class="oauth-button"
@click="loginWithOAuth(provider)">
<span v-if="provider.icon" class="provider-icon" v-html="provider.icon"></span>
<span class="provider-name">Login with {{ provider.name }}</span>
</button>
</div>
</div>
<div v-if="hasLocalLogin" class="login-local">
<h3>Local Login</h3>
<form @submit.prevent="handleLocalLogin" class="local-login-form">
<div v-if="loginError" class="error-message">
{{ loginError }}
</div>
<label for="username">Username:</label>
<input id="username" v-model="username" type="text" name="username" autocomplete="username" required />
<label for="password">Password:</label>
<input id="password" v-model="password" type="password" name="password" autocomplete="current-password"
required />
<button type="submit" :disabled="loading" class="login-button">
{{ loading ? 'Logging in...' : 'Login' }}
</button>
</form>
</div>
</div>
</Section>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import Section from 'picocrank/vue/components/Section.vue'
const router = useRouter()
const username = ref('')
const password = ref('')
const loading = ref(false)
const loginError = ref('')
const hasOAuth = ref(false)
const hasLocalLogin = ref(false)
const oauthProviders = ref([])
async function fetchLoginOptions() {
try {
const response = await fetch('webUiSettings.json')
const settings = await response.json()
hasOAuth.value = settings.AuthOAuth2Providers && settings.AuthOAuth2Providers.length > 0
hasLocalLogin.value = settings.AuthLocalLogin
if (hasOAuth.value) {
oauthProviders.value = settings.AuthOAuth2Providers
}
} catch (err) {
console.error('Failed to fetch login options:', err)
}
}
async function handleLocalLogin() {
loading.value = true
loginError.value = ''
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username.value,
password: password.value
})
})
if (response.ok) {
// Redirect to home page on successful login
router.push('/')
} else {
const error = await response.text()
loginError.value = error || 'Login failed. Please check your credentials.'
}
} catch (err) {
console.error('Login error:', err)
loginError.value = 'Network error. Please try again.'
} finally {
loading.value = false
}
}
function loginWithOAuth(provider) {
// Redirect to OAuth provider
window.location.href = provider.authUrl
}
onMounted(() => {
fetchLoginOptions()
})
</script>
<style scoped>
section {
margin: auto;
}
.login-view {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
}
form {
grid-template-columns: max-content 1fr;
gap: 1em;
}
</style>

View File

@@ -0,0 +1,250 @@
<template>
<Section title="Logs" :padding="false">
<template #toolbar>
<label class="input-with-icons">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor"
d="m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14" />
</svg>
<input placeholder="Filter current page" v-model="searchText" />
<button title="Clear search filter" :disabled="!searchText" @click="clearSearch">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor"
d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z" />
</svg>
</button>
</label>
</template>
<p class = "padding">This is a list of logs from actions that have been executed. You can filter the list by action title.</p>
<div v-show="filteredLogs.length > 0">
<table class="logs-table">
<thead>
<tr>
<th>Timestamp</th>
<th>Action</th>
<th>Metadata</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr v-for="log in filteredLogs" :key="log.executionTrackingId" class="log-row" :title="log.actionTitle">
<td class="timestamp">{{ formatTimestamp(log.datetimeStarted) }}</td>
<td>
<span class="icon" v-html="log.actionIcon"></span>
<router-link :to="`/logs/${log.executionTrackingId}`">
{{ log.actionTitle }}
</router-link>
</td>
<td class="tags">
<span class="annotation">
<span class="annotation-key">User:</span>
<span class="annotation-val">{{ log.user }}</span>
</span>
<span v-if="log.tags && log.tags.length > 0" class="tag-list">
<span v-for="tag in log.tags" :key="tag" class="tag">{{ tag }}</span>
</span>
</td>
<td class="exit-code">
<span :class="getStatusClass(log) + ' annotation'">
{{ getStatusText(log) }}
</span>
</td>
</tr>
</tbody>
</table>
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" @page-change="handlePageChange" class = "padding"
@page-size-change="handlePageSizeChange" itemTitle="execution logs" />
</div>
<div v-show="logs.length === 0" class="empty-state">
<p>There are no logs to display.</p>
<router-link to="/">Return to index</router-link>
</div>
</Section>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import Pagination from '../components/Pagination.vue'
import Section from 'picocrank/vue/components/Section.vue'
const logs = ref([])
const searchText = ref('')
const pageSize = ref(10)
const currentPage = ref(1)
const loading = ref(false)
const totalCount = ref(0)
const filteredLogs = computed(() => {
if (!searchText.value) {
return logs.value
}
const searchLower = searchText.value.toLowerCase()
return logs.value.filter(log =>
log.actionTitle.toLowerCase().includes(searchLower)
)
})
async function fetchLogs() {
loading.value = true
try {
const startOffset = (currentPage.value - 1) * pageSize.value
const args = {
"startOffset": BigInt(startOffset),
}
const response = await window.client.getLogs(args)
logs.value = response.logs
pageSize.value = Number(response.pageSize) || 0
totalCount.value = Number(response.totalCount) || 0
} catch (err) {
console.error('Failed to fetch logs:', err)
window.showBigError('fetch-logs', 'getting logs', err, false)
} finally {
loading.value = false
}
}
function clearSearch() {
searchText.value = ''
}
function formatTimestamp(timestamp) {
if (!timestamp) return 'Unknown'
try {
const date = new Date(timestamp)
return date.toLocaleString()
} catch (err) {
return timestamp
}
}
function getStatusClass(log) {
if (log.timedOut) return 'status-timeout'
if (log.blocked) return 'status-blocked'
if (log.exitCode !== 0) return 'status-error'
return 'status-success'
}
function getStatusText(log) {
if (log.timedOut) return 'Timed out'
if (log.blocked) return 'Blocked'
if (log.exitCode !== 0) return `Exit code ${log.exitCode}`
return 'Completed'
}
function handlePageChange(page) {
currentPage.value = page
fetchLogs()
}
function handlePageSizeChange(newPageSize) {
pageSize.value = newPageSize
currentPage.value = 1 // Reset to first page
}
onMounted(() => {
fetchLogs()
})
</script>
<style scoped>
.logs-view {
padding: 1rem;
}
.input-with-icons {
display: flex;
align-items: center;
gap: 0.5rem;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
padding: 0.5rem;
}
.input-with-icons input {
border: none;
outline: none;
flex: 1;
font-size: 1rem;
}
.input-with-icons button {
background: none;
border: none;
cursor: pointer;
padding: 0.25rem;
border-radius: 3px;
}
.input-with-icons button:hover:not(:disabled) {
background: #f5f5f5;
}
.input-with-icons button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.timestamp {
font-family: monospace;
font-size: 0.875rem;
color: #666;
}
.icon {
margin-right: 0.5rem;
font-size: 1.2em;
}
.content {
color: #007bff;
text-decoration: none;
cursor: pointer;
}
.content:hover {
text-decoration: underline;
}
.status-success {
color: #28a745;
font-weight: 500;
}
.status-error {
color: #dc3545;
font-weight: 500;
}
.status-timeout {
color: #ffc107;
font-weight: 500;
}
.status-blocked {
color: #6c757d;
font-weight: 500;
}
.empty-state {
text-align: center;
padding: 2rem;
color: #666;
}
.empty-state a {
color: #007bff;
text-decoration: none;
}
.empty-state a:hover {
text-decoration: underline;
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<div class="not-found-view">
<div class="not-found-container">
<div class="not-found-content">
<h1>404</h1>
<h2>Page Not Found</h2>
<div class="actions">
<button class = "button good" @click="goToHome">
Go to Home
</button>
<button class="button neutral" @click="goBack">
Go Back
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'NotFoundView',
methods: {
goBack() {
this.$router.go(-1)
},
goToHome() {
this.$router.push('/')
}
}
}
</script>
<style scoped>
.not-found-content {
padding: 3rem 2rem;
text-align: center;
}
.not-found-content h1 {
font-size: 6rem;
margin: 0;
font-weight: 700;
line-height: 1;
}
.not-found-content h2 {
font-size: 2rem;
margin: 0 0 1rem 0;
color: #333;
}
.not-found-content p {
font-size: 1.1rem;
color: #666;
margin-bottom: 2rem;
}
</style>

105
frontend/style.css Normal file
View File

@@ -0,0 +1,105 @@
header {
position: fixed;
width: 100%;
z-index: 5;
}
aside {
padding-top: 4em;
z-index: 3; /* Make sure the sidebar is on top of the terminal */
}
fieldset {
display: grid;
grid-template-columns: repeat(auto-fit, 180px);
grid-auto-rows: 1fr;
justify-content: center;
place-items: stretch;
}
main {
padding-top: 4em;
}
action-button {
display: flex;
flex-direction: column;
flex-grow: 1;
}
action-button > button {
display: flex;
flex-direction: column;
flex-grow: 1;
justify-content: center;
font-weight: normal;
font-size: 0.85em;
box-shadow: 0 0 .6em #aaa;
}
action-button > button .icon {
font-size: 3em;
}
dialog {
border-radius: 1em;
}
footer span {
margin-right: 1em;
}
legend {
font-weight: bold;
text-align: center;
padding: 1em;
padding-top: 1.5em;
}
button.neutral {
background-color: transparent;
color: white;
}
section {
padding: 0;
}
.display {
border: 1px solid #666;
padding: 1em;
border-radius: .7em;
box-shadow: 0 0 .6em #aaa;
text-align: center;
font-size: small;
display: flex;
flex-direction: column;
flex-grow: 1;
justify-content: center;
align-items: center;
}
aside .flex-row {
padding-left: 1em;
padding-right: .5em;
}
#sidebar-toggler-button {
margin-right: .5em;
}
div.buttons button svg {
vertical-align: middle;
}
footer {
font-size: small;
}
th {
background-color: #fff;
}
section.small {
border-radius: .4em;
}

29
frontend/vite.config.js Normal file
View File

@@ -0,0 +1,29 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
plugins: [
Components({
dirs: ['resources/vue/'],
extensions: ['vue'],
deep: true,
dts: false,
}),
vue(),
],
server: {
proxy: {
'/webUiSettings.json': {
target: 'http://localhost:1337',
changeOrigin: true,
secure: false,
},
'/api': {
target: 'http://localhost:1337',
changeOrigin: true,
secure: false,
}
},
},
})

3765
gen/grpc/OliveTin.pb.go Normal file

File diff suppressed because it is too large Load Diff

1383
gen/grpc/OliveTin.pb.gw.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,700 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc (unknown)
// source: OliveTin.proto
package grpc
import (
context "context"
httpbody "google.golang.org/genproto/googleapis/api/httpbody"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
OliveTinApiService_GetDashboardComponents_FullMethodName = "/OliveTinApiService/GetDashboardComponents"
OliveTinApiService_StartAction_FullMethodName = "/OliveTinApiService/StartAction"
OliveTinApiService_StartActionAndWait_FullMethodName = "/OliveTinApiService/StartActionAndWait"
OliveTinApiService_StartActionByGet_FullMethodName = "/OliveTinApiService/StartActionByGet"
OliveTinApiService_StartActionByGetAndWait_FullMethodName = "/OliveTinApiService/StartActionByGetAndWait"
OliveTinApiService_KillAction_FullMethodName = "/OliveTinApiService/KillAction"
OliveTinApiService_ExecutionStatus_FullMethodName = "/OliveTinApiService/ExecutionStatus"
OliveTinApiService_GetLogs_FullMethodName = "/OliveTinApiService/GetLogs"
OliveTinApiService_ValidateArgumentType_FullMethodName = "/OliveTinApiService/ValidateArgumentType"
OliveTinApiService_WhoAmI_FullMethodName = "/OliveTinApiService/WhoAmI"
OliveTinApiService_SosReport_FullMethodName = "/OliveTinApiService/SosReport"
OliveTinApiService_DumpVars_FullMethodName = "/OliveTinApiService/DumpVars"
OliveTinApiService_DumpPublicIdActionMap_FullMethodName = "/OliveTinApiService/DumpPublicIdActionMap"
OliveTinApiService_GetReadyz_FullMethodName = "/OliveTinApiService/GetReadyz"
OliveTinApiService_LocalUserLogin_FullMethodName = "/OliveTinApiService/LocalUserLogin"
OliveTinApiService_PasswordHash_FullMethodName = "/OliveTinApiService/PasswordHash"
OliveTinApiService_Logout_FullMethodName = "/OliveTinApiService/Logout"
)
// OliveTinApiServiceClient is the client API for OliveTinApiService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type OliveTinApiServiceClient interface {
GetDashboardComponents(ctx context.Context, in *GetDashboardComponentsRequest, opts ...grpc.CallOption) (*GetDashboardComponentsResponse, error)
StartAction(ctx context.Context, in *StartActionRequest, opts ...grpc.CallOption) (*StartActionResponse, error)
StartActionAndWait(ctx context.Context, in *StartActionAndWaitRequest, opts ...grpc.CallOption) (*StartActionAndWaitResponse, error)
StartActionByGet(ctx context.Context, in *StartActionByGetRequest, opts ...grpc.CallOption) (*StartActionByGetResponse, error)
StartActionByGetAndWait(ctx context.Context, in *StartActionByGetAndWaitRequest, opts ...grpc.CallOption) (*StartActionByGetAndWaitResponse, error)
KillAction(ctx context.Context, in *KillActionRequest, opts ...grpc.CallOption) (*KillActionResponse, error)
ExecutionStatus(ctx context.Context, in *ExecutionStatusRequest, opts ...grpc.CallOption) (*ExecutionStatusResponse, error)
GetLogs(ctx context.Context, in *GetLogsRequest, opts ...grpc.CallOption) (*GetLogsResponse, error)
ValidateArgumentType(ctx context.Context, in *ValidateArgumentTypeRequest, opts ...grpc.CallOption) (*ValidateArgumentTypeResponse, error)
WhoAmI(ctx context.Context, in *WhoAmIRequest, opts ...grpc.CallOption) (*WhoAmIResponse, error)
SosReport(ctx context.Context, in *SosReportRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
DumpVars(ctx context.Context, in *DumpVarsRequest, opts ...grpc.CallOption) (*DumpVarsResponse, error)
DumpPublicIdActionMap(ctx context.Context, in *DumpPublicIdActionMapRequest, opts ...grpc.CallOption) (*DumpPublicIdActionMapResponse, error)
GetReadyz(ctx context.Context, in *GetReadyzRequest, opts ...grpc.CallOption) (*GetReadyzResponse, error)
LocalUserLogin(ctx context.Context, in *LocalUserLoginRequest, opts ...grpc.CallOption) (*LocalUserLoginResponse, error)
PasswordHash(ctx context.Context, in *PasswordHashRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
}
type oliveTinApiServiceClient struct {
cc grpc.ClientConnInterface
}
func NewOliveTinApiServiceClient(cc grpc.ClientConnInterface) OliveTinApiServiceClient {
return &oliveTinApiServiceClient{cc}
}
func (c *oliveTinApiServiceClient) GetDashboardComponents(ctx context.Context, in *GetDashboardComponentsRequest, opts ...grpc.CallOption) (*GetDashboardComponentsResponse, error) {
out := new(GetDashboardComponentsResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_GetDashboardComponents_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) StartAction(ctx context.Context, in *StartActionRequest, opts ...grpc.CallOption) (*StartActionResponse, error) {
out := new(StartActionResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_StartAction_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) StartActionAndWait(ctx context.Context, in *StartActionAndWaitRequest, opts ...grpc.CallOption) (*StartActionAndWaitResponse, error) {
out := new(StartActionAndWaitResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_StartActionAndWait_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) StartActionByGet(ctx context.Context, in *StartActionByGetRequest, opts ...grpc.CallOption) (*StartActionByGetResponse, error) {
out := new(StartActionByGetResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_StartActionByGet_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) StartActionByGetAndWait(ctx context.Context, in *StartActionByGetAndWaitRequest, opts ...grpc.CallOption) (*StartActionByGetAndWaitResponse, error) {
out := new(StartActionByGetAndWaitResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_StartActionByGetAndWait_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) KillAction(ctx context.Context, in *KillActionRequest, opts ...grpc.CallOption) (*KillActionResponse, error) {
out := new(KillActionResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_KillAction_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) ExecutionStatus(ctx context.Context, in *ExecutionStatusRequest, opts ...grpc.CallOption) (*ExecutionStatusResponse, error) {
out := new(ExecutionStatusResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_ExecutionStatus_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) GetLogs(ctx context.Context, in *GetLogsRequest, opts ...grpc.CallOption) (*GetLogsResponse, error) {
out := new(GetLogsResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_GetLogs_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) ValidateArgumentType(ctx context.Context, in *ValidateArgumentTypeRequest, opts ...grpc.CallOption) (*ValidateArgumentTypeResponse, error) {
out := new(ValidateArgumentTypeResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_ValidateArgumentType_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) WhoAmI(ctx context.Context, in *WhoAmIRequest, opts ...grpc.CallOption) (*WhoAmIResponse, error) {
out := new(WhoAmIResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_WhoAmI_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) SosReport(ctx context.Context, in *SosReportRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) {
out := new(httpbody.HttpBody)
err := c.cc.Invoke(ctx, OliveTinApiService_SosReport_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) DumpVars(ctx context.Context, in *DumpVarsRequest, opts ...grpc.CallOption) (*DumpVarsResponse, error) {
out := new(DumpVarsResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_DumpVars_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) DumpPublicIdActionMap(ctx context.Context, in *DumpPublicIdActionMapRequest, opts ...grpc.CallOption) (*DumpPublicIdActionMapResponse, error) {
out := new(DumpPublicIdActionMapResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_DumpPublicIdActionMap_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) GetReadyz(ctx context.Context, in *GetReadyzRequest, opts ...grpc.CallOption) (*GetReadyzResponse, error) {
out := new(GetReadyzResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_GetReadyz_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) LocalUserLogin(ctx context.Context, in *LocalUserLoginRequest, opts ...grpc.CallOption) (*LocalUserLoginResponse, error) {
out := new(LocalUserLoginResponse)
err := c.cc.Invoke(ctx, OliveTinApiService_LocalUserLogin_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) PasswordHash(ctx context.Context, in *PasswordHashRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) {
out := new(httpbody.HttpBody)
err := c.cc.Invoke(ctx, OliveTinApiService_PasswordHash_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *oliveTinApiServiceClient) Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) {
out := new(httpbody.HttpBody)
err := c.cc.Invoke(ctx, OliveTinApiService_Logout_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// OliveTinApiServiceServer is the server API for OliveTinApiService service.
// All implementations should embed UnimplementedOliveTinApiServiceServer
// for forward compatibility
type OliveTinApiServiceServer interface {
GetDashboardComponents(context.Context, *GetDashboardComponentsRequest) (*GetDashboardComponentsResponse, error)
StartAction(context.Context, *StartActionRequest) (*StartActionResponse, error)
StartActionAndWait(context.Context, *StartActionAndWaitRequest) (*StartActionAndWaitResponse, error)
StartActionByGet(context.Context, *StartActionByGetRequest) (*StartActionByGetResponse, error)
StartActionByGetAndWait(context.Context, *StartActionByGetAndWaitRequest) (*StartActionByGetAndWaitResponse, error)
KillAction(context.Context, *KillActionRequest) (*KillActionResponse, error)
ExecutionStatus(context.Context, *ExecutionStatusRequest) (*ExecutionStatusResponse, error)
GetLogs(context.Context, *GetLogsRequest) (*GetLogsResponse, error)
ValidateArgumentType(context.Context, *ValidateArgumentTypeRequest) (*ValidateArgumentTypeResponse, error)
WhoAmI(context.Context, *WhoAmIRequest) (*WhoAmIResponse, error)
SosReport(context.Context, *SosReportRequest) (*httpbody.HttpBody, error)
DumpVars(context.Context, *DumpVarsRequest) (*DumpVarsResponse, error)
DumpPublicIdActionMap(context.Context, *DumpPublicIdActionMapRequest) (*DumpPublicIdActionMapResponse, error)
GetReadyz(context.Context, *GetReadyzRequest) (*GetReadyzResponse, error)
LocalUserLogin(context.Context, *LocalUserLoginRequest) (*LocalUserLoginResponse, error)
PasswordHash(context.Context, *PasswordHashRequest) (*httpbody.HttpBody, error)
Logout(context.Context, *LogoutRequest) (*httpbody.HttpBody, error)
}
// UnimplementedOliveTinApiServiceServer should be embedded to have forward compatible implementations.
type UnimplementedOliveTinApiServiceServer struct {
}
func (UnimplementedOliveTinApiServiceServer) GetDashboardComponents(context.Context, *GetDashboardComponentsRequest) (*GetDashboardComponentsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetDashboardComponents not implemented")
}
func (UnimplementedOliveTinApiServiceServer) StartAction(context.Context, *StartActionRequest) (*StartActionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartAction not implemented")
}
func (UnimplementedOliveTinApiServiceServer) StartActionAndWait(context.Context, *StartActionAndWaitRequest) (*StartActionAndWaitResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartActionAndWait not implemented")
}
func (UnimplementedOliveTinApiServiceServer) StartActionByGet(context.Context, *StartActionByGetRequest) (*StartActionByGetResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartActionByGet not implemented")
}
func (UnimplementedOliveTinApiServiceServer) StartActionByGetAndWait(context.Context, *StartActionByGetAndWaitRequest) (*StartActionByGetAndWaitResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartActionByGetAndWait not implemented")
}
func (UnimplementedOliveTinApiServiceServer) KillAction(context.Context, *KillActionRequest) (*KillActionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method KillAction not implemented")
}
func (UnimplementedOliveTinApiServiceServer) ExecutionStatus(context.Context, *ExecutionStatusRequest) (*ExecutionStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExecutionStatus not implemented")
}
func (UnimplementedOliveTinApiServiceServer) GetLogs(context.Context, *GetLogsRequest) (*GetLogsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetLogs not implemented")
}
func (UnimplementedOliveTinApiServiceServer) ValidateArgumentType(context.Context, *ValidateArgumentTypeRequest) (*ValidateArgumentTypeResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ValidateArgumentType not implemented")
}
func (UnimplementedOliveTinApiServiceServer) WhoAmI(context.Context, *WhoAmIRequest) (*WhoAmIResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method WhoAmI not implemented")
}
func (UnimplementedOliveTinApiServiceServer) SosReport(context.Context, *SosReportRequest) (*httpbody.HttpBody, error) {
return nil, status.Errorf(codes.Unimplemented, "method SosReport not implemented")
}
func (UnimplementedOliveTinApiServiceServer) DumpVars(context.Context, *DumpVarsRequest) (*DumpVarsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DumpVars not implemented")
}
func (UnimplementedOliveTinApiServiceServer) DumpPublicIdActionMap(context.Context, *DumpPublicIdActionMapRequest) (*DumpPublicIdActionMapResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DumpPublicIdActionMap not implemented")
}
func (UnimplementedOliveTinApiServiceServer) GetReadyz(context.Context, *GetReadyzRequest) (*GetReadyzResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetReadyz not implemented")
}
func (UnimplementedOliveTinApiServiceServer) LocalUserLogin(context.Context, *LocalUserLoginRequest) (*LocalUserLoginResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method LocalUserLogin not implemented")
}
func (UnimplementedOliveTinApiServiceServer) PasswordHash(context.Context, *PasswordHashRequest) (*httpbody.HttpBody, error) {
return nil, status.Errorf(codes.Unimplemented, "method PasswordHash not implemented")
}
func (UnimplementedOliveTinApiServiceServer) Logout(context.Context, *LogoutRequest) (*httpbody.HttpBody, error) {
return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented")
}
// UnsafeOliveTinApiServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to OliveTinApiServiceServer will
// result in compilation errors.
type UnsafeOliveTinApiServiceServer interface {
mustEmbedUnimplementedOliveTinApiServiceServer()
}
func RegisterOliveTinApiServiceServer(s grpc.ServiceRegistrar, srv OliveTinApiServiceServer) {
s.RegisterService(&OliveTinApiService_ServiceDesc, srv)
}
func _OliveTinApiService_GetDashboardComponents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetDashboardComponentsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).GetDashboardComponents(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_GetDashboardComponents_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).GetDashboardComponents(ctx, req.(*GetDashboardComponentsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_StartAction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StartActionRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).StartAction(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_StartAction_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).StartAction(ctx, req.(*StartActionRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_StartActionAndWait_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StartActionAndWaitRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).StartActionAndWait(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_StartActionAndWait_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).StartActionAndWait(ctx, req.(*StartActionAndWaitRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_StartActionByGet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StartActionByGetRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).StartActionByGet(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_StartActionByGet_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).StartActionByGet(ctx, req.(*StartActionByGetRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_StartActionByGetAndWait_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StartActionByGetAndWaitRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).StartActionByGetAndWait(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_StartActionByGetAndWait_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).StartActionByGetAndWait(ctx, req.(*StartActionByGetAndWaitRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_KillAction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(KillActionRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).KillAction(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_KillAction_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).KillAction(ctx, req.(*KillActionRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_ExecutionStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ExecutionStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).ExecutionStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_ExecutionStatus_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).ExecutionStatus(ctx, req.(*ExecutionStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_GetLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetLogsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).GetLogs(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_GetLogs_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).GetLogs(ctx, req.(*GetLogsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_ValidateArgumentType_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ValidateArgumentTypeRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).ValidateArgumentType(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_ValidateArgumentType_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).ValidateArgumentType(ctx, req.(*ValidateArgumentTypeRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_WhoAmI_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(WhoAmIRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).WhoAmI(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_WhoAmI_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).WhoAmI(ctx, req.(*WhoAmIRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_SosReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SosReportRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).SosReport(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_SosReport_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).SosReport(ctx, req.(*SosReportRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_DumpVars_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DumpVarsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).DumpVars(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_DumpVars_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).DumpVars(ctx, req.(*DumpVarsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_DumpPublicIdActionMap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DumpPublicIdActionMapRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).DumpPublicIdActionMap(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_DumpPublicIdActionMap_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).DumpPublicIdActionMap(ctx, req.(*DumpPublicIdActionMapRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_GetReadyz_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetReadyzRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).GetReadyz(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_GetReadyz_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).GetReadyz(ctx, req.(*GetReadyzRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_LocalUserLogin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LocalUserLoginRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).LocalUserLogin(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_LocalUserLogin_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).LocalUserLogin(ctx, req.(*LocalUserLoginRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_PasswordHash_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PasswordHashRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).PasswordHash(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_PasswordHash_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).PasswordHash(ctx, req.(*PasswordHashRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OliveTinApiService_Logout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LogoutRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OliveTinApiServiceServer).Logout(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OliveTinApiService_Logout_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OliveTinApiServiceServer).Logout(ctx, req.(*LogoutRequest))
}
return interceptor(ctx, in, info, handler)
}
// OliveTinApiService_ServiceDesc is the grpc.ServiceDesc for OliveTinApiService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var OliveTinApiService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "OliveTinApiService",
HandlerType: (*OliveTinApiServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetDashboardComponents",
Handler: _OliveTinApiService_GetDashboardComponents_Handler,
},
{
MethodName: "StartAction",
Handler: _OliveTinApiService_StartAction_Handler,
},
{
MethodName: "StartActionAndWait",
Handler: _OliveTinApiService_StartActionAndWait_Handler,
},
{
MethodName: "StartActionByGet",
Handler: _OliveTinApiService_StartActionByGet_Handler,
},
{
MethodName: "StartActionByGetAndWait",
Handler: _OliveTinApiService_StartActionByGetAndWait_Handler,
},
{
MethodName: "KillAction",
Handler: _OliveTinApiService_KillAction_Handler,
},
{
MethodName: "ExecutionStatus",
Handler: _OliveTinApiService_ExecutionStatus_Handler,
},
{
MethodName: "GetLogs",
Handler: _OliveTinApiService_GetLogs_Handler,
},
{
MethodName: "ValidateArgumentType",
Handler: _OliveTinApiService_ValidateArgumentType_Handler,
},
{
MethodName: "WhoAmI",
Handler: _OliveTinApiService_WhoAmI_Handler,
},
{
MethodName: "SosReport",
Handler: _OliveTinApiService_SosReport_Handler,
},
{
MethodName: "DumpVars",
Handler: _OliveTinApiService_DumpVars_Handler,
},
{
MethodName: "DumpPublicIdActionMap",
Handler: _OliveTinApiService_DumpPublicIdActionMap_Handler,
},
{
MethodName: "GetReadyz",
Handler: _OliveTinApiService_GetReadyz_Handler,
},
{
MethodName: "LocalUserLogin",
Handler: _OliveTinApiService_LocalUserLogin_Handler,
},
{
MethodName: "PasswordHash",
Handler: _OliveTinApiService_PasswordHash_Handler,
},
{
MethodName: "Logout",
Handler: _OliveTinApiService_Logout_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "OliveTin.proto",
}

103
go.mod
View File

@@ -1,103 +0,0 @@
module github.com/OliveTin/OliveTin
go 1.18
require (
github.com/bufbuild/buf v1.15.1
github.com/fsnotify/fsnotify v1.6.0
github.com/fzipp/gocyclo v0.6.0
github.com/go-critic/go-critic v0.7.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/uuid v1.3.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.9.0
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.2
golang.org/x/exp v0.0.0-20230307190834-24139beb5833
google.golang.org/grpc v1.53.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
google.golang.org/protobuf v1.30.0
)
require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/bufbuild/connect-go v1.5.2 // indirect
github.com/bufbuild/protocompile v0.5.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cristalhq/acmd v0.11.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/cli v23.0.1+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v23.0.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/fgprof v0.9.3 // indirect
github.com/go-chi/chi/v5 v5.0.8 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.1.0 // indirect
github.com/go-toolsmith/astfmt v1.1.0 // indirect
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/pkgload v1.2.2 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/uuid/v5 v5.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-containerregistry v0.13.0 // indirect
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quasilyte/go-ruleguard v0.3.19 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/rs/cors v1.8.3 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.7.0 // indirect
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

659
go.sum
View File

@@ -1,659 +0,0 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/bufbuild/buf v1.15.1 h1:v7sK2uMEsGX4Z2hvu+xiMheH3C3AKBGfxPBgdUZYDQ8=
github.com/bufbuild/buf v1.15.1/go.mod h1:TQeGKam1QMfHy/xsSnnMpxN3JK5HBb6aNvZj4m52gkE=
github.com/bufbuild/connect-go v1.5.2 h1:G4EZd5gF1U1ZhhbVJXplbuUnfKpBZ5j5izqIwu2g2W8=
github.com/bufbuild/connect-go v1.5.2/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk=
github.com/bufbuild/protocompile v0.5.1 h1:mixz5lJX4Hiz4FpqFREJHIXLfaLBntfaJv1h+/jS+Qg=
github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/containerd/stargz-snapshotter/estargz v0.12.1 h1:+7nYmHJb0tEkcRaAW+MHqoKaJYZmkikupxCqVtmPuY0=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/cristalhq/acmd v0.11.1 h1:DJ4fh2Pv0nPKmqT646IU/0Vh5FNdGblxvF+3/W3NAUI=
github.com/cristalhq/acmd v0.11.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY=
github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-critic/go-critic v0.7.0 h1:tqbKzB8pqi0NsRZ+1pyU4aweAF7A7QN0Pi4Q02+rYnQ=
github.com/go-critic/go-critic v0.7.0/go.mod h1:moYzd7GdVXE2C2hYTwd7h0CPcqlUeclsyBRwMa38v64=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=
github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s=
github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw=
github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw=
github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ=
github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco=
github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4=
github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA=
github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA=
github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk=
github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw=
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-containerregistry v0.13.0 h1:y1C7Z3e149OJbOPDBxLYR8ITPz8dTKqQwjErKVHJC8k=
github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso=
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 h1:2uT3aivO7NVpUPGcQX7RbHijHMyWix/yCnIrCWc+5co=
github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc=
github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw=
github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo=
github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU=
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo=
github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb h1:WGs/bGIWYyAY5PVgGGMXqGGCxSJz4fpoUExb/vgqNCU=
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 h1:znp6mq/drrY+6khTAlJUDNFFcDGV2ENLYKpMq8SyCds=
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -0,0 +1,8 @@
env:
browser: true
es2021: true
extends: 'eslint:recommended'
parserOptions:
ecmaVersion: 12
sourceType: module
rules: {}

View File

@@ -0,0 +1,3 @@
---
require:
- mochaSetup.mjs

View File

@@ -1,6 +1,24 @@
cypress:
npm install
./cypressRun.sh "general"
./cypressRun.sh "hiddenNav"
default: test-install test-run
.PHONY: cypress container
test-install:
npm install --no-fund
test-run:
# GitHub Actions fails badly on the default timeout of 2000ms
npx mocha -t 10000
find-flakey-tests:
echo "Running test-run infinately"
sh -c "while make test-run; do :; done"
nginx:
podman-compose up -d nginx
clean:
podman-compose down
getsnapshot:
rm -rf /opt/OliveTin-snapshot/*
gh run download -D /opt/OliveTin-snapshot/
.PHONY: default

View File

@@ -1 +1,14 @@
# OliveTin-integration-tests
# OliveTin-integration-tests
## GitHub Actions (Ubuntu, Local Process)
- `mocha` is run with the default runner that starts and stops OliveTin as a local process (ie, localhost:1337).
## Running different configurations (Local Process, VM, Container)
- Get the snapshot you want to test `make getsnapshot`
- To test against VMs:
-- `export OLIVETIN_TEST_RUNNER=vm`
-- `vagrant up fedora38` (or whatever distro you like defined in `Vagrantfile`)
-- `. envVagrant.sh fedora38` to set the $IP and $PORT
- `mocha`

View File

@@ -2,34 +2,35 @@
# (eg, snapshot builds on GitHub)
Vagrant.configure("2") do |config|
config.vm.box = "generic/centos8"
config.vm.provision "shell", inline: "mkdir /etc/OliveTin && chmod o+w /etc/OliveTin/", privileged: true
config.vm.provision "file", source: "configs/config.general.yaml/.", destination: "/etc/OliveTin/config.yaml"
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: "mkdir /etc/OliveTin && chmod o+w /etc/OliveTin/ && mkdir -p /opt/OliveTin-configs/ && chmod 0777 /opt/OliveTin-configs", privileged: true
config.vm.provision "file", source: "configs/.", destination: "/opt/OliveTin-configs/"
config.vm.provider :libvirt do |libvirt|
libvirt.management_network_device = 'virbr0'
end
config.vm.define :f36 do |f36|
f36.vm.box = "generic/fedora36"
f36.vm.provision "file", source: "/opt/OliveTin-vagrant/linux_amd64_rpm/.", destination: "."
f36.vm.provision "shell", inline: "rpm -U OliveTin* && systemctl enable --now OliveTin && systemctl disable --now firewalld"
config.vm.define :stream9 do |i|
i.vm.box = "centos/stream9"
i.vm.provision "file", source: "/opt/OliveTin-snapshot/OliveTin_linux_amd64.rpm", destination: "$HOME/"
i.vm.provision "shell", inline: "rpm -U OliveTin* && systemctl enable --now OliveTin && systemctl disable --now firewalld"
end
config.vm.define :debian do |debian|
debian.vm.box = "generic/debian10"
debian.vm.provision "file", source: "/opt/OliveTin-vagrant/linux_amd64_deb/.", destination: "."
debian.vm.provision "shell", inline: "dpkg --force-confold -i OliveTin* && systemctl enable --now OliveTin"
config.vm.define :fedora38 do |i|
i.vm.box = "generic/fedora38"
i.vm.provision "file", source: "/opt/OliveTin-snapshot/OliveTin_linux_amd64.rpm", destination: "$HOME/"
i.vm.provision "shell", inline: "rpm -U OliveTin* && systemctl enable --now OliveTin && systemctl disable --now firewalld"
end
config.vm.define :ubuntu do |ubuntu|
ubuntu.vm.box = "generic/ubuntu2110"
ubuntu.vm.provision "file", source: "/opt/OliveTin-vagrant/linux_amd64_deb/.", destination: "."
ubuntu.vm.provision "shell", inline: "dpkg --force-confold -i OliveTin* && systemctl enable --now OliveTin && systemctl disable --now firewalld"
config.vm.define :debian12 do |i|
i.vm.box = "debian/bookworm64"
i.vm.provision "file", source: "/opt/OliveTin-snapshot/OliveTin_linux_amd64.deb", destination: "$HOME/"
i.vm.provision "shell", inline: "dpkg --force-confold -i OliveTin* && systemctl enable --now OliveTin"
end
# TODO
#
config.vm.define :ubuntu2310 do |i|
i.vm.box = "ubuntu/mantic64"
i.vm.provision "file", source: "/opt/OliveTin-snapshot/OliveTin_linux_amd64.deb", destination: "$HOME/"
i.vm.provision "shell", inline: "dpkg --force-confold -i OliveTin* && systemctl enable --now OliveTin && systemctl disable --now firewalld"
end
end

View File

@@ -0,0 +1,17 @@
---
version: "3.8"
services:
nginx:
container_name: nginx
image: docker.io/nginx
volumes:
- ./proxies/nginx/:/etc/nginx/
ports:
- "8443:8443"
restart: unless-stopped
networks:
- otproxy
networks:
otproxy:
name: otproxy

View File

@@ -0,0 +1,36 @@
logLevel: debug
actions:
- title: Ping
shell: echo "Ping executed"
icon: ping
- title: Action 1
shell: echo "Action 1 executed"
icon: check
- title: Action 2
shell: echo "Action 2 executed"
icon: check
- title: Action 3
shell: echo "Action 3 executed"
icon: check
- title: Action 4
shell: echo "Action 4 executed"
icon: check
dashboards:
- title: Test
contents:
# Uncomment to see the dashboard with the "Ping" action only
- title: Ping
- title: Fieldset 1
type: fieldset
contents:
- title: Action 1
- title: Action 2
- title: Fieldset 2
type: fieldset
contents:
- title: Action 3
- title: Action 4

View File

@@ -0,0 +1,21 @@
#
# Integration Test Config: emptyDashboardsAreHidden
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
actions:
- title: Ping
shell: ping example.com
icon: ping
entity: server
dashboards:
- title: Empty Dashboard
contents: []

View File

@@ -0,0 +1,18 @@
#
# Integration Test Config: Entities
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
actions:
- title: Ping {{ server.hostname }}
shell: ping {{ server.hostname }}
icon: ping
entity: server
entities:
- file: entities/servers.yaml
name: server

View File

@@ -0,0 +1,3 @@
- hostname: server1
- hostname: server2
- hostname: server3

View File

@@ -0,0 +1,9 @@
actions:
- title: 'Test me {{ test_me.name }}'
popupOnStart: execution-dialog-stdout-only
entity: testrows
shell: echo "{{ test_me.val }}"
entities:
- name: testrows
file: entities/data.json

View File

@@ -0,0 +1,5 @@
{"name":"INT with 10 numbers","val":1234567890}
{"name":"INT with 6 numbers","val":123456}
{"name":"INT with 7 numbers","val":1234567}
{"name":"FLOAT with 6 numbers","val":1.234567}
{"name":"FLOAT with 10 numbers","val":1.234567890}

View File

@@ -1,17 +1,17 @@
#
# Integration Test Config: General
#
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
checkForUpdates: false
actions:
actions:
- title: Ping Google.com
shell: ping google.com -c 1
icon: ping
- title: restart lightdm
icon: poop
shell: ssh root@overseer 'service lightdm restart'
@@ -24,6 +24,13 @@ actions:
shell: sleep 5
icon: "&#x1F62A"
- title: dir-popup
shell: dir
popupOnStart: execution-dialog-stdout-only
- title: cd-passive
shell: cd
- title: "Run Ansible Playbook"
icon: "&#x1F1E6"
shell: ansible-playbook -i /etc/hosts /root/myRepo/myPlaybook.yaml
@@ -32,4 +39,3 @@ actions:
- title: Restart Plex
icon: smile
shell: docker restart plex

View File

@@ -1,12 +1,12 @@
#
# Integration Test Config: General
#
#
showFooter: false
checkForUpdates: false
checkForUpdates: false
# Actions (buttons) to show up on the WebUI:
actions:
actions:
- title: Ping example.com
shell: ping example.com -c 1
icon: ping

View File

@@ -1,14 +1,14 @@
#
# Integration Test Config: General
#
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
showNavigation: false
checkForUpdates: false
checkForUpdates: false
# Actions (buttons) to show up on the WebUI:
actions:
actions:
- title: Ping example.com
shell: ping example.com -c 1
icon: ping

View File

@@ -0,0 +1,25 @@
---
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
actions:
- title: Ping Google.com
shell: ping google.com -c 1
icon: ping
- title: Test multiple dropdowns
shell: echo {{ salutation }} {{ person }}
icon: ping
arguments:
- name: salutation
choices:
- value: Hello
- value: Goodbye
- name: person
choices:
- value: Alice
- value: Bob
- value: Dave

View File

@@ -0,0 +1,28 @@
#
# Integration Test Config: General
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
actions:
- title: action1
shell: date
icon: clock
- title: action2
shell: date
icon: clock
- title: action3
shell: date
icon: clock
dashboards:
- title: My Dashboard
contents:
- title: action1
- title: action2
- title: action3

View File

@@ -0,0 +1,15 @@
#
# Integration Test Config: General
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
pageTitle: "My Custom App"
actions:
- title: sleep 2 seconds
shell: sleep 2
icon: "&#x1F971"

View File

@@ -0,0 +1,14 @@
# Integration Test Config: Policy All False
#
logLevel: "DEBUG"
checkForUpdates: false
defaultPolicy:
showDiagnostics: false
showLogList: false
actions:
- title: sleep 2 seconds
shell: sleep 2
icon: "&#x1F971"

View File

@@ -0,0 +1,16 @@
#
# Integration Test Config: General
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
prometheus:
enabled: true
defaultGoMetrics: false
actions:
- title: Hello OliveTin
shell: echo "Hello OliveTin"

View File

@@ -0,0 +1,14 @@
# Integration Test Config: Sleep
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
actions:
- title: Sleep
shell: sleep 10
popupOnStart: execution-dialog
timeout: 9

Some files were not shown because too many files have changed in this diff Show More