Compare commits

...

121 Commits

Author SHA1 Message Date
jamesread
9df61ab044 feature: Rudimentary "windows support" 2023-02-16 16:40:24 +00:00
jamesread
11bb3f129f fmt: gofmt 2023-02-16 16:21:53 +00:00
jamesread
0335e58b12 feature: Cleaned up jwt auth, and added header auth 2023-02-15 17:41:33 +00:00
James Read
2d173266df feature: Cron support (#102) 2023-02-03 08:53:10 +00:00
James Read
f05de1c726 feature: Execute actions on startup. Externalize the executor and add… (#101)
* feature: Execute actions on startup. Externalize the executor and add tags to logs.

* fmt: Codestyle fixes
2023-02-02 09:35:18 +00:00
Bernard Crnković
b6196a4b3f fix wrong source of "usergroup" metadata (#99)
* extract hardcoded jwt field names into config

* Update config.go

* bugfix: source group from usergroup field instead of password

Co-authored-by: James Read <contact@jread.com>
2023-01-11 20:41:52 +00:00
Bernard Crnković
e18df74d5a extract hardcoded jwt claim names into config (#97)
* extract hardcoded jwt field names into config

* Update config.go

Co-authored-by: James Read <contact@jread.com>
2023-01-10 22:29:31 +00:00
dependabot[bot]
edf10fdd9f build(deps): bump json5 from 1.0.1 to 1.0.2 in /webui (#94)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 21:12:52 +00:00
jamesread
81934355ed cicd: Vagrant fedora update 2023-01-02 10:49:20 +00:00
jamesread
e318084300 feature: Changlog format now groups issues 2022-11-13 21:06:07 +00:00
jamesread
476f74efa8 cicd: Wrong path to var 2022-11-13 20:34:20 +00:00
jamesread
e309dd6e67 feature: man page 2022-11-13 20:24:27 +00:00
jamesread
49cb2e5c0a fmt: Ineffectual assignment 2022-11-13 14:23:35 +04:00
jamesread
66370508ff cicd: yamllint github workflows 2022-11-13 13:55:12 +04:00
jamesread
875186ee24 cicd: Actions version bump 2022-11-13 13:34:14 +04:00
jamesread
384ef9787b Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2022-11-13 12:54:52 +04:00
jamesread
dbcd39e91b cicd: Bump codeql from v1 to v2 2022-11-13 12:40:41 +04:00
jamesread
2244d2c3ef Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2022-11-13 08:36:20 +00:00
jamesread
37c54b5f77 feature: Look for webui in more directories 2022-11-13 12:35:47 +04:00
jamesread
f48e7dac83 fmt: gofmt 2022-11-13 07:54:50 +00:00
jamesread
21b33086ae fmt: ST1005 https://staticcheck.io/docs/checks/#ST1005 2022-11-13 07:34:23 +00:00
jamesread
6143b2f8ed cicd: Jiggeled targets 2022-11-12 12:55:15 +04:00
jamesread
d53c88f314 fmt: gofmt 2022-11-12 12:20:17 +04:00
jamesread
f42ac5d744 depbump: Migrate from go-cron to cron (the underlying lib) 2022-11-12 12:19:20 +04:00
jamesread
58f3aaf47d cicd: githooks no longer triggered by grpc. protoc added as alternative to buf. 2022-11-12 12:12:09 +04:00
James Read
244404afbc Sidebar (#88)
* feature: allow configurable title

* feature: sidebar prototype

* Spelling fix - Thanks @jonny7read

Spelling fix - Thanks @jonny7read

Co-authored-by: Jonny Read <jonny7read@gmail.com>

* feature: sidebar support

* bugfix: pagetitle

* fmt: hide sidebar under feature toggle

* fmt: Codestyle in style.css and main.js

Co-authored-by: Matthew Strasiotto <39424834+matthewstrasiotto@users.noreply.github.com>
Co-authored-by: Jonny Read <jonny7read@gmail.com>
2022-11-11 12:13:47 +04:00
jamesread
eca3145b1a bugfix: OliveTin openRC chmod +x 2022-10-26 19:59:49 +01:00
jamesread
b560f9c749 bugfix: openrc for apk wasnt being installed properly 2022-10-26 17:24:47 +01:00
jamesread
cf582e7152 feature: #83 - Restore Alpine packages 2022-10-26 11:54:58 +01:00
James Read
8b9932f85c Merge pull request #65 from EzequielBruni/main
Created a service file for OpenRC (Alpine Linux/Gentoo)
2022-10-26 09:28:20 +01:00
James Read
4ec6f8f014 Merge pull request #82 from OliveTin/exec-coc-simplication
fmt: fmt
2022-10-26 09:05:07 +01:00
jamesread
1a8659f81f feature: Error messages now link to that error in docs 2022-10-24 23:28:35 +01:00
jamesread
e950a00a1e fmt: fmt 2022-10-24 23:17:31 +01:00
jamesread
f9ac78d27f fmt: Remove unused sliceutil 2022-10-24 22:51:31 +01:00
James Read
65afdeca36 Merge pull request #81 from OliveTin/feature-input-description
feature: #61 - Descriptions in arguments
2022-10-21 15:47:12 +01:00
jamesread
8e59ac9fb4 bugfix: Fixing CSS class name convention 2022-10-21 15:21:07 +01:00
jamesread
984dae7450 feature: #61 - Descriptions in arguments 2022-10-21 15:14:58 +01:00
jamesread
be7effd317 cicd: Upgrade checkout action from v2 -> v3 https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/ 2022-10-20 09:15:06 +01:00
jamesread
9e7d785ede feature: #68 Remove version from .rpm and .deb 2022-10-19 17:51:41 +01:00
jamesread
434e998151 cicd: Ignore errors when creating podman-container target - the container may not exist 2022-10-19 15:14:13 +01:00
jamesread
b97e75dd67 depbump: webui 2022-10-19 15:13:06 +01:00
jamesread
5424aff946 bugfix: Remove microdnf cache 2022-10-19 15:12:42 +01:00
jamesread
08a1ac2591 feature: #71 URL argument type! 2022-10-19 13:26:22 +01:00
jamesread
fb70cf7dfe cicd: Remove cicd and refactor from changelog - as they dont deliver end user benefits 2022-10-19 12:42:53 +01:00
jamesread
b14a1f411d test: Unsupported argument type 2022-10-19 12:42:22 +01:00
jamesread
fadc616a67 doc: Allow "test" for unittests, integration tests, etc 2022-10-19 10:02:41 +01:00
jamesread
cfde9e5148 bugfix: Safer handling of username/usergroup metadata 2022-10-19 09:48:36 +01:00
jamesread
cc8cad10db feature: drop arm32v7 container because Fedora dropped it 2022-10-01 09:06:41 +01:00
jamesread
d15461a67b Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2022-09-29 17:18:02 +02:00
jamesread
917857d213 cicd: I hate multiarch docker builds 2022-09-29 17:17:54 +02:00
jamesread
770c6c06bf cicd: useradd after installing it 2022-09-29 08:57:16 +01:00
jamesread
95c589478d cicd: need shadow-utils for useradd 2022-09-29 08:46:59 +01:00
jamesread
b51c139264 feature: Switched to fedora-minimal 2022-09-29 02:21:53 +02:00
jamesread
2ef86beea5 cicd: buf mod update seemed to be needed 2022-09-29 01:21:12 +02:00
jamesread
d029f7b5bd cicd: Manual trigger of workflow to test docker images 2022-09-29 01:12:05 +02:00
jamesread
dfaec75e94 feature: #62 Warn users on detecting PUID or PGID 2022-08-28 22:05:16 +01:00
jamesread
9df1a127c2 feature: #68 - Remove version number from package names 2022-08-27 17:55:40 +01:00
jamesread
d28c24d8c9 cicd: Build in serial to help with GitHub memory limits 2022-08-27 17:55:08 +01:00
jamesread
70c4f0db50 Merge branch 'feature-jwt' 2022-08-27 17:53:45 +01:00
jamesread
061033e5da cicd: kaniko, I am sorry, it was my fault 2022-08-27 15:46:21 +01:00
jamesread
7cea239a43 cicd: Kaniko seems super fussy 2022-08-27 15:35:31 +01:00
jamesread
736c9dee2d cicd: try workspace 2022-08-27 15:34:47 +01:00
jamesread
28753bfabd cicd: print cwd, and probably put go files in correct place 2022-08-27 15:33:44 +01:00
jamesread
2d9335a1b9 cicd: Go install verbose so its better for cicd logs 2022-08-27 15:22:12 +01:00
jamesread
40acb86e10 cicd: kaniko is stupider 2022-08-27 15:18:23 +01:00
jamesread
9cbeb9edc6 cicd: Docker is stupid 2022-08-27 15:17:08 +01:00
jamesread
051ede1280 cicd: adding go files back 2022-08-27 14:48:27 +01:00
jamesread
bb67ea58b6 cicd: go.mod 2022-08-27 13:28:06 +01:00
jamesread
e3a5312614 cicd: go.mod needed for go install 2022-08-27 13:25:32 +01:00
jamesread
adbed0d037 cicd: Remove tabs in Dockerfile 2022-08-27 13:22:46 +01:00
jamesread
99238d21b3 cicd: Move make instructions to dockerfile 2022-08-27 13:13:52 +01:00
jamesread
bfe38e03c3 cicd: copy makefile 2022-08-27 13:10:51 +01:00
jamesread
cfb337f992 cicd: gobuilder cannot install iptuils in a container 2022-08-27 13:06:21 +01:00
jamesread
e7b7a73176 cicd: makefile for gobuilder 2022-08-27 12:50:23 +01:00
jamesread
31db838bfd cicd: go-image-builder 2022-08-27 12:42:14 +01:00
jamesread
1c0a57abea cicd: sha full version 2022-08-24 22:15:39 +01:00
jamesread
f4fdde9b54 cicd: sha full version 2022-08-24 22:13:08 +01:00
jamesread
462efe74c4 cicd: short github hash in dist name 2022-08-24 22:03:33 +01:00
jamesread
e9fbcce220 fmt: Reduce cyclo complexity 2022-08-24 20:52:13 +01:00
jamesread
c38b0351e4 cicd: Short commit hash 2022-08-24 20:50:42 +01:00
jamesread
a92ac09235 cicd: Include branch name in snapshots 2022-08-24 19:46:40 +01:00
jamesread
8a7bf7d565 cicd: upgrade github actions quite considerably 2022-08-24 14:44:10 +01:00
jamesread
0949999840 feature: Initial version of JWT/ACLs 2022-08-24 12:00:33 +01:00
jamesread
7824ce176d depbump: Forgot go-mod-tidy 2022-06-10 19:44:31 +01:00
jamesread
83ce4a3165 doc: Needed more commit types to be clearer 2022-06-10 19:41:52 +01:00
jamesread
a140201267 depbump: June 10th 2022-06-10 19:41:14 +01:00
jamesread
f9b6d60ca8 cicd: integration test for hidden footer 2022-06-10 19:25:23 +01:00
Ezequiel Bruni
9286536fda Created service file for OpenRC 2022-05-15 02:46:42 -05:00
jamesread
496cb400d0 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2022-05-01 10:03:23 +01:00
jamesread
b816884e94 feature: Default to relative API path, which should help reverse proxy configs 2022-05-01 10:03:11 +01:00
jamesread
ed7fd2e6ef cicd: ignore installation-id 2022-05-01 10:02:38 +01:00
James Read
c322a50329 Update CONTRIBUTING.adoc
Added description for buf.
2022-04-26 15:39:04 +01:00
jamesread
0b75bce275 doc: Simplified make deps 2022-04-26 15:33:19 +01:00
James Read
d3581e4829 Merge pull request #57 from Fale/rename
bugfix: update code to reflect new repository name. Thank you very much @Fale
2022-04-26 15:10:06 +01:00
Fabio Alessandro Locati
8485a0e446 bugfix: update code to reflect new repository name 2022-04-26 13:43:40 +02:00
jamesread
4f708648e8 cicd: dep bump integration-tests 2022-04-18 09:19:39 +01:00
jamesread
2d7157703c bugfix: Goreleaser now requires explicit bindir. As we are not a distro package, use /usr/local/bin/, which matches the systemd unit file, and the Linux filesystem standard. 2022-04-07 17:13:59 +01:00
jamesread
17c1804129 bugfix: Issue #33 - argument names now allow a-zA-Z0-9_ 2022-04-05 22:58:00 +01:00
jamesread
e05083ebeb bugfix: installation ID now follows configdir 2022-04-05 14:24:40 +01:00
jamesread
0a77f89374 Merge branch 'main' of ssh://github.com/OliveTin/OliveTin 2022-04-05 12:19:30 +01:00
jamesread
ebd1c4e938 security: Use quoted values for origin, URL, and force quoting. 2022-04-05 12:19:24 +01:00
James Read
5115aa1142 Merge pull request #52 from OliveTin/issue-38-config-flag
feature: issue #38 - Config Directories
2022-04-05 12:18:14 +01:00
jamesread
76971603b4 feature: General dependency bump 2022-04-05 11:47:51 +01:00
jamesread
6f5fd20a2c fmt: gofmt cleanup 2022-04-05 11:28:35 +01:00
jamesread
42cde3ba70 security: CVE-2021-44906 npm minimist 2022-04-05 11:13:46 +01:00
jamesread
86a48f4ace security: webui npm packages should have a package-lock.json 2022-04-05 11:10:32 +01:00
jamesread
a725b377cc feature: Customizable external rest address 2022-04-05 11:06:41 +01:00
jamesread
63068dfdea cicd: Remove old dependencies - no longer need machineid 2022-04-05 11:04:57 +01:00
jamesread
3ad640aee0 feature: issue #38 - Config Directories 2022-03-23 16:17:45 +00:00
James Read
bb96072682 Merge pull request #50 from jonesrussell/rej_shownavigation
bugfix: Rename "HideNavigation" to "ShowNavigation"
2022-03-23 15:44:00 +00:00
James Read
24b8857165 Merge branch 'main' into rej_shownavigation 2022-03-23 15:43:43 +00:00
James Read
51112aa2f4 Merge pull request #48 from jonesrussell/rej_showfooter
feature: Show/Hide footer - thank you @jonesrussell !
2022-03-22 22:08:56 +00:00
Russell Jones
5bd90adc1f bugfix: Rename "HideNavigation" to "ShowNavigation" 2022-03-22 20:04:27 +00:00
jamesread
81c26d997d cicd: Make the checklist a little easier to go through. 2022-03-22 10:50:56 +00:00
Russell Jones
af78385759 feature: Show/Hide footer 2022-03-22 00:43:28 +00:00
jamesread
420105ec99 fmt: css ids/classes to use kebab-case 2022-02-23 15:29:56 +00:00
jamesread
10e380a03b cicd: dep bump in integration-tests 2022-02-23 14:49:56 +00:00
jamesread
c985d31e4a cicd: dep bump 2022-02-23 14:47:03 +00:00
jamesread
cabf045202 feature: Switch from MachineID to InstanceID in update checks 2022-02-23 14:18:12 +00:00
jamesread
8ea431b2e4 doc: Added links to install instructions 2022-01-24 20:38:19 +00:00
jamesread
62a45bd214 feature: Send isInContainer to update service 2022-01-11 23:17:50 +00:00
59 changed files with 8944 additions and 962 deletions

View File

@@ -11,6 +11,9 @@ print("Commit message is: " + commitmsg)
ALLOWED_COMMIT_TYPES = [
"cicd",
"test",
"refactor",
"depbump",
"typo",
"fmt",
"doc",

View File

@@ -6,14 +6,17 @@ Dont be afraid to ask for advice before working on a contribution. If your
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/jamesread/OliveTin/blob/main/CONTRIBUTING.adoc)
Helpful information to understand the project can be found here: [CONTRIBUTING](https://github.com/OliveTin/OliveTin/blob/main/CONTRIBUTING.adoc)
^^^ please delete the lines above when raising a PR to keep the request to the bare essentials ^^^
# 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 freature branch.
- [ ] `make daemon-compile`, `make daemon-codestyle` and `make daemon-unittests` runs cleanly.
- [ ] `make webui-codestyle` should runs cleanly.
- [ ] 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.

View File

@@ -1,44 +1,54 @@
---
name: "Build Snapshot"
on: [push]
on:
- push
- workflow_dispatch
jobs:
build-snapshot:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
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@v2
with:
go-version: '^1.16.0'
uses: actions/setup-go@v3
with:
go-version: '>=1.18.0'
cache: true
- name: grpc
run: make grpc
- name: goreleaser
uses: goreleaser/goreleaser-action@v2
with:
uses: goreleaser/goreleaser-action@v3
with:
distribution: goreleaser
version: latest
args: release --snapshot --rm-dist
args: release --snapshot --rm-dist --parallelism 1
- name: Archive binaries
uses: actions/upload-artifact@v2
with:
name: dist
uses: actions/upload-artifact@v3.1.0
with:
name: "OliveTin-snapshot-${{ github.ref_name }}-${{ github.sha }}-dist"
path: dist/OliveTin*.*
- name: Archive integration tests
uses: actions/upload-artifact@v2
with:
uses: actions/upload-artifact@v3.1.0
with:
name: integration-tests
path: integration-tests

View File

@@ -1,8 +1,9 @@
---
name: "Build Tag"
on:
push:
tags:
tags:
- '*'
jobs:
@@ -10,19 +11,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
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@v2
with:
go-version: '^1.16.0'
uses: actions/setup-go@v3
with:
go-version: '^1.18.0'
cache: true
- name: Login to Docker Hub
uses: docker/login-action@v1
@@ -35,21 +43,21 @@ jobs:
- name: goreleaser
uses: goreleaser/goreleaser-action@v2
with:
with:
distribution: goreleaser
version: latest
args: release --rm-dist
env:
args: release --rm-dist --parallelism 1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Archive binaries
uses: actions/upload-artifact@v2
with:
with:
name: dist
path: dist/OliveTin*.*
- name: Archive integration tests
uses: actions/upload-artifact@v2
with:
with:
name: integration-tests
path: integration-tests

View File

@@ -1,3 +1,4 @@
---
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
@@ -13,16 +14,15 @@ name: "CodeQL"
on:
push:
paths:
paths:
- 'cmd/**'
- 'internal/**'
- 'webui/**'
- 'integration-tests/**'
- 'OliveTin.proto'
branches: [ main ]
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
branches: [main]
schedule:
- cron: '25 10 * * 5'
@@ -38,40 +38,17 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
language: ['go', 'javascript']
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
#- name: Autobuild
# uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@@ -1,3 +1,4 @@
---
name: "Codestyle checks"
on:
@@ -19,7 +20,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
with:
go-version: '^1.16.0'
- name: deps

2
.gitignore vendored
View File

@@ -1,4 +1,3 @@
webui/package-lock.json
webui/node_modules
**/*.swp
**/*.swo
@@ -9,3 +8,4 @@ gen/
reports
releases/
dist/
installation-id.txt

View File

@@ -34,18 +34,32 @@ builds:
goarch: arm64
ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }}
- -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{ .CommitDate }}
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Commit }}"
name_template: "{{ .Branch }}-{{ .ShortCommit }}"
changelog:
sort: asc
groups:
- title: 'Security'
regexp: '^.*?security(\([[:word:]]+\))??!?:.+$'
order: 0
- title: 'Features'
regexp: '^.*?feature(\([[:word:]]+\))??!?:.+$'
order: 1
- title: 'Bug fixes'
regexp: '^.*?bugfix(\([[:word:]]+\))??!?:.+$'
order: 2
- title: Others
order: 999
filters:
exclude:
- '^docs:'
- '^test:'
- '^cicd:'
- '^refactor:'
archives:
-
@@ -58,12 +72,13 @@ archives:
- Dockerfile
- webui
- OliveTin.service
- ./var/
replacements:
darwin: macOS
arm: arm32v
name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}"
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}"
wrap_in_directory: true
@@ -78,7 +93,6 @@ dockers:
goos: linux
goarch: amd64
skip_push: false
build_flag_templates:
- "--platform=linux/amd64"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
@@ -94,7 +108,6 @@ dockers:
goos: linux
goarch: arm64
skip_push: false
build_flag_templates:
- "--platform=linux/arm64"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
@@ -103,46 +116,31 @@ dockers:
extra_files:
- webui
# This container image actually uses the goarm v5 binary, because v5 helps
# support rpi 1's, but it seems most container images start with v7.
- image_templates:
- "docker.io/jamesread/olivetin:{{ .Tag }}-armv7"
dockerfile: Dockerfile.armv7
goos: linux
goarch: arm
goarm: 7
skip_push: false
build_flag_templates:
- "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
extra_files:
- webui
docker_manifests:
- name_template: docker.io/jamesread/olivetin:{{ .Version }}
image_templates:
- docker.io/jamesread/olivetin:{{ .Version }}-amd64
- docker.io/jamesread/olivetin:{{ .Version }}-arm64
- docker.io/jamesread/olivetin:{{ .Version }}-armv7
- name_template: docker.io/jamesread/olivetin:latest
image_templates:
- docker.io/jamesread/olivetin:{{ .Version }}-amd64
- docker.io/jamesread/olivetin:{{ .Version }}-arm64
- docker.io/jamesread/olivetin:{{ .Version }}-armv7
nfpms:
- maintainer: James Read <contact@jread.com>
- id: default
maintainer: James Read <contact@jread.com>
description: OliveTin is a web interface for running Linux shell commands.
homepage: https://github.com/jamesread/OliveTin
homepage: https://github.com/OliveTin/OliveTin
license: AGPL-3.0
formats:
- deb
- rpm
bindir: /usr/local/bin/
file_name_template: '{{ .PackageName }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
contents:
- src: OliveTin.service
dst: /etc/systemd/system/OliveTin.service
@@ -154,8 +152,41 @@ nfpms:
dst: /etc/OliveTin/config.yaml
type: "config|noreplace"
- src: var/manpage/OliveTin.1.gz
dst: /usr/share/man/man1/OliveTin.1.gz
- id: openrc
maintainer: James Read <contact@jread.com>
description: OliveTin is a web interface for running Linux shell commands.
homepage: https://github.com/OliveTin/OliveTin
license: AGPL-3.0
formats:
- apk
bindir: /usr/local/bin/
file_name_template: '{{ .PackageName }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
contents:
- src: var/openrc/OliveTin
dst: /etc/init.d/OliveTin
- src: webui
dst: /var/www/olivetin/
- src: config.yaml
dst: /etc/OliveTin/config.yaml
type: "config|noreplace"
- src: var/manpage/OliveTin.1.gz
dst: /usr/share/man/man1/OliveTin.1.gz
release:
footer: |
## Container images ([on Docker Hub](https://hub.docker.com/r/jamesread/olivetin/tags?page=1&ordering=last_updated))
- `docker pull docker.io/jamesread/olivetin:{{ .Version }}`
## Useful links
- [Which download do I need?](https://docs.olivetin.app/choose-package.html)

View File

@@ -29,12 +29,10 @@ dnf install git go protobuf-compiler make -y
git clone https://github.com/OliveTin/OliveTin.git
cd OliveTin
# For each dependency in tools.go;
go install "github.com/bufbuild/buf/cmd/buf"
go install ...
buf generate
# `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
./OliveTin
```

View File

@@ -1,15 +1,14 @@
FROM --platform=linux/amd64 docker.io/amd64/fedora
RUN useradd -rm olivetin -u 1000
FROM --platform=linux/amd64 registry.fedoraproject.org/fedora-minimal:36-x86_64
RUN mkdir -p /config /var/www/olivetin \
&& \
dnf install -y \
&& microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
iputils \
openssh-clients \
shadow-utils \
docker \
&& dnf clean all && \
rm -rf /var/cache/dnf
&& microdnf clean all
RUN useradd --system --create-home olivetin -u 1000
EXPOSE 1337/tcp

View File

@@ -1,14 +1,13 @@
FROM --platform=linux/arm64 docker.io/arm64v8/fedora
RUN useradd -rm olivetin -u 1000
FROM --platform=linux/arm64 registry.fedoraproject.org/fedora-minimal:36-aarch64
RUN mkdir -p /config /var/www/olivetin \
&& \
dnf install -y \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
iputils \
openssh-clients \
&& dnf clean all && \
rm -rf /var/cache/dnf
shadow-utils \
openssh-clients
RUN useradd --system --create-home olivetin -u 1000
EXPOSE 1337/tcp

View File

@@ -1,14 +1,13 @@
FROM --platform=linux/arm/v7 arm32v7/fedora:latest
RUN useradd -rm olivetin -u 1000
FROM --platform=linux/armhfp registry.fedoraproject.org/fedora-minimal:36-armhfp
RUN mkdir -p /config /var/www/olivetin \
&& \
dnf install -y \
microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \
iputils \
openssh-clients \
&& dnf clean all && \
rm -rf /var/cache/dnf
shadow-utils \
openssh-clients
RUN useradd --system --create-home olivetin -u 1000
EXPOSE 1337/tcp

View File

@@ -1,13 +1,13 @@
compile: daemon-compile-x64-lin
daemon-compile-armhf:
GOARCH=arm GOARM=6 go build -o OliveTin.armhf github.com/jamesread/OliveTin/cmd/OliveTin
GOARCH=arm GOARM=6 go build -o OliveTin.armhf github.com/OliveTin/OliveTin/cmd/OliveTin
daemon-compile-x64-lin:
GOOS=linux go build -o OliveTin github.com/jamesread/OliveTin/cmd/OliveTin
GOOS=linux go build -o OliveTin github.com/OliveTin/OliveTin/cmd/OliveTin
daemon-compile-x64-win:
GOOS=windows GOARCH=amd64 go build -o OliveTin.exe github.com/jamesread/OliveTin/cmd/OliveTin
GOOS=windows GOARCH=amd64 go build -o OliveTin.exe github.com/OliveTin/OliveTin/cmd/OliveTin
daemon-compile: daemon-compile-armhf daemon-compile-x64-lin daemon-compile-x64-win
@@ -34,15 +34,20 @@ go-tools:
go install "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
go install "google.golang.org/protobuf/cmd/protoc-gen-go"
grpc: githooks go-tools
grpc: go-tools
buf generate
dist: protoc
protoc:
protoc --go_out=. --go-grpc_out=. --grpc-gateway_out=. -I .:/usr/include/ OliveTin.proto
podman-image:
buildah bud -t olivetin
podman-container:
podman kill olivetin
podman rm olivetin
podman kill olivetin || true
podman rm olivetin || true
podman create --name olivetin -p 1337:1337 -v /etc/OliveTin/:/config:ro olivetin
podman start olivetin

View File

@@ -20,6 +20,8 @@ message ActionArgument {
string defaultValue = 4;
repeated ActionArgumentChoice choices = 5;
string description = 6;
}
message ActionArgumentChoice {
@@ -68,6 +70,7 @@ message LogEntry {
string user = 7;
string userClass = 8;
string actionIcon = 9;
repeated string tags = 10;
}
message GetLogsResponse {
@@ -84,6 +87,12 @@ message ValidateArgumentTypeResponse {
string description = 2;
}
message WhoAmIRequest {}
message WhoAmIResponse {
string authenticatedUser = 1;
}
service OliveTinApi {
rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) {
option (google.api.http) = {
@@ -110,4 +119,10 @@ service OliveTinApi {
body: "*"
};
}
rpc WhoAmI(WhoAmIRequest) returns (WhoAmIResponse) {
option (google.api.http) = {
get: "/api/WhoAmI"
};
}
}

View File

@@ -64,6 +64,13 @@ All documentation can be found at http://docs.olivetin.app . This includes insta
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

View File

@@ -4,7 +4,4 @@ deps:
- remote: buf.build
owner: googleapis
repository: googleapis
branch: main
commit: d1a849b8f8304950832335723096e954
digest: b1-zJkwX0YeOp1Wa0Jaj_RqMLa2-oEzePH6PJEK8aaMeI4=
create_time: 2021-08-26T15:07:19.652533Z
commit: e9fcfb66f77242e5b8fd4564d7a01033

View File

@@ -1,17 +1,23 @@
package main
import (
"flag"
log "github.com/sirupsen/logrus"
grpcapi "github.com/jamesread/OliveTin/internal/grpcapi"
updatecheck "github.com/jamesread/OliveTin/internal/updatecheck"
"github.com/OliveTin/OliveTin/internal/executor"
grpcapi "github.com/OliveTin/OliveTin/internal/grpcapi"
"github.com/OliveTin/OliveTin/internal/oncron"
"github.com/OliveTin/OliveTin/internal/onstartup"
updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck"
"github.com/jamesread/OliveTin/internal/httpservers"
"github.com/OliveTin/OliveTin/internal/httpservers"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/fsnotify/fsnotify"
config "github.com/jamesread/OliveTin/internal/config"
"github.com/spf13/viper"
"os"
"path"
)
var (
@@ -22,6 +28,11 @@ var (
)
func init() {
log.SetFormatter(&log.TextFormatter{
ForceQuote: true,
DisableTimestamp: true,
})
log.WithFields(log.Fields{
"version": version,
"commit": commit,
@@ -30,10 +41,18 @@ func init() {
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(".")
viper.AddConfigPath(configDir)
viper.AddConfigPath("/config") // For containers.
viper.AddConfigPath("/etc/OliveTin/")
@@ -54,9 +73,18 @@ func init() {
})
reloadConfig()
warnIfPuidGuid()
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)
@@ -67,13 +95,22 @@ func reloadConfig() {
}
func main() {
log.Info("OliveTin started")
configDir := path.Dir(viper.ConfigFileUsed())
log.WithFields(log.Fields{
"configDir": configDir,
}).Infof("OliveTin started")
log.Debugf("Config: %+v", cfg)
go updatecheck.StartUpdateChecker(version, commit, cfg)
executor := executor.DefaultExecutor()
go grpcapi.Start(cfg)
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

@@ -25,11 +25,13 @@ actions:
title: host
type: ascii_identifier
default: example.com
description: The host that you want to ping
- 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

88
go.mod
View File

@@ -1,22 +1,78 @@
module github.com/jamesread/OliveTin
module github.com/OliveTin/OliveTin
go 1.16
go 1.18
require (
github.com/bufbuild/buf v0.54.1
github.com/denisbrodbeck/machineid v1.0.1
github.com/fsnotify/fsnotify v1.4.9
github.com/fzipp/gocyclo v0.3.1
github.com/go-co-op/gocron v1.6.2
github.com/go-critic/go-critic v0.6.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0
github.com/bufbuild/buf v1.3.1
github.com/fsnotify/fsnotify v1.5.4
github.com/fzipp/gocyclo v0.5.0
github.com/go-critic/go-critic v0.6.2
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/google/uuid v1.3.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.8.1
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/tools v0.1.7 // indirect
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced
google.golang.org/grpc v1.40.0-dev.0.20210708170655-30dfb4b933a5
github.com/spf13/viper v1.12.0
github.com/stretchr/testify v1.7.2
golang.org/x/exp v0.0.0-20220823124025-807a23277127
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac
google.golang.org/grpc v1.47.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
google.golang.org/protobuf v1.27.1
google.golang.org/protobuf v1.28.0
)
require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-toolsmith/astcast v1.0.0 // indirect
github.com/go-toolsmith/astcopy v1.0.0 // indirect
github.com/go-toolsmith/astequal v1.0.1 // indirect
github.com/go-toolsmith/astfmt v1.0.0 // indirect
github.com/go-toolsmith/astp v1.0.0 // indirect
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 // indirect
github.com/go-toolsmith/strparse v1.0.0 // indirect
github.com/go-toolsmith/typep v1.0.2 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect
github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f // indirect
github.com/jhump/protoreflect v1.11.1-0.20220213155251-0c2aedc66cf4 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/profile v1.6.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quasilyte/go-ruleguard v0.3.15 // indirect
github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.0 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.12 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

346
go.sum
View File

@@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
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=
@@ -15,9 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
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.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
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=
@@ -26,7 +25,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
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=
@@ -36,24 +34,17 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
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/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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/bufbuild/buf v0.54.1 h1:k5zYgSOlNg17mZCBgKo6TWktCiSvBdOx+v591t3JPjY=
github.com/bufbuild/buf v0.54.1/go.mod h1:BRVv/lQDPFt0AGt79VgXMQK5HHXRW5VFhAu+mNnOmeM=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/bufbuild/buf v1.3.1 h1:AelWcENnbNEjwxmQXIZaU51GHgnWQ8Mc94kZdDUKgRs=
github.com/bufbuild/buf v1.3.1/go.mod h1:CTRUb23N+zlm1U8ZIBKz0Sqluk++qQloB2i/MZNZHIs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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=
@@ -61,34 +52,31 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
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/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
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/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fzipp/gocyclo v0.5.0 h1:jMgQATRpq/msyXdnO36+sOEDhQ4EWJDta3RIGA9GRqA=
github.com/fzipp/gocyclo v0.5.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-co-op/gocron v1.6.2 h1:x5g1tWnWcXIZesdosJJcbziRi4XG6tKB92yKLUpoBkU=
github.com/go-co-op/gocron v1.6.2/go.mod h1:DbJm9kdgr1sEvWpHCA7dFFs/PGHPMil9/97EXCRPr4k=
github.com/go-critic/go-critic v0.6.1 h1:lS8B9LH/VVsvQQP7Ao5TJyQqteVKVs3E4dXiHMyubtI=
github.com/go-critic/go-critic v0.6.1/go.mod h1:SdNCfU0yF3UBjtaZGw6586/WocupMOJuiqgom5DsQxM=
github.com/go-critic/go-critic v0.6.2 h1:L5SDut1N4ZfsWZY0sH4DCrsHLHnhuuWak2wa165t9gs=
github.com/go-critic/go-critic v0.6.2/go.mod h1:td1s27kfmLpe5G/DPjlnFI7o1UCzePptwU7Az0V5iCM=
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=
@@ -101,29 +89,28 @@ github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLpo
github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw=
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg=
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o=
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM=
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk=
github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
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 v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU=
github.com/golang/glog v0.0.0-20210429001901-424d2337a529/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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/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=
@@ -131,7 +118,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
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/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
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=
@@ -147,11 +133,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
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.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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=
@@ -165,9 +148,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/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.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
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=
@@ -180,157 +162,117 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
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-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 h1:ajue7SzQMywqRjg2fK7dcpc0QhFGpTR2plWfV4EZWR4=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0/go.mod h1:r1hZAcvfFXuYmcKyCJI9wlyOPIZUJl6FCB8Cpca/NLE=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 h1:BGNSrTRW4rwfhJiFwvwF4XQ0Y72Jj9YEgxVrtovbD5o=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3/go.mod h1:VHn7KgNsRriXa4mcgtkpR00OXyQY6g67JWMvn+R27A4=
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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
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/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jhump/protoreflect v1.9.1-0.20210817181203-db1a327a393e h1:Yb4fEGk+GtBSNuvy5rs0ZJt/jtopc/z9azQaj3xbies=
github.com/jhump/protoreflect v1.9.1-0.20210817181203-db1a327a393e/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a h1:d4+I1YEKVmWZrgkt6jpXBnLgV2ZjO0YxEtLDdfIZfH4=
github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw=
github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f h1:BNuUg9k2EiJmlMwjoef3e8vZLHplbVw6DrjGFjLL+Yo=
github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f/go.mod h1:qr2b5kx4HbFS7/g4uYO5qv9ei8303JMsC7ESbYiqr2Q=
github.com/jhump/protoreflect v1.11.1-0.20220213155251-0c2aedc66cf4 h1:E2CdxLXYSn6Zrj2+u8DWrwMJW3YZLSWtM/7kIL8OL18=
github.com/jhump/protoreflect v1.11.1-0.20220213155251-0c2aedc66cf4/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
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.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
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/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30=
github.com/quasilyte/go-ruleguard v0.3.13 h1:O1G41cq1jUr3cJmqp7vOUT0SokqjzmS9aESWJuIDRaY=
github.com/quasilyte/go-ruleguard v0.3.13/go.mod h1:Ul8wwdqR6kBVOCt2dipDBkE+T6vAV/iixkrKuRTN1oQ=
github.com/quasilyte/go-ruleguard v0.3.15 h1:iWYzp1z72IlXTioET0+XI6SjQdPfMGfuAiZiKznOt7g=
github.com/quasilyte/go-ruleguard v0.3.15/go.mod h1:NhuWhnlVEM1gT1A4VJHYfy9MuYSxxwHgxWoPsn9llB4=
github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.10/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.12-0.20220101150716-969a394a9451/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.12/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20210428214800-545e0d2e0bf7/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 h1:P4QPNn+TK49zJjXKERt/vyPbv/mCHB/zQ4flDYOMN+M=
github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM=
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY=
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
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/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
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.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
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.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
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.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/twitchtv/twirp v8.1.0+incompatible h1:KGXanpa9LXdVE/V5P/tA27rkKFmXRGCtSNT7zdeeVOY=
github.com/twitchtv/twirp v8.1.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
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=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
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=
@@ -340,23 +282,23 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
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-20190820162420-60c769a6c586/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/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=
@@ -367,6 +309,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
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-20220823124025-807a23277127 h1:S4NrSKDfihhl3+4jSTgwoIevKxX9p7Iv9x++OEIptDo=
golang.org/x/exp v0.0.0-20220823124025-807a23277127/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
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=
@@ -380,8 +324,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
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/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/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=
@@ -392,12 +334,12 @@ 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.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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=
@@ -426,13 +368,12 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/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-20210119194325-5f4716e94777/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.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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=
@@ -442,10 +383,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
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/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1/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=
@@ -456,11 +393,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
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.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/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=
@@ -470,7 +404,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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=
@@ -493,22 +426,21 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
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-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
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=
@@ -523,13 +455,11 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/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-20190328211700-ab21143f2384/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=
@@ -539,8 +469,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
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-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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=
@@ -562,10 +490,7 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc
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-20200522201501-cb1345f3a375/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-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
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-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@@ -576,17 +501,15 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201230224404-63754364767c/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.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
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=
@@ -607,9 +530,6 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
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/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
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=
@@ -652,14 +572,10 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
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-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
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-20220608133413-ed9918b62aac h1:ByeiW1F67iV9o8ipGskA+HWzSkMbRJuKLlwCdPxzn7A=
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
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=
@@ -678,10 +594,9 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
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.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0-dev.0.20210708170655-30dfb4b933a5 h1:jeEzNnOogdiVxvaPNbt/QFOggkBTaUPBkQ2/NIngeyk=
google.golang.org/grpc v1.40.0-dev.0.20210708170655-30dfb4b933a5/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -694,25 +609,28 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
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.25.1-0.20200805231151-a709e31e5d12/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.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=
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=

View File

@@ -11,10 +11,10 @@ Vagrant.configure("2") do |config|
libvirt.management_network_device = 'virbr0'
end
config.vm.define :f34 do |f34|
f34.vm.box = "generic/fedora34"
f34.vm.provision "file", source: "/opt/OliveTin-vagrant/linux_amd64_rpm/.", destination: "."
f34.vm.provision "shell", inline: "rpm -U OliveTin* && systemctl enable --now OliveTin && systemctl disable --now firewalld"
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"
end
config.vm.define :debian do |debian|

View File

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

View File

@@ -4,7 +4,7 @@
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
hideNavigation: true
showNavigation: false
checkForUpdates: false
# Actions (buttons) to show up on the WebUI:

View File

@@ -8,11 +8,11 @@ describe('Homepage rendering', () => {
})
it('Default buttons are rendered', () => {
cy.get("#rootGroup button").should('have.length', 6)
cy.get("#root-group button").should('have.length', 6)
})
it('Switcher navigation is visible', () => {
cy.get('#sectionSwitcher').then($el => {
cy.get('#section-switcher').then($el => {
expect(Cypress.dom.isHidden($el)).to.be.false
})
})

View File

@@ -0,0 +1,14 @@
describe('Hidden Footer', () => {
beforeEach(() => {
cy.visit("/")
cy.wait(500)
});
it('Footer is hidden', () => {
cy.get('footer').then($el => {
expect(Cypress.dom.isHidden($el)).to.be.true
})
})
});

View File

@@ -9,7 +9,7 @@ describe('Hidden Nav', () => {
})
it('Switcher navigation is hidden', () => {
cy.get('#sectionSwitcher').then($el => {
cy.get('#section-switcher').then($el => {
expect(Cypress.dom.isHidden($el)).to.be.true
})
})

File diff suppressed because it is too large Load Diff

View File

@@ -2,86 +2,135 @@ package acl
import (
"context"
config "github.com/jamesread/OliveTin/internal/config"
config "github.com/OliveTin/OliveTin/internal/config"
log "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
"google.golang.org/grpc/metadata"
)
// User respresents a person.
type User struct {
Username string
type AuthenticatedUser struct {
Username string
Usergroup string
acls []string
}
// IsAllowedExec checks if a User is allowed to execute an Action
func IsAllowedExec(cfg *config.Config, user *User, action *config.Action) bool {
canExec := cfg.DefaultPermissions.Exec
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"CanExec": canExec,
}).Debug("isAllowedExec Permission Default")
for _, permissionEntry := range action.Permissions {
if isUserInGroup(user, permissionEntry.Usergroup) {
// IsAllowedExec checks if a AuthenticatedUser is allowed to execute an Action
func IsAllowedExec(cfg *config.Config, user *AuthenticatedUser, action *config.Action) bool {
for _, acl := range getRelevantAcls(cfg, action.Acls, user) {
if acl.Permissions.Exec {
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"CanExec": permissionEntry.Exec,
}).Debug("isAllowedExec Permission Entry")
"User": user.Username,
"Action": action.Title,
"ACL": acl.Name,
}).Debug("isAllowedExec - Matched ACL")
canExec = permissionEntry.Exec
return true
}
}
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"CanExec": canExec,
}).Debug("isAllowedExec Final Result")
"User": user.Username,
"Action": action.Title,
}).Debug("isAllowedExec - No ACLs matched")
return canExec
return cfg.DefaultPermissions.Exec
}
// IsAllowedView checks if a User is allowed to view an Action
func IsAllowedView(cfg *config.Config, user *User, action *config.Action) bool {
canView := cfg.DefaultPermissions.View
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"CanView": canView,
}).Debug("isAllowedView Permission Default")
for idx, permissionEntry := range action.Permissions {
if isUserInGroup(user, permissionEntry.Usergroup) {
func IsAllowedView(cfg *config.Config, user *AuthenticatedUser, action *config.Action) bool {
for _, acl := range getRelevantAcls(cfg, action.Acls, user) {
if acl.Permissions.View {
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"CanView": permissionEntry.View,
"Index": idx,
}).Debug("isAllowedView Permission Entry")
"User": user.Username,
"Action": action.Title,
"ACL": acl.Name,
}).Debug("isAllowedView - Matched ACL")
canView = permissionEntry.View
return true
}
}
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"CanView": canView,
}).Debug("isAllowedView Final Result")
"User": user.Username,
"Action": action.Title,
}).Debug("isAllowedView - No ACLs matched")
return canView
return cfg.DefaultPermissions.View
}
func isUserInGroup(user *User, usergroup string) bool {
return true
func getMetdataKeyOrEmpty(md metadata.MD, key string) string {
mdValues := md.Get(key)
if len(mdValues) > 0 {
return mdValues[0]
}
return ""
}
// UserFromContext tries to find a user from a grpc context - obviously this is
// a stub at the moment.
func UserFromContext(ctx context.Context) *User {
return &User{
Username: "Guest",
// UserFromContext tries to find a user from a grpc context
func UserFromContext(ctx context.Context, cfg *config.Config) *AuthenticatedUser {
md, ok := metadata.FromIncomingContext(ctx)
ret := &AuthenticatedUser{}
if ok {
ret.Username = getMetdataKeyOrEmpty(md, "username")
ret.Usergroup = getMetdataKeyOrEmpty(md, "usergroup")
}
buildUserAcls(cfg, ret)
log.WithFields(log.Fields{
"username": ret.Username,
"usergroup": ret.Usergroup,
}).Infof("UserFromContext")
return ret
}
func buildUserAcls(cfg *config.Config, user *AuthenticatedUser) {
for _, acl := range cfg.AccessControlLists {
if slices.Contains(acl.MatchUsernames, user.Username) {
user.acls = append(user.acls, acl.Name)
continue
}
if slices.Contains(acl.MatchUsergroups, user.Usergroup) {
user.acls = append(user.acls, acl.Name)
continue
}
}
}
func isACLRelevant(cfg *config.Config, actionAcls []string, acl config.AccessControlList, user *AuthenticatedUser) bool {
if !slices.Contains(user.acls, acl.Name) {
return false
}
if acl.AddToEveryAction {
return true
}
if slices.Contains(actionAcls, acl.Name) {
return true
}
return false
}
func getRelevantAcls(cfg *config.Config, actionAcls []string, user *AuthenticatedUser) []*config.AccessControlList {
var ret []*config.AccessControlList
for _, acl := range cfg.AccessControlLists {
if isACLRelevant(cfg, actionAcls, acl, user) {
ret = append(ret, &acl)
}
}
return ret
}

View File

@@ -3,23 +3,26 @@ package config
// Action represents the core functionality of OliveTin - commands that show up
// as buttons in the UI.
type Action struct {
ID string
Title string
Icon string
Shell string
CSS map[string]string `mapstructure:"omitempty"`
Timeout int
Permissions []PermissionsEntry
Arguments []ActionArgument
ID string
Title string
Icon string
Shell string
CSS map[string]string `mapstructure:"omitempty"`
Timeout int
Acls []string
ExecOnStartup bool
ExecOnCron []string
Arguments []ActionArgument
}
// ActionArgument objects appear on Actions.
type ActionArgument struct {
Name string
Title string
Type string
Default string
Choices []ActionArgumentChoice
Name string
Title string
Description string
Type string
Default string
Choices []ActionArgumentChoice
}
// ActionArgumentChoice represents a predefined choice for an argument.
@@ -37,30 +40,25 @@ type Entity struct {
CSS map[string]string
}
// PermissionsEntry defines what users can do with an action.
type PermissionsEntry struct {
Usergroup string
View bool
Exec bool
}
// DefaultPermissions will be used when no PermissionsEntry overrides it.
type DefaultPermissions struct {
// PermissionsList defines what users can do with an action.
type PermissionsList struct {
View bool
Exec bool
}
// UserGroup is a group of users.
type UserGroup struct {
Name string
Members []string
// AccessControlList defines what permissions apply to a user or user group.
type AccessControlList struct {
Name string
AddToEveryAction bool
MatchUsergroups []string
MatchUsernames []string
Permissions PermissionsList
}
// Config is the global config used through the whole app.
type Config struct {
UseSingleHTTPFrontend bool
ThemeName string
HideNavigation bool
ListenAddressSingleHTTPFrontend string
ListenAddressWebUI string
ListenAddressRestActions string
@@ -70,25 +68,39 @@ type Config struct {
Actions []Action `mapstructure:"actions"`
Entities []Entity `mapstructure:"entities"`
CheckForUpdates bool
PageTitle string
ShowFooter bool
ShowNavigation bool
ShowNewVersions bool
Usergroups []UserGroup
DefaultPermissions DefaultPermissions
AuthJwtCookieName string
AuthJwtSecret string
AuthJwtClaimUsername string
AuthJwtClaimUserGroup string
AuthHttpHeaderUsername string
AuthHttpHeaderUserGroup string
DefaultPermissions PermissionsList
AccessControlLists []AccessControlList
}
// DefaultConfig gets a new Config structure with sensible default values.
func DefaultConfig() *Config {
config := Config{}
config.UseSingleHTTPFrontend = true
config.HideNavigation = false
config.PageTitle = "OliveTin"
config.ShowFooter = true
config.ShowNavigation = true
config.ShowNewVersions = true
config.ListenAddressSingleHTTPFrontend = "0.0.0.0:1337"
config.ListenAddressRestActions = "localhost:1338"
config.ListenAddressGrpcActions = "localhost:1339"
config.ListenAddressWebUI = "localhost:1340"
config.ExternalRestAddress = "."
config.LogLevel = "INFO"
config.CheckForUpdates = true
config.ShowNewVersions = true
config.DefaultPermissions.Exec = true
config.DefaultPermissions.View = true
config.AuthJwtClaimUsername = "name"
config.AuthJwtClaimUserGroup = "group"
return &config
}

View File

@@ -21,3 +21,13 @@ func (action *Action) FindArg(name string) *ActionArgument {
return nil
}
func (cfg *Config) FindAcl(aclTitle string) *AccessControlList {
for _, acl := range cfg.AccessControlLists {
if acl.Name == aclTitle {
return &acl
}
}
return nil
}

View File

@@ -31,3 +31,16 @@ func TestFindAction(t *testing.T) {
assert.Nil(t, c.FindAction("waffles"), "Find non-existent action")
}
func TestFindAcl(t *testing.T) {
c := DefaultConfig()
acl1 := AccessControlList{
Name: "Testing ACL",
}
c.AccessControlLists = append(c.AccessControlLists, acl1)
assert.NotNil(t, c.FindAcl("Testing ACL"), "Find a ACL that should exist")
assert.Nil(t, c.FindAcl("Chocolate Cake"), "Find a ACL that does not exist")
}

View File

@@ -13,7 +13,7 @@ import (
func AllowCors(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if origin := r.Header.Get("Origin"); origin != "" {
log.Debugf("Adding CORS header origin: %v", origin)
log.Debugf("Adding CORS header origin: %q", origin)
w.Header().Set("Access-Control-Allow-Origin", origin)
}

View File

@@ -0,0 +1,121 @@
package executor
import (
config "github.com/OliveTin/OliveTin/internal/config"
log "github.com/sirupsen/logrus"
"errors"
"net/url"
"regexp"
"strings"
)
var (
typecheckRegex = map[string]string{
"very_dangerous_raw_string": "",
"int": "^[\\d]+$",
"ascii": "^[a-zA-Z0-9]+$",
"ascii_identifier": "^[a-zA-Z0-9\\-\\.\\_]+$",
"ascii_sentence": "^[a-zA-Z0-9 \\,\\.]+$",
}
)
func parseActionArguments(rawShellCommand string, values map[string]string, action *config.Action) (string, error) {
log.WithFields(log.Fields{
"cmd": rawShellCommand,
}).Infof("Before Parse Args")
r := regexp.MustCompile("{{ *?([a-zA-Z0-9_]+?) *?}}")
matches := r.FindAllStringSubmatch(rawShellCommand, -1)
for _, match := range matches {
argValue, argProvided := values[match[1]]
if !argProvided {
log.Infof("%v", values)
return "", errors.New("Required arg not provided: " + match[1])
}
err := typecheckActionArgument(match[1], argValue, action)
if err != nil {
return "", err
}
log.WithFields(log.Fields{
"name": match[1],
"value": argValue,
}).Debugf("Arg assigned")
rawShellCommand = strings.ReplaceAll(rawShellCommand, match[0], argValue)
}
log.WithFields(log.Fields{
"cmd": rawShellCommand,
}).Infof("After Parse Args")
return rawShellCommand, nil
}
func typecheckActionArgument(name string, value string, action *config.Action) error {
arg := action.FindArg(name)
if arg == nil {
return errors.New("Action arg not defined: " + name)
}
if len(arg.Choices) > 0 {
return typecheckChoice(value, arg)
}
return TypeSafetyCheck(name, value, arg.Type)
}
func typecheckChoice(value string, arg *config.ActionArgument) error {
for _, choice := range arg.Choices {
if value == choice.Value {
return nil
}
}
return errors.New("argument value is not one of the predefined choices")
}
// TypeSafetyCheck checks argument values match a specific type. The types are
// defined in typecheckRegex, and, you guessed it, uses regex to check for allowed
// characters.
func TypeSafetyCheck(name string, value string, argumentType string) error {
if argumentType == "url" {
return typeSafetyCheckUrl(name, value)
}
return typeSafetyCheckRegex(name, value, argumentType)
}
func typeSafetyCheckRegex(name string, value string, argumentType string) error {
pattern, found := typecheckRegex[argumentType]
if !found {
return errors.New("argument type not implemented " + argumentType)
}
matches, _ := regexp.MatchString(pattern, value)
if !matches {
log.WithFields(log.Fields{
"name": name,
"value": value,
"type": argumentType,
}).Warn("Arg type check safety failure")
return errors.New("invalid argument, doesn't match " + argumentType)
}
return nil
}
func typeSafetyCheckUrl(name string, value string) error {
_, err := url.ParseRequestURI(value)
return err
}

View File

@@ -0,0 +1,69 @@
package executor
import (
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSanitizeUnsafe(t *testing.T) {
assert.Nil(t, TypeSafetyCheck("", "_zomg_ c:/ haxxor ' bobby tables && rm -rf ", "very_dangerous_raw_string"))
}
func TestSanitizeUnimplemented(t *testing.T) {
err := TypeSafetyCheck("", "I am a happy little argument", "greeting_type")
assert.NotNil(t, err, "Test an argument type that does not exist")
}
func TestArgumentNameNumbers(t *testing.T) {
a1 := config.Action{
Title: "Do some tickles",
Shell: "echo 'Tickling {{ person1name }}'",
Arguments: []config.ActionArgument{
{
Name: "person1name",
Type: "ascii",
},
},
}
values := map[string]string{
"person1name": "Fred",
}
out, err := parseActionArguments(a1.Shell, values, &a1)
assert.Equal(t, "echo 'Tickling Fred'", out)
assert.Nil(t, err)
}
func TestArgumentNotProvided(t *testing.T) {
a1 := config.Action{
Title: "Do some tickles",
Shell: "echo 'Tickling {{ personName }}'",
Arguments: []config.ActionArgument{
{
Name: "person",
Type: "ascii",
},
},
}
values := map[string]string{}
out, err := parseActionArguments(a1.Shell, values, &a1)
assert.Equal(t, "", out)
assert.Equal(t, err.Error(), "Required arg not provided: personName")
}
func TestTypeSafetyCheckUrl(t *testing.T) {
assert.Nil(t, TypeSafetyCheck("test1", "http://google.com", "url"), "Test URL: google.com")
assert.Nil(t, TypeSafetyCheck("test2", "http://technowax.net:80?foo=bar", "url"), "Test URL: technowax.net with query arguments")
assert.Nil(t, TypeSafetyCheck("test3", "http://localhost:80?foo=bar", "url"), "Test URL: localhost with query arguments")
assert.NotNil(t, TypeSafetyCheck("test4", "http://lo host:80", "url"), "Test a badly formed URL")
assert.NotNil(t, TypeSafetyCheck("test5", "12345", "url"), "Test a badly formed URL")
assert.NotNil(t, TypeSafetyCheck("test6", "_!23;", "url"), "Test a badly formed URL")
}

View File

@@ -1,29 +1,30 @@
package executor
import (
pb "github.com/jamesread/OliveTin/gen/grpc"
acl "github.com/jamesread/OliveTin/internal/acl"
config "github.com/jamesread/OliveTin/internal/config"
pb "github.com/OliveTin/OliveTin/gen/grpc"
acl "github.com/OliveTin/OliveTin/internal/acl"
config "github.com/OliveTin/OliveTin/internal/config"
log "github.com/sirupsen/logrus"
"context"
"errors"
"os/exec"
"regexp"
"strings"
"time"
"bytes"
"context"
"os/exec"
"runtime"
"time"
)
var (
typecheckRegex = map[string]string{
"very_dangerous_raw_string": "",
"int": "^[\\d]+$",
"ascii": "^[a-zA-Z0-9]+$",
"ascii_identifier": "^[a-zA-Z0-9\\-\\.\\_]+$",
"ascii_sentence": "^[a-zA-Z0-9 \\,\\.]+$",
}
)
// ExecutionRequest is a request to execute an action. It's passed to an
// Executor. They're created from the grpcapi.
type ExecutionRequest struct {
ActionName string
Arguments map[string]string
Tags []string
action *config.Action
Cfg *config.Config
AuthenticatedUser *acl.AuthenticatedUser
logEntry *InternalLogEntry
finalParsedCommand string
}
// InternalLogEntry objects are created by an Executor, and represent the final
// state of execution (even if the command is not executed). It's designed to be
@@ -34,6 +35,7 @@ type InternalLogEntry struct {
Stderr string
TimedOut bool
ExitCode int32
Tags []string
/*
The following two properties are obviously on Action normally, but it's useful
@@ -44,71 +46,14 @@ type InternalLogEntry struct {
ActionIcon string
}
// ExecutionRequest is a request to execute an action. It's passed to an
// Executor. They're created from the grpcapi.
type ExecutionRequest struct {
ActionName string
Arguments map[string]string
action *config.Action
Cfg *config.Config
User *acl.User
logEntry *InternalLogEntry
finalParsedCommand string
}
type executorStep interface {
Exec(*ExecutionRequest) bool
}
type executorStepFunc func(*ExecutionRequest) bool
// Executor represents a helper class for executing commands. It's main method
// is ExecRequest
type Executor struct {
Logs []InternalLogEntry
chainOfCommand []executorStep
}
// DefaultExecutor returns an Executor, with a sensible "chain of command" for
// executing actions.
func DefaultExecutor() *Executor {
e := Executor{}
e.chainOfCommand = []executorStep{
stepFindAction{},
stepACLCheck{},
stepParseArgs{},
stepLogStart{},
stepExec{},
stepLogFinish{},
}
return &e
}
type stepFindAction struct{}
func (s stepFindAction) Exec(req *ExecutionRequest) bool {
actualAction := req.Cfg.FindAction(req.ActionName)
if actualAction == nil {
log.WithFields(log.Fields{
"actionName": req.ActionName,
}).Warnf("Action not found")
req.logEntry.Stderr = "Action not found"
return false
}
req.action = actualAction
req.logEntry.ActionIcon = actualAction.Icon
return true
}
type stepACLCheck struct{}
func (s stepACLCheck) Exec(req *ExecutionRequest) bool {
return acl.IsAllowedExec(req.Cfg, req.User, req.action)
chainOfCommand []executorStepFunc
}
// ExecRequest processes an ExecutionRequest
@@ -122,7 +67,7 @@ func (e *Executor) ExecRequest(req *ExecutionRequest) *pb.StartActionResponse {
}
for _, step := range e.chainOfCommand {
if !step.Exec(req) {
if !step(req) {
break
}
}
@@ -142,34 +87,46 @@ func (e *Executor) ExecRequest(req *ExecutionRequest) *pb.StartActionResponse {
}
}
type stepLogStart struct{}
// DefaultExecutor returns an Executor, with a sensible "chain of command" for
// executing actions.
func DefaultExecutor() *Executor {
e := Executor{}
e.chainOfCommand = []executorStepFunc{
stepFindAction,
stepACLCheck,
stepParseArgs,
stepLogStart,
stepExec,
stepLogFinish,
}
func (e stepLogStart) Exec(req *ExecutionRequest) bool {
log.WithFields(log.Fields{
"title": req.action.Title,
"timeout": req.action.Timeout,
}).Infof("Action starting")
return &e
}
func stepFindAction(req *ExecutionRequest) bool {
actualAction := req.Cfg.FindAction(req.ActionName)
if actualAction == nil {
log.WithFields(log.Fields{
"actionName": req.ActionName,
}).Warnf("Action not found")
req.logEntry.Stderr = "Action not found"
return false
}
req.action = actualAction
req.logEntry.ActionIcon = actualAction.Icon
return true
}
type stepLogFinish struct{}
func (e stepLogFinish) Exec(req *ExecutionRequest) bool {
log.WithFields(log.Fields{
"title": req.action.Title,
"stdout": req.logEntry.Stdout,
"stderr": req.logEntry.Stderr,
"timedOut": req.logEntry.TimedOut,
"exit": req.logEntry.ExitCode,
}).Infof("Action finished")
return true
func stepACLCheck(req *ExecutionRequest) bool {
return acl.IsAllowedExec(req.Cfg, req.AuthenticatedUser, req.action)
}
type stepParseArgs struct{}
func (e stepParseArgs) Exec(req *ExecutionRequest) bool {
func stepParseArgs(req *ExecutionRequest) bool {
var err error
req.finalParsedCommand, err = parseActionArguments(req.action.Shell, req.Arguments, req.action)
@@ -185,21 +142,48 @@ func (e stepParseArgs) Exec(req *ExecutionRequest) bool {
return true
}
type stepExec struct{}
func stepLogStart(req *ExecutionRequest) bool {
log.WithFields(log.Fields{
"title": req.action.Title,
"timeout": req.action.Timeout,
}).Infof("Action starting")
func (e stepExec) Exec(req *ExecutionRequest) bool {
return true
}
func stepLogFinish(req *ExecutionRequest) bool {
log.WithFields(log.Fields{
"title": req.action.Title,
"stdout": req.logEntry.Stdout,
"stderr": req.logEntry.Stderr,
"timedOut": req.logEntry.TimedOut,
"exit": req.logEntry.ExitCode,
}).Infof("Action finished")
return true
}
func wrapCommandInShell(ctx context.Context, finalParsedCommand string) *exec.Cmd {
if runtime.GOOS == "windows" {
return exec.CommandContext(ctx, "cmd", "/C", finalParsedCommand)
}
return exec.CommandContext(ctx, "sh", "-c", finalParsedCommand)
}
func stepExec(req *ExecutionRequest) bool {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.action.Timeout)*time.Second)
defer cancel()
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd := exec.CommandContext(ctx, "sh", "-c", req.finalParsedCommand)
cmd := wrapCommandInShell(ctx, req.finalParsedCommand)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
runerr := cmd.Run()
req.logEntry.ExitCode = int32(cmd.ProcessState.ExitCode())
req.logEntry.Stdout = stdout.String()
req.logEntry.Stderr = stderr.String()
@@ -212,91 +196,7 @@ func (e stepExec) Exec(req *ExecutionRequest) bool {
req.logEntry.TimedOut = true
}
req.logEntry.Tags = req.Tags
return true
}
func parseActionArguments(rawShellCommand string, values map[string]string, action *config.Action) (string, error) {
log.WithFields(log.Fields{
"cmd": rawShellCommand,
}).Infof("Before Parse Args")
r := regexp.MustCompile("{{ *?([a-z]+?) *?}}")
matches := r.FindAllStringSubmatch(rawShellCommand, -1)
for _, match := range matches {
argValue, argProvided := values[match[1]]
if !argProvided {
log.Infof("%v", values)
return "", errors.New("Required arg not provided: " + match[1])
}
err := typecheckActionArgument(match[1], argValue, action)
if err != nil {
return "", err
}
log.WithFields(log.Fields{
"name": match[1],
"value": argValue,
}).Debugf("Arg assigned")
rawShellCommand = strings.ReplaceAll(rawShellCommand, match[0], argValue)
}
log.WithFields(log.Fields{
"cmd": rawShellCommand,
}).Infof("After Parse Args")
return rawShellCommand, nil
}
func typecheckActionArgument(name string, value string, action *config.Action) error {
arg := action.FindArg(name)
if arg == nil {
return errors.New("Action arg not defined: " + name)
}
if len(arg.Choices) > 0 {
return typecheckChoice(value, arg)
}
return TypeSafetyCheck(name, value, arg.Type)
}
func typecheckChoice(value string, arg *config.ActionArgument) error {
for _, choice := range arg.Choices {
if value == choice.Value {
return nil
}
}
return errors.New("argument value is not one of the predefined choices")
}
// TypeSafetyCheck checks argument values match a specific type. The types are
// defined in typecheckRegex, and, you guessed it, uses regex to check for allowed
// characters.
func TypeSafetyCheck(name string, value string, typ string) error {
pattern, found := typecheckRegex[typ]
if !found {
return errors.New("argument type not implemented " + typ)
}
matches, _ := regexp.MatchString(pattern, value)
if !matches {
log.WithFields(log.Fields{
"name": name,
"type": typ,
"value": value,
}).Warn("Arg type check safety failure")
return errors.New("invalid argument, doesn't match " + typ)
}
return nil
}

View File

@@ -4,14 +4,10 @@ import (
"github.com/stretchr/testify/assert"
"testing"
acl "github.com/jamesread/OliveTin/internal/acl"
config "github.com/jamesread/OliveTin/internal/config"
acl "github.com/OliveTin/OliveTin/internal/acl"
config "github.com/OliveTin/OliveTin/internal/config"
)
func TestSanitizeUnsafe(t *testing.T) {
assert.Nil(t, TypeSafetyCheck("", "_zomg_ c:/ haxxor ' bobby tables && rm -rf ", "very_dangerous_raw_string"))
}
func testingExecutor() (*Executor, *config.Config) {
e := DefaultExecutor()
@@ -38,9 +34,9 @@ func TestCreateExecutorAndExec(t *testing.T) {
e, cfg := testingExecutor()
req := ExecutionRequest{
ActionName: "Do some tickles",
User: &acl.User{Username: "Mr Tickle"},
Cfg: cfg,
ActionName: "Do some tickles",
AuthenticatedUser: &acl.AuthenticatedUser{Username: "Mr Tickle"},
Cfg: cfg,
Arguments: map[string]string{
"person": "yourself",
},
@@ -68,3 +64,47 @@ func TestExecNonExistant(t *testing.T) {
assert.Equal(t, int32(-1337), req.logEntry.ExitCode, "Log entry is set to an internal error code")
assert.Equal(t, "", req.logEntry.ActionIcon, "Log entry icon wasnt found")
}
func TestArgumentNameCamelCase(t *testing.T) {
a1 := config.Action{
Title: "Do some tickles",
Shell: "echo 'Tickling {{ personName }}'",
Arguments: []config.ActionArgument{
{
Name: "personName",
Type: "ascii",
},
},
}
values := map[string]string{
"personName": "Fred",
}
out, err := parseActionArguments(a1.Shell, values, &a1)
assert.Equal(t, "echo 'Tickling Fred'", out)
assert.Nil(t, err)
}
func TestArgumentNameSnakeCase(t *testing.T) {
a1 := config.Action{
Title: "Do some tickles",
Shell: "echo 'Tickling {{ person_name }}'",
Arguments: []config.ActionArgument{
{
Name: "person_name",
Type: "ascii",
},
},
}
values := map[string]string{
"person_name": "Fred",
}
out, err := parseActionArguments(a1.Shell, values, &a1)
assert.Equal(t, "echo 'Tickling Fred'", out)
assert.Nil(t, err)
}

View File

@@ -2,23 +2,25 @@ package grpcapi
import (
ctx "context"
pb "github.com/jamesread/OliveTin/gen/grpc"
pb "github.com/OliveTin/OliveTin/gen/grpc"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"net"
acl "github.com/jamesread/OliveTin/internal/acl"
config "github.com/jamesread/OliveTin/internal/config"
executor "github.com/jamesread/OliveTin/internal/executor"
acl "github.com/OliveTin/OliveTin/internal/acl"
config "github.com/OliveTin/OliveTin/internal/config"
executor "github.com/OliveTin/OliveTin/internal/executor"
)
var (
cfg *config.Config
ex = executor.DefaultExecutor()
)
type oliveTinAPI struct {
pb.UnimplementedOliveTinApiServer
executor *executor.Executor
}
func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) (*pb.StartActionResponse, error) {
@@ -31,17 +33,17 @@ func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest)
}
execReq := executor.ExecutionRequest{
ActionName: req.ActionName,
Arguments: args,
User: acl.UserFromContext(ctx),
Cfg: cfg,
ActionName: req.ActionName,
Arguments: args,
AuthenticatedUser: acl.UserFromContext(ctx, cfg),
Cfg: cfg,
}
return ex.ExecRequest(&execReq), nil
return api.executor.ExecRequest(&execReq), nil
}
func (api *oliveTinAPI) GetDashboardComponents(ctx ctx.Context, req *pb.GetDashboardComponentsRequest) (*pb.GetDashboardComponentsResponse, error) {
user := acl.UserFromContext(ctx)
user := acl.UserFromContext(ctx, cfg)
res := actionsCfgToPb(cfg.Actions, user)
@@ -59,7 +61,7 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.Ge
// TODO Limit to 10 entries or something to prevent browser lag.
for _, logEntry := range ex.Logs {
for _, logEntry := range api.executor.Logs {
ret.Logs = append(ret.Logs, &pb.LogEntry{
ActionTitle: logEntry.ActionTitle,
ActionIcon: logEntry.ActionIcon,
@@ -68,6 +70,7 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.Ge
Stderr: logEntry.Stderr,
TimedOut: logEntry.TimedOut,
ExitCode: logEntry.ExitCode,
Tags: logEntry.Tags,
})
}
@@ -93,8 +96,20 @@ func (api *oliveTinAPI) ValidateArgumentType(ctx ctx.Context, req *pb.ValidateAr
}, nil
}
func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *pb.WhoAmIRequest) (*pb.WhoAmIResponse, error) {
user := acl.UserFromContext(ctx, cfg)
res := &pb.WhoAmIResponse{
AuthenticatedUser: user.Username,
}
log.Warnf("usergroup: %v", user.Usergroup)
return res, nil
}
// Start will start the GRPC API.
func Start(globalConfig *config.Config) {
func Start(globalConfig *config.Config, ex *executor.Executor) {
cfg = globalConfig
lis, err := net.Listen("tcp", cfg.ListenAddressGrpcActions)
@@ -104,7 +119,7 @@ func Start(globalConfig *config.Config) {
}
grpcServer := grpc.NewServer()
pb.RegisterOliveTinApiServer(grpcServer, newServer())
pb.RegisterOliveTinApiServer(grpcServer, newServer(ex))
err = grpcServer.Serve(lis)
@@ -113,7 +128,8 @@ func Start(globalConfig *config.Config) {
}
}
func newServer() *oliveTinAPI {
func newServer(ex *executor.Executor) *oliveTinAPI {
server := oliveTinAPI{}
server.executor = ex
return &server
}

View File

@@ -3,12 +3,12 @@ package grpcapi
import (
"crypto/md5"
"fmt"
pb "github.com/jamesread/OliveTin/gen/grpc"
acl "github.com/jamesread/OliveTin/internal/acl"
config "github.com/jamesread/OliveTin/internal/config"
pb "github.com/OliveTin/OliveTin/gen/grpc"
acl "github.com/OliveTin/OliveTin/internal/acl"
config "github.com/OliveTin/OliveTin/internal/config"
)
func actionsCfgToPb(cfgActions []config.Action, user *acl.User) *pb.GetDashboardComponentsResponse {
func actionsCfgToPb(cfgActions []config.Action, user *acl.AuthenticatedUser) *pb.GetDashboardComponentsResponse {
res := &pb.GetDashboardComponentsResponse{}
for _, action := range cfgActions {
@@ -23,7 +23,7 @@ func actionsCfgToPb(cfgActions []config.Action, user *acl.User) *pb.GetDashboard
return res
}
func actionCfgToPb(action config.Action, user *acl.User) *pb.Action {
func actionCfgToPb(action config.Action, user *acl.AuthenticatedUser) *pb.Action {
btn := pb.Action{
Id: fmt.Sprintf("%x", md5.Sum([]byte(action.Title))),
Title: action.Title,
@@ -36,6 +36,7 @@ func actionCfgToPb(action config.Action, user *acl.User) *pb.Action {
Name: cfgArg.Name,
Title: cfgArg.Title,
Type: cfgArg.Type,
Description: cfgArg.Description,
DefaultValue: cfgArg.Default,
Choices: buildChoices(cfgArg.Choices),
}

View File

@@ -12,8 +12,9 @@ import (
log "github.com/sirupsen/logrus"
pb "github.com/jamesread/OliveTin/gen/grpc"
config "github.com/jamesread/OliveTin/internal/config"
pb "github.com/OliveTin/OliveTin/gen/grpc"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/executor"
)
const bufSize = 1024 * 1024
@@ -21,9 +22,11 @@ const bufSize = 1024 * 1024
var lis *bufconn.Listener
func init() {
ex := executor.DefaultExecutor()
lis = bufconn.Listen(bufSize)
s := grpc.NewServer()
pb.RegisterOliveTinApiServer(s, newServer())
pb.RegisterOliveTinApiServer(s, newServer(ex))
go func() {
if err := s.Serve(lis); err != nil {

View File

@@ -1,16 +1,17 @@
package httpservers
import (
config "github.com/jamesread/OliveTin/internal/config"
config "github.com/OliveTin/OliveTin/internal/config"
)
// StartServers will start 3 HTTP servers. The WebUI, the Rest API, and a proxy
// for both of them.
func StartServers(cfg *config.Config) {
go startWebUIServer(cfg)
go startRestAPIServer(cfg)
if cfg.UseSingleHTTPFrontend {
StartSingleHTTPFrontend(cfg)
go StartSingleHTTPFrontend(cfg)
}
startRestAPIServer(cfg)
}

View File

@@ -5,20 +5,60 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/encoding/protojson"
"net/http"
gw "github.com/jamesread/OliveTin/gen/grpc"
gw "github.com/OliveTin/OliveTin/gen/grpc"
cors "github.com/jamesread/OliveTin/internal/cors"
config "github.com/jamesread/OliveTin/internal/config"
config "github.com/OliveTin/OliveTin/internal/config"
cors "github.com/OliveTin/OliveTin/internal/cors"
)
var (
cfg *config.Config
)
func parseHttpHeaderForAuth(req *http.Request) (string, string) {
username, ok := req.Header[cfg.AuthHttpHeaderUsername]
if !ok {
return "", ""
}
if cfg.AuthHttpHeaderUserGroup != "" {
usergroup, ok := req.Header[cfg.AuthHttpHeaderUserGroup]
if ok {
return username[0], usergroup[0]
}
}
return username[0], ""
}
func parseRequestMetadata(ctx context.Context, req *http.Request) metadata.MD {
username := ""
usergroup := ""
if cfg.AuthJwtCookieName != "" {
username, usergroup = parseJwtCookie(req)
}
if cfg.AuthHttpHeaderUsername != "" {
username, usergroup = parseHttpHeaderForAuth(req)
}
md := metadata.Pairs(
"username", username,
"usergroup", usergroup,
)
log.Debugf("jwt usable claims: %+v", md)
return md
}
func startRestAPIServer(globalConfig *config.Config) error {
cfg = globalConfig
@@ -32,6 +72,7 @@ func startRestAPIServer(globalConfig *config.Config) error {
// The JSONPb.EmitDefaults is necssary, so "empty" fields are returned in JSON.
mux := runtime.NewServeMux(
runtime.WithMetadata(parseRequestMetadata),
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
Marshaler: &runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{

View File

@@ -0,0 +1,67 @@
package httpservers
import (
"errors"
"fmt"
"github.com/golang-jwt/jwt/v4"
log "github.com/sirupsen/logrus"
"net/http"
)
func parseJwtToken(cookieValue string) (*jwt.Token, error) {
return jwt.Parse(cookieValue, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(cfg.AuthJwtSecret), nil
})
}
func getClaimsFromJwtToken(cookieValue string) (jwt.MapClaims, error) {
token, err := parseJwtToken(cookieValue)
if err != nil {
log.Errorf("jwt parse failure: %v", err)
return nil, errors.New("jwt parse failure")
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims, nil
} else {
return nil, errors.New("jwt token isn't valid")
}
}
func lookupClaimValueOrDefault(claims jwt.MapClaims, key string, def string) string {
if val, ok := claims[key]; ok {
return fmt.Sprintf("%s", val)
} else {
return def
}
}
func parseJwtCookie(request *http.Request) (string, string) {
cookie, err := request.Cookie(cfg.AuthJwtCookieName)
if err != nil {
log.Debugf("jwt cookie check %v name: %v", err, cfg.AuthJwtCookieName)
return "", ""
}
claims, err := getClaimsFromJwtToken(cookie.Value)
log.Debugf("jwt claims data: %+v", claims)
if err != nil {
log.Warnf("jwt claim error: %+v", err)
return "", ""
}
username := lookupClaimValueOrDefault(claims, cfg.AuthJwtClaimUsername, "")
usergroup := lookupClaimValueOrDefault(claims, cfg.AuthJwtClaimUserGroup, "")
return username, usergroup
}

View File

@@ -9,7 +9,7 @@ away, and several other issues.
*/
import (
config "github.com/jamesread/OliveTin/internal/config"
config "github.com/OliveTin/OliveTin/internal/config"
log "github.com/sirupsen/logrus"
"net/http"
"net/http/httputil"
@@ -32,12 +32,12 @@ func StartSingleHTTPFrontend(cfg *config.Config) {
mux := http.NewServeMux()
mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
log.Debugf("api req: %v", r.URL)
log.Debugf("api req: %q", r.URL)
apiProxy.ServeHTTP(w, r)
})
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Debugf("ui req: %v", r.URL)
log.Debugf("ui req: %q", r.URL)
webuiProxy.ServeHTTP(w, r)
})

View File

@@ -2,27 +2,31 @@ package httpservers
import (
"encoding/json"
// cors "github.com/jamesread/OliveTin/internal/cors"
// cors "github.com/OliveTin/OliveTin/internal/cors"
log "github.com/sirupsen/logrus"
"net/http"
"os"
config "github.com/jamesread/OliveTin/internal/config"
updatecheck "github.com/jamesread/OliveTin/internal/updatecheck"
config "github.com/OliveTin/OliveTin/internal/config"
updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck"
)
type webUISettings struct {
Rest string
ThemeName string
HideNavigation bool
ShowFooter bool
ShowNavigation bool
ShowNewVersions bool
AvailableVersion string
CurrentVersion string
ShowNewVersions bool
PageTitle string
}
func findWebuiDir() string {
directoriesToSearch := []string{
"./webui",
"/usr/share/OliveTin/webui/",
"/var/www/OliveTin/",
"/var/www/olivetin/",
"/etc/OliveTin/webui/",
}
@@ -43,19 +47,15 @@ func findWebuiDir() string {
}
func generateWebUISettings(w http.ResponseWriter, r *http.Request) {
restAddress := ""
if !cfg.UseSingleHTTPFrontend {
restAddress = cfg.ExternalRestAddress
}
jsonRet, _ := json.Marshal(webUISettings{
Rest: restAddress + "/api/",
Rest: cfg.ExternalRestAddress + "/api/",
ThemeName: cfg.ThemeName,
HideNavigation: cfg.HideNavigation,
ShowFooter: cfg.ShowFooter,
ShowNavigation: cfg.ShowNavigation,
ShowNewVersions: cfg.ShowNewVersions,
AvailableVersion: updatecheck.AvailableVersion,
CurrentVersion: updatecheck.CurrentVersion,
ShowNewVersions: cfg.ShowNewVersions,
PageTitle: cfg.PageTitle,
})
_, err := w.Write([]byte(jsonRet))

50
internal/oncron/cron.go Normal file
View File

@@ -0,0 +1,50 @@
package oncron
import (
"github.com/OliveTin/OliveTin/internal/acl"
"github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/executor"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus"
)
func Schedule(cfg *config.Config, ex *executor.Executor) {
scheduler := cron.New(cron.WithSeconds())
for _, action := range cfg.Actions {
for _, cronline := range action.ExecOnCron {
scheduleAction(cfg, scheduler, cronline, ex, action)
}
}
scheduler.Start()
}
func scheduleAction(cfg *config.Config, scheduler *cron.Cron, cronline string, ex *executor.Executor, action config.Action) {
log.WithFields(log.Fields{
"action": action.Title,
"cronline": cronline,
}).Infof("Scheduling Action for cron")
_, err := scheduler.AddFunc(cronline, func() {
req := &executor.ExecutionRequest{
ActionName: action.Title,
Cfg: cfg,
Tags: []string{"cron"},
AuthenticatedUser: &acl.AuthenticatedUser{
Username: "cron",
},
}
ex.ExecRequest(req)
})
if err != nil {
log.WithFields(log.Fields{
"action": action.Title,
"cronError": err,
}).Errorf("CRON schedule error")
return
}
}

View File

@@ -0,0 +1,32 @@
package onstartup
import (
"github.com/OliveTin/OliveTin/internal/acl"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/executor"
log "github.com/sirupsen/logrus"
)
func Execute(cfg *config.Config, ex *executor.Executor) {
user := &acl.AuthenticatedUser{
Username: "startup-user",
}
for _, action := range cfg.Actions {
if action.ExecOnStartup {
log.WithFields(log.Fields{
"action": action.Title,
}).Infof("Startup action")
req := &executor.ExecutionRequest{
ActionName: action.Title,
Arguments: nil,
Cfg: cfg,
Tags: []string{"startup"},
AuthenticatedUser: user,
}
ex.ExecRequest(req)
}
}
}

View File

@@ -3,14 +3,15 @@ package updatecheck
import (
"bytes"
"encoding/json"
"github.com/denisbrodbeck/machineid"
"github.com/go-co-op/gocron"
config "github.com/jamesread/OliveTin/internal/config"
"errors"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/google/uuid"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
"os"
"runtime"
"time"
)
type updateRequest struct {
@@ -18,7 +19,8 @@ type updateRequest struct {
CurrentCommit string
OS string
Arch string
MachineID string
InstallationID string
InContainer bool
}
// AvailableVersion is updated when checking with the update service.
@@ -27,20 +29,51 @@ var AvailableVersion = "none"
// CurrentVersion is set by the main cmd (which is in tern set as a compile constant)
var CurrentVersion = "?"
func machineID() string {
v, err := machineid.ProtectedID("OliveTin")
func installationID(filename string) string {
var content string
contentBytes, err := ioutil.ReadFile(filename)
if err != nil {
log.Warnf("Error getting machine ID: %v", err)
return "?"
fileHandle, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
log.Warnf("Could not read + create installation ID file: %v", err)
return "cant-create"
}
content = uuid.NewString()
fileHandle.WriteString(content)
fileHandle.Close()
} else {
content = string(contentBytes)
_, err := uuid.Parse(content)
if err != nil {
log.Errorf("Invalid installation ID, %v", err)
content = "invalid-installation-id"
}
}
return v
log.WithFields(log.Fields{
"content": content,
"from": filename,
}).Infof("Installation ID")
return content
}
func isInContainer() bool {
if _, err := os.Stat("/.dockerenv"); errors.Is(err, os.ErrNotExist) {
return false
}
return true
}
// StartUpdateChecker will start a job that runs periodically, checking
// for updates.
func StartUpdateChecker(currentVersion string, currentCommit string, cfg *config.Config) {
func StartUpdateChecker(currentVersion string, currentCommit string, cfg *config.Config, configDir string) {
CurrentVersion = currentVersion
if !cfg.CheckForUpdates {
@@ -53,16 +86,23 @@ func StartUpdateChecker(currentVersion string, currentCommit string, cfg *config
CurrentCommit: currentCommit,
OS: runtime.GOOS,
Arch: runtime.GOARCH,
MachineID: machineID(),
InstallationID: installationID(configDir + "/installation-id.txt"),
InContainer: isInContainer(),
}
s := gocron.NewScheduler(time.UTC)
s := cron.New(cron.WithSeconds())
s.Every(7).Days().Do(func() {
// Several values have been tried here.
// 1st: Every 24h - very spammy.
// 2nd: Every 7d - (168 hours - much more reasonable, but it checks in at the same time/day each week.
// Current: Every 100h is not so spammy, and has the advantage that the checkin time "shifts" hours.
s.AddFunc("@every 100h", func() {
actualCheckForUpdate(payload)
})
s.StartAsync()
go actualCheckForUpdate(payload) // On startup
go s.Start()
}
func doRequest(jsonUpdateRequest []byte) string {
@@ -92,6 +132,8 @@ func doRequest(jsonUpdateRequest []byte) string {
func actualCheckForUpdate(payload updateRequest) {
jsonUpdateRequest, err := json.Marshal(payload)
log.Debugf("Update request payload: %+v", payload)
if err != nil {
log.Errorf("Update check failed %v", err)
return

View File

@@ -1,3 +1,4 @@
//go:build tools
// +build tools
package tools

BIN
var/manpage/OliveTin.1.gz Normal file

Binary file not shown.

7
var/openrc/OliveTin Executable file
View File

@@ -0,0 +1,7 @@
#!/sbin/openrc-run
name=$RC_SVCNAME
description="OliveTin"
command="/usr/local/bin/OliveTin"
pidfile="/run/${RC_SVCNAME}.pid"
command_background=true

View File

@@ -0,0 +1,14 @@
FROM fedora
RUN dnf install -v go -y --exclude=iputils
RUN pwd
RUN ls -l
COPY go.mod /workspace/
COPY go.sum /workspace/
WORKDIR /workspace
RUN go install -v "github.com/bufbuild/buf/cmd/buf"
RUN go install -v "github.com/fzipp/gocyclo/cmd/gocyclo"
RUN go install -v "github.com/go-critic/go-critic/cmd/gocritic"
RUN go install -v "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway"
RUN go install -v "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
RUN go install -v "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
RUN go install -v "google.golang.org/protobuf/cmd/protoc-gen-go"

View File

@@ -16,7 +16,24 @@
<body>
<main title = "main content">
<fieldset id = "sectionSwitcher" title = "Sections">
<div id = "perma-widget" hidden>
<div id = "sidebar-toggle-wrapper">
<label for = "sidebar-toggler" id = "sidebar-toggler-button" title = "Toggle sidebar" tabindex = "0">&#9776;</label>
</div>
<h1 id = "page-title">OliveTin</h1>
</div>
<div id = "content-sidebar">
<input type = "checkbox" id = "sidebar-toggler" hidden checked />
<aside>
<ul>
<li>Foo</li>
<li>Bar</li>
</ul>
</aside>
</div>
<fieldset id = "section-switcher" title = "Sections">
<button id = "showActions">Actions</button>
<button id = "showLogs">Logs</button>
</fieldset>
@@ -35,7 +52,7 @@
</section>
<section id = "contentActions" title = "Actions" hidden >
<fieldset id = "rootGroup" title = "Dashboard of buttons">
<fieldset id = "root-group" title = "Dashboard of buttons">
</fieldset>
</section>
@@ -50,12 +67,12 @@
<a href = "https://docs.olivetin.app" target = "_new">Documentation</a> |
<a href = "https://github.com/OliveTin/OliveTin/issues/new/choose" target = "_new">Raise an issue on GitHub</a> |
<span id = "currentVersion">Version: ?</p>
<a id = "availableVersion" href = "http://olivetin.app" target = "_blank" hidden>?</a>
<a id = "available-version" href = "http://olivetin.app" target = "_blank" hidden>?</a>
</p>
</footer>
<template id = "tplArgumentForm">
<form class = "actionArguments">
<form class = "action-arguments">
<div class = "wrapper">
<div>
<span class = "icon" role = "icon"></span>
@@ -80,12 +97,12 @@
</template>
<template id = "tplLogRow">
<tr class = "logRow">
<tr class = "log-row">
<td class = "timestamp">?</td>
<td>
<span class = "icon" role = "icon"></span>
<span class = "content">?</span>
<details>
<summary>stdout</summary>
<pre class = "stdout">
@@ -100,8 +117,9 @@
</pre>
</details>
<div class = "tags"></div>
</td>
<td class = "exitCode">?</td>
<td class = "exit-code">?</td>
</tr>
</template>
@@ -117,9 +135,9 @@
const domErr = document.createElement('div')
domErr.classList.add('error')
domErr.innerHTML = '<h1>Error ' + friendlyType + '</h1><p>' + message + "</p><p><a href = 'http://docs.olivetin.app/troubleshooting.html' target = 'blank'/>OliveTin Documentation</a></p>"
domErr.innerHTML = '<h1>Error ' + friendlyType + '</h1><p>' + message + "</p><p><a href = 'http://docs.olivetin.app/err-" + type + ".html' target = 'blank'/>" + type + " error in OliveTin Documentation</a></p>"
document.getElementById('rootGroup').appendChild(domErr)
document.getElementById('root-group').appendChild(domErr)
}
</script>

View File

@@ -84,13 +84,13 @@ class ActionButton extends window.HTMLElement {
marshalLogsJsonToHtml({ logs: [json.logEntry] })
if (json.logEntry.timedOut) {
this.onActionResult('actionTimeout', 'Timed out')
this.onActionResult('action-timeout', 'Timed out')
} else if (json.logEntry.exitCode === -1337) {
this.onActionError('Error')
} else if (json.logEntry.exitCode !== 0) {
this.onActionResult('actionNonZeroExit', 'Exit code ' + json.logEntry.exitCode)
this.onActionResult('action-nonzero-exit', 'Exit code ' + json.logEntry.exitCode)
} else {
this.onActionResult('actionSuccess', 'Success!')
this.onActionResult('action-success', 'Success!')
}
}).catch(err => {
this.onActionError(err)
@@ -113,10 +113,10 @@ class ActionButton extends window.HTMLElement {
this.btn.disabled = false
this.isWaiting = false
this.updateDom()
this.btn.classList.add('actionFailed')
this.btn.classList.add('action-failed')
setTimeout(() => {
this.btn.classList.remove('actionFailed')
this.btn.classList.remove('action-failed')
}, 1000)
}
@@ -139,13 +139,13 @@ class ActionButton extends window.HTMLElement {
updateDom () {
if (this.temporaryStatusMessage != null) {
this.domTitle.innerText = this.temporaryStatusMessage
this.domTitle.classList.add('temporaryStatusMessage')
this.domTitle.classList.add('temporary-status-message')
this.isWaiting = false
this.disabled = false
setTimeout(() => {
this.temporaryStatusMessage = null
this.domTitle.classList.remove('temporaryStatusMessage')
this.domTitle.classList.remove('temporary-status-message')
this.updateDom()
}, 2000)
} else if (this.isWaiting) {

View File

@@ -1,7 +1,7 @@
class ArgumentForm extends window.HTMLElement {
setup (json, callback) {
this.setAttribute('class', 'actionArguments')
this.setAttribute('class', 'action-arguments')
this.constructTemplate()
this.domTitle.innerText = json.title
@@ -64,6 +64,7 @@ class ArgumentForm extends window.HTMLElement {
domFieldWrapper.appendChild(this.createDomLabel(arg))
domFieldWrapper.appendChild(this.createDomInput(arg))
domFieldWrapper.appendChild(this.createDomDescription(arg))
this.domArgs.appendChild(domFieldWrapper)
}
@@ -130,6 +131,14 @@ class ArgumentForm extends window.HTMLElement {
return domEl
}
createDomDescription (arg) {
const domArgumentDescription = document.createElement('span')
domArgumentDescription.classList.add('argument-description')
domArgumentDescription.innerText = arg.description
return domArgumentDescription
}
createSelectOption (choice) {
const domEl = document.createElement('option')

View File

@@ -10,7 +10,7 @@ export function marshalActionButtonsJsonToHtml (json) {
htmlButton = document.createElement('action-button')
htmlButton.constructFromJson(jsonButton)
document.getElementById('rootGroup').appendChild(htmlButton)
document.getElementById('root-group').appendChild(htmlButton)
} else {
htmlButton.updateFromJson(jsonButton)
htmlButton.updateDom()
@@ -55,7 +55,15 @@ export function marshalLogsJsonToHtml (json) {
row.querySelector('.icon').innerHTML = logEntry.actionIcon
row.querySelector('pre.stdout').innerText = logEntry.stdout
row.querySelector('pre.stderr').innerText = logEntry.stderr
row.querySelector('.exitCode').innerText = logTableExitCode
row.querySelector('.exit-code').innerText = logTableExitCode
for (const tag of logEntry.tags) {
const domTag = document.createElement('span')
domTag.classList.add('tag')
domTag.innerText = tag
row.querySelector('.tags').append(domTag)
}
document.querySelector('#logTableBody').prepend(row)
}

View File

@@ -58,11 +58,18 @@ function processWebuiSettingsJson (settings) {
document.querySelector('#currentVersion').innerText = 'Version: ' + settings.CurrentVersion
if (settings.ShowNewVersions && settings.AvailableVersion !== 'none') {
document.querySelector('#availableVersion').innerText = 'New Version Available: ' + settings.AvailableVersion
document.querySelector('#availableVersion').hidden = false
document.querySelector('#available-version').innerText = 'New Version Available: ' + settings.AvailableVersion
document.querySelector('#available-version').hidden = false
}
document.querySelector('#sectionSwitcher').hidden = settings.HideNavigation
document.querySelector('#section-switcher').hidden = !settings.ShowNavigation
document.querySelector('footer[title="footer"]').hidden = !settings.ShowFooter
if (settings.PageTitle) {
document.title = settings.PageTitle
const titleElem = document.querySelector('#page-title')
if (titleElem) titleElem.innerText = settings.PageTitle
}
}
function main () {

5743
webui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,13 +5,13 @@
"repository": "http://github.com/OliveTin/OliveTin",
"main": "main.js",
"devDependencies": {
"stylelint": "^13.13.0",
"stylelint-config-standard": "^22.0.0",
"eslint": "^7.25.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1"
"eslint-plugin-promise": "^4.3.1",
"stylelint": "^14.5.3",
"stylelint-config-standard": "^25.0.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"

View File

@@ -11,7 +11,7 @@ fieldset {
padding: 0;
}
fieldset#rootGroup {
fieldset#root-group {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
grid-template-rows: auto auto auto auto;
@@ -20,11 +20,79 @@ fieldset#rootGroup {
border: 0;
}
#sidebar-toggle-wrapper {
display: inline;
}
h1 {
display: inline;
padding-left: 1em;
font-size: small;
}
label#sidebar-toggler-button {
top: 1em;
left: 0.5em;
height: 2em;
width: 2em;
border-radius: 50%;
background-color: white;
text-align: center;
display: inline-grid;
place-items: center;
padding: 0;
box-shadow: 0 0 5px 0 #444;
color: #666;
}
label#sidebar-toggler-button:hover,
label#sidebar-toggler-button:focus {
color: black;
cursor: pointer;
}
aside {
position: absolute;
width: 180px;
height: 100%;
left: 0;
top: 0;
padding-top: 4em;
transition: 0.5s ease;
background-color: white;
border: 0 0 10px 0;
box-shadow: 0 0 10px 0 #444;
}
input:checked ~ aside {
left: -250px;
}
aside ul {
padding: 0;
margin: 0;
}
aside ul li {
list-style: none;
text-align: left;
padding-left: 1em;
padding-top: 0.5em;
padding-bottom: 0.5em;
border-bottom: 1px inset black;
}
aside ul li:hover {
color: black;
background-color: #efefef;
cursor: pointer;
}
table {
background-color: white;
border-collapse: collapse;
width: 100%;
box-shadow: 0 0 10px 0 #444;
box-shadow: 0 0 5px 0 #444;
}
th,
@@ -53,7 +121,7 @@ span[role="icon"] {
}
form span[role="icon"],
tr.logRow span[role="icon"] {
tr.log-row span[role="icon"] {
display: inline-block;
padding-right: 0.2em;
}
@@ -63,7 +131,7 @@ tr.logRow span[role="icon"] {
padding: 1em;
}
.title.temporaryStatusMessage {
.title.temporary-status-message {
color: gray;
}
@@ -117,13 +185,13 @@ input[type="submit"]:disabled {
cursor: not-allowed;
}
fieldset#sectionSwitcher {
fieldset#section-switcher {
border: 0;
text-align: right;
margin-bottom: 1em;
}
fieldset#sectionSwitcher button {
fieldset#section-switcher button {
padding: 1em;
color: black;
display: table-cell;
@@ -135,60 +203,60 @@ fieldset#sectionSwitcher button {
cursor: pointer;
}
fieldset#rootGroup action-button button {
fieldset#root-group action-button button {
width: 100%;
height: 100%;
}
fieldset#sectionSwitcher button:first-child {
fieldset#section-switcher button:first-child {
border-radius: 1em 0 0 1em;
}
fieldset#sectionSwitcher button:last-child {
fieldset#section-switcher button:last-child {
border-radius: 0 1em 1em 0;
}
button.activeSection {
button.active-section {
font-weight: bold;
}
/* Button animations */
.actionFailed {
animation: kfActionFailed 1s;
.action-failed {
animation: kf-action-failed 1s;
}
@keyframes kfActionFailed {
@keyframes kf-action-failed {
0% { background-color: black; }
20% { background-color: red; }
0% { background-color: inherit; }
}
.actionSuccess {
animation: kfActionSuccess 1s;
.action-success {
animation: kf-action-success 1s;
}
@keyframes kfActionSuccess {
@keyframes kf-action-success {
0% { background-color: black; }
20% { background-color: limegreen; }
0% { background-color: inherit; }
}
.actionNonZeroExit {
animation: kfActionNonZeroExit 1s;
.action-nonzero-exit {
animation: kf-action-nonzero-exit 1s;
}
@keyframes kfActionNonZeroExit {
@keyframes kf-action-nonzero-exit {
0% { background-color: black; }
20% { background-color: orange; }
0% { background-color: inherit; }
}
.actionTimeout {
animation: kfActionTimeout 1s;
.action-timeout {
animation: kf-action-timeout 1s;
}
@keyframes kfActionTimeout {
@keyframes kf-action-timeout {
0% { background-color: black; }
20% { background-color: cyan; }
0% { background-color: inherit; }
@@ -230,7 +298,7 @@ details[open] {
display: block;
}
form.actionArguments {
form.action-arguments {
position: absolute;
top: 0;
bottom: 0;
@@ -257,6 +325,15 @@ label {
padding-right: 1em;
}
#perma-widget {
position: absolute;
z-index: 2;
}
#perma-widget label {
display: inline;
}
input {
padding: 0.6em;
}
@@ -274,14 +351,18 @@ form input[type="submit"]:first-child {
margin-right: 1em;
}
button[name=cancel]:hover {
button[name="cancel"]:hover {
background-color: salmon;
}
input[name=start]:hover {
input[name="start"]:hover {
background-color: #aceaac;
}
span.argument-description {
margin-left: 1em;
}
form div.buttons {
text-align: right;
}
@@ -292,7 +373,7 @@ pre {
min-height: 1em;
}
td.exitCode {
td.exit-code {
text-align: center;
}
@@ -300,19 +381,25 @@ input.invalid {
background-color: salmon;
}
#availableVersion {
#available-version {
background-color: #aceaac;
padding: 0.2em;
border-radius: 1em;
}
span.tag {
background-color: lightgray;
border-radius: 0.6em;
padding: 0.2em;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #333;
color: white;
}
form.actionArguments {
form.action-arguments {
background-color: #333;
}