diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..4161931 --- /dev/null +++ b/.air.toml @@ -0,0 +1,44 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./OliveTin" + cmd = "go build -o OliveTin github.com/OliveTin/OliveTin/cmd/OliveTin" + delay = 1 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = true + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + time = false + +[misc] + clean_on_exit = false + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/.github/ISSUE_TEMPLATE/support_request.md b/.github/ISSUE_TEMPLATE/support_request.md index b0e48d5..02a6299 100644 --- a/.github/ISSUE_TEMPLATE/support_request.md +++ b/.github/ISSUE_TEMPLATE/support_request.md @@ -39,7 +39,7 @@ If possible, please copy and paste your OliveTin logs from when the error happen **Screenshot of WebDeveloper console logs** If you know how, and if you think it's relevant, a screenshot of the -WebDeveloper console from when you clicked a button is often really helpful. +WebDeveloper console from when you clicked a button is often really helpful. **Anything else?** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d7ba602..4d87839 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ First of all, thank you for considering to raise a pull request! Don’t be afraid to ask for advice before working on a contribution. If you’re thinking about a bigger change, especially that might affect the core working or architecture, it’s almost essential to talk and ask about what you’re planning might affect things. Some of the larger future plans may not be documented well so it’s difficult to understand how your change might affect the general direction and roadmap of this project without asking. -The preferred way to communicate is probably via Discord or GitHub issues. +The preferred way to communicate is probably via Discord or GitHub issues. Helpful information to understand the project can be found here: [CONTRIBUTING](https://github.com/OliveTin/OliveTin/blob/main/CONTRIBUTING.adoc) @@ -13,10 +13,10 @@ Helpful information to understand the project can be found here: [CONTRIBUTING]( # Checklist Please put a X in the boxes as evidence of reading through the checklist. -- [ ] I have forked the project, and raised this PR on a feature branch. +- [ ] 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. +- [ ] `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. diff --git a/.github/workflows/build-snapshot.yml b/.github/workflows/build-snapshot.yml index d58001d..0010827 100644 --- a/.github/workflows/build-snapshot.yml +++ b/.github/workflows/build-snapshot.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '>=1.18.0' + go-version: '^1.18.0' cache: true - name: grpc diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index dbb48bf..04cb053 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -19,9 +19,10 @@ jobs: uses: actions/checkout@v2 - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: '^1.16.0' + go-version: '^1.18.0' + cache: true - name: deps run: make grpc diff --git a/.gitignore b/.gitignore index 32883c0..a5f7f5d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ reports releases/ dist/ installation-id.txt +tmp/ diff --git a/.goreleaser.yml b/.goreleaser.yml index 4f75283..86e5b9a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -18,7 +18,7 @@ builds: goarm: - 5 # For old RPIs - - 6 + - 6 - 7 main: cmd/OliveTin/main.go @@ -62,10 +62,10 @@ changelog: - '^refactor:' archives: - - + - format: tar.gz - files: + files: - config.yaml - LICENSE - README.md @@ -225,15 +225,14 @@ release: ## 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 }}` - + ## Upgrade warnings, or breaking changes - - - No such issues between the last release and this version. + + - No such issues between the last release and this version. ## Useful links - [Which download do I need?](https://docs.olivetin.app/choose-package.html) - [Ask for help and chat with others users in the Discord community](https://discord.gg/jhYWWpNJ3v) - + Thanks for your interest in OliveTin! - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..fd16ba2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index ebd05e9..5b23b32 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -7,9 +7,9 @@ of multiple projects, your time and interest in contributing is most welcome. If you're not sure where to get started, raise an issue in the project. Ideas may be discussed, purely on their merits and issues. Our Code of Conduct -(CoC) is straightforward - it's important that contributors feel comfortable in -discussion throughout the whole process. This project respects the -link:https://www.kernel.org/doc/html/latest/process/code-of-conduct.html[Linux Kernel code of conduct]. +(CoC) is straightforward - it's important that contributors feel comfortable in +discussion throughout the whole process. This project respects the +link:https://www.kernel.org/doc/html/latest/process/code-of-conduct.html[Linux Kernel code of conduct]. == If you're not sure, ask! @@ -18,19 +18,19 @@ contribution. If you're thinking about a bigger change, especially that might affect the core working or architecture, it's almost essential to talk and ask about what you're planning might affect things. Some of the larger future plans may not be documented well so it's difficult to understand how your change might affect -the general direction and roadmap of this project without asking. +the general direction and roadmap of this project without asking. -The preferred way to communicate is probably via Discord or GitHub issues. +The preferred way to communicate is probably via Discord or GitHub issues. -=== Dev environment setup and clean build - Fedora +=== Dev environment setup and clean build - Fedora ``` -dnf install git go protobuf-compiler make -y +dnf install git go protobuf-compiler make -y git clone https://github.com/OliveTin/OliveTin.git cd OliveTin -# `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 +# `make grpc` will also run `make go-tools`, which installs "buf". This binary +# will be put in your GOPATH/bin/, which should be on your path. buf is used to # generate the protobuf / grpc stubs. make grpc make @@ -39,10 +39,10 @@ make === Getting started to contribute; -The project layout is reasonably straightforward; +The project layout is reasonably straightforward; * See the `Makefile` for common targets. This project was originally created on top of Fedora, but it should be usable on Debian/your faveourite distro with minor changes (if any). -* The API is defined in protobuf+grpc - you will need to `make grpc`. +* The API is defined in protobuf+grpc - you will need to `make grpc`. * The Go daemon is built from the `cmd` and `internal` directories mostly. * The webui is just a single page application with a bit of Javascript in the `webui` directory. This can happily be hosted on another webserver. diff --git a/Dockerfile b/Dockerfile index bd931f2..bb13114 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,16 +4,16 @@ LABEL org.opencontainers.image.source https://github.com/OliveTin/OliveTin LABEL org.opencontainers.image.title=OliveTin RUN mkdir -p /config /var/www/olivetin \ - && microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \ + && microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \ iputils \ openssh-clients \ shadow-utils \ docker \ && microdnf clean all -RUN useradd --system --create-home olivetin -u 1000 +RUN useradd --system --create-home olivetin -u 1000 -EXPOSE 1337/tcp +EXPOSE 1337/tcp VOLUME /config diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index e3361fe..089b221 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -5,14 +5,14 @@ LABEL org.opencontainers.image.title=OliveTin RUN mkdir -p /config /var/www/olivetin \ && \ - microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \ + microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \ iputils \ shadow-utils \ - openssh-clients + openssh-clients -RUN useradd --system --create-home olivetin -u 1000 +RUN useradd --system --create-home olivetin -u 1000 -EXPOSE 1337/tcp +EXPOSE 1337/tcp VOLUME /config diff --git a/Dockerfile.armv7 b/Dockerfile.armv7 index c7e9bab..ae004e7 100644 --- a/Dockerfile.armv7 +++ b/Dockerfile.armv7 @@ -5,14 +5,14 @@ LABEL org.opencontainers.image.title=OliveTin RUN mkdir -p /config /var/www/olivetin \ && \ - microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \ + microdnf install -y --nodocs --noplugins --setopt=keepcache=0 --setopt=install_weak_deps=0 \ iputils \ - shadow-utils \ - openssh-clients + shadow-utils \ + openssh-clients -RUN useradd --system --create-home olivetin -u 1000 +RUN useradd --system --create-home olivetin -u 1000 -EXPOSE 1337/tcp +EXPOSE 1337/tcp VOLUME /config diff --git a/Jenkinsfile b/Jenkinsfile index ff5ffe9..f39f6a2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,7 +14,7 @@ pipeline { sh 'make go-tools' } } - + stage('Compile') { steps { withEnv(["PATH+GO=/root/go/bin/"]) { @@ -25,9 +25,9 @@ pipeline { } } } - + stage ('Post-Compile') { - parallel { + parallel { stage('Codestyle') { steps { withEnv(["PATH+GO=/root/go/bin/"]) { @@ -45,6 +45,6 @@ pipeline { } } } - + } } diff --git a/Makefile b/Makefile index 5486db0..107dade 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ compile: daemon-compile-x64-lin -daemon-compile-armhf: +daemon-compile-armhf: GOARCH=arm GOARM=6 go build -o OliveTin.armhf github.com/OliveTin/OliveTin/cmd/OliveTin -daemon-compile-x64-lin: +daemon-compile-x64-lin: GOOS=linux go build -o OliveTin github.com/OliveTin/OliveTin/cmd/OliveTin daemon-compile-x64-win: @@ -14,7 +14,7 @@ daemon-compile: daemon-compile-armhf daemon-compile-x64-lin daemon-compile-x64-w daemon-codestyle: go fmt ./... go vet ./... - gocyclo -over 4 cmd internal + gocyclo -over 4 cmd internal gocritic check ./... daemon-unittests: @@ -24,7 +24,7 @@ daemon-unittests: githooks: cp -v .githooks/* .git/hooks/ - + go-tools: go install "github.com/bufbuild/buf/cmd/buf" go install "github.com/fzipp/gocyclo/cmd/gocyclo" @@ -37,7 +37,7 @@ go-tools: grpc: go-tools buf generate -dist: protoc +dist: protoc protoc: protoc --go_out=. --go-grpc_out=. --grpc-gateway_out=. -I .:/usr/include/ OliveTin.proto @@ -54,7 +54,7 @@ podman-container: integration-tests-docker-image: docker rm -f olivetin && docker rmi -f olivetin docker build -t olivetin:latest . - docker create --name olivetin -p 1337:1337 -v `pwd`/integration-tests/configs/:/config/ olivetin + docker create --name olivetin -p 1337:1337 -v `pwd`/integration-tests/configs/:/config/ olivetin devrun: compile killall OliveTin || true @@ -70,4 +70,4 @@ webui-codestyle: clean: rm -rf dist OliveTin OliveTin.armhf OliveTin.exe reports gen -.PHONY: grpc +.PHONY: grpc diff --git a/OliveTin.proto b/OliveTin.proto index 38fa1ab..f320ebe 100644 --- a/OliveTin.proto +++ b/OliveTin.proto @@ -8,16 +8,16 @@ message Action { string id = 1; string title = 2; string icon = 3; - bool canExec = 4; - + bool can_exec = 4; repeated ActionArgument arguments = 5; + bool popup_on_start = 6; } message ActionArgument { string name = 1; - string title = 2; + string title = 2; string type = 3; - string defaultValue = 4; + string default_value = 4; repeated ActionArgumentChoice choices = 5; @@ -44,9 +44,11 @@ message GetDashboardComponentsResponse { message GetDashboardComponentsRequest {} message StartActionRequest { - string actionName = 1; + string action_name = 1; repeated StartActionArgument arguments = 2; + + string uuid = 3; } message StartActionArgument { @@ -55,22 +57,28 @@ message StartActionArgument { } message StartActionResponse { - LogEntry logEntry = 1; + string execution_uuid = 2; } message GetLogsRequest{}; message LogEntry { - string datetime = 1; - string actionTitle = 2; + string datetime_started = 1; + string action_title = 2; string stdout = 3; string stderr = 4; - bool timedOut = 5; - int32 exitCode = 6; + bool timed_out = 5; + int32 exit_code = 6; string user = 7; - string userClass = 8; - string actionIcon = 9; + string user_class = 8; + string action_icon = 9; repeated string tags = 10; + string execution_uuid = 11; + string datetime_finished = 12; + string uuid = 13; + bool execution_started = 14; + bool execution_finished = 15; + bool blocked = 16; } message GetLogsResponse { @@ -87,10 +95,26 @@ message ValidateArgumentTypeResponse { string description = 2; } +message WatchExecutionRequest { + string execution_uuid = 1; +} + +message WatchExecutionUpdate { + string update = 1; +} + +message ExecutionStatusRequest { + string execution_uuid = 1; +} + +message ExecutionStatusResponse { + LogEntry log_entry = 1; +} + message WhoAmIRequest {} message WhoAmIResponse { - string authenticatedUser = 1; + string authenticated_user = 1; } message SosReportRequest {} @@ -99,7 +123,7 @@ message SosReportResponse { string alert = 1; } -service OliveTinApi { +service OliveTinApiService { rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) { option (google.api.http) = { get: "/api/GetDashboardComponents" @@ -113,6 +137,13 @@ service OliveTinApi { }; } + rpc ExecutionStatus(ExecutionStatusRequest) returns (ExecutionStatusResponse) { + option (google.api.http) = { + post: "/api/ExecutionStatus" + body: "*" + }; + } + rpc GetLogs(GetLogsRequest) returns (GetLogsResponse) { option (google.api.http) = { get: "/api/GetLogs" diff --git a/README.md b/README.md index ebf534e..36fd3ff 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ project logo -OliveTin gives **safe** and **simple** access to predefined shell commands from a web interface. +OliveTin gives **safe** and **simple** access to predefined shell commands from a web interface. [![Discord](https://img.shields.io/discord/846737624960860180?label=Discord%20Server)](https://discord.gg/jhYWWpNJ3v) [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/awesome-selfhosted/awesome-selfhosted#automation) @@ -11,7 +11,7 @@ OliveTin gives **safe** and **simple** access to predefined shell commands from [![Go Report Card](https://goreportcard.com/badge/github.com/Olivetin/OliveTin)](https://goreportcard.com/report/github.com/OliveTin/OliveTin) [![Build Snapshot](https://github.com/OliveTin/OliveTin/actions/workflows/build-snapshot.yml/badge.svg)](https://github.com/OliveTin/OliveTin/actions/workflows/build-snapshot.yml) -## Use cases +## Use cases **Safely** give access to commands, for less technical people; @@ -34,10 +34,10 @@ OliveTin gives **safe** and **simple** access to predefined shell commands from ## Features * **Responsive, touch-friendly UI** - great for tablets and mobile -* **Super simple config in YAML** - because if it's not YAML now-a-days, it's not "cloud native" :-) +* **Super simple config in YAML** - because if it's not YAML now-a-days, it's not "cloud native" :-) * **Dark mode** - for those of you that roll that way. -* **Accessible** - passes all the accessibility checks in Firefox, and issues with accessibility are taken seriously. -* **Container** - available for quickly testing and getting it up and running, great for the selfhosted community. +* **Accessible** - passes all the accessibility checks in Firefox, and issues with accessibility are taken seriously. +* **Container** - available for quickly testing and getting it up and running, great for the selfhosted community. * **Integrate with anything** - OliveTin just runs Linux shell commands, so theoretially you could integrate with a bunch of stuff just by using curl, ping, etc. However, writing your own shell scripts is a great way to extend OliveTin. * **Lightweight on resources** - uses only a few MB of RAM and barely any CPU. Written in Go, with a web interface written as a modern, responsive, Single Page App that uses the REST/gRPC API. * **Good amount of unit tests and style checks** - helps potential contributors be consistent, and helps with maintainability. @@ -48,17 +48,17 @@ Desktop web browser; ![Desktop screenshot](media/screenshotDesktop.png) -Desktop web browser (dark mode); +Desktop web browser (dark mode); ![Desktop screenshot](media/screenshotDesktopDark.png) -Mobile screen size (responsive layout); +Mobile screen size (responsive layout); ![Mobile screenshot](media/screenshotMobile.png) ## Documentation -All documentation can be found at http://docs.olivetin.app . This includes installation and usage guide, etc. +All documentation can be found at http://docs.olivetin.app . This includes installation and usage guide, etc. ### Quickstart reference for `config.yaml` @@ -75,19 +75,19 @@ Put this `config.yaml` in `/etc/OliveTin/` if you're running a standard service, ```yaml # Listen on all addresses available, port 1337 -listenAddressSingleHTTPFrontend: 0.0.0.0:1337 +listenAddressSingleHTTPFrontend: 0.0.0.0:1337 # Choose from INFO (default), WARN and DEBUG logLevel: "INFO" # Actions (buttons) to show up on the WebUI: -actions: - # Docs: https://docs.olivetin.app/action-container-control.html +actions: + # Docs: https://docs.olivetin.app/action-container-control.html - title: Restart Plex icon: restart shell: docker restart plex - - # This will send 1 ping + + # This will send 1 ping # Docs: https://docs.olivetin.app/action-ping.html - title: Ping host shell: ping {{ host }} -c {{ count }} @@ -102,7 +102,7 @@ actions: title: Count type: int default: 1 - + # Restart http on host "webserver1" # Docs: https://docs.olivetin.app/action-ssh.html - title: restart httpd @@ -111,4 +111,3 @@ actions: ``` A full example config can be found at in this repository - [config.yaml](https://github.com/OliveTin/OliveTin/blob/main/config.yaml). - diff --git a/SECURITY.md b/SECURITY.md index e852ab0..f0a4010 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported Versions -Currently, only the `main` branch is "supported". +Currently, only the `main` branch is "supported". | Version | Supported | | ------- | ------------------ | @@ -10,4 +10,4 @@ Currently, only the `main` branch is "supported". ## Reporting a Vulnerability -Please email `contact@jread.com` for responsible disclosure. Accepted issues will be made public once patched, and you will be given credit. +Please email `contact@jread.com` for responsible disclosure. Accepted issues will be made public once patched, and you will be given credit. diff --git a/buf.gen.yaml b/buf.gen.yaml index ae3bb91..c5b5b9b 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -17,4 +17,3 @@ plugins: # - name: openapiv2 # out: reports/openapiv2 - diff --git a/buf.yaml b/buf.yaml index ef2ec64..a8230a7 100644 --- a/buf.yaml +++ b/buf.yaml @@ -1,5 +1,5 @@ version: v1 -deps: +deps: - buf.build/googleapis/googleapis lint: use: diff --git a/cmd/OliveTin/main.go b/cmd/OliveTin/main.go index 04dfb17..c6ca646 100644 --- a/cmd/OliveTin/main.go +++ b/cmd/OliveTin/main.go @@ -11,6 +11,7 @@ import ( "github.com/OliveTin/OliveTin/internal/oncron" "github.com/OliveTin/OliveTin/internal/onstartup" updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck" + "github.com/OliveTin/OliveTin/internal/websocket" "github.com/OliveTin/OliveTin/internal/httpservers" @@ -110,6 +111,7 @@ func main() { log.Debugf("Config: %+v", cfg) executor := executor.DefaultExecutor() + executor.AddListener(websocket.ExecutionListener) go onstartup.Execute(cfg, executor) go oncron.Schedule(cfg, executor) diff --git a/config.yaml b/config.yaml index a7ac3f3..44a7c2b 100644 --- a/config.yaml +++ b/config.yaml @@ -1,25 +1,30 @@ -# There is a built-in micro proxy that will host the webui and REST API all on -# one port (this is called the "Single HTTP Frontend") and means you just need -# one open port in the container/firewalls/etc. +# There is a built-in micro proxy that will host the webui and REST API all on +# one port (this is called the "Single HTTP Frontend") and means you just need +# one open port in the container/firewalls/etc. # # Listen on all addresses available, port 1337 -listenAddressSingleHTTPFrontend: 0.0.0.0:1337 +listenAddressSingleHTTPFrontend: 0.0.0.0:1337 # Choose from INFO (default), WARN and DEBUG logLevel: "INFO" # Actions (buttons) to show up on the WebUI: -actions: +actions: # This will run a simple script that you create. - title: Run backup script shell: /opt/backupScript.sh + maxConcurrent: 1 icon: backup +- title: date + shell: date + # This will send 1 ping (-c 1) # Docs: https://docs.olivetin.app/action-ping.html - title: Ping host shell: ping {{ host }} -c {{ count }} icon: ping + timeout: 100 arguments: - name: host title: host @@ -32,15 +37,15 @@ actions: type: int default: 1 description: How many times to do you want to ping? - + # Restart lightdm on host "server1" # Docs: https://docs.olivetin.app/action-ping.html - title: restart httpd icon: restart shell: ssh root@server1 'service httpd restart' - # OliveTin can run long-running jobs like Ansible playbooks. - # + # OliveTin can run long-running jobs like Ansible playbooks. + # # For such jobs, you will need to install ansible-playbook on the host where # you are running OliveTin, or in the container. # @@ -51,7 +56,7 @@ actions: timeout: 120 # OliveTin can control containers - docker is just a command line app. - # + # # However, if you are running in a container you will need to do some setup, # see the docs below. # @@ -76,4 +81,3 @@ actions: shell: sleep 5 timeout: 5 icon: "😪" - diff --git a/go.mod b/go.mod index 08d384f..0a62723 100644 --- a/go.mod +++ b/go.mod @@ -3,41 +3,45 @@ module github.com/OliveTin/OliveTin go 1.18 require ( - github.com/bufbuild/buf v1.15.1 + github.com/bufbuild/buf v1.26.0 github.com/fsnotify/fsnotify v1.6.0 github.com/fzipp/gocyclo v0.6.0 - github.com/go-critic/go-critic v0.7.0 + github.com/go-critic/go-critic v0.8.2 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.3.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 + github.com/gorilla/websocket v1.4.1 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 github.com/robfig/cron/v3 v3.0.1 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.2 - golang.org/x/exp v0.0.0-20230307190834-24139beb5833 - google.golang.org/grpc v1.53.0 + github.com/stretchr/testify v1.8.4 + golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 + google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 + google.golang.org/grpc v1.57.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect - github.com/bufbuild/connect-go v1.5.2 // indirect - github.com/bufbuild/protocompile v0.5.1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/bufbuild/connect-go v1.10.0 // indirect + github.com/bufbuild/connect-opentelemetry-go v0.4.0 // indirect + github.com/bufbuild/protocompile v0.6.0 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cristalhq/acmd v0.11.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v23.0.1+incompatible // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v23.0.3+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/cli v24.0.5+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v24.0.5+incompatible // indirect + github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect - github.com/go-chi/chi/v5 v5.0.8 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-chi/chi/v5 v5.0.10 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect @@ -47,25 +51,24 @@ require ( github.com/go-toolsmith/pkgload v1.2.2 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-containerregistry v0.13.0 // indirect - github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect + github.com/google/go-containerregistry v0.16.1 // indirect + github.com/google/pprof v0.0.0-20230808223545-4887780b67fb // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 // indirect - github.com/klauspost/compress v1.16.0 // indirect - github.com/klauspost/pgzip v1.2.5 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -75,29 +78,33 @@ require ( github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/rs/cors v1.8.3 // indirect + github.com/rs/cors v1.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.6.1 // indirect + github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect - go.opentelemetry.io/otel v1.14.0 // indirect - go.opentelemetry.io/otel/sdk v1.14.0 // indirect - go.opentelemetry.io/otel/trace v1.14.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.10.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect - google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect + github.com/tetratelabs/wazero v1.4.0 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect + go.opentelemetry.io/otel v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel/sdk v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20230809150735-7b3493d9a819 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/tools v0.12.0 // indirect + google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index 3bd55b9..16728f3 100644 --- a/go.sum +++ b/go.sum @@ -40,15 +40,17 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/bufbuild/buf v1.15.1 h1:v7sK2uMEsGX4Z2hvu+xiMheH3C3AKBGfxPBgdUZYDQ8= -github.com/bufbuild/buf v1.15.1/go.mod h1:TQeGKam1QMfHy/xsSnnMpxN3JK5HBb6aNvZj4m52gkE= -github.com/bufbuild/connect-go v1.5.2 h1:G4EZd5gF1U1ZhhbVJXplbuUnfKpBZ5j5izqIwu2g2W8= -github.com/bufbuild/connect-go v1.5.2/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= -github.com/bufbuild/protocompile v0.5.1 h1:mixz5lJX4Hiz4FpqFREJHIXLfaLBntfaJv1h+/jS+Qg= -github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/bufbuild/buf v1.26.0 h1:rB8pErEkxdUNhVZ3+ClFEoJRaa+o2FjEecCWL2S3Qs4= +github.com/bufbuild/buf v1.26.0/go.mod h1:UMPncXMWgrmIM+0QpwTEwjNr2SA0z2YIVZZsmNflvB4= +github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg= +github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= +github.com/bufbuild/connect-opentelemetry-go v0.4.0 h1:6JAn10SNqlQ/URhvRNGrIlczKw1wEXknBUUtmWqOiak= +github.com/bufbuild/connect-opentelemetry-go v0.4.0/go.mod h1:nwPXYoDOoc2DGyKE/6pT1Q9MPSi2Et2e6BieMD0l6WU= +github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY= +github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -57,7 +59,8 @@ 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/containerd/stargz-snapshotter/estargz v0.12.1 h1:+7nYmHJb0tEkcRaAW+MHqoKaJYZmkikupxCqVtmPuY0= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= @@ -66,14 +69,14 @@ github.com/cristalhq/acmd v0.11.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgB github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= -github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= -github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc= +github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= +github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -91,16 +94,16 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= -github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-critic/go-critic v0.7.0 h1:tqbKzB8pqi0NsRZ+1pyU4aweAF7A7QN0Pi4Q02+rYnQ= -github.com/go-critic/go-critic v0.7.0/go.mod h1:moYzd7GdVXE2C2hYTwd7h0CPcqlUeclsyBRwMa38v64= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-critic/go-critic v0.8.2 h1:mekhZ9jw5NBEj3I8o/EywXw5zBfGAJuMo4VVVjtxF80= +github.com/go-critic/go-critic v0.8.2/go.mod h1:nZPlrtVfOuLOe8GpvWTfcMzfkG0QVZWAziAeXpivfQo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= @@ -122,7 +125,6 @@ github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJ github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -130,8 +132,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -173,8 +175,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-containerregistry v0.13.0 h1:y1C7Z3e149OJbOPDBxLYR8ITPz8dTKqQwjErKVHJC8k= -github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= +github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= 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= @@ -189,8 +191,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= -github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= -github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230808223545-4887780b67fb h1:oqpb3Cwpc7EOml5PVGMYbSGmwNui2R7i8IW83gs4W0c= +github.com/google/pprof v0.0.0-20230808223545-4887780b67fb/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -198,8 +200,10 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= 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= @@ -207,7 +211,6 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 h1:2uT3aivO7NVpUPGcQX7RbHijHMyWix/yCnIrCWc+5co= @@ -217,10 +220,10 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= -github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -233,15 +236,15 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -266,18 +269,18 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= +github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 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= @@ -294,11 +297,14 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= +github.com/tetratelabs/wazero v1.4.0 h1:9/MirYvmkJ/zSUOygKY/ia3t+e+RqIZXKbylIby1WYk= +github.com/tetratelabs/wazero v1.4.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= 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= @@ -309,19 +315,22 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= -go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= +go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= +go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= +go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= +go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= +go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= +go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= 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= @@ -329,8 +338,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= 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= @@ -341,12 +350,12 @@ 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-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s= -golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb h1:WGs/bGIWYyAY5PVgGGMXqGGCxSJz4fpoUExb/vgqNCU= -golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230809150735-7b3493d9a819 h1:qdPQGUfaPzFgEbhQCulaXk+s0ETcox/vQd+f9YCIuxY= +golang.org/x/exp/typeparams v0.0.0-20230809150735-7b3493d9a819/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -370,8 +379,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -403,8 +412,8 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= 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= @@ -424,8 +433,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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -465,19 +474,19 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -531,8 +540,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= 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= @@ -599,8 +608,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 h1:znp6mq/drrY+6khTAlJUDNFFcDGV2ENLYKpMq8SyCds= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvaragTn5NnkY6IiKk/XvHzEWepo71N0= +google.golang.org/genproto v0.0.0-20230807174057-1744710a1577/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1:xv8KoglAClYGkprUSmDTKaILtzfD8XzG9NYVXMprjKo= +google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= 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= @@ -617,8 +630,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -633,8 +646,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/integration-tests/Makefile b/integration-tests/Makefile index a001d2f..e7dbf2c 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -1,6 +1,6 @@ cypress: npm install ./cypressRun.sh "general" - ./cypressRun.sh "hiddenNav" + ./cypressRun.sh "hiddenNav" .PHONY: cypress container diff --git a/integration-tests/README.md b/integration-tests/README.md index f4ddc4b..491677f 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -1 +1 @@ -# OliveTin-integration-tests \ No newline at end of file +# OliveTin-integration-tests diff --git a/integration-tests/Vagrantfile b/integration-tests/Vagrantfile index 632281a..e8cf8e8 100644 --- a/integration-tests/Vagrantfile +++ b/integration-tests/Vagrantfile @@ -2,7 +2,7 @@ # (eg, snapshot builds on GitHub) -Vagrant.configure("2") do |config| +Vagrant.configure("2") do |config| config.vm.box = "generic/centos8" config.vm.provision "shell", inline: "mkdir /etc/OliveTin && chmod o+w /etc/OliveTin/", privileged: true config.vm.provision "file", source: "configs/config.general.yaml/.", destination: "/etc/OliveTin/config.yaml" diff --git a/integration-tests/configs/config.general.yaml b/integration-tests/configs/config.general.yaml index a3b0b0e..eb34858 100644 --- a/integration-tests/configs/config.general.yaml +++ b/integration-tests/configs/config.general.yaml @@ -1,17 +1,17 @@ # # Integration Test Config: General -# +# -listenAddressSingleHTTPFrontend: 0.0.0.0:1337 +listenAddressSingleHTTPFrontend: 0.0.0.0:1337 logLevel: "DEBUG" -checkForUpdates: false +checkForUpdates: false -actions: +actions: - title: Ping Google.com shell: ping google.com -c 1 icon: ping - + - title: restart lightdm icon: poop shell: ssh root@overseer 'service lightdm restart' @@ -32,4 +32,3 @@ actions: - title: Restart Plex icon: smile shell: docker restart plex - diff --git a/integration-tests/configs/config.hiddenFooter.yaml b/integration-tests/configs/config.hiddenFooter.yaml index 9565139..a2fc7fa 100644 --- a/integration-tests/configs/config.hiddenFooter.yaml +++ b/integration-tests/configs/config.hiddenFooter.yaml @@ -1,12 +1,12 @@ # # Integration Test Config: General -# +# showFooter: false -checkForUpdates: false +checkForUpdates: false # Actions (buttons) to show up on the WebUI: -actions: +actions: - title: Ping example.com shell: ping example.com -c 1 icon: ping diff --git a/integration-tests/configs/config.hiddenNav.yaml b/integration-tests/configs/config.hiddenNav.yaml index f3ec261..4f32e94 100644 --- a/integration-tests/configs/config.hiddenNav.yaml +++ b/integration-tests/configs/config.hiddenNav.yaml @@ -1,14 +1,14 @@ # # Integration Test Config: General -# +# -listenAddressSingleHTTPFrontend: 0.0.0.0:1337 +listenAddressSingleHTTPFrontend: 0.0.0.0:1337 showNavigation: false -checkForUpdates: false +checkForUpdates: false # Actions (buttons) to show up on the WebUI: -actions: +actions: - title: Ping example.com shell: ping example.com -c 1 icon: ping diff --git a/integration-tests/cypress/e2e/general/defaultHomepageRender.cy.js b/integration-tests/cypress/e2e/general/defaultHomepageRender.cy.js index 8c54410..f6c38d4 100644 --- a/integration-tests/cypress/e2e/general/defaultHomepageRender.cy.js +++ b/integration-tests/cypress/e2e/general/defaultHomepageRender.cy.js @@ -17,5 +17,3 @@ describe('Homepage rendering', () => { }) }) }); - - diff --git a/integration-tests/cypress/e2e/hiddenFooter/hiddenFooter.cy.js b/integration-tests/cypress/e2e/hiddenFooter/hiddenFooter.cy.js index faf5f52..c19965f 100644 --- a/integration-tests/cypress/e2e/hiddenFooter/hiddenFooter.cy.js +++ b/integration-tests/cypress/e2e/hiddenFooter/hiddenFooter.cy.js @@ -10,5 +10,3 @@ describe('Hidden Footer', () => { }) }) }); - - diff --git a/integration-tests/cypress/e2e/hiddenNav/hiddenNav.cy.js b/integration-tests/cypress/e2e/hiddenNav/hiddenNav.cy.js index 387bf20..abb6602 100644 --- a/integration-tests/cypress/e2e/hiddenNav/hiddenNav.cy.js +++ b/integration-tests/cypress/e2e/hiddenNav/hiddenNav.cy.js @@ -14,5 +14,3 @@ describe('Hidden Nav', () => { }) }) }); - - diff --git a/integration-tests/cypress/support/commands.js b/integration-tests/cypress/support/commands.js index 72b085b..119ab03 100644 --- a/integration-tests/cypress/support/commands.js +++ b/integration-tests/cypress/support/commands.js @@ -23,4 +23,3 @@ // // -- This will overwrite an existing command -- // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) - diff --git a/integration-tests/cypressRun.sh b/integration-tests/cypressRun.sh index 9732a15..da959c1 100755 --- a/integration-tests/cypressRun.sh +++ b/integration-tests/cypressRun.sh @@ -8,4 +8,3 @@ cp -f ./configs/config.$1.yaml ./configs/config.yaml docker start olivetin NO_COLOR=1 ./node_modules/.bin/cypress run --headless -s cypress/integration/$1/* || true docker kill olivetin - diff --git a/integration-tests/package-lock.json b/integration-tests/package-lock.json index e35a842..c30ef21 100644 --- a/integration-tests/package-lock.json +++ b/integration-tests/package-lock.json @@ -26,7 +26,10 @@ "version": "2.88.12", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -345,7 +348,10 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -858,6 +864,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -944,6 +969,17 @@ "node": ">= 0.4.0" } }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -957,7 +993,10 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "engines": { "node": ">= 0.4" }, @@ -969,7 +1008,10 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "engines": { "node": ">= 0.4" }, @@ -1391,7 +1433,10 @@ "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1510,8 +1555,12 @@ "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", +<<<<<<< HEAD "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true +======= + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f }, "node_modules/pump": { "version": "3.0.0", @@ -1527,7 +1576,10 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "engines": { "node": ">=6" } @@ -1536,7 +1588,10 @@ "version": "6.10.4", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "dependencies": { "side-channel": "^1.0.4" }, @@ -1547,11 +1602,32 @@ "url": "https://github.com/sponsors/ljharb" } }, +<<<<<<< HEAD "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true +======= + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/ramda": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==" +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f }, "node_modules/request-progress": { "version": "3.0.0", @@ -1565,8 +1641,12 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", +<<<<<<< HEAD "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true +======= + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f }, "node_modules/restore-cursor": { "version": "3.1.0", @@ -1677,7 +1757,10 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -1810,7 +1893,10 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -1825,7 +1911,10 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "engines": { "node": ">= 4.0.0" } @@ -1894,6 +1983,23 @@ "requires-port": "^1.0.0" } }, +<<<<<<< HEAD +======= + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -1971,5 +2077,1272 @@ "fd-slicer": "~1.1.0" } } +<<<<<<< HEAD +======= + }, + "dependencies": { + "@cypress/request": { + "version": "2.88.12", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", + "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "~6.10.3", + "safe-buffer": "^5.1.2", + "tough-cookie": "^4.1.3", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + } + }, + "@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "requires": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz", + "integrity": "sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A==" + }, + "@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" + }, + "@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==" + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=" + }, + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-table3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "requires": { + "colors": "1.4.0", + "string-width": "^4.2.0" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "optional": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "cypress": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.7.0.tgz", + "integrity": "sha512-b1bMC3VQydC6sXzBMFnSqcvwc9dTZMgcaOzT0vpSD+Gq1yFc+72JDWi55sfUK5eIeNLAtWOGy1NNb6UlhMvB+Q==", + "requires": { + "@cypress/request": "^2.88.6", + "@cypress/xvfb": "^1.2.4", + "@types/node": "^14.14.31", + "@types/sinonjs__fake-timers": "^6.0.2", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.0", + "commander": "^5.1.0", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "eventemitter2": "^6.4.3", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.0", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.5", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "proxy-from-env": "1.0.0", + "ramda": "~0.27.1", + "request-progress": "^3.0.0", + "supports-color": "^8.1.1", + "tmp": "~0.2.1", + "untildify": "^4.0.0", + "url": "^0.11.0", + "yauzl": "^2.10.0" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dayjs": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", + "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "requires": { + "pify": "^2.2.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "requires": { + "async": "^3.2.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "requires": { + "ini": "2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "requires": { + "ci-info": "^3.2.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=" + }, + "listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=" + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=" + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "ramda": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==" + }, + "request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "requires": { + "throttleit": "^1.0.0" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "requires": { + "rimraf": "^3.0.0" + } + }, + "tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" + } + } + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } +>>>>>>> e8cb6619389e869655ac3bd0ef699c7ba321be1f } } diff --git a/internal/acl/acl.go b/internal/acl/acl.go index 5640fa2..8aa7222 100644 --- a/internal/acl/acl.go +++ b/internal/acl/acl.go @@ -75,7 +75,10 @@ func getMetdataKeyOrEmpty(md metadata.MD, key string) string { func UserFromContext(ctx context.Context, cfg *config.Config) *AuthenticatedUser { md, ok := metadata.FromIncomingContext(ctx) - ret := &AuthenticatedUser{} + ret := &AuthenticatedUser{ + Username: "guest", + Usergroup: "guest", + } if ok { ret.Username = getMetdataKeyOrEmpty(md, "username") @@ -87,7 +90,7 @@ func UserFromContext(ctx context.Context, cfg *config.Config) *AuthenticatedUser log.WithFields(log.Fields{ "username": ret.Username, "usergroup": ret.Usergroup, - }).Infof("UserFromContext") + }).Debugf("UserFromContext") return ret } diff --git a/internal/config/config.go b/internal/config/config.go index a2707d5..fdb6e98 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,7 +12,9 @@ type Action struct { Acls []string ExecOnStartup bool ExecOnCron []string + MaxConcurrent int Arguments []ActionArgument + PopupOnStart bool } // ActionArgument objects appear on Actions. @@ -73,9 +75,10 @@ type Config struct { ShowNavigation bool ShowNewVersions bool AuthJwtCookieName string - AuthJwtSecret string + AuthJwtSecret string // mutually exclusive with pub key config fields AuthJwtClaimUsername string AuthJwtClaimUserGroup string + AuthJwtPubKeyPath string // will read pub key from file on disk AuthHttpHeaderUsername string AuthHttpHeaderUserGroup string DefaultPermissions PermissionsList diff --git a/internal/config/sanitize.go b/internal/config/sanitize.go index 7f815de..8e127ad 100644 --- a/internal/config/sanitize.go +++ b/internal/config/sanitize.go @@ -30,6 +30,10 @@ func (action *Action) sanitize() { action.Icon = lookupHTMLIcon(action.Icon) + if action.MaxConcurrent < 1 { + action.MaxConcurrent = 1 + } + for idx := range action.Arguments { action.Arguments[idx].sanitize() } diff --git a/internal/executor/arguments.go b/internal/executor/arguments.go index da97ebd..a82a30d 100644 --- a/internal/executor/arguments.go +++ b/internal/executor/arguments.go @@ -22,8 +22,9 @@ var ( func parseActionArguments(rawShellCommand string, values map[string]string, action *config.Action) (string, error) { log.WithFields(log.Fields{ - "cmd": rawShellCommand, - }).Infof("Before Parse Args") + "actionTitle": action.Title, + "cmd": rawShellCommand, + }).Infof("Action parse args - Before") r := regexp.MustCompile("{{ *?([a-zA-Z0-9_]+?) *?}}") matches := r.FindAllStringSubmatch(rawShellCommand, -1) @@ -51,8 +52,9 @@ func parseActionArguments(rawShellCommand string, values map[string]string, acti } log.WithFields(log.Fields{ - "cmd": rawShellCommand, - }).Infof("After Parse Args") + "actionTitle": action.Title, + "cmd": rawShellCommand, + }).Infof("Action parse args - After") return rawShellCommand, nil } diff --git a/internal/executor/executor.go b/internal/executor/executor.go index 92a0ce3..ae6bbab 100644 --- a/internal/executor/executor.go +++ b/internal/executor/executor.go @@ -8,91 +8,77 @@ import ( "bytes" "context" + "fmt" + "io" "os/exec" "runtime" "time" ) +// Executor represents a helper class for executing commands. It's main method +// is ExecRequest +type Executor struct { + Logs map[string]*InternalLogEntry + + listeners []listener + + chainOfCommand []executorStepFunc +} + // 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 + UUID string Tags []string action *config.Action Cfg *config.Config AuthenticatedUser *acl.AuthenticatedUser logEntry *InternalLogEntry finalParsedCommand string + executor *Executor } // 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 // easily serializable. type InternalLogEntry struct { - Datetime string - Stdout string - Stderr string - TimedOut bool - ExitCode int32 - Tags []string + DatetimeStarted string + DatetimeFinished string + Stdout string + Stderr string + StdoutBuffer io.ReadCloser + StderrBuffer io.ReadCloser + TimedOut bool + Blocked bool + ExitCode int32 + Tags []string + ExecutionStarted bool + ExecutionFinished bool /* - The following two properties are obviously on Action normally, but it's useful + The following 3 properties are obviously on Action normally, but it's useful that logs are lightweight (so we don't need to have an action associated to logs, etc. Therefore, we duplicate those values here. */ ActionTitle string ActionIcon string + UUID string } 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 []executorStepFunc -} - -// ExecRequest processes an ExecutionRequest -func (e *Executor) ExecRequest(req *ExecutionRequest) *pb.StartActionResponse { - req.logEntry = &InternalLogEntry{ - Datetime: time.Now().Format("2006-01-02 15:04:05"), - ActionTitle: req.ActionName, - Stdout: "", - Stderr: "", - ExitCode: -1337, // If an Action is not actually executed, this is the default exit code. - } - - for _, step := range e.chainOfCommand { - if !step(req) { - break - } - } - - e.Logs = append(e.Logs, *req.logEntry) - - return &pb.StartActionResponse{ - LogEntry: &pb.LogEntry{ - ActionTitle: req.logEntry.ActionTitle, - ActionIcon: req.logEntry.ActionIcon, - Datetime: req.logEntry.Datetime, - Stderr: req.logEntry.Stderr, - Stdout: req.logEntry.Stdout, - TimedOut: req.logEntry.TimedOut, - ExitCode: req.logEntry.ExitCode, - }, - } -} - // DefaultExecutor returns an Executor, with a sensible "chain of command" for // executing actions. func DefaultExecutor() *Executor { e := Executor{} + e.Logs = make(map[string]*InternalLogEntry) + e.chainOfCommand = []executorStepFunc{ + stepLogRequested, stepFindAction, + stepConcurrencyCheck, stepACLCheck, stepParseArgs, stepLogStart, @@ -103,6 +89,88 @@ func DefaultExecutor() *Executor { return &e } +type listener interface { + OnExecutionStarted(actionName string) + OnExecutionFinished(logEntry *InternalLogEntry) +} + +func (e *Executor) AddListener(m listener) { + e.listeners = append(e.listeners, m) +} + +// ExecRequest processes an ExecutionRequest +func (e *Executor) ExecRequest(req *ExecutionRequest) *pb.StartActionResponse { + // req.UUID is now set by the client, so that they can track the request + // from start to finish. This means that a malicious client could send + // duplicate UUIDs (or just random strings), but this is the only way. + req.executor = e + req.logEntry = &InternalLogEntry{ + DatetimeStarted: time.Now().Format("2006-01-02 15:04:05"), + ActionTitle: req.ActionName, + UUID: req.UUID, + Stdout: "", + Stderr: "", + ExitCode: -1337, // If an Action is not actually executed, this is the default exit code. + ExecutionStarted: false, + ExecutionFinished: false, + } + + e.Logs[req.UUID] = req.logEntry + + for _, listener := range e.listeners { + listener.OnExecutionStarted(req.ActionName) + } + + go e.execChain(req) + + return &pb.StartActionResponse{ + ExecutionUuid: req.UUID, + } +} + +func (e *Executor) execChain(req *ExecutionRequest) { + for _, step := range e.chainOfCommand { + if !step(req) { + break + } + } + + req.logEntry.ExecutionFinished = true + + // This isn't a step, because we want to notify all listeners, irrespective + // of how many steps were actually executed. + notifyListeners(req) +} + +func getConcurrentCount(req *ExecutionRequest) int { + concurrentCount := 0 + + for _, log := range req.executor.Logs { + if log.ActionTitle == req.ActionName && !log.ExecutionFinished { + concurrentCount += 1 + } + } + + return concurrentCount +} + +func stepConcurrencyCheck(req *ExecutionRequest) bool { + concurrentCount := getConcurrentCount(req) + + // Note that the current execution is counted int the logs, so when checking we +1 + if concurrentCount >= (req.action.MaxConcurrent + 1) { + msg := fmt.Sprintf("Blocked from executing. This would mean this action is running %d times concurrently, but this action has maxExecutions set to %d.", concurrentCount, req.action.MaxConcurrent) + + log.Warnf(msg) + + req.logEntry.Stdout = msg + req.logEntry.Blocked = true + return false + } + + return true +} + func stepFindAction(req *ExecutionRequest) bool { actualAction := req.Cfg.FindAction(req.ActionName) @@ -142,10 +210,18 @@ func stepParseArgs(req *ExecutionRequest) bool { return true } +func stepLogRequested(req *ExecutionRequest) bool { + log.WithFields(log.Fields{ + "actionTitle": req.ActionName, + }).Infof("Action requested") + + return true +} + func stepLogStart(req *ExecutionRequest) bool { log.WithFields(log.Fields{ - "title": req.action.Title, - "timeout": req.action.Timeout, + "actionTitle": req.action.Title, + "timeout": req.action.Timeout, }).Infof("Action starting") return true @@ -153,16 +229,22 @@ func stepLogStart(req *ExecutionRequest) bool { 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, + "actionTitle": 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 notifyListeners(req *ExecutionRequest) { + for _, listener := range req.executor.listeners { + listener.OnExecutionFinished(req.logEntry) + } +} + func wrapCommandInShell(ctx context.Context, finalParsedCommand string) *exec.Cmd { if runtime.GOOS == "windows" { return exec.CommandContext(ctx, "cmd", "/C", finalParsedCommand) @@ -181,8 +263,17 @@ func stepExec(req *ExecutionRequest) bool { cmd := wrapCommandInShell(ctx, req.finalParsedCommand) cmd.Stdout = &stdout cmd.Stderr = &stderr + req.logEntry.StdoutBuffer, _ = cmd.StdoutPipe() + req.logEntry.StderrBuffer, _ = cmd.StderrPipe() - runerr := cmd.Run() + req.logEntry.ExecutionStarted = true + + runerr := cmd.Start() + + cmd.Wait() + + // req.logEntry.Stdout = req.logEntry.StdoutBuffer.String() + // req.logEntry.Stderr = req.logEntry.StderrBuffer.String() req.logEntry.ExitCode = int32(cmd.ProcessState.ExitCode()) req.logEntry.Stdout = stdout.String() @@ -197,6 +288,7 @@ func stepExec(req *ExecutionRequest) bool { } req.logEntry.Tags = req.Tags + req.logEntry.DatetimeFinished = time.Now().Format("2006-01-02 15:04:05") return true } diff --git a/internal/grpcapi/grpcApi.go b/internal/grpcapi/grpcApi.go index d6f1353..431333c 100644 --- a/internal/grpcapi/grpcApi.go +++ b/internal/grpcapi/grpcApi.go @@ -7,6 +7,7 @@ import ( "google.golang.org/grpc" "net" + "sort" acl "github.com/OliveTin/OliveTin/internal/acl" config "github.com/OliveTin/OliveTin/internal/config" @@ -19,7 +20,7 @@ var ( ) type oliveTinAPI struct { - pb.UnimplementedOliveTinApiServer + pb.UnimplementedOliveTinApiServiceServer executor *executor.Executor } @@ -35,6 +36,7 @@ func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) execReq := executor.ExecutionRequest{ ActionName: req.ActionName, + UUID: req.Uuid, Arguments: args, AuthenticatedUser: acl.UserFromContext(ctx, cfg), Cfg: cfg, @@ -43,6 +45,62 @@ func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) return api.executor.ExecRequest(&execReq), nil } +func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *pb.ExecutionStatusRequest) (*pb.ExecutionStatusResponse, error) { + res := &pb.ExecutionStatusResponse{} + + logEntry, ok := api.executor.Logs[req.ExecutionUuid] + + if !ok { + return res, nil + } + + res.LogEntry = &pb.LogEntry{ + ActionTitle: logEntry.ActionTitle, + ActionIcon: logEntry.ActionIcon, + DatetimeStarted: logEntry.DatetimeStarted, + DatetimeFinished: logEntry.DatetimeFinished, + Stdout: logEntry.Stdout, + Stderr: logEntry.Stderr, + TimedOut: logEntry.TimedOut, + Blocked: logEntry.Blocked, + ExitCode: logEntry.ExitCode, + Tags: logEntry.Tags, + ExecutionUuid: logEntry.UUID, + ExecutionStarted: logEntry.ExecutionStarted, + ExecutionFinished: logEntry.ExecutionFinished, + } + + return res, nil +} + +/** +func (api *oliveTinAPI) WatchExecution(req *pb.WatchExecutionRequest, srv pb.OliveTinApi_WatchExecutionServer) error { + log.Infof("Watch") + + if logEntry, ok := api.executor.Logs[req.ExecutionUuid]; !ok { + log.Errorf("Execution not found: %v", req.ExecutionUuid) + + return nil + } else { + if logEntry.ExecutionStarted { + for !logEntry.ExecutionCompleted { + tmp := make([]byte, 256) + + red, err := io.ReadAtLeast(logEntry.StdoutBuffer, tmp, 1) + + log.Infof("%v %v", red, err) + + srv.Send(&pb.WatchExecutionUpdate{ + Update: string(tmp), + }) + } + } + + return nil + } +} +*/ + func (api *oliveTinAPI) GetDashboardComponents(ctx ctx.Context, req *pb.GetDashboardComponentsRequest) (*pb.GetDashboardComponentsResponse, error) { user := acl.UserFromContext(ctx, cfg) @@ -62,19 +120,30 @@ 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 api.executor.Logs { + for uuid, logEntry := range api.executor.Logs { ret.Logs = append(ret.Logs, &pb.LogEntry{ - ActionTitle: logEntry.ActionTitle, - ActionIcon: logEntry.ActionIcon, - Datetime: logEntry.Datetime, - Stdout: logEntry.Stdout, - Stderr: logEntry.Stderr, - TimedOut: logEntry.TimedOut, - ExitCode: logEntry.ExitCode, - Tags: logEntry.Tags, + ActionTitle: logEntry.ActionTitle, + ActionIcon: logEntry.ActionIcon, + DatetimeStarted: logEntry.DatetimeStarted, + DatetimeFinished: logEntry.DatetimeFinished, + Stdout: logEntry.Stdout, + Stderr: logEntry.Stderr, + TimedOut: logEntry.TimedOut, + Blocked: logEntry.Blocked, + ExitCode: logEntry.ExitCode, + Tags: logEntry.Tags, + ExecutionUuid: uuid, + ExecutionStarted: logEntry.ExecutionStarted, + ExecutionFinished: logEntry.ExecutionFinished, }) } + sorter := func(i, j int) bool { + return ret.Logs[i].DatetimeStarted < ret.Logs[j].DatetimeStarted + } + + sort.Slice(ret.Logs, sorter) + return ret, nil } @@ -130,7 +199,7 @@ func Start(globalConfig *config.Config, ex *executor.Executor) { } grpcServer := grpc.NewServer() - pb.RegisterOliveTinApiServer(grpcServer, newServer(ex)) + pb.RegisterOliveTinApiServiceServer(grpcServer, newServer(ex)) err = grpcServer.Serve(lis) diff --git a/internal/grpcapi/grpcApiActions.go b/internal/grpcapi/grpcApiActions.go index e70a75f..5fb1f4b 100644 --- a/internal/grpcapi/grpcApiActions.go +++ b/internal/grpcapi/grpcApiActions.go @@ -25,10 +25,11 @@ func actionsCfgToPb(cfgActions []config.Action, user *acl.AuthenticatedUser) *pb 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, - Icon: action.Icon, - CanExec: acl.IsAllowedExec(cfg, user, &action), + Id: fmt.Sprintf("%x", md5.Sum([]byte(action.Title))), + Title: action.Title, + Icon: action.Icon, + CanExec: acl.IsAllowedExec(cfg, user, &action), + PopupOnStart: action.PopupOnStart, } for _, cfgArg := range action.Arguments { diff --git a/internal/grpcapi/grpcApi_test.go b/internal/grpcapi/grpcApi_test.go index 9c95e72..646db2b 100644 --- a/internal/grpcapi/grpcApi_test.go +++ b/internal/grpcapi/grpcApi_test.go @@ -26,7 +26,7 @@ func init() { lis = bufconn.Listen(bufSize) s := grpc.NewServer() - pb.RegisterOliveTinApiServer(s, newServer(ex)) + pb.RegisterOliveTinApiServiceServer(s, newServer(ex)) go func() { if err := s.Serve(lis); err != nil { @@ -39,7 +39,7 @@ func bufDialer(context.Context, string) (net.Conn, error) { return lis.Dial() } -func getNewTestServerAndClient(t *testing.T, injectedConfig *config.Config) (*grpc.ClientConn, pb.OliveTinApiClient) { +func getNewTestServerAndClient(t *testing.T, injectedConfig *config.Config) (*grpc.ClientConn, pb.OliveTinApiServiceClient) { cfg = injectedConfig ctx := context.Background() @@ -50,7 +50,7 @@ func getNewTestServerAndClient(t *testing.T, injectedConfig *config.Config) (*gr t.Fatalf("Failed to dial bufnet: %v", err) } - client := pb.NewOliveTinApiClient(conn) + client := pb.NewOliveTinApiServiceClient(conn) return conn, client } diff --git a/internal/httpservers/restapi.go b/internal/httpservers/restapi.go index 07d9327..bbc85be 100644 --- a/internal/httpservers/restapi.go +++ b/internal/httpservers/restapi.go @@ -59,6 +59,10 @@ func parseRequestMetadata(ctx context.Context, req *http.Request) metadata.MD { return md } +func SetGlobalRestConfig(config *config.Config) { + cfg = config +} + func startRestAPIServer(globalConfig *config.Config) error { cfg = globalConfig @@ -76,7 +80,7 @@ func startRestAPIServer(globalConfig *config.Config) error { runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{ Marshaler: &runtime.JSONPb{ MarshalOptions: protojson.MarshalOptions{ - UseProtoNames: true, + UseProtoNames: false, // eg: canExec for js instead of can_exec from protobuf EmitUnpopulated: true, }, }, @@ -84,7 +88,7 @@ func startRestAPIServer(globalConfig *config.Config) error { ) opts := []grpc.DialOption{grpc.WithInsecure()} - err := gw.RegisterOliveTinApiHandlerFromEndpoint(ctx, mux, cfg.ListenAddressGrpcActions, opts) + err := gw.RegisterOliveTinApiServiceHandlerFromEndpoint(ctx, mux, cfg.ListenAddressGrpcActions, opts) if err != nil { log.Errorf("Could not register REST API Handler %v", err) diff --git a/internal/httpservers/restapi_auth_jwt.go b/internal/httpservers/restapi_auth_jwt.go index 4441310..7d5d6f9 100644 --- a/internal/httpservers/restapi_auth_jwt.go +++ b/internal/httpservers/restapi_auth_jwt.go @@ -1,14 +1,58 @@ package httpservers import ( + "crypto/rsa" "errors" "fmt" "github.com/golang-jwt/jwt/v4" log "github.com/sirupsen/logrus" "net/http" + "os" ) -func parseJwtToken(cookieValue string) (*jwt.Token, error) { +var ( + pubKeyBytes []byte = nil + pubKey *rsa.PublicKey +) + +func readPublicKey() error { + if pubKeyBytes != nil { + return nil // Already read. + } + + pubKeyBytes, err := os.ReadFile(cfg.AuthJwtPubKeyPath) + if err != nil { + return fmt.Errorf("couldn't read public key from file %s", cfg.AuthJwtPubKeyPath) + } + + // Since the token is RSA (which we validated at the start of this function), the return type of this function actually has to be rsa.PublicKey! + pubKey, err = jwt.ParseRSAPublicKeyFromPEM(pubKeyBytes) + if err != nil { + return fmt.Errorf("error parsing public key object (from %s)", cfg.AuthJwtPubKeyPath) + } + + return nil +} + +func parseJwtTokenWithKey(cookieValue string) (*jwt.Token, error) { + err := readPublicKey() + + if err != nil { + return nil, err + } + + return jwt.Parse(cookieValue, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { + return nil, fmt.Errorf( + "expected token algorithm '%v' but got '%v'", + jwt.SigningMethodRS256.Name, + token.Header) + } + return pubKey, nil + }) +} + +func parseJwtTokenWithoutKey(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 { @@ -20,6 +64,14 @@ func parseJwtToken(cookieValue string) (*jwt.Token, error) { }) } +func parseJwtToken(cookieValue string) (*jwt.Token, error) { + if cfg.AuthJwtPubKeyPath != "" { // activate this path only if pub key is specified + return parseJwtTokenWithKey(cookieValue) + } else { + return parseJwtTokenWithoutKey(cookieValue) + } +} + func getClaimsFromJwtToken(cookieValue string) (jwt.MapClaims, error) { token, err := parseJwtToken(cookieValue) diff --git a/internal/httpservers/restapi_test.go b/internal/httpservers/restapi_test.go new file mode 100644 index 0000000..7c0263e --- /dev/null +++ b/internal/httpservers/restapi_test.go @@ -0,0 +1,125 @@ +package httpservers + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + config2 "github.com/OliveTin/OliveTin/internal/config" + "github.com/OliveTin/OliveTin/internal/cors" + "github.com/golang-jwt/jwt/v4" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/encoding/protojson" + "io" + "net" + "net/http" + "os" + "testing" + "time" +) + +func createKeys() (*rsa.PrivateKey, string) { + tmpFile, _ := os.CreateTemp(os.TempDir(), "olivetin-jwt-") + defer os.Remove(tmpFile.Name()) + + fmt.Println("Created File: " + tmpFile.Name()) + + privateKey, _ := rsa.GenerateKey(rand.Reader, 2048) + pubKey := &privateKey.PublicKey + // https://stackoverflow.com/questions/13555085/save-and-load-crypto-rsa-privatekey-to-and-from-the-disk + pkixPubKey, _ := x509.MarshalPKIXPublicKey(pubKey) + pubPem := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: pkixPubKey, + }, + ) + + if err := os.WriteFile(tmpFile.Name(), pubPem, 0755); err != nil { + fmt.Printf("error when dumping pubKey: %s \n", err) + } + + return privateKey, tmpFile.Name() +} + +func testBase(t *testing.T, expire int64, expectCode int) { + privateKey, publicKeyPath := createKeys() + + // default config + overrides + config := config2.DefaultConfig() + config.AuthJwtPubKeyPath = publicKeyPath + config.AuthJwtClaimUsername = "sub" + config.AuthJwtClaimUserGroup = "olivetinGroup" + config.AuthJwtCookieName = "authorization_token" + SetGlobalRestConfig(config) // ugly, setting global var, we should pass configs as params to modules... :/ + + token := jwt.New(jwt.SigningMethodRS256) + + claims := token.Claims.(jwt.MapClaims) + claims["nbf"] = time.Now().Unix() - 1000 + claims["exp"] = time.Now().Unix() + expire + claims["sub"] = "test" + claims["olivetinGroup"] = "test" + + tokenStr, _ := token.SignedString(privateKey) + + // init mux endpoint like in restapi.go (but using dummy response handler) + mux := runtime.NewServeMux( + runtime.WithMetadata(parseRequestMetadata), // i am guessing this is critical middleware for authorizing request cookie + runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{ + Marshaler: &runtime.JSONPb{ + MarshalOptions: protojson.MarshalOptions{ + UseProtoNames: true, + EmitUnpopulated: true, + }, + }, + }), + ) + mux.HandlePath("GET", "/", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) { + username, usergroup := parseJwtCookie(r) + if username == "" { + w.WriteHeader(403) + } + w.Write([]byte(fmt.Sprintf("username=%v, usergroup=%v", username, usergroup))) + }) + + // make server and attach handler + srv := &http.Server{Handler: cors.AllowCors(mux)} + lis, _ := net.Listen("tcp", ":1337") + + go func() { + if err := srv.Serve(lis); err != nil { + t.Errorf("couldn't start server: %v", err) + } + }() + + // make http client and send request to myself + client := &http.Client{} + req, _ := http.NewRequest("GET", "http://localhost:1337/", nil) + cookie := &http.Cookie{ + Name: "authorization_token", + Value: tokenStr, + MaxAge: 300, + } + req.AddCookie(cookie) + res, err := client.Do(req) + + if err != nil { + assert.Equal(t, expectCode, -1) + } else { + defer res.Body.Close() + assert.Equal(t, expectCode, res.StatusCode) + body, _ := io.ReadAll(res.Body) + fmt.Println(string(body)) + } +} + +func TestJWTSignatureVerificationSucceeds(t *testing.T) { + testBase(t, 1000, 200) +} + +func TestJWTSignatureVerificationFails(t *testing.T) { + testBase(t, -500, 403) +} diff --git a/internal/httpservers/singleFrontend.go b/internal/httpservers/singleFrontend.go index 6e4a926..8c76ce4 100644 --- a/internal/httpservers/singleFrontend.go +++ b/internal/httpservers/singleFrontend.go @@ -10,10 +10,12 @@ away, and several other issues. import ( config "github.com/OliveTin/OliveTin/internal/config" + "github.com/OliveTin/OliveTin/internal/websocket" log "github.com/sirupsen/logrus" "net/http" "net/http/httputil" "net/url" + "strings" ) // StartSingleHTTPFrontend will create a reverse proxy that proxies the API @@ -37,8 +39,12 @@ func StartSingleHTTPFrontend(cfg *config.Config) { }) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - log.Debugf("ui req: %q", r.URL) - webuiProxy.ServeHTTP(w, r) + if strings.Contains(r.Header.Get("Connection"), "Upgrade") { + websocket.HandleWebsocket(w, r) + } else { + log.Debugf("ui req: %q", r.URL) + webuiProxy.ServeHTTP(w, r) + } }) srv := &http.Server{ diff --git a/internal/httpservers/webuiServer_test.go b/internal/httpservers/webuiServer_test.go index 94ea73c..57aab5a 100644 --- a/internal/httpservers/webuiServer_test.go +++ b/internal/httpservers/webuiServer_test.go @@ -1,6 +1,7 @@ package httpservers import ( + config "github.com/OliveTin/OliveTin/internal/config" "github.com/stretchr/testify/assert" "os" "testing" @@ -9,6 +10,8 @@ import ( func TestGetWebuiDir(t *testing.T) { os.Chdir("../../") // go test sets the cwd to "httpservers" by default + cfg = config.DefaultConfig() + dir := findWebuiDir() assert.Equal(t, "./webui", dir, "Finding the webui dir") diff --git a/internal/websocket/websocket.go b/internal/websocket/websocket.go new file mode 100644 index 0000000..8a61287 --- /dev/null +++ b/internal/websocket/websocket.go @@ -0,0 +1,122 @@ +package websocket + +import ( + pb "github.com/OliveTin/OliveTin/gen/grpc" + "github.com/OliveTin/OliveTin/internal/executor" + ws "github.com/gorilla/websocket" + log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/encoding/protojson" + "net/http" +) + +var upgrader = ws.Upgrader{} + +type WebsocketClient struct { + conn *ws.Conn +} + +var clients []*WebsocketClient + +var marshalOptions = protojson.MarshalOptions{ + UseProtoNames: false, // eg: canExec for js instead of can_exec from protobuf + EmitUnpopulated: true, +} + +var ExecutionListener WebsocketExecutionListener + +type WebsocketExecutionListener struct{} + +func (WebsocketExecutionListener) OnExecutionStarted(title string) { + /* + broadcast(ExecutionStarted{ + Type: "ExecutionStarted", + Action: title, + }); + */ +} + +func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.InternalLogEntry) { + le := &pb.LogEntry{ + ActionTitle: logEntry.ActionTitle, + ActionIcon: logEntry.ActionIcon, + DatetimeStarted: logEntry.DatetimeStarted, + DatetimeFinished: logEntry.DatetimeFinished, + Stdout: logEntry.Stdout, + Stderr: logEntry.Stderr, + TimedOut: logEntry.TimedOut, + Blocked: logEntry.Blocked, + ExitCode: logEntry.ExitCode, + Tags: logEntry.Tags, + Uuid: logEntry.UUID, + ExecutionStarted: logEntry.ExecutionStarted, + ExecutionFinished: logEntry.ExecutionFinished, + } + + broadcast("ExecutionFinished", le) +} + +func broadcast(messageType string, pbmsg *pb.LogEntry) { + payload, err := marshalOptions.Marshal(pbmsg) + + // + // So, the websocket wants to encode messages using the same protomarshaller + // as the REST API - this gives consistency instead of using encoding/json + // and allows us to set specific marshalOptions. + // + // However, the protomarshaller will marshal the type, but the JavaScript at + // the other end has no idea what type this object is - as we're just sending + // it as JSON over the websocket. + // + // Therefore, we wrap the nicely marsheled bytes in a hacky JSON string + // literal and encode that string just with a byte array cast. + hackyMessageEnvelope := "{\"type\": \"" + messageType + "\", \"payload\": " + + hackyMessage := []byte{} + hackyMessage = append(hackyMessage, []byte(hackyMessageEnvelope)...) + hackyMessage = append(hackyMessage, payload...) + hackyMessage = append(hackyMessage, []byte("}")...) + // + + if err != nil { + log.Errorf("websocket marshal error: %v", err) + return + } + + for _, client := range clients { + client.conn.WriteMessage(1, hackyMessage) + } +} + +func (c *WebsocketClient) messageLoop() { + for { + mt, message, err := c.conn.ReadMessage() + + if err != nil { + log.Printf("err: %v", err) + break + } + + log.Infof("websocket recv: %s %d", message, mt) + } +} + +func HandleWebsocket(w http.ResponseWriter, r *http.Request) bool { + c, err := upgrader.Upgrade(w, r, nil) + + if err != nil { + log.Warnf("Websocket issue: %v", err) + return false + } + + // defer c.Close() + + wsclient := &WebsocketClient{ + conn: c, + } + + clients = append(clients, wsclient) + + go wsclient.messageLoop() + + return true +} diff --git a/var/initscript/OliveTin b/var/initscript/OliveTin index 4942037..b8b6779 100755 --- a/var/initscript/OliveTin +++ b/var/initscript/OliveTin @@ -48,7 +48,7 @@ stop() status() { PID=$(pidof OliveTin) - RETVAL=$? + RETVAL=$? if [ $RETVAL -eq 1 ] ; then echo "OliveTin is stopped" diff --git a/var/openrc/OliveTin b/var/openrc/OliveTin index 9d7f3d3..bf112ff 100755 --- a/var/openrc/OliveTin +++ b/var/openrc/OliveTin @@ -4,4 +4,4 @@ name=$RC_SVCNAME description="OliveTin" command="/usr/local/bin/OliveTin" pidfile="/run/${RC_SVCNAME}.pid" -command_background=true \ No newline at end of file +command_background=true diff --git a/webui/index.html b/webui/index.html index 12343ad..7eccdad 100644 --- a/webui/index.html +++ b/webui/index.html @@ -62,47 +62,96 @@ + +
+ + +

Log: + ? +

+
+

+ Started: unknown. + Finished: unknown +

+

+ Exit Code: unknown +

+

+ Status: unknown +

+ + +
+ stdout +
+					?
+				
+
+ +
+ stderr +
+					?
+				
+
+ +
+ +
+
+ + diff --git a/webui/js/ActionButton.js b/webui/js/ActionButton.js index cdc4421..68e706d 100644 --- a/webui/js/ActionButton.js +++ b/webui/js/ActionButton.js @@ -1,5 +1,5 @@ -import { marshalLogsJsonToHtml } from './marshaller.js' import './ArgumentForm.js' +import './ExecutionButton.js' class ActionButton extends window.HTMLElement { constructFromJson (json) { @@ -25,6 +25,7 @@ class ActionButton extends window.HTMLElement { }) document.body.appendChild(frm) + frm.querySelector('dialog').showModal() } else { this.startAction() } @@ -32,7 +33,8 @@ class ActionButton extends window.HTMLElement { this.updateFromJson(json) - this.updateDom() + this.domTitle.innerText = this.btn.title + this.domIcon.innerHTML = this.unicodeIcon this.setAttribute('id', 'actionButton_' + json.id) } @@ -52,20 +54,27 @@ class ActionButton extends window.HTMLElement { } startAction (actionArgs) { - this.btn.disabled = true - this.isWaiting = true - this.updateDom() + // this.btn.disabled = true + // this.isWaiting = true + // this.updateDom() this.btn.classList = [] // Removes old animation classes if (actionArgs === undefined) { actionArgs = [] } + // UUIDs are create client side, so that we can setup a "execution-button" + // to track the execution before we send the request to the server. const startActionArgs = { actionName: this.btn.title, - arguments: actionArgs + arguments: actionArgs, + uuid: window.crypto.randomUUID() } + const btnExecution = document.createElement('execution-button') + btnExecution.constructFromJson(startActionArgs.uuid) + this.querySelector('div.executions').appendChild(btnExecution) + window.fetch(this.actionCallUrl, { method: 'POST', headers: { @@ -80,45 +89,12 @@ class ActionButton extends window.HTMLElement { } } ).then((json) => { - marshalLogsJsonToHtml({ logs: [json.logEntry] }) - - if (json.logEntry.timedOut) { - this.onActionResult('action-timeout', 'Timed out') - } else if (json.logEntry.exitCode === -1337) { - this.onActionError('Error') - } else if (json.logEntry.exitCode !== 0) { - this.onActionResult('action-nonzero-exit', 'Exit code ' + json.logEntry.exitCode) - } else { - this.onActionResult('action-success', 'Success!') - } + // The button used to wait for the action to finish, but now it is fire & forget }).catch(err => { this.onActionError(err) }) } - onActionResult (cssClass, temporaryStatusMessage) { - this.btn.disabled = false - this.temporaryStatusMessage = '[ ' + temporaryStatusMessage + ' ]' - this.updateDom() - this.btn.classList.add(cssClass) - - setTimeout(() => { - this.btn.classList.remove(cssClass) - }, 1000) - } - - onActionError (err) { - console.error('callback error', err) - this.btn.disabled = false - this.isWaiting = false - this.updateDom() - this.btn.classList.add('action-failed') - - setTimeout(() => { - this.btn.classList.remove('action-failed') - }, 1000) - } - constructDomFromTemplate () { const tpl = document.getElementById('tplActionButton') const content = tpl.content.cloneNode(true) @@ -134,27 +110,6 @@ class ActionButton extends window.HTMLElement { this.domTitle = this.btn.querySelector('.title') this.domIcon = this.btn.querySelector('.icon') } - - updateDom () { - if (this.temporaryStatusMessage != null) { - this.domTitle.innerText = this.temporaryStatusMessage - this.domTitle.classList.add('temporary-status-message') - this.isWaiting = false - this.disabled = false - - setTimeout(() => { - this.temporaryStatusMessage = null - this.domTitle.classList.remove('temporary-status-message') - this.updateDom() - }, 2000) - } else if (this.isWaiting) { - this.domTitle.innerText = 'Waiting...' - } else { - this.domTitle.innerText = this.btn.title - } - - this.domIcon.innerHTML = this.unicodeIcon - } } window.customElements.define('action-button', ActionButton) diff --git a/webui/js/ExecutionButton.js b/webui/js/ExecutionButton.js new file mode 100644 index 0000000..a05aa3f --- /dev/null +++ b/webui/js/ExecutionButton.js @@ -0,0 +1,105 @@ +import { ExecutionDialog } from './ExecutionDialog.js' + +class ExecutionButton extends window.HTMLElement { + constructFromJson (json) { + this.executionUuid = json + + this.appendChild(document.createElement('button')) + this.isWaiting = true + + this.setAttribute('id', 'execution-' + json) + + this.btn = this.querySelector('button') + this.btn.innerText = 'Executing...' + this.btn.onclick = () => { + this.show() + } + } + + show () { + if (window.executionDialog === undefined) { + window.executionDialog = new ExecutionDialog() + } + + const executionStatusArgs = { + executionUuid: this.executionUuid + } + + window.executionDialog.constructFromJson(this.executionUuid) + window.executionDialog.show() + + window.fetch(window.restBaseUrl + 'ExecutionStatus', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(executionStatusArgs) + }).then((res) => { + if (res.ok) { + return res.json() + } else { + throw new Error(res.statusText) + } + } + ).then((json) => { + window.executionDialog.renderResult(json) + }).catch(err => { + window.executionDialog.renderError(err) + }) + } + + onFinished (LogEntry) { + if (LogEntry.timedOut) { + this.onActionResult('action-timeout', 'Timed out') + } else if (LogEntry.blocked) { + this.onActionResult('action-blocked', 'Blocked!') + } else if (LogEntry.exitCode !== 0) { + this.onActionResult('action-nonzero-exit', 'Exit code ' + LogEntry.exitCode) + } else { + this.onActionResult('action-success', 'Success!') + } + } + + onActionResult (cssClass, temporaryStatusMessage) { + this.temporaryStatusMessage = '[ ' + temporaryStatusMessage + ' ]' + this.updateDom() + this.btn.classList.add(cssClass) + + setTimeout(() => { + this.btn.classList.remove(cssClass) + }, 1000) + } + + onActionError (err) { + console.error('callback error', err) + this.btn.disabled = false + this.isWaiting = false + this.updateDom() + this.btn.classList.add('action-failed') + + setTimeout(() => { + this.btn.classList.remove('action-failed') + }, 1000) + } + + updateDom () { + if (this.temporaryStatusMessage != null) { + this.btn.innerText = this.temporaryStatusMessage + this.btn.classList.add('temporary-status-message') + this.isWaiting = false + this.disabled = false + + setTimeout(() => { + this.temporaryStatusMessage = null + this.btn.classList.remove('temporary-status-message') + this.updateDom() + }, 2000) + } else if (this.isWaiting) { + this.btn.innerText = 'Waiting...' + } else { + this.btn.innerText = 'Finished' + } + } +} + +window.customElements.define('execution-button', ExecutionButton) diff --git a/webui/js/ExecutionDialog.js b/webui/js/ExecutionDialog.js new file mode 100644 index 0000000..2e6399a --- /dev/null +++ b/webui/js/ExecutionDialog.js @@ -0,0 +1,66 @@ +// This ExecutionDialog is NOT a custom HTML element, but rather just picks up +// the element out of index.html and just re-uses that - as only +// one dialog can be shown at a time. +export class ExecutionDialog { + constructFromJson (json) { + this.executionUuid = json + + this.dlg = document.querySelector('dialog#executionResults') + + this.domIcon = this.dlg.querySelector('.icon') + this.domTitle = this.dlg.querySelector('.title') + this.domStdout = this.dlg.querySelector('.stdout') + this.domStderr = this.dlg.querySelector('.stderr') + this.domDatetimeStarted = this.dlg.querySelector('.datetimeStarted') + this.domDatetimeFinished = this.dlg.querySelector('.datetimeFinished') + this.domExitCode = this.dlg.querySelector('.exitCode') + this.domStatus = this.dlg.querySelector('.status') + } + + show () { + this.dlg.showModal() + } + + renderResult (res) { + this.executionUuid = res.logEntry.executionUuid + + if (res.logEntry.executionFinished) { + this.domStatus.innerText = 'Completed' + this.domDatetimeFinished.innerText = res.logEntry.datetimeFinished + + if (res.logEntry.blocked) { + this.domStatus.innerText = 'Blocked' + } + + if (res.logEntry.timedOut) { + this.domExitCode.innerText = 'Timed out' + this.domStatus.innerText = 'Timed out' + } else { + this.domExitCode.innerText = res.logEntry.exitCode + } + } else { + this.domDatetimeFinished.innerText = 'Still running...' + this.domExitCode.innerText = 'Still running...' + this.domStatus.innerText = 'Still running...' + } + + this.domIcon.innerHTML = res.logEntry.actionIcon + this.domTitle.innerText = res.logEntry.actionTitle + + this.domStdout.innerText = res.logEntry.stdout + + if (res.logEntry.stderr === '') { + this.domStderr.parentElement.hidden = true + this.domStderr.innerText = res.logEntry.stderr + } else { + this.domStderr.parentElement.hidden = false + this.domStderr.innerText = res.logEntry.stderr + } + + this.domDatetimeStarted.innerText = res.logEntry.datetimeStarted + } + + renderError (err) { + this.dlg.querySelector('pre').innerText = JSON.stringify(err) + } +} diff --git a/webui/js/marshaller.js b/webui/js/marshaller.js index d0b3697..5e83d29 100644 --- a/webui/js/marshaller.js +++ b/webui/js/marshaller.js @@ -50,7 +50,7 @@ export function marshalLogsJsonToHtml (json) { logTableExitCode += ' (timed out)' } - row.querySelector('.timestamp').innerText = logEntry.datetime + row.querySelector('.timestamp').innerText = logEntry.datetimeStarted row.querySelector('.content').innerText = logEntry.actionTitle row.querySelector('.icon').innerHTML = logEntry.actionIcon row.querySelector('pre.stdout').innerText = logEntry.stdout diff --git a/webui/js/websocket.js b/webui/js/websocket.js new file mode 100644 index 0000000..b9ce468 --- /dev/null +++ b/webui/js/websocket.js @@ -0,0 +1,73 @@ +import { marshalLogsJsonToHtml } from './marshaller.js' + +window.ws = null + +export function checkWebsocketConnection () { + if (window.ws === null || window.ws.readyState === 3) { + reconnectWebsocket() + } +} + +function reconnectWebsocket () { + window.websocketAvailable = false + + let proto = 'ws:' + + if (window.location.protocol === 'https:') { + proto = 'wss:' + } + + const websocketConnectionUrl = proto + window.location.host + '/websocket' + const ws = window.ws = new WebSocket(websocketConnectionUrl) + + ws.addEventListener('open', websocketOnOpen) + ws.addEventListener('message', websocketOnMessage) + ws.addEventListener('error', websocketOnError) + ws.addEventListener('close', websocketOnClose) +} + +function websocketOnOpen (evt) { + window.websocketAvailable = true + + window.ws.send('monitor') + + window.refreshLoop() +} + +function websocketOnMessage (msg) { + // FIXME check msg status is OK + const j = JSON.parse(msg.data) + + switch (j.type) { + case 'ExecutionFinished': + updatePageAfterFinished(j.payload) + break + default: + window.showBigError('Unknown message type from server: ' + j.type) + } +} + +function updatePageAfterFinished (logEntry) { + document.querySelector('execution-button#execution-' + logEntry.uuid).onFinished(logEntry) + + marshalLogsJsonToHtml({ + logs: [logEntry] + }) + + // If the current execution dialog is open, update that too + if (window.executionDialog != null && window.executionDialog.dlg.open && window.executionDialog.executionUuid === logEntry.uuid) { + window.executionDialog.renderResult({ + logEntry: logEntry + }) + } +} + +function websocketOnError (err) { + window.websocketAvailable = false + window.refreshLoop() + console.error(err) +} + +function websocketOnClose () { + window.websocketAvailable = false +} diff --git a/webui/main.js b/webui/main.js index 7853e76..65e9e41 100644 --- a/webui/main.js +++ b/webui/main.js @@ -1,6 +1,7 @@ 'use strict' import { marshalActionButtonsJsonToHtml, marshalLogsJsonToHtml } from './js/marshaller.js' +import { checkWebsocketConnection } from './js/websocket.js' function showSection (name) { for (const otherName of ['Actions', 'Logs']) { @@ -19,15 +20,42 @@ function setupSections () { showSection('Actions') } +function refreshLoop () { + if (window.websocketAvailable) { + document.querySelector('#serverConnection').classList.remove('error') + document.querySelector('#serverConnection').innerText = 'websocket' + + // Websocket updates are streamed live, not updated on a loop. + } else if (window.restAvailable) { + // Fallback to rest, but try to reconnect the websocket anyway. + + fetchGetDashboardComponents() + checkWebsocketConnection() + + document.querySelector('#serverConnection').classList.remove('error') + document.querySelector('#serverConnection').innerText = 'rest' + + fetchGetLogs() + } else { + document.querySelector('#serverConnection').innerText = 'disconnected, trying to reconnect...' + document.querySelector('#serverConnection').classList.add('error') + + // Still try to fetch the dashboard, if successfull window.restAvailable = true + fetchGetDashboardComponents() + } +} + function fetchGetDashboardComponents () { window.fetch(window.restBaseUrl + 'GetDashboardComponents', { cors: 'cors' }).then(res => { return res.json() }).then(res => { + window.restAvailable = true marshalActionButtonsJsonToHtml(res) - }).catch(err => { - window.showBigError('fetch-buttons', 'getting buttons', err, 'blat') + }).catch(() => { // err is 1st arg + window.restAvailable = false + // window.showBigError('fetch-buttons', 'getting buttons', err, 'blat') }) } @@ -55,7 +83,7 @@ function processWebuiSettingsJson (settings) { document.head.appendChild(themeCss) } - document.querySelector('#currentVersion').innerText = 'Version: ' + settings.CurrentVersion + document.querySelector('#currentVersion').innerText = settings.CurrentVersion if (settings.ShowNewVersions && settings.AvailableVersion !== 'none') { document.querySelector('#available-version').innerText = 'New Version Available: ' + settings.AvailableVersion @@ -80,10 +108,11 @@ function main () { }).then(res => { processWebuiSettingsJson(res) - fetchGetDashboardComponents() - fetchGetLogs() + window.restAvailable = true + window.refreshLoop = refreshLoop + window.refreshLoop() - window.buttonInterval = setInterval(fetchGetDashboardComponents, 3000) + setInterval(refreshLoop, 3000) }).catch(err => { window.showBigError('fetch-webui-settings', 'getting webui settings', err) }) diff --git a/webui/package-lock.json b/webui/package-lock.json index 11685da..90e45e6 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -1053,9 +1053,9 @@ } }, "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2639,9 +2639,9 @@ } }, "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -2796,9 +2796,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4155,9 +4155,9 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -5281,9 +5281,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "type-fest": { @@ -5399,9 +5399,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" diff --git a/webui/style.css b/webui/style.css index 947a68a..efbb71c 100644 --- a/webui/style.css +++ b/webui/style.css @@ -7,6 +7,13 @@ body { margin: 0; } +dialog { + min-width: 600px; + text-align: left; + padding: 1em; + box-shadow: 0 0 6px 0 #444; +} + fieldset { padding: 0; } @@ -120,7 +127,7 @@ span[role="icon"] { vertical-align: middle; } -form span[role="icon"], +.action-header span[role="icon"], tr.log-row span[role="icon"] { display: inline-block; padding-right: 0.2em; @@ -128,6 +135,9 @@ tr.log-row span[role="icon"] { .error { background-color: salmon; +} + +div.error { padding: 1em; } @@ -146,6 +156,7 @@ div.entity { } h2 { + margin-top: 0; font-size: 1em; display: inline-block; } @@ -185,6 +196,11 @@ input[type="submit"]:disabled { cursor: not-allowed; } +div.executions button { + margin-top: .2em; + margin-bottom: .2em; +} + fieldset#section-switcher { border: 0; text-align: right; @@ -254,6 +270,14 @@ button.active-section { 20% { background-color: cyan; } } +.action-blocked { + animation: kf-action-blocked 1s; +} + +@keyframes kf-action-blocked { + 20% { background-color: purple; } +} + footer, footer a { color: black; @@ -282,21 +306,9 @@ details[open] { display: block; } -form.action-arguments { - position: absolute; - inset: 0; - padding: 1em; - box-shadow: 0 0 6px 0 #aaa; - background-color: #dee3e7; -} - form div.wrapper { - border-radius: 1em; - box-shadow: 0 0 10px 0 #444; background-color: white; - border: 1px solid #999; text-align: left; - padding: 1em; } label {