├── .github ├── dependabot.yml ├── prerelease.sh └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── .goreleaser.pre.yml ├── .goreleaser.yml ├── .revive.toml ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── cmd └── strongbox │ └── main.go ├── go.mod ├── go.sum ├── internal ├── cli │ ├── cli.go │ └── cli_test.go └── cmd │ ├── cmd.go │ ├── cmd_test.go │ ├── kv.go │ ├── kv_test.go │ ├── secret.go │ ├── secret_test.go │ ├── state.go │ ├── state_test.go │ ├── transit.go │ ├── transit_test.go │ ├── utils.go │ ├── utils_test.go │ ├── vault.go │ └── vault_test.go └── pkg └── rand ├── rand.go └── rand_test.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | - package-ecosystem: docker 10 | directory: "/" 11 | schedule: 12 | interval: weekly 13 | time: "10:00" 14 | open-pull-requests-limit: 10 15 | -------------------------------------------------------------------------------- /.github/prerelease.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | RELEASE_ID=$(curl -sL https://api.github.com/repos/${REPOSITORY}/releases/tags/edge | jq -r .id) 6 | HEAD_SHA=$(curl -sL https://api.github.com/repos/${REPOSITORY}/git/refs/heads/main | jq -r .object.sha) 7 | PRERELEASE_TAG=$(git describe --always --abbrev=7 --tags --exclude=edge) 8 | 9 | # Bump the edge tag to the head of main 10 | curl -sL \ 11 | -X PATCH \ 12 | -u "_:${GITHUB_TOKEN}" \ 13 | -H "Accept: application/vnd.github.v3+json" \ 14 | -d '{"sha":"'${HEAD_SHA}'","force":true}' \ 15 | "https://api.github.com/repos/${REPOSITORY}/git/refs/tags/edge" 16 | 17 | # Ensure we execute some cleanup functions on exit 18 | function cleanup { 19 | git tag -d ${PRERELEASE_TAG} || true 20 | git fetch --tags -f || true 21 | } 22 | trap cleanup EXIT 23 | 24 | # Build the binaries using a prerelease tag 25 | git tag -d edge 26 | git tag -f ${PRERELEASE_TAG} 27 | goreleaser release \ 28 | --rm-dist \ 29 | --skip-validate \ 30 | -f .goreleaser.pre.yml 31 | 32 | # Delete existing assets from the edge prerelease on GitHub 33 | for asset_url in $(curl -sL -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${REPOSITORY}/releases/tags/edge | jq -r ".assets[].url"); do 34 | echo "deleting edge release asset: ${asset_url}" 35 | curl -sL \ 36 | -X DELETE \ 37 | -u "_:${GITHUB_TOKEN}" \ 38 | ${asset_url} 39 | done 40 | 41 | # Upload new assets onto the edge prerelease on GitHub 42 | for asset in $(find dist -type f -name "${NAME}_edge*"); do 43 | echo "uploading ${asset}.." 44 | curl -sL \ 45 | -u "_:${GITHUB_TOKEN}" \ 46 | -H "Accept: application/vnd.github.v3+json" \ 47 | -H "Content-Type: $(file -b --mime-type ${asset})" \ 48 | --data-binary @${asset} \ 49 | "https://uploads.github.com/repos/${REPOSITORY}/releases/${RELEASE_ID}/assets?name=$(basename $asset)" 50 | done 51 | 52 | # Upload snaps to the edge channel 53 | find dist -type f -name "*.snap" -exec snapcraft upload --release edge '{}' \; 54 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: release 3 | 4 | on: 5 | push: 6 | tags: 7 | - 'v[0-9]+.[0-9]+.[0-9]+' 8 | branches: 9 | - main 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | 15 | env: 16 | DOCKER_CLI_EXPERIMENTAL: 'enabled' 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Set up QEMU 25 | uses: docker/setup-qemu-action@v1 26 | 27 | - name: Set up Docker Buildx 28 | uses: docker/setup-buildx-action@v1 29 | 30 | - name: docker.io Login 31 | uses: docker/login-action@v1 32 | with: 33 | registry: docker.io 34 | username: ${{ github.repository_owner }} 35 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 36 | 37 | - name: ghcr.io login 38 | uses: docker/login-action@v1 39 | with: 40 | registry: ghcr.io 41 | username: ${{ github.repository_owner }} 42 | password: ${{ secrets.GH_PAT }} 43 | 44 | - name: quay.io Login 45 | uses: docker/login-action@v1 46 | with: 47 | registry: quay.io 48 | username: ${{ github.repository_owner }} 49 | password: ${{ secrets.QUAY_TOKEN }} 50 | 51 | - name: Snapcraft config 52 | uses: samuelmeuli/action-snapcraft@v1 53 | with: 54 | snapcraft_token: ${{ secrets.SNAPCRAFT_TOKEN }} 55 | 56 | - name: Set up Go 57 | uses: actions/setup-go@v2 58 | with: 59 | go-version: 1.17 60 | 61 | - name: Import GPG key 62 | uses: crazy-max/ghaction-import-gpg@v3 63 | with: 64 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} 65 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 66 | 67 | - name: Install goreleaser 68 | uses: goreleaser/goreleaser-action@v2 69 | with: 70 | version: v1.4.1 71 | install-only: true 72 | 73 | - name: Run goreleaser 74 | run: make ${{ github.ref == 'refs/heads/main' && 'pre' || '' }}release 75 | env: 76 | GITHUB_TOKEN: ${{ secrets.GH_PAT }} 77 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: test 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | tags: 9 | - 'v[0-9]+.[0-9]+.[0-9]+' 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | test: 16 | strategy: 17 | matrix: 18 | os: 19 | - ubuntu-20.04 20 | - macos-11.0 21 | - windows-2022 22 | 23 | runs-on: ${{ matrix.os }} 24 | 25 | steps: 26 | - name: Checkout code 27 | uses: actions/checkout@v2 28 | 29 | - name: Install Go 30 | uses: actions/setup-go@v2 31 | with: 32 | go-version: 1.17 33 | 34 | - name: Lint 35 | if: ${{ matrix.os == 'ubuntu-20.04' }} 36 | run: make lint 37 | 38 | - name: Test 39 | run: make coverage 40 | 41 | - name: Publish coverage to coveralls.io 42 | uses: shogo82148/actions-goveralls@v1 43 | if: ${{ matrix.os == 'ubuntu-20.04' }} 44 | with: 45 | path-to-profile: coverage.out 46 | 47 | - name: Build 48 | run: make build 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | strongbox 2 | !cmd/strongbox 3 | *.out 4 | .strongbox_state.yml 5 | dist 6 | -------------------------------------------------------------------------------- /.goreleaser.pre.yml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod download 4 | 5 | builds: 6 | - main: ./cmd/strongbox 7 | env: 8 | - CGO_ENABLED=0 9 | goos: 10 | - darwin 11 | - linux 12 | - windows 13 | goarch: 14 | - 386 15 | - amd64 16 | - arm64 17 | flags: 18 | - -trimpath 19 | ignore: 20 | - goos: darwin 21 | goarch: 386 22 | 23 | archives: 24 | - name_template: '{{ .ProjectName }}_edge_{{ .Os }}_{{ .Arch }}' 25 | format_overrides: 26 | - goos: windows 27 | format: zip 28 | 29 | release: 30 | disable: true 31 | 32 | snapcrafts: 33 | - summary: Safely manage Hashicorp Vault secrets at rest 34 | description: Manage Vault secrets as you manage other resources 35 | license: Apache-2.0 36 | confinement: strict 37 | grade: devel 38 | apps: 39 | strongbox: 40 | plugs: [home, network] 41 | 42 | dockers: 43 | - image_templates: 44 | - 'docker.io/mvisonneau/strongbox:latest-amd64' 45 | - 'ghcr.io/mvisonneau/strongbox:latest-amd64' 46 | - 'quay.io/mvisonneau/strongbox:latest-amd64' 47 | ids: [strongbox] 48 | goarch: amd64 49 | use_buildx: true 50 | build_flag_templates: 51 | - --platform=linux/amd64 52 | - --label=org.opencontainers.image.title={{ .ProjectName }} 53 | - --label=org.opencontainers.image.description={{ .ProjectName }} 54 | - --label=org.opencontainers.image.url=https://github.com/mvisonneau/strongbox 55 | - --label=org.opencontainers.image.source=https://github.com/mvisonneau/strongbox 56 | - --label=org.opencontainers.image.version={{ .Version }} 57 | - --label=org.opencontainers.image.created={{ time "2006-01-02T15:04:05Z07:00" }} 58 | - --label=org.opencontainers.image.revision={{ .FullCommit }} 59 | - --label=org.opencontainers.image.licenses=Apache-2.0 60 | 61 | - image_templates: 62 | - 'docker.io/mvisonneau/strongbox:latest-arm64' 63 | - 'ghcr.io/mvisonneau/strongbox:latest-arm64' 64 | - 'quay.io/mvisonneau/strongbox:latest-arm64' 65 | ids: [strongbox] 66 | goarch: arm64 67 | use_buildx: true 68 | build_flag_templates: 69 | - --platform=linux/arm64 70 | - --label=org.opencontainers.image.title={{ .ProjectName }} 71 | - --label=org.opencontainers.image.description={{ .ProjectName }} 72 | - --label=org.opencontainers.image.url=https://github.com/mvisonneau/strongbox 73 | - --label=org.opencontainers.image.source=https://github.com/mvisonneau/strongbox 74 | - --label=org.opencontainers.image.version={{ .Version }} 75 | - --label=org.opencontainers.image.created={{ time "2006-01-02T15:04:05Z07:00" }} 76 | - --label=org.opencontainers.image.revision={{ .FullCommit }} 77 | - --label=org.opencontainers.image.licenses=Apache-2.0 78 | 79 | docker_manifests: 80 | - name_template: docker.io/mvisonneau/strongbox:latest 81 | image_templates: 82 | - docker.io/mvisonneau/strongbox:latest-amd64 83 | - docker.io/mvisonneau/strongbox:latest-arm64 84 | 85 | - name_template: ghcr.io/mvisonneau/strongbox:latest 86 | image_templates: 87 | - ghcr.io/mvisonneau/strongbox:latest-amd64 88 | - ghcr.io/mvisonneau/strongbox:latest-arm64 89 | 90 | - name_template: quay.io/mvisonneau/strongbox:latest 91 | image_templates: 92 | - quay.io/mvisonneau/strongbox:latest-amd64 93 | - quay.io/mvisonneau/strongbox:latest-arm64 94 | 95 | signs: 96 | - artifacts: checksum 97 | args: 98 | [ 99 | '-u', 100 | 'C09CA9F71C5C988E65E3E5FCADEA38EDC46F25BE', 101 | '--output', 102 | '${signature}', 103 | '--detach-sign', 104 | '${artifact}', 105 | ] 106 | 107 | checksum: 108 | name_template: '{{ .ProjectName }}_edge_sha512sums.txt' 109 | algorithm: sha512 110 | 111 | changelog: 112 | skip: true 113 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod download 4 | 5 | builds: 6 | - main: ./cmd/strongbox 7 | env: 8 | - CGO_ENABLED=0 9 | goos: 10 | - darwin 11 | - linux 12 | - windows 13 | goarch: 14 | - 386 15 | - amd64 16 | - arm64 17 | flags: 18 | - -trimpath 19 | ignore: 20 | - goos: darwin 21 | goarch: 386 22 | 23 | archives: 24 | - name_template: '{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}' 25 | format_overrides: 26 | - goos: windows 27 | format: zip 28 | 29 | nfpms: 30 | - maintainer: &author Maxime VISONNEAU 31 | description: &description Safely manage Hashicorp Vault secrets at rest 32 | license: &license Apache-2.0 33 | homepage: &homepage https://github.com/mvisonneau/strongbox 34 | vendor: *author 35 | file_name_template: '{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}' 36 | formats: 37 | - deb 38 | - rpm 39 | 40 | brews: 41 | - description: *description 42 | homepage: *homepage 43 | folder: Formula 44 | tap: 45 | owner: mvisonneau 46 | name: homebrew-tap 47 | 48 | scoop: 49 | description: *description 50 | homepage: *homepage 51 | license: *license 52 | bucket: 53 | owner: mvisonneau 54 | name: scoops 55 | 56 | snapcrafts: 57 | - name: strongbox 58 | summary: *description 59 | description: Manage Vault secrets as you manage other resources 60 | license: *license 61 | grade: stable 62 | apps: 63 | strongbox: 64 | plugs: [home, network] 65 | 66 | dockers: 67 | - image_templates: 68 | - 'docker.io/mvisonneau/strongbox:{{ .Tag }}-amd64' 69 | - 'ghcr.io/mvisonneau/strongbox:{{ .Tag }}-amd64' 70 | - 'quay.io/mvisonneau/strongbox:{{ .Tag }}-amd64' 71 | ids: [strongbox] 72 | goarch: amd64 73 | use_buildx: true 74 | build_flag_templates: 75 | - --platform=linux/amd64 76 | - --label=org.opencontainers.image.title={{ .ProjectName }} 77 | - --label=org.opencontainers.image.description={{ .ProjectName }} 78 | - --label=org.opencontainers.image.url=https://github.com/mvisonneau/strongbox 79 | - --label=org.opencontainers.image.source=https://github.com/mvisonneau/strongbox 80 | - --label=org.opencontainers.image.version={{ .Version }} 81 | - --label=org.opencontainers.image.created={{ time "2006-01-02T15:04:05Z07:00" }} 82 | - --label=org.opencontainers.image.revision={{ .FullCommit }} 83 | - --label=org.opencontainers.image.licenses=Apache-2.0 84 | 85 | - image_templates: 86 | - 'docker.io/mvisonneau/strongbox:{{ .Tag }}-arm64' 87 | - 'ghcr.io/mvisonneau/strongbox:{{ .Tag }}-arm64' 88 | - 'quay.io/mvisonneau/strongbox:{{ .Tag }}-arm64' 89 | ids: [strongbox] 90 | goarch: arm64 91 | use_buildx: true 92 | build_flag_templates: 93 | - --platform=linux/arm64 94 | - --label=org.opencontainers.image.title={{ .ProjectName }} 95 | - --label=org.opencontainers.image.description={{ .ProjectName }} 96 | - --label=org.opencontainers.image.url=https://github.com/mvisonneau/strongbox 97 | - --label=org.opencontainers.image.source=https://github.com/mvisonneau/strongbox 98 | - --label=org.opencontainers.image.version={{ .Version }} 99 | - --label=org.opencontainers.image.created={{ time "2006-01-02T15:04:05Z07:00" }} 100 | - --label=org.opencontainers.image.revision={{ .FullCommit }} 101 | - --label=org.opencontainers.image.licenses=Apache-2.0 102 | 103 | docker_manifests: 104 | - name_template: docker.io/mvisonneau/strongbox:{{ .Tag }} 105 | image_templates: 106 | - docker.io/mvisonneau/strongbox:{{ .Tag }}-amd64 107 | - docker.io/mvisonneau/strongbox:{{ .Tag }}-arm64 108 | 109 | - name_template: ghcr.io/mvisonneau/strongbox:{{ .Tag }} 110 | image_templates: 111 | - ghcr.io/mvisonneau/strongbox:{{ .Tag }}-amd64 112 | - ghcr.io/mvisonneau/strongbox:{{ .Tag }}-arm64 113 | 114 | - name_template: quay.io/mvisonneau/strongbox:{{ .Tag }} 115 | image_templates: 116 | - quay.io/mvisonneau/strongbox:{{ .Tag }}-amd64 117 | - quay.io/mvisonneau/strongbox:{{ .Tag }}-arm64 118 | 119 | checksum: 120 | name_template: '{{ .ProjectName }}_{{ .Tag }}_sha512sums.txt' 121 | algorithm: sha512 122 | 123 | signs: 124 | - artifacts: checksum 125 | args: 126 | [ 127 | '-u', 128 | 'C09CA9F71C5C988E65E3E5FCADEA38EDC46F25BE', 129 | '--output', 130 | '${signature}', 131 | '--detach-sign', 132 | '${artifact}', 133 | ] 134 | 135 | changelog: 136 | skip: true 137 | -------------------------------------------------------------------------------- /.revive.toml: -------------------------------------------------------------------------------- 1 | ignoreGeneratedHeader = false 2 | severity = "warning" 3 | confidence = 0.8 4 | errorCode = 1 5 | warningCode = 1 6 | 7 | [rule.blank-imports] 8 | [rule.context-as-argument] 9 | [rule.context-keys-type] 10 | [rule.cyclomatic] 11 | arguments = [40] 12 | [rule.dot-imports] 13 | [rule.error-return] 14 | [rule.error-strings] 15 | [rule.error-naming] 16 | [rule.exported] 17 | [rule.if-return] 18 | [rule.increment-decrement] 19 | [rule.var-naming] 20 | [rule.var-declaration] 21 | [rule.package-comments] 22 | [rule.range] 23 | [rule.receiver-naming] 24 | [rule.time-naming] 25 | [rule.unexported-return] 26 | [rule.indent-error-flow] 27 | [rule.errorf] 28 | [rule.empty-block] 29 | [rule.superfluous-else] 30 | [rule.unused-parameter] 31 | [rule.unreachable-code] 32 | [rule.redefines-builtin-id] -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [0ver](https://0ver.org). 7 | 8 | ## [Unreleased] 9 | 10 | ## [v0.2.2] - 2022-02-11 11 | 12 | ### Added 13 | 14 | - Release container images to `quay.io` 15 | 16 | ### Changed 17 | 18 | - Bumped go to `1.17` 19 | - Bumped most dependencies 20 | 21 | ## [v0.2.1] - 2021-06-01 22 | 23 | ### Added 24 | 25 | - Support for stdin input when ciphering 26 | - Added new tests 27 | - Release `snapcraft` packages 28 | - Release `ghcr.io` images 29 | - Publish "edge" artifacts (docker, snapcraft and binaries) for every `main` commit 30 | - `arm64` container images 31 | 32 | ### Changed 33 | 34 | - Replaced Drone CI with GitHub actions 35 | - Throw a warning instead of exiting if `IPC_LOCK` is unsuccessful 36 | - Updated to go `1.16` 37 | - Refactored codebase following golang best practices 38 | - Updated all dependencies 39 | 40 | ## [0.2.0] - 2020-09-28 41 | 42 | ### Added 43 | 44 | - **Support for KV v2** 45 | - Support of `~/.vault-token` file for Vault authentication 46 | - gosec tests as part of the linting process 47 | - Lock process memory before proceeding to operations with Vault API 48 | 49 | ### Changed 50 | 51 | - Moved **logger** definition into its own package 52 | - Moved **cli** definition into its own package 53 | - Refactored client instanciations 54 | - Bumped to `yaml.v3` 55 | - Bumped to go `1.15` and goreleaser `0.143.0` 56 | - Refactored the rand function with crypto/rand and base4 57 | - Fixed newly discovered lint issues 58 | - Outsourced logger configuration 59 | - Upgraded urfave/cli to v2 60 | - Bumped Vault to `1.5.4` 61 | - Switched default branch to **main** 62 | - Moved `get-secret-path` and `set-secret-path` functions under `secret get-path/set-path` 63 | - Removed redundant config path data in statefile 64 | - Use s5 + Vault engine as ciphering/deciphering mechanism for the local state 65 | 66 | ### Deleted 67 | 68 | - Removed **config** package 69 | 70 | ## [0.1.8] - 2019-07-18 71 | 72 | ### Added 73 | 74 | - `homebrew` package release 75 | - `deb` package release 76 | - `rpm` package release 77 | - `scoop` package release 78 | - `freebsd` packages 79 | 80 | ### Changed 81 | 82 | - Fixed goimports test not breaking on errors 83 | - Bumped Vault to **1.1.3** 84 | - Updated go dependencies to their latest versions (2019-07-18) 85 | 86 | ### Removed 87 | 88 | - Replaced `gox` with `goreleaser` 89 | 90 | ## [0.1.7] - 2019-03-31 91 | 92 | ### Added 93 | 94 | - Release binaries are now automatically built and published from the CI 95 | 96 | ### Changed 97 | 98 | - Optimized Makefile 99 | - Upgraded Vault in test container to `1.1.0` 100 | - Upgraded dependencies 101 | - Fixed test coverage reports 102 | - Moved CI from `Travis` to `Drone` 103 | 104 | ## [0.1.6] - 2019-03-28 105 | 106 | ### Added 107 | 108 | - Also build for **arm64** 109 | 110 | ### Changed 111 | 112 | - Fixed Dockerfile build 113 | - Fixed Travis CI builds 114 | - Wait a bit longer for Vault container to be ready in dev-env 115 | - Removed the IPC_LOCK capability over the build container 116 | - Fixed the ldflags breaking darwin and windows builds 117 | - ignore dist folder in git 118 | - Do not use go mod for build dependencies 119 | - Tidied `go.mod` 120 | 121 | ## [0.1.5] - 2019-03-18 122 | 123 | ### Added 124 | 125 | - Added gox and ghr features to release binaries 126 | 127 | ### Changed 128 | 129 | - Fixed a panic issue on `status` and `plan` command when the Vault path doesn't contain any value 130 | - Updated Travis CI configuration 131 | - Upgraded Vault to `1.0.3` 132 | - Upgraded to golang `1.12` 133 | - Switched to `gomodules` 134 | - Enhanced makefile 135 | - Updated all dependencies to their latest versions 136 | - Made the secondary container in dev-env use the same version of Vault 137 | - Added `IPC_LOCK` capabilities to the dev-env docker container 138 | - Upgraded Vault libraries to `0.9.6` 139 | - Updated license to `Apache 2.0` 140 | 141 | ## [0.1.4] - 2018-02-01 142 | 143 | ### Added 144 | 145 | - Added a flag to pass sensitive content through stdin - #8 146 | - New function `strongbox transit delete ` 147 | 148 | ### Changed 149 | 150 | - Lint CI job was failing issue since last commits 151 | - Fixed a bug while returning an empty transit key list 152 | - Updated dependencies 153 | - Support Vault `0.9.3` for development env 154 | 155 | ## [0.1.3] - 2018-01-15 156 | 157 | ### Added 158 | 159 | - Embedded authentication against Vault using [approle](https://www.vaultproject.io/docs/auth/approle.html) auth backend - #6 160 | - Switched base release container from empty (`scratch`) to `busybox` in order to be able to use it natively with GitLab CI\ 161 | 162 | ## [0.1.2] - 2018-01-14 163 | 164 | ### Added 165 | 166 | - Implemented a function to rotate transit keys - #2 167 | - Got a full test environment in Makefile, added Vault container 168 | - Possibility to generate random passwords on secret writes - #4 169 | - Added links in Changelog 170 | 171 | ### Changed 172 | 173 | - Nicer version output 174 | - Updated CLI, added some flags on secret write and read functions 175 | - Enhanced functions usage outputs 176 | - Fixed `status` command on empty Vault Cluster 177 | 178 | ## [0.1.1] - 2018-01-13 179 | 180 | ### Added 181 | 182 | - Added CHANGELOG.md 183 | - Updated dependencies 184 | 185 | ### Changed 186 | 187 | - Fixed Dockerfile 188 | - Fixed build versioning 189 | 190 | ## [0.1.0] - 2018-01-12 191 | 192 | ### Added 193 | 194 | - Dockerfile for building the app 195 | - Implement the CLI 196 | - Management of state file 197 | - Management of Vault transit keys 198 | - Management of secrets 199 | - Plan and apply changes on Vault 200 | - Makefile 201 | - CI 202 | - Some unit tests 203 | - License 204 | 205 | [Unreleased]: https://github.com/mvisonneau/strongbox/compare/v0.2.2...HEAD 206 | [v0.2.2]: https://github.com/mvisonneau/strongbox/compare/v0.2.1...v0.2.2 207 | [v0.2.1]: https://github.com/mvisonneau/strongbox/compare/0.2.0...v0.2.1 208 | [0.2.0]: https://github.com/mvisonneau/strongbox/compare/0.1.8...0.2.0 209 | [0.1.8]: https://github.com/mvisonneau/strongbox/compare/0.1.7...0.1.8 210 | [0.1.7]: https://github.com/mvisonneau/strongbox/compare/0.1.6...0.1.7 211 | [0.1.6]: https://github.com/mvisonneau/strongbox/compare/0.1.5...0.1.6 212 | [0.1.5]: https://github.com/mvisonneau/strongbox/compare/0.1.4...0.1.5 213 | [0.1.4]: https://github.com/mvisonneau/strongbox/compare/0.1.3...0.1.4 214 | [0.1.3]: https://github.com/mvisonneau/strongbox/compare/0.1.2...0.1.3 215 | [0.1.2]: https://github.com/mvisonneau/strongbox/compare/0.1.1...0.1.2 216 | [0.1.1]: https://github.com/mvisonneau/strongbox/compare/0.1.0...0.1.1 217 | [0.1.0]: https://github.com/mvisonneau/strongbox/tree/0.1.0 218 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ## 2 | # BUILD CONTAINER 3 | ## 4 | 5 | FROM alpine:3.15.0 as certs 6 | 7 | RUN \ 8 | apk add --no-cache ca-certificates 9 | 10 | ## 11 | # RELEASE CONTAINER 12 | ## 13 | 14 | FROM busybox:1.35-glibc 15 | 16 | WORKDIR / 17 | 18 | COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ 19 | COPY strongbox /usr/local/bin/ 20 | 21 | # Run as nobody user 22 | USER 65534 23 | 24 | ENTRYPOINT ["/usr/local/bin/strongbox"] 25 | CMD [""] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | https://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright 2017 - Maxime VISONNEAU 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | https://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME := strongbox 2 | FILES := $(shell git ls-files */*.go) 3 | REPOSITORY := mvisonneau/$(NAME) 4 | VAULT_VERSION := 1.7.2 5 | .DEFAULT_GOAL := help 6 | 7 | .PHONY: setup 8 | setup: ## Install required libraries/tools for build tasks 9 | @command -v gofumpt 2>&1 >/dev/null || go install mvdan.cc/gofumpt@v0.2.1 10 | @command -v gosec 2>&1 >/dev/null || go install github.com/securego/gosec/v2/cmd/gosec@v2.9.6 11 | @command -v ineffassign 2>&1 >/dev/null || go install github.com/gordonklaus/ineffassign@v0.0.0-20210914165742-4cc7213b9bc8 12 | @command -v misspell 2>&1 >/dev/null || go install github.com/client9/misspell/cmd/misspell@v0.3.4 13 | @command -v revive 2>&1 >/dev/null || go install github.com/mgechev/revive@v1.1.3 14 | 15 | .PHONY: fmt 16 | fmt: setup ## Format source code 17 | gofumpt -w $(FILES) 18 | 19 | .PHONY: lint 20 | lint: revive vet gofumpt ineffassign misspell gosec ## Run all lint related tests against the codebase 21 | 22 | .PHONY: revive 23 | revive: setup ## Test code syntax with revive 24 | revive -config .revive.toml $(FILES) 25 | 26 | .PHONY: vet 27 | vet: ## Test code syntax with go vet 28 | go vet ./... 29 | 30 | .PHONY: gofumpt 31 | gofumpt: setup ## Test code syntax with gofumpt 32 | gofumpt -d $(FILES) > gofumpt.out 33 | @if [ -s gofumpt.out ]; then cat gofumpt.out; rm gofumpt.out; exit 1; else rm gofumpt.out; fi 34 | 35 | .PHONY: ineffassign 36 | ineffassign: setup ## Test code syntax for ineffassign 37 | ineffassign ./... 38 | 39 | .PHONY: misspell 40 | misspell: setup ## Test code with misspell 41 | misspell -error $(FILES) 42 | 43 | .PHONY: gosec 44 | gosec: setup ## Test code for security vulnerabilities 45 | gosec ./... 46 | 47 | .PHONY: test 48 | test: ## Run the tests against the codebase 49 | go test -v -count=1 -race ./... 50 | 51 | .PHONY: install 52 | install: ## Build and install locally the binary (dev purpose) 53 | go install ./cmd/$(NAME) 54 | 55 | .PHONY: build 56 | build: ## Build the binaries using local GOOS 57 | go build ./cmd/$(NAME) 58 | 59 | .PHONY: release 60 | release: ## Build & release the binaries (stable) 61 | git tag -d edge 62 | goreleaser release --rm-dist 63 | find dist -type f -name "*.snap" -exec snapcraft upload --release stable,edge '{}' \; 64 | 65 | .PHONY: prerelease 66 | prerelease: setup ## Build & prerelease the binaries (edge) 67 | @\ 68 | REPOSITORY=$(REPOSITORY) \ 69 | NAME=$(NAME) \ 70 | GITHUB_TOKEN=$(GITHUB_TOKEN) \ 71 | .github/prerelease.sh 72 | 73 | .PHONY: clean 74 | clean: ## Remove binary if it exists 75 | rm -f $(NAME) 76 | 77 | .PHONY: coverage 78 | coverage: ## Generates coverage report 79 | rm -rf *.out 80 | go test -count=1 -race -v ./... -coverpkg=./... -coverprofile=coverage.out 81 | 82 | .PHONY: coverage-html 83 | coverage-html: ## Generates coverage report and displays it in the browser 84 | go tool cover -html=coverage.out 85 | 86 | .PHONY: dev-env 87 | dev-env: ## Build a local development environment using Docker 88 | @docker run -d --cap-add IPC_LOCK --name vault vault:$(VAULT_VERSION) 89 | @sleep 2 90 | @docker run -it --rm --cap-add IPC_LOCK \ 91 | -e VAULT_ADDR=http://$$(docker inspect vault | jq -r '.[0].NetworkSettings.IPAddress'):8200 \ 92 | -e VAULT_TOKEN=$$(docker logs vault 2>/dev/null | grep 'Root Token' | cut -d' ' -f3 | sed -E "s/[[:cntrl:]]\[[0-9]{1,3}m//g") \ 93 | vault:$(VAULT_VERSION) secrets enable transit 94 | @docker run -it --rm --cap-add IPC_LOCK \ 95 | -v $(shell pwd):/$(NAME) \ 96 | -w /$(NAME) \ 97 | -e VAULT_ADDR=http://$$(docker inspect vault | jq -r '.[0].NetworkSettings.IPAddress'):8200 \ 98 | -e VAULT_TOKEN=$$(docker logs vault 2>/dev/null | grep 'Root Token' | cut -d' ' -f3 | sed -E "s/[[:cntrl:]]\[[0-9]{1,3}m//g") \ 99 | golang:1.17 \ 100 | /bin/bash -c 'make setup; make install; bash' 101 | @docker kill vault 102 | @docker rm vault -f 103 | 104 | .PHONY: is-git-dirty 105 | is-git-dirty: ## Tests if git is in a dirty state 106 | @git status --porcelain 107 | @test $(shell git status --porcelain | grep -c .) -eq 0 108 | 109 | .PHONY: all 110 | all: lint test build coverage ## Test, builds and ship package for all supported platforms 111 | 112 | .PHONY: help 113 | help: ## Displays this help 114 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mvisonneau/strongbox 2 | 3 | [![PkgGoDev](https://pkg.go.dev/badge/github.com/mvisonneau/strongbox)](https://pkg.go.dev/mod/github.com/mvisonneau/strongbox) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/mvisonneau/strongbox)](https://goreportcard.com/report/github.com/mvisonneau/strongbox) 5 | [![Docker Pulls](https://img.shields.io/docker/pulls/mvisonneau/strongbox.svg)](https://hub.docker.com/r/mvisonneau/strongbox/) 6 | [![test](https://github.com/mvisonneau/strongbox/actions/workflows/test.yml/badge.svg)](https://github.com/mvisonneau/strongbox/actions/workflows/test.yml) 7 | [![Coverage Status](https://coveralls.io/repos/github/mvisonneau/strongbox/badge.svg?branch=main)](https://coveralls.io/github/mvisonneau/strongbox?branch=main) 8 | [![release](https://github.com/mvisonneau/strongbox/actions/workflows/release.yml/badge.svg)](https://github.com/mvisonneau/strongbox/actions/workflows/release.yml) 9 | [![strongbox](https://snapcraft.io/strongbox/badge.svg)](https://snapcraft.io/strongbox) 10 | 11 | Securely store secrets at rest using [Hashicorp Vault](https://www.vaultproject.io/). 12 | 13 | ## Concept 14 | 15 | Vault is really good at safely storing data. Allowing us to query an HTTP endpoint in order to perform actions against our sensitive values. The goal of this project is to give us an additional abstraction layer, allowing us to easily store and versionize those secrets outside of it. 16 | 17 | The idea is to leverage the [Vault Transit Secret backend](https://www.vaultproject.io/docs/secrets/transit/) in order to cipher/decipher our secrets and store them securely. The goal being, end up with a file that can easily be used in order to recover a lost secret/key. As well as storing it safely into a **git repository** for instance. 18 | 19 | ## Compatibility 20 | 21 | `strongbox` supports **both version 1 and 2** of the [Vault K/V](https://www.vaultproject.io/api/secret/kv/kv-v1.html) 22 | 23 | ## Installation 24 | 25 | Have a look onto the [latest release page](https://github.com/mvisonneau/strongbox/releases/latest) and pick your flavor. The exhaustive list of os/archs binaries we are releasing can be found in [here](https://github.com/mvisonneau/strongbox/blob/main/.goreleaser.yml#L8-16). 26 | 27 | ### Go 28 | 29 | ```bash 30 | ~$ go install github.com/mvisonneau/strongbox/cmd/strongbox@latest 31 | ``` 32 | 33 | ### Homebrew 34 | 35 | ```bash 36 | ~$ brew install mvisonneau/tap/strongbox 37 | ``` 38 | 39 | ### Snapcraft 40 | 41 | ```bash 42 | ~$ snap install strongbox 43 | ``` 44 | 45 | ### Docker 46 | 47 | ```bash 48 | ~$ docker run -it --rm docker.io/mvisonneau/strongbox 49 | ~$ docker run -it --rm ghcr.io/mvisonneau/strongbox 50 | ~$ docker run -it --rm quay.io/mvisonneau/strongbox 51 | ``` 52 | 53 | ### Scoop 54 | 55 | ```bash 56 | ~$ scoop bucket add https://github.com/mvisonneau/scoops 57 | ~$ scoop install strongbox 58 | ``` 59 | 60 | ### Binaries, DEB and RPM packages 61 | 62 | For the following ones, you need to know which version you want to install, to fetch the latest available : 63 | 64 | ```bash 65 | ~$ export STRONGBOX_VERSION=$(curl -s "https://api.github.com/repos/mvisonneau/strongbox/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') 66 | ``` 67 | 68 | ```bash 69 | # Binary (eg: freebsd/amd64) 70 | ~$ wget https://github.com/mvisonneau/strongbox/releases/download/${STRONGBOX_VERSION}/strongbox_${STRONGBOX_VERSION}_freebsd_arm64.tar.gz 71 | ~$ tar zxvf strongbox_${STRONGBOX_VERSION}_freebsd_amd64.tar.gz -C /usr/local/bin 72 | 73 | # DEB package (eg: linux/386) 74 | ~$ wget https://github.com/mvisonneau/strongbox/releases/download/${STRONGBOX_VERSION}/strongbox_${STRONGBOX_VERSION}_linux_386.deb 75 | ~$ dpkg -i strongbox_${STRONGBOX_VERSION}_linux_386.deb 76 | 77 | # RPM package (eg: linux/arm64) 78 | ~$ wget https://github.com/mvisonneau/strongbox/releases/download/${STRONGBOX_VERSION}/strongbox_${STRONGBOX_VERSION}_linux_arm64.rpm 79 | ~$ rpm -ivh strongbox_${STRONGBOX_VERSION}_linux_arm64.rpm 80 | ``` 81 | 82 | ## TL;DR - Get started and try it out in less than a minute 83 | 84 | - Prereqs : **git**, **make** and **docker** 85 | 86 | If you want to have a quick look and see how it works and/or you don't already have am operational **Vault cluster**, you can easily spin up a complete test environment: 87 | 88 | ```bash 89 | # Install 90 | ~$ git clone git@github.com:mvisonneau/strongbox.git 91 | ~$ make dev-env 92 | ~$ make install 93 | 94 | # Example commands to start with 95 | ~$ strongbox init 96 | ~$ strongbox transit create test 97 | ~$ strongbox secret write mysecret -k mykey -v sensitive_value 98 | ~$ strongbox status 99 | 100 | # You can input longer strings using the '-' keyword for stdin input 101 | ~$ strongbox secret write mysecret -k verylong -v - < foo:key 321 | => foo:key2 322 | => foo:key3 323 | => bar:key 324 | ``` 325 | 326 | ```bash 327 | ~$ strongbox apply 328 | => Added/Updated secret 'foo' and managed keys 329 | => Added/Updated secret 'bar' and managed keys 330 | ``` 331 | 332 | FYI, the values that we store in Vault are deciphered. You can check that they have been correctly created using the Vault API or the Vault client : 333 | 334 | ```bash 335 | ~$ vault list secret/test 336 | Keys 337 | ---- 338 | bar 339 | foo 340 | 341 | ~$ vault read secret/test/foo 342 | Key Value 343 | --- ----- 344 | refresh_interval 768h0m0s 345 | key sensitive 346 | key2 sensitive2 347 | key3 sensitive3 348 | ``` 349 | 350 | #### Rotate secrets 351 | 352 | If you feel that you need to rotate the encryption of your state file or that the transit you are using might have been compromised, `strongbox` allows you to easily do it. 353 | 354 | ```bash 355 | # Check your current key name 356 | ~ strongbox transit info | grep name | cut -d'|' -f 3 | xargs 357 | old 358 | 359 | # Create a new key 360 | ~$ strongbox transit create new 361 | Transit key created successfully 362 | 363 | # Rotate! 364 | ~$ strongbox state rotate-from old 365 | Rotated secrets from 'old' to 'new' 366 | ``` 367 | 368 | ## Develop / Test 369 | 370 | If you use docker, you can easily get started using : 371 | 372 | ```bash 373 | ~$ make dev-env 374 | # You should then be able to use go commands to work onto the project, eg: 375 | ~$ make install 376 | ~$ strongbox 377 | ``` 378 | 379 | This command will spin up a Vault container and a build one with everything required in terms of go dependencies in order to get started. 380 | 381 | ## Build / Release 382 | 383 | If you want to build and/or release your own version of `strongbox`, you need the following prerequisites : 384 | 385 | - [git](https://git-scm.com/) 386 | - [golang](https://golang.org/) 387 | - [make](https://www.gnu.org/software/make/) 388 | - [goreleaser](https://goreleaser.com/) 389 | 390 | ```bash 391 | ~$ git clone git@github.com:mvisonneau/strongbox.git && cd strongbox 392 | 393 | # Build the binaries locally 394 | ~$ make build 395 | 396 | # Build the binaries and release them (you will need a GITHUB_TOKEN and to reconfigure .goreleaser.yml) 397 | ~$ make release 398 | ``` 399 | 400 | ## Contribute 401 | 402 | Contributions are more than welcome! Feel free to submit a [PR](https://github.com/mvisonneau/strongbox/pulls). 403 | -------------------------------------------------------------------------------- /cmd/strongbox/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/mvisonneau/strongbox/internal/cli" 7 | ) 8 | 9 | var version = "" 10 | 11 | func main() { 12 | cli.Run(version, os.Args) 13 | } 14 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mvisonneau/strongbox 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/fatih/color v1.13.0 7 | github.com/hashicorp/vault/api v1.3.1 8 | github.com/hashicorp/vault/sdk v0.3.0 9 | github.com/mitchellh/go-homedir v1.1.0 10 | github.com/mvisonneau/go-helpers v0.0.1 11 | github.com/mvisonneau/s5 v0.0.0-20200911102212-e0293447f0a8 12 | github.com/olekukonko/tablewriter v0.0.5 13 | github.com/sirupsen/logrus v1.8.1 14 | github.com/stretchr/testify v1.7.0 15 | github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8 16 | github.com/urfave/cli/v2 v2.3.0 17 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b 18 | ) 19 | 20 | require ( 21 | cloud.google.com/go v0.100.2 // indirect 22 | cloud.google.com/go/compute v1.2.0 // indirect 23 | cloud.google.com/go/iam v0.1.1 // indirect 24 | cloud.google.com/go/kms v1.2.0 // indirect 25 | github.com/armon/go-metrics v0.3.10 // indirect 26 | github.com/armon/go-radix v1.0.0 // indirect 27 | github.com/aws/aws-sdk-go v1.42.51 // indirect 28 | github.com/cenkalti/backoff/v3 v3.2.2 // indirect 29 | github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect 30 | github.com/davecgh/go-spew v1.1.1 // indirect 31 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 32 | github.com/golang/protobuf v1.5.2 // indirect 33 | github.com/golang/snappy v0.0.4 // indirect 34 | github.com/google/go-cmp v0.5.7 // indirect 35 | github.com/googleapis/gax-go/v2 v2.1.1 // indirect 36 | github.com/hashicorp/errwrap v1.1.0 // indirect 37 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 38 | github.com/hashicorp/go-hclog v1.1.0 // indirect 39 | github.com/hashicorp/go-immutable-radix v1.3.1 // indirect 40 | github.com/hashicorp/go-multierror v1.1.1 // indirect 41 | github.com/hashicorp/go-plugin v1.4.3 // indirect 42 | github.com/hashicorp/go-retryablehttp v0.7.0 // indirect 43 | github.com/hashicorp/go-rootcerts v1.0.2 // indirect 44 | github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect 45 | github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2 // indirect 46 | github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect 47 | github.com/hashicorp/go-sockaddr v1.0.2 // indirect 48 | github.com/hashicorp/go-uuid v1.0.2 // indirect 49 | github.com/hashicorp/go-version v1.4.0 // indirect 50 | github.com/hashicorp/golang-lru v0.5.4 // indirect 51 | github.com/hashicorp/hcl v1.0.0 // indirect 52 | github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect 53 | github.com/jchavannes/go-pgp v0.0.0-20200131171414-e5978e6d02b4 // indirect 54 | github.com/jmespath/go-jmespath v0.4.0 // indirect 55 | github.com/mattn/go-colorable v0.1.12 // indirect 56 | github.com/mattn/go-isatty v0.0.14 // indirect 57 | github.com/mattn/go-runewidth v0.0.13 // indirect 58 | github.com/mitchellh/copystructure v1.2.0 // indirect 59 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 60 | github.com/mitchellh/mapstructure v1.4.3 // indirect 61 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 62 | github.com/oklog/run v1.1.0 // indirect 63 | github.com/pierrec/lz4 v2.6.1+incompatible // indirect 64 | github.com/pmezard/go-difflib v1.0.0 // indirect 65 | github.com/rivo/uniseg v0.2.0 // indirect 66 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 67 | github.com/ryanuber/go-glob v1.0.0 // indirect 68 | go.opencensus.io v0.23.0 // indirect 69 | go.uber.org/atomic v1.9.0 // indirect 70 | golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2 // indirect 71 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect 72 | golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect 73 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect 74 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 75 | golang.org/x/text v0.3.7 // indirect 76 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect 77 | google.golang.org/api v0.68.0 // indirect 78 | google.golang.org/appengine v1.6.7 // indirect 79 | google.golang.org/genproto v0.0.0-20220210181026-6fee9acbd336 // indirect 80 | google.golang.org/grpc v1.44.0 // indirect 81 | google.golang.org/protobuf v1.27.1 // indirect 82 | gopkg.in/square/go-jose.v2 v2.6.0 // indirect 83 | ) 84 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= 22 | cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= 23 | cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= 24 | cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= 25 | cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= 26 | cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= 27 | cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= 28 | cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= 29 | cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= 30 | cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y= 31 | cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= 32 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 33 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 34 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 35 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 36 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 37 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 38 | cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= 39 | cloud.google.com/go/compute v1.2.0 h1:EKki8sSdvDU0OO9mAXGwPXOTOgPz2l08R0/IutDH11I= 40 | cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC29qE3Xmw= 41 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 42 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 43 | cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= 44 | cloud.google.com/go/iam v0.1.1 h1:4CapQyNFjiksks1/x7jsvsygFPhihslYk5GptIrlX68= 45 | cloud.google.com/go/iam v0.1.1/go.mod h1:CKqrcnI/suGpybEHxZ7BMehL0oA4LpdyJdUlTl9jVMw= 46 | cloud.google.com/go/kms v1.2.0 h1:4wZHCsSgCW3JhTlTYLi8gBHDYa/uQujOMjWOCKwGNHY= 47 | cloud.google.com/go/kms v1.2.0/go.mod h1:o3goAYwBWMzsalQbiksm9/gRIrLeDv2kssHn4h/mEoo= 48 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 49 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 50 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 51 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 52 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 53 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 54 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 55 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 56 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 57 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 58 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 59 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 60 | github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= 61 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 62 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 63 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 64 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 65 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 66 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 67 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 68 | github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= 69 | github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= 70 | github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= 71 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 72 | github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= 73 | github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 74 | github.com/aws/aws-sdk-go v1.34.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= 75 | github.com/aws/aws-sdk-go v1.42.51 h1:PRxXC/0+8x2gK1WjgKwzFBubokGrJCc0N70iKPAY8UM= 76 | github.com/aws/aws-sdk-go v1.42.51/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= 77 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 78 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 79 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 80 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 81 | github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= 82 | github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= 83 | github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= 84 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 85 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 86 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 87 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 88 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 89 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 90 | github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= 91 | github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= 92 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 93 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 94 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 95 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 96 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 97 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 98 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 99 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 100 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 101 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 102 | github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= 103 | github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 104 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 105 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 106 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 107 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 108 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 109 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 110 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 111 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 112 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 113 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 114 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= 115 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 116 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 117 | github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= 118 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 119 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 120 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 121 | github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= 122 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= 123 | github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= 124 | github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= 125 | github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= 126 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 127 | github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= 128 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 129 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 130 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 131 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 132 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 133 | github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= 134 | github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= 135 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 136 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 137 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 138 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 139 | github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 140 | github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= 141 | github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 142 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 143 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 144 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 145 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 146 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 147 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 148 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 149 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 150 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 151 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 152 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 153 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 154 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 155 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 156 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 157 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 158 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 159 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 160 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 161 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 162 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 163 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 164 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 165 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 166 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 167 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 168 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 169 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 170 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 171 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 172 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 173 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 174 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 175 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 176 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 177 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 178 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 179 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 180 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 181 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 182 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 183 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 184 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 185 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 186 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 187 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 188 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 189 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 190 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 191 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 192 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 193 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 194 | github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= 195 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 196 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 197 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 198 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 199 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 200 | github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 201 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 202 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 203 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 204 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 205 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 206 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 207 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 208 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 209 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 210 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 211 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 212 | github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 213 | github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 214 | github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 215 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 216 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 217 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 218 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 219 | github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= 220 | github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= 221 | github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 222 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 223 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 224 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= 225 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 226 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 227 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 228 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 229 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 230 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= 231 | github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 232 | github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 233 | github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 234 | github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 235 | github.com/hashicorp/go-hclog v1.1.0 h1:QsGcniKx5/LuX2eYoeL+Np3UKYPNaN7YKpTh29h8rbw= 236 | github.com/hashicorp/go-hclog v1.1.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 237 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 238 | github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= 239 | github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 240 | github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= 241 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 242 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 243 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 244 | github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= 245 | github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM= 246 | github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= 247 | github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= 248 | github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= 249 | github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= 250 | github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= 251 | github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= 252 | github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 253 | github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= 254 | github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 255 | github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= 256 | github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= 257 | github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= 258 | github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= 259 | github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= 260 | github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2 h1:Tz6v3Jb2DRnDCfifRSjYKG0m8dLdNq6bcDkB41en7nw= 261 | github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= 262 | github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= 263 | github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= 264 | github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= 265 | github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= 266 | github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= 267 | github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= 268 | github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= 269 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 270 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 271 | github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= 272 | github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 273 | github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 274 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 275 | github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4= 276 | github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 277 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 278 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 279 | github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= 280 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 281 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 282 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 283 | github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= 284 | github.com/hashicorp/vault/api v1.3.1 h1:pkDkcgTh47PRjY1NEFeofqR4W/HkNUi9qIakESO2aRM= 285 | github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFywzhptMsTIUw= 286 | github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= 287 | github.com/hashicorp/vault/sdk v0.3.0 h1:kR3dpxNkhh/wr6ycaJYqp6AFT/i2xaftbfnwZduTKEY= 288 | github.com/hashicorp/vault/sdk v0.3.0/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= 289 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 290 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 291 | github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= 292 | github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= 293 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 294 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 295 | github.com/jchavannes/go-pgp v0.0.0-20200131171414-e5978e6d02b4 h1:AfTUqDjVFyY40SghT85bXRhpj34DOuIUQLB4DwExzkQ= 296 | github.com/jchavannes/go-pgp v0.0.0-20200131171414-e5978e6d02b4/go.mod h1:dtFptCZ3M/9AWU38htm1xFvWqaJr5ZvkiOiozne99Ps= 297 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 298 | github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= 299 | github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= 300 | github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= 301 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 302 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 303 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 304 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 305 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 306 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 307 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 308 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 309 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 310 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 311 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 312 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 313 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 314 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 315 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 316 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 317 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 318 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 319 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 320 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 321 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 322 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 323 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 324 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 325 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 326 | github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= 327 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 328 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 329 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 330 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 331 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 332 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 333 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 334 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 335 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 336 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 337 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 338 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 339 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 340 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= 341 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 342 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 343 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 344 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 345 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 346 | github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= 347 | github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 348 | github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 349 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 350 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 351 | github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 352 | github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= 353 | github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 354 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 355 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= 356 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 357 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 358 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 359 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 360 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 361 | github.com/mvisonneau/go-helpers v0.0.0-20200224131125-cb5cc4e6def9/go.mod h1:IGzQk4Sr2yIiknxXmOqvhf6uQy+8bVzvkP1005Tbt9I= 362 | github.com/mvisonneau/go-helpers v0.0.1 h1:jp/eaRBixQeCwILkqSDlNIAtRjBdRR3AENTxx5Ts04Y= 363 | github.com/mvisonneau/go-helpers v0.0.1/go.mod h1:9gxWJlesYQqoVW4jj+okotqvG5CB8BfLD06UbyyfKZA= 364 | github.com/mvisonneau/s5 v0.0.0-20200911102212-e0293447f0a8 h1:qdmeSt/UlyDvaf5zAE2/z6CA6qLuBFownbG+nkC40iw= 365 | github.com/mvisonneau/s5 v0.0.0-20200911102212-e0293447f0a8/go.mod h1:LVEfC6/GMzkTkYJAK41AF7Hj62Aw1w40FxmEsHYHxbw= 366 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 367 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 368 | github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= 369 | github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= 370 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 371 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 372 | github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= 373 | github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 374 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 375 | github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 376 | github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= 377 | github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 378 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 379 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 380 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 381 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 382 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 383 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 384 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 385 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 386 | github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 387 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 388 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 389 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 390 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 391 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 392 | github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 393 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 394 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 395 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 396 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 397 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 398 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 399 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 400 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 401 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 402 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 403 | github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 404 | github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= 405 | github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= 406 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 407 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 408 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 409 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 410 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 411 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 412 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 413 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 414 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 415 | github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= 416 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 417 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 418 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 419 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 420 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 421 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 422 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 423 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 424 | github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8 h1:RB0v+/pc8oMzPsN97aZYEwNuJ6ouRJ2uhjxemJ9zvrY= 425 | github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8/go.mod h1:IlWNj9v/13q7xFbaK4mbyzMNwrZLaWSHx/aibKIZuIg= 426 | github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 427 | github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= 428 | github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 429 | github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= 430 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 431 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 432 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 433 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 434 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 435 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 436 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 437 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 438 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 439 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 440 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 441 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 442 | go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= 443 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 444 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 445 | go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= 446 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 447 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 448 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 449 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 450 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 451 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 452 | golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 453 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 454 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 455 | golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2 h1:XdAboW3BNMv9ocSCOk/u1MFioZGzCNkiJZ19v9Oe3Ig= 456 | golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 457 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 458 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 459 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 460 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 461 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 462 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 463 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 464 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 465 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 466 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 467 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 468 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 469 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 470 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 471 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 472 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 473 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 474 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 475 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 476 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 477 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 478 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 479 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 480 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 481 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 482 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 483 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 484 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 485 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 486 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 487 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 488 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 489 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 490 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 491 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 492 | golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 493 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 494 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 495 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 496 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 497 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 498 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 499 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 500 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 501 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 502 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 503 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 504 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 505 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 506 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 507 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 508 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 509 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 510 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 511 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 512 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 513 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 514 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 515 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 516 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 517 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 518 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 519 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 520 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 521 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 522 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 523 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 524 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 525 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 526 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 527 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 528 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 529 | golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 530 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 531 | golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 532 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= 533 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 534 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 535 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 536 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 537 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 538 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 539 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 540 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 541 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 542 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 543 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 544 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 545 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 546 | golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 547 | golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 548 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 549 | golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= 550 | golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 551 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 552 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 553 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 554 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 555 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 556 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 557 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 558 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 559 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 560 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 561 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 562 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 563 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 564 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 565 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 566 | golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 567 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 568 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 569 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 570 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 571 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 572 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 573 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 574 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 575 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 576 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 577 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 578 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 579 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 580 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 581 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 582 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 583 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 584 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 585 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 586 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 587 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 588 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 589 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 590 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 591 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 592 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 593 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 594 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 595 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 596 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 597 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 598 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 599 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 600 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 601 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 602 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 603 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 604 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 605 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 606 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 607 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 608 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 609 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 610 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 611 | golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 612 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 613 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 614 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 615 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 616 | golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 617 | golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 618 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 619 | golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 620 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 621 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 622 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 623 | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 624 | golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 625 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= 626 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 627 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 628 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= 629 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 630 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 631 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 632 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 633 | golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 634 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 635 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 636 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 637 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 638 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 639 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 640 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 641 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 642 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 643 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 644 | golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 645 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= 646 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 647 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 648 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 649 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 650 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 651 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 652 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 653 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 654 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 655 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 656 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 657 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 658 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 659 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 660 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 661 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 662 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 663 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 664 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 665 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 666 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 667 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 668 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 669 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 670 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 671 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 672 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 673 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 674 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 675 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 676 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 677 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 678 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 679 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 680 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 681 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 682 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 683 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 684 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 685 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 686 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 687 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 688 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 689 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 690 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 691 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 692 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 693 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 694 | golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 695 | golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 696 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 697 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 698 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 699 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 700 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 701 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 702 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 703 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 704 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 705 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 706 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 707 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 708 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 709 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 710 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 711 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 712 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 713 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 714 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 715 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 716 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 717 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 718 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 719 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 720 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 721 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 722 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 723 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 724 | google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= 725 | google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= 726 | google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= 727 | google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= 728 | google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= 729 | google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 730 | google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 731 | google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= 732 | google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= 733 | google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= 734 | google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM= 735 | google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M= 736 | google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= 737 | google.golang.org/api v0.68.0 h1:9eJiHhwJKIYX6sX2fUZxQLi7pDRA/MYu8c12q6WbJik= 738 | google.golang.org/api v0.68.0/go.mod h1:sOM8pTpwgflXRhz+oC8H2Dr+UcbMqkPPWNJo88Q7TH8= 739 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 740 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 741 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 742 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 743 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 744 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 745 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 746 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 747 | google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 748 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 749 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 750 | google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 751 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 752 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 753 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 754 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 755 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 756 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 757 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 758 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 759 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 760 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 761 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 762 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 763 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 764 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 765 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 766 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 767 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 768 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 769 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 770 | google.golang.org/genproto v0.0.0-20200410110633-0848e9f44c36/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 771 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 772 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 773 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 774 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 775 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 776 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 777 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 778 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 779 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 780 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 781 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 782 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 783 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 784 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 785 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 786 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 787 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 788 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 789 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 790 | google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= 791 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 792 | google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 793 | google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 794 | google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= 795 | google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 796 | google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 797 | google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 798 | google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 799 | google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= 800 | google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 801 | google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 802 | google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 803 | google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 804 | google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 805 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 806 | google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 807 | google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 808 | google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 809 | google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 810 | google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 811 | google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 812 | google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 813 | google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 814 | google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 815 | google.golang.org/genproto v0.0.0-20220204002441-d6cc3cc0770e/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 816 | google.golang.org/genproto v0.0.0-20220210181026-6fee9acbd336 h1:RK2ysGpQApbI6U7xn+ROT2rrm08lE/t8AcGqG8XI1CY= 817 | google.golang.org/genproto v0.0.0-20220210181026-6fee9acbd336/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= 818 | google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 819 | google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 820 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 821 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 822 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 823 | google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 824 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 825 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 826 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 827 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 828 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 829 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 830 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 831 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 832 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 833 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 834 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 835 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 836 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 837 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 838 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 839 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 840 | google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 841 | google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 842 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 843 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 844 | google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 845 | google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 846 | google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 847 | google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= 848 | google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= 849 | google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= 850 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 851 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 852 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 853 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 854 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 855 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 856 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 857 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 858 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 859 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 860 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 861 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 862 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 863 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 864 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 865 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 866 | gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= 867 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 868 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 869 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 870 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 871 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 872 | gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 873 | gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 874 | gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= 875 | gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 876 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 877 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 878 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 879 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 880 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 881 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 882 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 883 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 884 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 885 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 886 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 887 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 888 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 889 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 890 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 891 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 892 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 893 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 894 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 895 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 896 | -------------------------------------------------------------------------------- /internal/cli/cli.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "time" 7 | 8 | "github.com/urfave/cli/v2" 9 | 10 | "github.com/mvisonneau/strongbox/internal/cmd" 11 | ) 12 | 13 | // Run handles the instanciation of the CLI application 14 | func Run(version string, args []string) { 15 | err := NewApp(version, time.Now()).Run(args) 16 | if err != nil { 17 | fmt.Println(err) 18 | os.Exit(1) 19 | } 20 | } 21 | 22 | // NewApp configures the CLI application 23 | func NewApp(version string, start time.Time) (app *cli.App) { 24 | app = cli.NewApp() 25 | app.Name = "strongbox" 26 | app.Version = version 27 | app.Usage = "Manage Hashicorp Vault secrets at rest" 28 | app.EnableBashCompletion = true 29 | 30 | app.Flags = cli.FlagsByName{ 31 | &cli.StringFlag{ 32 | Name: "state", 33 | Aliases: []string{"s"}, 34 | EnvVars: []string{"STRONGBOX_STATE"}, 35 | Usage: "load state from `FILE`", 36 | Value: ".strongbox_state.yml", 37 | }, 38 | &cli.StringFlag{ 39 | Name: "vault-addr", 40 | EnvVars: []string{"VAULT_ADDR"}, 41 | Usage: "vault address", 42 | }, 43 | &cli.StringFlag{ 44 | Name: "vault-token", 45 | EnvVars: []string{"VAULT_TOKEN"}, 46 | Usage: "vault token", 47 | }, 48 | &cli.StringFlag{ 49 | Name: "vault-role-id", 50 | EnvVars: []string{"VAULT_ROLE_ID"}, 51 | Usage: "vault role id", 52 | }, 53 | &cli.StringFlag{ 54 | Name: "vault-secret-id", 55 | EnvVars: []string{"VAULT_SECRET_ID"}, 56 | Usage: "vault secret id", 57 | }, 58 | &cli.StringFlag{ 59 | Name: "log-level", 60 | EnvVars: []string{"STRONGBOX_LOG_LEVEL"}, 61 | Usage: "log level (debug,info,warn,fatal,panic)", 62 | Value: "info", 63 | }, 64 | &cli.StringFlag{ 65 | Name: "log-format", 66 | EnvVars: []string{"STRONGBOX_LOG_FORMAT"}, 67 | Usage: "log format (json,text)", 68 | Value: "text", 69 | }, 70 | } 71 | 72 | app.Commands = cli.CommandsByName{ 73 | { 74 | Name: "transit", 75 | Usage: "perform actions on transit key/backend", 76 | Subcommands: cli.CommandsByName{ 77 | { 78 | Name: "use", 79 | Usage: "configure a transit key to use", 80 | ArgsUsage: "", 81 | Action: cmd.ExecWrapper(cmd.TransitUse), 82 | }, 83 | { 84 | Name: "info", 85 | Usage: "get information about the currently used transit key", 86 | ArgsUsage: " ", 87 | Action: cmd.ExecWrapper(cmd.TransitInfo), 88 | }, 89 | { 90 | Name: "list", 91 | Usage: "list available transit keys", 92 | ArgsUsage: " ", 93 | Action: cmd.ExecWrapper(cmd.TransitList), 94 | }, 95 | { 96 | Name: "create", 97 | Usage: "create and use a transit key", 98 | ArgsUsage: "", 99 | Action: cmd.ExecWrapper(cmd.TransitCreate), 100 | }, 101 | { 102 | Name: "delete", 103 | Usage: "delete an existing transit key from Vault", 104 | ArgsUsage: "", 105 | Action: cmd.ExecWrapper(cmd.TransitDelete), 106 | }, 107 | }, 108 | }, 109 | { 110 | Name: "secret", 111 | Usage: "perform actions on secrets (locally)", 112 | Subcommands: cli.CommandsByName{ 113 | { 114 | Name: "write", 115 | Usage: "write a secret", 116 | ArgsUsage: "-s -k [-v or -r or -V]", 117 | Flags: cli.FlagsByName{ 118 | &cli.StringFlag{ 119 | Name: "secret", 120 | Aliases: []string{"s"}, 121 | Usage: "secret name", 122 | }, 123 | &cli.StringFlag{ 124 | Name: "key", 125 | Aliases: []string{"k"}, 126 | Usage: "key name", 127 | }, 128 | &cli.StringFlag{ 129 | Name: "value", 130 | Aliases: []string{"v"}, 131 | Usage: "sensitive value of the key to cipher", 132 | }, 133 | &cli.BoolFlag{ 134 | Name: "masked_value", 135 | Aliases: []string{"V"}, 136 | Usage: "sensitive value of the key to cipher (stdin)", 137 | }, 138 | &cli.IntFlag{ 139 | Name: "random", 140 | Aliases: []string{"r"}, 141 | Usage: "automatically generates a string of this length", 142 | }, 143 | }, 144 | Action: cmd.ExecWrapper(cmd.SecretWrite), 145 | }, 146 | { 147 | Name: "read", 148 | Usage: "read secret value", 149 | ArgsUsage: "-s [-k ]", 150 | Flags: cli.FlagsByName{ 151 | &cli.StringFlag{ 152 | Name: "secret", 153 | Aliases: []string{"s"}, 154 | Usage: "secret name", 155 | }, 156 | &cli.StringFlag{ 157 | Name: "key", 158 | Aliases: []string{"k"}, 159 | Usage: "key name", 160 | }, 161 | }, 162 | Action: cmd.ExecWrapper(cmd.SecretRead), 163 | }, 164 | { 165 | Name: "delete", 166 | Usage: "delete secret", 167 | ArgsUsage: "-s [-k ]", 168 | Flags: cli.FlagsByName{ 169 | &cli.StringFlag{ 170 | Name: "secret", 171 | Aliases: []string{"s"}, 172 | Usage: "secret name", 173 | }, 174 | &cli.StringFlag{ 175 | Name: "key", 176 | Aliases: []string{"k"}, 177 | Usage: "key name", 178 | }, 179 | }, 180 | Action: cmd.ExecWrapper(cmd.SecretDelete), 181 | }, 182 | { 183 | Name: "list", 184 | Usage: "list all managed secrets", 185 | ArgsUsage: " ", 186 | Action: cmd.ExecWrapper(cmd.SecretList), 187 | }, 188 | { 189 | Name: "rotate-from", 190 | Usage: "rotate local secrets encryption from an old transit key", 191 | ArgsUsage: "", 192 | Action: cmd.ExecWrapper(cmd.SecretRotateFrom), 193 | }, 194 | }, 195 | }, 196 | { 197 | Name: "kv", 198 | Usage: "perform actions on kv configuration (locally)", 199 | Subcommands: cli.CommandsByName{ 200 | { 201 | Name: "get-path", 202 | Usage: "display the currently used vault KV path in the statefile", 203 | ArgsUsage: " ", 204 | Action: cmd.ExecWrapper(cmd.KVGetPath), 205 | }, 206 | { 207 | Name: "set-path", 208 | Usage: "update the vault secret KV path in the statefile", 209 | ArgsUsage: "", 210 | Action: cmd.ExecWrapper(cmd.KVSetPath), 211 | }, 212 | { 213 | Name: "get-version", 214 | Usage: "display the currently used vault KV version in the statefile", 215 | ArgsUsage: " ", 216 | Action: cmd.ExecWrapper(cmd.KVGetVersion), 217 | }, 218 | { 219 | Name: "set-version", 220 | Usage: "update the vault KV version in the statefile", 221 | ArgsUsage: "", 222 | Action: cmd.ExecWrapper(cmd.KVSetVersion), 223 | }, 224 | }, 225 | }, 226 | { 227 | Name: "init", 228 | Usage: "Create a empty state file at configured location", 229 | ArgsUsage: " ", 230 | Action: cmd.ExecWrapper(cmd.Init), 231 | }, 232 | { 233 | Name: "status", 234 | Usage: "display current status", 235 | ArgsUsage: " ", 236 | Action: cmd.ExecWrapper(cmd.Status), 237 | }, 238 | { 239 | Name: "plan", 240 | Usage: "compare local version with vault cluster", 241 | ArgsUsage: " ", 242 | Action: cmd.ExecWrapper(cmd.Plan), 243 | }, 244 | { 245 | Name: "apply", 246 | Usage: "synchronize vault managed secrets", 247 | ArgsUsage: " ", 248 | Action: cmd.ExecWrapper(cmd.Apply), 249 | }, 250 | } 251 | 252 | app.Metadata = map[string]interface{}{ 253 | "startTime": start, 254 | } 255 | 256 | return 257 | } 258 | -------------------------------------------------------------------------------- /internal/cli/cli_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestRun(t *testing.T) { 11 | assert.NotPanics(t, func() { Run("0.0.0", []string{"strongbox", "--version"}) }) 12 | } 13 | 14 | func TestNewApp(t *testing.T) { 15 | app := NewApp("0.0.0", time.Now()) 16 | assert.Equal(t, "strongbox", app.Name) 17 | assert.Equal(t, "0.0.0", app.Version) 18 | } 19 | -------------------------------------------------------------------------------- /internal/cmd/cmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/fatih/color" 8 | "github.com/urfave/cli/v2" 9 | ) 10 | 11 | // Init .. 12 | func Init(_ *cli.Context) (int, error) { 13 | s.Init() 14 | return 0, nil 15 | } 16 | 17 | // Status .. 18 | func Status(_ *cli.Context) (int, error) { 19 | s.Load() 20 | s.Status() 21 | v.Status() 22 | return 0, nil 23 | } 24 | 25 | // Plan .. 26 | func Plan(_ *cli.Context) (int, error) { 27 | return run("plan") 28 | } 29 | 30 | // Apply .. 31 | func Apply(_ *cli.Context) (int, error) { 32 | return run("apply") 33 | } 34 | 35 | func run(action string) (int, error) { 36 | s.Load() 37 | 38 | // Fetch local values 39 | local := make(map[string]map[string]string) 40 | for k, l := range s.Secrets { 41 | if local[k] == nil { 42 | local[k] = make(map[string]string) 43 | } 44 | for m, n := range l { 45 | local[k][m] = v.Decipher(n) 46 | } 47 | } 48 | 49 | // Fetch remote values 50 | remote := make(map[string]map[string]string) 51 | listPath := s.VaultKVPath() 52 | if s.VaultKVVersion() == 2 { 53 | listPath = s.VaultKVPath() + "metadata" 54 | } 55 | 56 | d, err := v.Client.Logical().List(listPath) 57 | if err != nil { 58 | return 1, err 59 | } 60 | 61 | if d != nil { 62 | if keys, ok := d.Data["keys"]; ok { 63 | for _, k := range keys.([]interface{}) { 64 | if remote[k.(string)] == nil { 65 | remote[k.(string)] = make(map[string]string) 66 | } 67 | 68 | readPath := s.VaultKVPath() + k.(string) 69 | if s.VaultKVVersion() == 2 { 70 | readPath = s.VaultKVPath() + "data/" + k.(string) 71 | } 72 | 73 | l, err := v.Client.Logical().Read(readPath) 74 | if err != nil { 75 | return 1, err 76 | } 77 | 78 | if s.VaultKVVersion() == 2 { 79 | if _, ok := l.Data["data"]; !ok { 80 | return 1, fmt.Errorf("unable to parse content from Vault API response") 81 | } 82 | 83 | for m, n := range l.Data["data"].(map[string]interface{}) { 84 | remote[k.(string)][m] = n.(string) 85 | } 86 | } else { 87 | for m, n := range l.Data { 88 | remote[k.(string)][m] = n.(string) 89 | } 90 | } 91 | } 92 | } 93 | } 94 | 95 | eq := reflect.DeepEqual(local, remote) 96 | if eq { 97 | color.Green("Nothing to do! Local state and remote Vault config are in synctx.") 98 | return 0, nil 99 | } 100 | 101 | return reconcile(local, remote, action) 102 | } 103 | 104 | func reconcile(local map[string]map[string]string, remote map[string]map[string]string, action string) (int, error) { 105 | var addSecret, deleteSecret []string 106 | addSecretKey := make(map[string][]string) 107 | deleteSecretKey := make(map[string][]string) 108 | addSecretKeyCount := 0 109 | deleteSecretKeyCount := 0 110 | 111 | for kl, vl := range local { 112 | foundSecret := false 113 | for kr, vr := range remote { 114 | if kl == kr { 115 | foundSecret = true 116 | for klk := range vl { 117 | foundSecretKey := false 118 | for krk := range vr { 119 | if klk == krk { 120 | foundSecretKey = true 121 | break 122 | } 123 | } 124 | 125 | if !foundSecretKey { 126 | if addSecretKey[kl] == nil { 127 | addSecretKey[kl] = make([]string, 0) 128 | } 129 | addSecretKey[kl] = append(addSecretKey[kl], klk) 130 | addSecretKeyCount++ 131 | } 132 | } 133 | break 134 | } 135 | } 136 | 137 | if !foundSecret { 138 | addSecret = append(addSecret, kl) 139 | addSecretKey[kl] = make([]string, 0) 140 | for klk := range vl { 141 | addSecretKey[kl] = append(addSecretKey[kl], klk) 142 | addSecretKeyCount++ 143 | } 144 | } 145 | } 146 | 147 | for kr, vr := range remote { 148 | foundSecret := false 149 | for kl, vl := range local { 150 | if kr == kl { 151 | foundSecret = true 152 | for krk := range vr { 153 | foundSecretKey := false 154 | for klk := range vl { 155 | if krk == klk { 156 | foundSecretKey = true 157 | break 158 | } 159 | } 160 | 161 | if !foundSecretKey { 162 | fmt.Println(kr, krk) 163 | if deleteSecretKey[kr] == nil { 164 | deleteSecretKey[kr] = make([]string, 0) 165 | } 166 | deleteSecretKey[kr] = append(deleteSecretKey[kr], krk) 167 | deleteSecretKeyCount++ 168 | } 169 | } 170 | break 171 | } 172 | } 173 | 174 | if !foundSecret { 175 | deleteSecret = append(deleteSecret, kr) 176 | deleteSecretKey[kr] = make([]string, 0) 177 | for krk := range vr { 178 | deleteSecretKey[kr] = append(deleteSecretKey[kr], krk) 179 | deleteSecretKeyCount++ 180 | } 181 | } 182 | } 183 | 184 | switch action { 185 | case "plan": 186 | if (len(addSecret) > 0) || (addSecretKeyCount > 0) { 187 | color.Green("Add/Update: %v secret(s) and %v key(s)", len(addSecret), addSecretKeyCount) 188 | for k, l := range addSecretKey { 189 | for _, m := range l { 190 | color.Green("=> %v:%v", k, m) 191 | } 192 | } 193 | } 194 | if (len(deleteSecret) > 0) || (deleteSecretKeyCount > 0) { 195 | color.Red("Remove: %v secret(s) and %v key(s)", len(deleteSecret), deleteSecretKeyCount) 196 | for k, l := range deleteSecretKey { 197 | for _, m := range l { 198 | color.Red("=> %v:%v", k, m) 199 | } 200 | } 201 | } 202 | case "apply": 203 | for _, k := range addSecret { 204 | payload := make(map[string]interface{}) 205 | for m, n := range local[k] { 206 | payload[m] = n 207 | } 208 | v.WriteSecret(k, payload) 209 | } 210 | for k := range addSecretKey { 211 | payload := make(map[string]interface{}) 212 | for m, n := range local[k] { 213 | payload[m] = n 214 | } 215 | v.WriteSecret(k, payload) 216 | } 217 | for _, k := range deleteSecret { 218 | v.DeleteSecret(k) 219 | } 220 | for k := range deleteSecretKey { 221 | payload := make(map[string]interface{}) 222 | for m, n := range local[k] { 223 | payload[m] = n 224 | } 225 | v.WriteSecret(k, payload) 226 | } 227 | default: 228 | return 1, fmt.Errorf("No action specified") 229 | } 230 | 231 | return 0, nil 232 | } 233 | -------------------------------------------------------------------------------- /internal/cmd/cmd_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | // TODO: Implement 4 | -------------------------------------------------------------------------------- /internal/cmd/kv.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/urfave/cli/v2" 8 | ) 9 | 10 | // KVGetPath .. 11 | func KVGetPath(_ *cli.Context) (int, error) { 12 | s.Load() 13 | fmt.Println(s.VaultKVPath()) 14 | 15 | return 0, nil 16 | } 17 | 18 | // KVSetPath .. 19 | func KVSetPath(ctx *cli.Context) (int, error) { 20 | if ctx.NArg() != 1 { 21 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 22 | return 1, err 23 | } 24 | return 1, nil 25 | } 26 | s.Load() 27 | s.SetVaultKVPath(ctx.Args().First()) 28 | 29 | return 0, nil 30 | } 31 | 32 | // KVGetVersion .. 33 | func KVGetVersion(_ *cli.Context) (int, error) { 34 | s.Load() 35 | fmt.Println(s.VaultKVVersion()) 36 | 37 | return 0, nil 38 | } 39 | 40 | // KVSetVersion .. 41 | func KVSetVersion(ctx *cli.Context) (int, error) { 42 | if ctx.NArg() != 1 { 43 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 44 | return 1, err 45 | } 46 | return 1, nil 47 | } 48 | s.Load() 49 | 50 | version, err := strconv.Atoi(ctx.Args().First()) 51 | if err != nil { 52 | return 1, err 53 | } 54 | 55 | if version != 1 && version != 2 { 56 | return 1, fmt.Errorf("KV version must be either 1 or 2, got %d", version) 57 | } 58 | 59 | s.SetVaultKVVersion(version) 60 | 61 | return 0, nil 62 | } 63 | -------------------------------------------------------------------------------- /internal/cmd/kv_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | // TODO: Implement! 4 | -------------------------------------------------------------------------------- /internal/cmd/secret.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | 8 | "github.com/mvisonneau/strongbox/pkg/rand" 9 | "github.com/tcnksm/go-input" 10 | cli "github.com/urfave/cli/v2" 11 | ) 12 | 13 | // SecretRead .. 14 | func SecretRead(ctx *cli.Context) (int, error) { 15 | if ctx.String("secret") == "" || ctx.String("key") == "" { 16 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 17 | return 1, err 18 | } 19 | return 1, nil 20 | } 21 | s.Load() 22 | fmt.Println(v.Decipher(s.ReadSecretKey(ctx.String("secret"), ctx.String("key")))) 23 | 24 | return 0, nil 25 | } 26 | 27 | // SecretWrite .. 28 | func SecretWrite(ctx *cli.Context) (int, error) { 29 | if ctx.String("secret") == "" || 30 | ctx.String("key") == "" || 31 | (ctx.String("value") == "" && !ctx.Bool("masked_value") && ctx.Int("random") == 0) || 32 | (ctx.String("value") != "" && ctx.Bool("masked_value")) || 33 | (ctx.String("value") != "" && ctx.Int("random") != 0) || 34 | (ctx.Bool("masked_value") && ctx.Int("random") != 0) { 35 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 36 | return 1, err 37 | } 38 | return 1, fmt.Errorf("invalid arguments provided") 39 | } 40 | 41 | s.Load() 42 | 43 | var secret string 44 | if ctx.Bool("masked_value") { 45 | ui := &input.UI{ 46 | Writer: os.Stdout, 47 | Reader: os.Stdin, 48 | } 49 | 50 | value, err := ui.Ask("Sensitive", &input.Options{ 51 | Required: true, 52 | Mask: true, 53 | MaskDefault: true, 54 | }) 55 | if err != nil { 56 | return 1, err 57 | } 58 | 59 | secret = v.Cipher(value) 60 | } else if ctx.String("value") == "-" { 61 | read, err := ioutil.ReadAll(os.Stdin) 62 | if err != nil { 63 | return 1, err 64 | } 65 | secret = v.Cipher(string(read)) 66 | } else if ctx.String("value") != "" { 67 | secret = v.Cipher(ctx.String("value")) 68 | } else if ctx.Int("random") != 0 { 69 | secret = v.Cipher(rand.String(ctx.Int("random"))) 70 | } else { 71 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 72 | return 1, err 73 | } 74 | return 1, nil 75 | } 76 | 77 | s.WriteSecretKey(ctx.String("secret"), ctx.String("key"), secret) 78 | 79 | return 0, nil 80 | } 81 | 82 | // SecretList .. 83 | func SecretList(ctx *cli.Context) (int, error) { 84 | s.Load() 85 | switch ctx.NArg() { 86 | case 1: 87 | s.ListSecrets(ctx.Args().First()) 88 | default: 89 | s.ListSecrets("") 90 | } 91 | 92 | return 0, nil 93 | } 94 | 95 | // SecretDelete .. 96 | func SecretDelete(ctx *cli.Context) (int, error) { 97 | if ctx.String("secret") == "" { 98 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 99 | return 1, err 100 | } 101 | return 1, nil 102 | } 103 | s.Load() 104 | 105 | if ctx.String("key") == "" { 106 | s.DeleteSecret(ctx.String("secret")) 107 | } else { 108 | s.DeleteSecretKey(ctx.String("secret"), ctx.String("key")) 109 | } 110 | 111 | return 0, nil 112 | } 113 | 114 | // SecretRotateFrom .. 115 | func SecretRotateFrom(ctx *cli.Context) (int, error) { 116 | if ctx.NArg() != 1 { 117 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 118 | return 1, err 119 | } 120 | return 1, nil 121 | } 122 | s.Load() 123 | s.RotateFromOldTransitKey(ctx.Args().First()) 124 | 125 | return 0, nil 126 | } 127 | -------------------------------------------------------------------------------- /internal/cmd/secret_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | // TODO: Implement 4 | -------------------------------------------------------------------------------- /internal/cmd/state.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | "strconv" 10 | 11 | "github.com/olekukonko/tablewriter" 12 | log "github.com/sirupsen/logrus" 13 | "gopkg.in/yaml.v3" 14 | ) 15 | 16 | // State : Handles state information 17 | type State struct { 18 | Vault struct { 19 | TransitKey string 20 | KV struct { 21 | Path string 22 | Version int 23 | } 24 | } 25 | Secrets map[string]map[string]string 26 | Config *StateConfig `yaml:"-"` 27 | } 28 | 29 | // StateConfig handles state client configuration 30 | type StateConfig struct { 31 | Path string 32 | } 33 | 34 | func getStateClient(sc *StateConfig) *State { 35 | return &State{ 36 | Config: sc, 37 | } 38 | } 39 | 40 | // Init : Generates an empty state file at the configured state file location 41 | func (s *State) Init() { 42 | log.Infof("Creating an empty state file at %v", s.Config.Path) 43 | s.SetVaultTransitKey("default") 44 | s.SetVaultKVPath("secret/") 45 | s.SetVaultKVVersion(2) 46 | s.save() 47 | } 48 | 49 | // SetVaultTransitKey : Update state file with a Vault/TransitKey value 50 | func (s *State) SetVaultTransitKey(value string) { 51 | s.Vault.TransitKey = value 52 | s.save() 53 | } 54 | 55 | // VaultTransitKey : Returns the value of the configured Vault/TransitKey 56 | func (s *State) VaultTransitKey() string { 57 | return s.Vault.TransitKey 58 | } 59 | 60 | // SetVaultKVPath : Update state file with a Vault/Secret/Path value 61 | func (s *State) SetVaultKVPath(value string) { 62 | s.Vault.KV.Path = value 63 | s.save() 64 | } 65 | 66 | // VaultKVPath : Returns the value of the configured Vault/Secret/Path 67 | func (s *State) VaultKVPath() string { 68 | if s.Vault.KV.Path == "" { 69 | return "secret/" 70 | } 71 | return s.Vault.KV.Path 72 | } 73 | 74 | // SetVaultKVVersion : Update state file with a Vault/Secret/Version value 75 | func (s *State) SetVaultKVVersion(version int) { 76 | s.Vault.KV.Version = version 77 | s.save() 78 | } 79 | 80 | // VaultKVVersion : Returns the value of the configured Vault/Secret/Version 81 | func (s *State) VaultKVVersion() int { 82 | if s.Vault.KV.Version == 0 { 83 | return 1 84 | } 85 | return s.Vault.KV.Version 86 | } 87 | 88 | // Load : Loads the statefile content in memory 89 | func (s *State) Load() { 90 | if s.Config.Path == "" { 91 | log.Fatal("State file must be defined") 92 | } 93 | 94 | log.Debugf("Loading from statefile: %v", s.Config.Path) 95 | if _, err := os.Stat(s.Config.Path); os.IsNotExist(err) { 96 | log.Fatalf("State file not found at location: %s, use 'strongbox init' to generate an empty one.\n", s.Config.Path) 97 | } 98 | 99 | filename, _ := filepath.Abs(s.Config.Path) 100 | data, err := ioutil.ReadFile(filepath.Clean(filename)) 101 | if err != nil { 102 | log.Fatal("Error: State file not found, create a new one using : 'strongbox init'") 103 | } 104 | 105 | err = yaml.Unmarshal(data, &s) 106 | if err != nil { 107 | log.Fatalf("Error: %v", err) 108 | } 109 | 110 | log.Debugf("Loaded Transit Key: %v", s.VaultTransitKey()) 111 | log.Debugf("Loaded KV Path: %v", s.VaultKVPath()) 112 | log.Debugf("Loaded KV Version: %v", s.VaultKVVersion()) 113 | log.Debugf("Loaded Secrets: %#v", s.Secrets) 114 | } 115 | 116 | // Status : Returns information about statefile content 117 | func (s *State) Status() { 118 | fmt.Println("[STRONGBOX STATE]") 119 | table := tablewriter.NewWriter(os.Stdout) 120 | table.Append([]string{"Transit Key", s.VaultTransitKey()}) 121 | table.Append([]string{"KV Path", s.VaultKVPath()}) 122 | table.Append([]string{"KV Version", strconv.Itoa(s.VaultKVVersion())}) 123 | table.Append([]string{"Secrets #", fmt.Sprintf("%v", len(s.Secrets))}) 124 | table.Render() 125 | } 126 | 127 | // ListSecrets : List the secrets, safely stored into the statefile 128 | func (s *State) ListSecrets(secret string) { 129 | log.Debug("Rendering local secrets list") 130 | 131 | if secret == "" { 132 | for k, l := range s.Secrets { 133 | table := tablewriter.NewWriter(os.Stdout) 134 | fmt.Printf("[%v]\n", k) 135 | for m, n := range l { 136 | table.Append([]string{m, n}) 137 | } 138 | table.Render() 139 | } 140 | } else { 141 | if s.Secrets[secret] == nil { 142 | fmt.Printf("No secret '%v' found\n", secret) 143 | os.Exit(1) 144 | } 145 | 146 | table := tablewriter.NewWriter(os.Stdout) 147 | for k, l := range s.Secrets[secret] { 148 | table.Append([]string{k, l}) 149 | } 150 | table.Render() 151 | } 152 | } 153 | 154 | // WriteSecretKey : Add or Update a key value within a secret 155 | func (s *State) WriteSecretKey(secret, key, value string) { 156 | if s.Secrets == nil { 157 | s.Secrets = map[string]map[string]string{} 158 | } 159 | 160 | if s.Secrets[secret] == nil { 161 | s.Secrets[secret] = map[string]string{} 162 | } 163 | 164 | s.Secrets[secret][key] = value 165 | s.save() 166 | } 167 | 168 | // ReadSecretKey : Read the value of a SecretKey 169 | func (s *State) ReadSecretKey(secret, key string) string { 170 | if s.Secrets == nil || s.Secrets[secret] == nil { 171 | fmt.Printf("No secret '%v' found\n", secret) 172 | os.Exit(1) 173 | } 174 | 175 | if s.Secrets[secret][key] == "" { 176 | fmt.Printf("No key '%v' found in secret '%v'\n", key, secret) 177 | os.Exit(1) 178 | } 179 | 180 | return s.Secrets[secret][key] 181 | } 182 | 183 | // DeleteSecret : Delete a secret from the statefile based on its name 184 | func (s *State) DeleteSecret(secret string) { 185 | if s.Secrets == nil || s.Secrets[secret] == nil { 186 | fmt.Printf("No secret '%v' found\n", secret) 187 | os.Exit(1) 188 | } 189 | 190 | delete(s.Secrets, secret) 191 | s.save() 192 | fmt.Println("Secret deleted!") 193 | } 194 | 195 | // DeleteSecretKey : Delete a secret:key from the statefile based on the secret and key names 196 | func (s *State) DeleteSecretKey(secret, key string) { 197 | if s.Secrets == nil || s.Secrets[secret] == nil { 198 | fmt.Printf("No secret '%v' found\n", secret) 199 | os.Exit(1) 200 | } 201 | 202 | if s.Secrets[secret][key] == "" { 203 | fmt.Printf("No key '%v' found in secret '%v'\n", key, secret) 204 | os.Exit(1) 205 | } 206 | 207 | delete(s.Secrets[secret], key) 208 | s.save() 209 | fmt.Println("Key deleted!") 210 | } 211 | 212 | // RotateFromOldTransitKey : Replace locally ciphered values with new transit key 213 | func (s *State) RotateFromOldTransitKey(key string) { 214 | transitKey := s.VaultTransitKey() 215 | if transitKey == key { 216 | log.Fatalf("%v is already the currently configured key, can't rotate with same key", key) 217 | } 218 | 219 | s.SetVaultTransitKey(key) 220 | secrets := make(map[string]map[string]string) 221 | for k, l := range s.Secrets { 222 | if secrets[k] == nil { 223 | secrets[k] = make(map[string]string) 224 | } 225 | for m, n := range l { 226 | secrets[k][m] = v.Decipher(n) 227 | } 228 | } 229 | 230 | s.SetVaultTransitKey(transitKey) 231 | 232 | for k, l := range secrets { 233 | for m, n := range l { 234 | s.WriteSecretKey(k, m, v.Cipher(n)) 235 | } 236 | } 237 | fmt.Printf("Rotated secrets from '%v' to '%v'\n", key, transitKey) 238 | } 239 | 240 | // save : write the statefile onto the disk 241 | func (s *State) save() { 242 | log.Debugf("Saving state file at %v", s.Config.Path) 243 | var output bytes.Buffer 244 | y := yaml.NewEncoder(&output) 245 | y.SetIndent(2) 246 | if err := y.Encode(&s); err != nil { 247 | log.Fatalf("Error: %v", err) 248 | } 249 | 250 | filename, err := filepath.Abs(s.Config.Path) 251 | if err != nil { 252 | log.Fatal(err) 253 | } 254 | 255 | if err = ioutil.WriteFile(filename, output.Bytes(), 0o600); err != nil { 256 | log.Fatal(err) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /internal/cmd/state_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "testing" 7 | 8 | log "github.com/sirupsen/logrus" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | var ( 14 | tmpDir string 15 | state State 16 | ) 17 | 18 | // mainWrapper is necessary to be able to leverage "defer" 19 | // as os.Exit does not honour it and is required by *testing.M 20 | func mainWrapper(m *testing.M) int { 21 | var err error 22 | if tmpDir, err = ioutil.TempDir(".", ".test"); err != nil { 23 | log.Fatal(err) 24 | } 25 | defer os.RemoveAll(tmpDir) 26 | return m.Run() 27 | } 28 | 29 | func TestMain(m *testing.M) { 30 | os.Exit(m.Run()) 31 | } 32 | 33 | func getTestStateClient() *State { 34 | var err error 35 | var tmpFile *os.File 36 | if tmpFile, err = ioutil.TempFile(tmpDir, "state"); err != nil { 37 | log.Fatal(err) 38 | } 39 | return getStateClient(&StateConfig{ 40 | Path: tmpFile.Name(), 41 | }) 42 | } 43 | 44 | func TestStateInit(t *testing.T) { 45 | s := getTestStateClient() 46 | s.Init() 47 | assert.Equal(t, "secret/", s.VaultKVPath()) 48 | } 49 | 50 | func TestStateSetVaultTransitKey(t *testing.T) { 51 | s := getTestStateClient() 52 | s.SetVaultTransitKey("foo") 53 | s.Load() 54 | assert.Equal(t, "foo", s.VaultTransitKey()) 55 | } 56 | 57 | func TestStateVaultTransitKey(t *testing.T) { 58 | s := getTestStateClient() 59 | s.Vault.TransitKey = "foo" 60 | assert.Equal(t, "foo", s.VaultTransitKey()) 61 | } 62 | 63 | func TestStateSetVaultKVPath(t *testing.T) { 64 | s := getTestStateClient() 65 | s.SetVaultKVPath("secret/foo/") 66 | s.Load() 67 | assert.Equal(t, "secret/foo/", s.VaultKVPath()) 68 | } 69 | 70 | func TestStateVaultKVPath(t *testing.T) { 71 | s := getTestStateClient() 72 | s.Vault.KV.Path = "secret/foo/" 73 | assert.Equal(t, "secret/foo/", s.VaultKVPath()) 74 | } 75 | 76 | func TestStateLoad(t *testing.T) { 77 | s := getTestStateClient() 78 | s.SetVaultTransitKey("foo") 79 | s.SetVaultKVPath("secret/foo/") 80 | assert.Equal(t, "foo", s.VaultTransitKey()) 81 | assert.Equal(t, "secret/foo/", s.VaultKVPath()) 82 | } 83 | 84 | func TestStateWriteSecretKey(t *testing.T) { 85 | s := getTestStateClient() 86 | s.Init() 87 | s.WriteSecretKey("foo", "bar", "sensitive") 88 | s.Load() 89 | 90 | require.Contains(t, s.Secrets, "foo") 91 | require.Contains(t, s.Secrets["foo"], "bar") 92 | assert.Equal(t, "sensitive", s.Secrets["foo"]["bar"]) 93 | } 94 | -------------------------------------------------------------------------------- /internal/cmd/transit.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import cli "github.com/urfave/cli/v2" 4 | 5 | // TransitUse .. 6 | func TransitUse(ctx *cli.Context) (int, error) { 7 | if ctx.NArg() != 1 { 8 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 9 | return 1, err 10 | } 11 | return 1, nil 12 | } 13 | s.Load() 14 | s.SetVaultTransitKey(ctx.Args().First()) 15 | 16 | return 0, nil 17 | } 18 | 19 | // TransitInfo .. 20 | func TransitInfo(_ *cli.Context) (int, error) { 21 | s.Load() 22 | v.GetTransitInfo() 23 | 24 | return 0, nil 25 | } 26 | 27 | // TransitList .. 28 | func TransitList(_ *cli.Context) (int, error) { 29 | v.ListTransitKeys() 30 | 31 | return 0, nil 32 | } 33 | 34 | // TransitCreate .. 35 | func TransitCreate(ctx *cli.Context) (int, error) { 36 | if ctx.NArg() != 1 { 37 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 38 | return 1, err 39 | } 40 | return 1, nil 41 | } 42 | s.Load() 43 | v.CreateTransitKey(ctx.Args().First()) 44 | s.SetVaultTransitKey(ctx.Args().First()) 45 | 46 | return 0, nil 47 | } 48 | 49 | // TransitDelete .. 50 | func TransitDelete(ctx *cli.Context) (int, error) { 51 | if ctx.NArg() != 1 { 52 | if err := cli.ShowSubcommandHelp(ctx); err != nil { 53 | return 1, err 54 | } 55 | return 1, nil 56 | } 57 | v.DeleteTransitKey(ctx.Args().First()) 58 | 59 | return 0, nil 60 | } 61 | -------------------------------------------------------------------------------- /internal/cmd/transit_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | // TODO: Implement 4 | -------------------------------------------------------------------------------- /internal/cmd/utils.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/hashicorp/vault/sdk/helper/mlock" 7 | "github.com/mvisonneau/go-helpers/logger" 8 | log "github.com/sirupsen/logrus" 9 | "github.com/urfave/cli/v2" 10 | ) 11 | 12 | var ( 13 | start time.Time 14 | s *State 15 | v *Vault 16 | ) 17 | 18 | func configure(ctx *cli.Context) (err error) { 19 | start = ctx.App.Metadata["startTime"].(time.Time) 20 | 21 | if err = logger.Configure(logger.Config{ 22 | Level: ctx.String("log-level"), 23 | Format: ctx.String("log-format"), 24 | }); err != nil { 25 | return 26 | } 27 | 28 | if v, err = getVaultClient(&VaultConfig{ 29 | Address: ctx.String("vault-addr"), 30 | Token: ctx.String("vault-token"), 31 | RoleID: ctx.String("vault-role-id"), 32 | SecretID: ctx.String("vault-secret-id"), 33 | }); err != nil { 34 | return 35 | } 36 | 37 | s = getStateClient(&StateConfig{ 38 | Path: ctx.String("state"), 39 | }) 40 | 41 | return 42 | } 43 | 44 | func exit(exitCode int, err error) cli.ExitCoder { 45 | defer log.WithFields( 46 | log.Fields{ 47 | "execution-time": time.Since(start), 48 | }, 49 | ).Debug("exited..") 50 | 51 | if err != nil { 52 | log.Error(err.Error()) 53 | } 54 | 55 | return cli.NewExitError("", exitCode) 56 | } 57 | 58 | // ExecWrapper gracefully logs and exits our `run` functions 59 | func ExecWrapper(f func(ctx *cli.Context) (int, error)) cli.ActionFunc { 60 | return func(ctx *cli.Context) error { 61 | if err := mlock.LockMemory(); err != nil { 62 | log.WithError(err).Warn("s5 requires the IPC_LOCK capability in order to secure its memory") 63 | } 64 | return exit(f(ctx)) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /internal/cmd/utils_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestExit(t *testing.T) { 11 | err := exit(20, fmt.Errorf("test")) 12 | assert.Equal(t, "", err.Error()) 13 | assert.Equal(t, 20, err.ExitCode()) 14 | } 15 | -------------------------------------------------------------------------------- /internal/cmd/vault.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | 9 | "github.com/fatih/color" 10 | "github.com/hashicorp/vault/api" 11 | "github.com/mitchellh/go-homedir" 12 | "github.com/olekukonko/tablewriter" 13 | log "github.com/sirupsen/logrus" 14 | 15 | s5 "github.com/mvisonneau/s5/cipher" 16 | s5Vault "github.com/mvisonneau/s5/cipher/vault" 17 | ) 18 | 19 | // Vault : Handles a Vault API Client 20 | type Vault struct { 21 | Client *api.Client 22 | } 23 | 24 | // VaultConfig handles Vault configuration 25 | type VaultConfig struct { 26 | Address string 27 | Token string 28 | RoleID string 29 | SecretID string 30 | } 31 | 32 | func getVaultClient(vc *VaultConfig) (*Vault, error) { 33 | log.Debug("Creating Vault client..") 34 | v, err := api.NewClient(nil) 35 | if err != nil { 36 | return nil, fmt.Errorf("Error creating Vault client: %v", err) 37 | } 38 | 39 | if vc.Address == "" { 40 | return nil, fmt.Errorf("Vault address must be defined") 41 | } 42 | 43 | if len(vc.Token) > 0 { 44 | v.SetToken(vc.Token) 45 | } else if len(vc.RoleID) > 0 && len(vc.SecretID) > 0 { 46 | data := map[string]interface{}{ 47 | "role_id": vc.RoleID, 48 | "secret_id": vc.SecretID, 49 | } 50 | 51 | r, err := v.Logical().Write("auth/approle/login", data) 52 | if err != nil { 53 | log.Fatalf("Can't authenticate against vault using provided approle credentials: %v", err) 54 | } 55 | 56 | if r.Auth == nil { 57 | log.Fatalf("no auth info returned with provided approle credentials") 58 | } 59 | 60 | v.SetToken(r.Auth.ClientToken) 61 | } else { 62 | home, _ := homedir.Dir() 63 | f, err := ioutil.ReadFile(filepath.Clean(home + "/.vault-token")) 64 | if err != nil { 65 | return nil, fmt.Errorf("Vault token is not defined (VAULT_TOKEN, (--vault-role-id and --vault-secret-id) or ~/.vault-token)") 66 | } 67 | 68 | v.SetToken(string(f)) 69 | } 70 | 71 | return &Vault{v}, nil 72 | } 73 | 74 | // GetTransitInfo : Fetch some information from Vault about the configured TransitKey 75 | func (v *Vault) GetTransitInfo() { 76 | d, err := v.Client.Logical().Read("transit/keys/" + s.Vault.TransitKey) 77 | if err != nil { 78 | log.Fatalf("Vault error: %v", err) 79 | } 80 | 81 | if d == nil { 82 | log.Fatalf("The configured transit key doesn't seem to exists : %v", s.Vault.TransitKey) 83 | } 84 | 85 | table := tablewriter.NewWriter(os.Stdout) 86 | table.SetHeader([]string{"Key", "Value"}) 87 | for k, l := range d.Data { 88 | table.Append([]string{k, fmt.Sprintf("%v", l)}) 89 | } 90 | table.Render() 91 | } 92 | 93 | // CreateTransitKey : Create a new transit key in Vault 94 | func (v *Vault) CreateTransitKey(key string) { 95 | _, err := v.Client.Logical().Write("transit/keys/"+key, make(map[string]interface{})) 96 | if err != nil { 97 | log.Fatalf("Vault error: %v", err) 98 | } 99 | 100 | fmt.Println("Transit key created successfully") 101 | } 102 | 103 | // ListTransitKeys : List available transit keys from Vault 104 | func (v *Vault) ListTransitKeys() { 105 | d, err := v.Client.Logical().List("transit/keys") 106 | if err != nil { 107 | log.Fatalf("Vault error: %v", err) 108 | } 109 | 110 | if d != nil { 111 | table := tablewriter.NewWriter(os.Stdout) 112 | table.SetHeader([]string{"Key"}) 113 | for _, l := range d.Data["keys"].([]interface{}) { 114 | table.Append([]string{l.(string)}) 115 | } 116 | table.Render() 117 | } 118 | } 119 | 120 | // DeleteTransitKey : Delete a transit key from Vault 121 | func (v *Vault) DeleteTransitKey(key string) { 122 | p := make(map[string]interface{}) 123 | p["deletion_allowed"] = "true" 124 | _, err := v.Client.Logical().Write("transit/keys/"+key+"/config", p) 125 | if err != nil { 126 | log.Fatalf("Vault error: %v", err) 127 | } 128 | 129 | _, err = v.Client.Logical().Delete("transit/keys/" + key) 130 | if err != nil { 131 | log.Fatalf("Vault error: %v", err) 132 | } 133 | color.Green("=> Deleted transit key '%v' from Vault", key) 134 | } 135 | 136 | // ListSecrets : Do what it says 137 | func (v *Vault) ListSecrets() { 138 | log.Debugf("Listing secrets in Vault KV Path: %v", s.VaultKVPath()) 139 | d, err := v.Client.Logical().List(s.VaultKVPath()) 140 | if err != nil { 141 | log.Fatalf("Vault error: %v", err) 142 | } 143 | 144 | table := tablewriter.NewWriter(os.Stdout) 145 | table.SetHeader([]string{"Key"}) 146 | for _, l := range d.Data["keys"].([]interface{}) { 147 | table.Append([]string{l.(string)}) 148 | } 149 | table.Render() 150 | } 151 | 152 | // Status : Return information about Vault API endpoint/cluster 153 | func (v *Vault) Status() { 154 | vh, err := v.Client.Sys().Health() 155 | fmt.Println("[VAULT]") 156 | if err != nil { 157 | log.Fatalf("Vault error: %v", err) 158 | } 159 | 160 | listPath := s.VaultKVPath() 161 | if s.VaultKVVersion() == 2 { 162 | listPath = s.VaultKVPath() + "metadata" 163 | } 164 | 165 | d, err := v.Client.Logical().List(listPath) 166 | if err != nil { 167 | log.Fatalf("vault error: %v", err) 168 | } 169 | 170 | secretsCount := 0 171 | if d != nil { 172 | if keys, ok := d.Data["keys"]; ok { 173 | secretsCount = len(keys.([]interface{})) 174 | } 175 | } 176 | 177 | table := tablewriter.NewWriter(os.Stdout) 178 | table.Append([]string{"Sealed", fmt.Sprintf("%v", vh.Sealed)}) 179 | table.Append([]string{"Cluster Version", vh.Version}) 180 | table.Append([]string{"Cluster ID", vh.ClusterID}) 181 | table.Append([]string{"Secrets #", fmt.Sprintf("%v", secretsCount)}) 182 | table.Render() 183 | } 184 | 185 | // Cipher : Cipher a value using the TransitKey 186 | func (v *Vault) Cipher(value string) string { 187 | s5Engine := s5Vault.Client{ 188 | Client: v.Client, 189 | Config: &s5Vault.Config{ 190 | Key: s.Vault.TransitKey, 191 | }, 192 | } 193 | 194 | cipheredValue, err := s5Engine.Cipher(value) 195 | if err != nil { 196 | log.Fatal(err) 197 | } 198 | 199 | return s5.GenerateOutput(cipheredValue) 200 | } 201 | 202 | // Decipher : Decipher a value using the TransitKey 203 | func (v *Vault) Decipher(value string) string { 204 | s5Engine := s5Vault.Client{ 205 | Client: v.Client, 206 | Config: &s5Vault.Config{ 207 | Key: s.Vault.TransitKey, 208 | }, 209 | } 210 | 211 | parsedInput, err := s5.ParseInput(value) 212 | if err != nil { 213 | log.Fatal(err) 214 | } 215 | 216 | decipheredValue, err := s5Engine.Decipher(parsedInput) 217 | if err != nil { 218 | log.Fatal(err) 219 | } 220 | 221 | return decipheredValue 222 | } 223 | 224 | // WriteSecret : Write a secret into Vault 225 | func (v *Vault) WriteSecret(secret string, data map[string]interface{}) { 226 | queryPath := s.VaultKVPath() + secret 227 | var payload map[string]interface{} 228 | if s.Vault.KV.Version == 2 { 229 | queryPath = s.VaultKVPath() + "data/" + secret 230 | payload = make(map[string]interface{}) 231 | payload["data"] = data 232 | } else { 233 | payload = data 234 | } 235 | 236 | _, err := v.Client.Logical().Write(queryPath, payload) 237 | if err != nil { 238 | log.Fatalf("Vault error: %v", err) 239 | } 240 | color.Green("=> Added/Updated secret '%v' and managed keys", secret) 241 | } 242 | 243 | // DeleteSecret : DeleteSecret a secret from Vault 244 | func (v *Vault) DeleteSecret(secret string) { 245 | _, err := v.Client.Logical().Delete(s.VaultKVPath() + secret) 246 | if err != nil { 247 | log.Fatalf("Vault error: %v", err) 248 | } 249 | color.Green("=> Deleted secret '%v' and its underlying keys", secret) 250 | } 251 | 252 | // DeleteSecretKey : Delete a key of a secret from Vault 253 | func (v *Vault) DeleteSecretKey(secret, key string) { 254 | // TODO: Implement! 255 | color.Yellow("=> [NOT IMPLEMENTED] - Deleted secret:key %v:%v", secret, key) 256 | } 257 | -------------------------------------------------------------------------------- /internal/cmd/vault_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | // TODO: Implement 4 | -------------------------------------------------------------------------------- /pkg/rand/rand.go: -------------------------------------------------------------------------------- 1 | package rand 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/base64" 6 | "log" 7 | ) 8 | 9 | // String : Generates a random string of a given length 10 | func String(length int) string { 11 | b := make([]byte, base64.RawStdEncoding.DecodedLen(length)) 12 | _, err := rand.Read(b) 13 | if err != nil { 14 | log.Fatalf(err.Error()) 15 | } 16 | return base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString(b) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/rand/rand_test.go: -------------------------------------------------------------------------------- 1 | package rand 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestString(t *testing.T) { 10 | assert.NotEqual(t, String(10), String(10), "strings should be different") 11 | assert.Len(t, String(10), 10, "length of string should be 10") 12 | } 13 | --------------------------------------------------------------------------------