From 305b867c17f2e1c1826a5090e162a72e785091a5 Mon Sep 17 00:00:00 2001 From: Dan Heath <76443935+Dan-Heath@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:10:25 +0000 Subject: [PATCH] backport of commit 347bf76a7e35b2ddb478a1d526c1d0240cf2ff4e --- .github/workflows/actionlint.yml | 2 +- .github/workflows/backport.yml | 2 +- .github/workflows/build.yml | 38 +- .github/workflows/enos-fmt.yml | 2 +- .github/workflows/enos-run.yml | 51 +-- .github/workflows/fuzz.yml | 6 +- .github/workflows/linting.yml | 4 +- .github/workflows/make-gen-delta.yml | 4 +- .github/workflows/schema-diff.yml | 2 +- .github/workflows/security-scan.yml | 14 +- .github/workflows/test-ci-bootstrap-oss.yml | 2 +- .github/workflows/test-ci-cleanup-oss.yml | 2 +- .github/workflows/test-cli-ui_oss.yml | 20 +- .github/workflows/test-race.yml | 22 +- .github/workflows/test-sql.yml | 2 +- .github/workflows/test.yml | 22 +- .../workflows/trigger-merge-to-downstream.yml | 2 +- .release/security-scan.hcl | 7 + CHANGELOG.md | 7 - CODEOWNERS | 6 +- api/go.mod | 6 +- api/go.sum | 20 +- enos/ci/bootstrap/main.tf | 3 +- enos/ci/service-user-iam/main.tf | 2 - enos/enos.hcl | 3 +- enos/modules/aws_bucket/main.tf | 21 +- go.mod | 12 +- go.sum | 24 +- internal/alias/target/alias_test.go | 6 +- .../internal/cache/refresh_test.go | 8 +- .../cache/repository_refresh_token_test.go | 5 +- .../internal/cache/repository_token.go | 42 +- .../internal/cache/repository_token_test.go | 359 +--------------- internal/clientcache/internal/db/db.go | 2 +- internal/clientcache/internal/db/schema.sql | 50 +-- internal/cmd/base/base.go | 3 - internal/cmd/base/dev.go | 32 +- internal/cmd/base/listener.go | 33 +- internal/cmd/base/servers.go | 24 +- internal/cmd/commands/connect/connect.go | 24 +- internal/cmd/commands/dev/dev.go | 13 +- .../server/controller_db_swap_test.go | 8 +- .../controller_ratelimit_reload_test.go | 16 +- .../commands/server/listener_reload_test.go | 2 +- internal/cmd/commands/server/server.go | 23 +- .../worker_initial_upstreams_reload_test.go | 2 +- .../server/worker_tags_reload_test.go | 2 +- internal/cmd/config/config.go | 141 ++----- internal/cmd/config/config_test.go | 97 ----- internal/cmd/config/options.go | 15 - internal/daemon/controller/controller.go | 10 +- internal/daemon/controller/controller_test.go | 6 +- .../handlers/targets/target_service.go | 14 +- .../targets/tcp/target_service_test.go | 170 ++------ internal/daemon/controller/testing.go | 5 +- internal/daemon/controller/testing_test.go | 25 -- .../daemon/worker/controller_connection.go | 11 +- internal/daemon/worker/testing.go | 6 +- internal/daemon/worker/testing_test.go | 24 -- internal/db/option.go | 12 - internal/db/option_test.go | 11 - internal/db/read_writer.go | 12 +- .../migrations/oss/postgres/7/03_job.up.sql | 3 - .../oss/postgres/93/01_job_run_clean.up.sql | 37 -- .../93/02_drop_job_jobs_to_run.up.sql | 10 - internal/gen/controller.swagger.json | 2 +- internal/host/plugin/host_address_test.go | 60 +-- internal/host/static/host.go | 3 +- internal/host/static/host_test.go | 36 +- internal/host/static/repository_host.go | 15 +- internal/host/static/repository_host_test.go | 156 ------- internal/host/static/testing.go | 24 -- .../iam/repository_principal_role_test.go | 12 +- .../controller/storage/job/store/v1/job.proto | 2 +- .../scheduler/additional_verification_test.go | 72 ++-- internal/scheduler/batch/batch_test.go | 11 - internal/scheduler/cleaner/cleaner.go | 30 ++ internal/scheduler/cleaner/cleaner_job.go | 57 +++ internal/scheduler/cleaner/cleaner_test.go | 64 +++ .../job/additional_verification_test.go | 3 +- internal/scheduler/job/doc.go | 2 +- internal/scheduler/job/options.go | 20 +- internal/scheduler/job/options_test.go | 15 + internal/scheduler/job/query.go | 21 +- internal/scheduler/job/repository_run.go | 57 ++- internal/scheduler/job/repository_run_test.go | 311 ++++++++++++-- internal/scheduler/job/run.go | 2 +- internal/scheduler/job/status.go | 3 + internal/scheduler/job/store/job.pb.go | 2 +- internal/scheduler/options.go | 16 + internal/scheduler/options_test.go | 14 + internal/scheduler/scheduler.go | 14 +- internal/scheduler/scheduler_test.go | 17 +- internal/server/repository_controller.go | 2 +- internal/server/repository_nonce.go | 2 +- internal/server/repository_worker.go | 6 +- internal/server/worker_auth.go | 2 +- internal/session/connection.go | 10 - internal/session/connection_test.go | 148 +------ internal/session/session.go | 8 +- internal/target/repository.go | 17 +- .../target/tcp/repository_tcp_target_test.go | 177 +------- internal/target/tcp/testing_test.go | 121 +----- internal/tests/api/targets/target_test.go | 33 +- internal/tests/cluster/ipv6_listener_test.go | 71 ++-- .../cluster/multi_controller_worker_test.go | 91 +---- .../tests/cluster/worker_bytesupdown_test.go | 23 +- internal/tests/cluster/worker_proxy_test.go | 25 +- internal/tests/helper/option.go | 13 - internal/tests/helper/testing_helper.go | 53 +-- internal/util/net.go | 72 ---- internal/util/net_test.go | 385 ------------------ plugins/boundary/mains/aws/go.mod | 86 ++-- plugins/boundary/mains/aws/go.sum | 238 +++++++---- plugins/boundary/mains/azure/go.mod | 18 +- plugins/boundary/mains/azure/go.sum | 37 +- plugins/boundary/mains/gcp/go.mod | 70 ---- plugins/boundary/mains/gcp/go.sum | 327 --------------- plugins/boundary/mains/gcp/main.go | 20 - plugins/boundary/mains/minio/go.mod | 12 +- plugins/boundary/mains/minio/go.sum | 34 +- plugins/kms/mains/alicloudkms/go.mod | 8 +- plugins/kms/mains/alicloudkms/go.sum | 20 +- plugins/kms/mains/awskms/go.mod | 8 +- plugins/kms/mains/awskms/go.sum | 16 +- plugins/kms/mains/azurekeyvault/go.mod | 29 +- plugins/kms/mains/azurekeyvault/go.sum | 97 ++--- plugins/kms/mains/gcpckms/go.mod | 15 +- plugins/kms/mains/gcpckms/go.sum | 39 +- plugins/kms/mains/ocikms/go.mod | 8 +- plugins/kms/mains/ocikms/go.sum | 20 +- plugins/kms/mains/transit/go.mod | 14 +- plugins/kms/mains/transit/go.sum | 34 +- sdk/go.mod | 10 +- sdk/go.sum | 22 +- .../internal/e2e/tests/base/search_test.go | 69 +--- version/VERSION | 2 +- .../connection-workflows/multi-hop.mdx | 57 +++ .../concepts/security/data-encryption.mdx | 29 +- .../content/docs/release-notes/v0_16_0.mdx | 21 + .../content/docs/release-notes/v0_17_0.mdx | 29 +- .../content/docs/release-notes/v0_18_0.mdx | 44 +- .../img/ui/multi-hop-egress-filter_dark.png | Bin 0 -> 136499 bytes .../img/ui/multi-hop-egress-filter_light.png | Bin 0 -> 135740 bytes 144 files changed, 1750 insertions(+), 3554 deletions(-) delete mode 100644 internal/db/schema/migrations/oss/postgres/93/01_job_run_clean.up.sql delete mode 100644 internal/db/schema/migrations/oss/postgres/93/02_drop_job_jobs_to_run.up.sql create mode 100644 internal/scheduler/cleaner/cleaner.go create mode 100644 internal/scheduler/cleaner/cleaner_job.go create mode 100644 internal/scheduler/cleaner/cleaner_test.go delete mode 100644 internal/util/net.go delete mode 100644 internal/util/net_test.go delete mode 100644 plugins/boundary/mains/gcp/go.mod delete mode 100644 plugins/boundary/mains/gcp/go.sum delete mode 100644 plugins/boundary/mains/gcp/main.go create mode 100644 website/public/img/ui/multi-hop-egress-filter_dark.png create mode 100644 website/public/img/ui/multi-hop-egress-filter_light.png diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index 55020d89bfe..2fe379b5160 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -11,7 +11,7 @@ jobs: actionlint: runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Check workflow files uses: docker://docker.mirror.hashicorp.services/rhysd/actionlint@sha256:5acca218639222e4afbc82fc6e9ef56cbe646ade3b07f3f5ec364b638258a244 with: diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 660b46f70f4..02466877cd7 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -16,7 +16,7 @@ jobs: runs-on: ${{ fromJSON(vars.RUNNER) }} container: hashicorpdev/backport-assistant:0.5.1 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 # Fetch all branches and tags - name: Check if any migrations have changed diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ac297eebce..427e40c0393 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: base-product-version: $${{ steps.set-product-version.outputs.base-product-version }} prerelease-product-version: ${{ steps.set-product-version.outputs.prerelease-product-version }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set Product version id: set-product-version uses: hashicorp/actions-set-product-version@v2 # TSCCR: loading action configs: failed to query HEAD reference: failed to get advertised references: authorization failed @@ -39,7 +39,7 @@ jobs: product-edition: ${{ steps.get-product-edition.outputs.product-edition }} go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Determine Go version id: get-go-version # We use .go-version as our source of truth for current Go @@ -48,7 +48,7 @@ jobs: echo "Building with Go $(cat .go-version)" echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" cache: false @@ -58,7 +58,7 @@ jobs: echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -86,7 +86,7 @@ jobs: runs-on: ${{ fromJSON(vars.BUILDER_LINUX) }} steps: - name: 'Checkout directory' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - run: | echo "Product Version - ${{ needs.set-product-version.outputs.product-version }}" echo "Product Prerelease - ${{ needs.set-product-version.outputs.prerelease-product-version }}" @@ -100,7 +100,7 @@ jobs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: 'Checkout directory' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Generate metadata file id: generate-metadata-file uses: hashicorp/actions-generate-metadata@v1 # TSCCR: loading action configs: failed to query HEAD reference: failed to get advertised references: authorization failed @@ -108,7 +108,7 @@ jobs: repository: boundary version: ${{ needs.set-product-version.outputs.product-version }} product: ${{ env.PKG_NAME }} - - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + - uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: metadata.json path: ${{ steps.generate-metadata-file.outputs.filepath }} @@ -137,9 +137,9 @@ jobs: GOPRIVATE: "github.com/hashicorp" GO111MODULE: on steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ matrix.go }} cache: false @@ -149,7 +149,7 @@ jobs: echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -205,11 +205,11 @@ jobs: GO111MODULE: on steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Git run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ matrix.go }} cache: false @@ -219,7 +219,7 @@ jobs: echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -279,12 +279,12 @@ jobs: echo "RPM_PACKAGE=$(basename out/*.rpm)" >> "$GITHUB_ENV" echo "DEB_PACKAGE=$(basename out/*.deb)" >> "$GITHUB_ENV" - name: Upload RPM package - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: ${{ env.RPM_PACKAGE }} path: out/${{ env.RPM_PACKAGE }} - name: Upload DEB package - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: ${{ env.DEB_PACKAGE }} path: out/${{ env.DEB_PACKAGE }} @@ -307,9 +307,9 @@ jobs: GO111MODULE: on steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ matrix.go }} cache: false @@ -319,7 +319,7 @@ jobs: echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -371,7 +371,7 @@ jobs: version: ${{ needs.set-product-version.outputs.product-version }} minor-version: ${{ needs.product-metadata.outputs.product-minor-version }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Docker Build (Action) uses: hashicorp/actions-docker-build@v2 # TSCCR: loading action configs: failed to query HEAD reference: failed to get advertised references: authorization failed with: diff --git a/.github/workflows/enos-fmt.yml b/.github/workflows/enos-fmt.yml index b8f46f3720d..154f73fe824 100644 --- a/.github/workflows/enos-fmt.yml +++ b/.github/workflows/enos-fmt.yml @@ -18,7 +18,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.SERVICE_USER_GITHUB_TOKEN }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # TSCCR: loading action configs: failed to query HEAD reference: failed to get advertised references: authorization failed with: terraform_wrapper: false diff --git a/.github/workflows/enos-run.yml b/.github/workflows/enos-run.yml index 1487b5d51d8..65aae3851a6 100644 --- a/.github/workflows/enos-run.yml +++ b/.github/workflows/enos-run.yml @@ -34,11 +34,11 @@ jobs: go-cache-key: ${{ steps.go-cache-key.outputs.key }} runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ inputs.go-version }} cache: false @@ -53,7 +53,7 @@ jobs: echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" echo "go-bin=$(go env GOPATH)/bin" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -103,14 +103,14 @@ jobs: ENOS_VAR_go_version: ${{ inputs.go-version }} steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ inputs.go-version }} cache: false - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.cache-go-build }} @@ -128,7 +128,7 @@ jobs: terraform_wrapper: false - name: Import GPG key for Boundary pass keystore id: import_gpg - uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0 + uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0 with: gpg_private_key: ${{ secrets.ENOS_GPG_PRIVATE_KEY }} passphrase: ${{ secrets.ENOS_GPG_PASSPHRASE }} @@ -160,7 +160,7 @@ jobs: echo "debug_data_artifact_name=enos-debug-data_$(echo ${{ matrix.filter }} | sed -e 's/ /_/g' | sed -e 's/:/=/g')" >> "$GITHUB_OUTPUT" - name: Set up dependency cache id: dep-cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: /tmp/test-deps key: enos-test-deps-password-store-1.7.4-vault-1.12.2 @@ -218,12 +218,12 @@ jobs: run: | mv ${{ steps.download-docker.outputs.download-path }}/*.tar enos/support/boundary_docker_image.tar - name: Set up Node.js - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 if: contains(matrix.filter, 'e2e_ui') with: node-version: '16.x' - name: Checkout boundary-ui - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 if: contains(matrix.filter, 'e2e_ui') with: repository: hashicorp/boundary-ui @@ -266,7 +266,7 @@ jobs: SCENARIO=$(echo "${{ matrix.filter }}" | cut -d' ' -f1) echo fragment="${SCENARIO}" >> "$GITHUB_OUTPUT" - name: Upload e2e tests output - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: test-${{ steps.split.outputs.fragment }} path: enos/*.log @@ -279,7 +279,7 @@ jobs: docker logs database - name: Upload e2e UI tests debug info if: contains(matrix.filter, 'e2e_ui') && steps.run.outcome == 'failure' - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: test-e2e-ui-debug path: enos/support/src/boundary-ui/ui/admin/tests/e2e/artifacts/test-failures @@ -292,7 +292,7 @@ jobs: enos scenario launch --timeout 60m0s --chdir ./enos ${{ matrix.filter }} - name: Upload Debug Data if: ${{ always() && steps.run_retry.outcome == 'failure' }} - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: # The name of the artifact is the same as the matrix scenario name with the spaces replaced with underscores and colons replaced by equals. name: ${{ steps.prepare_scenario.outputs.debug_data_artifact_name }} @@ -327,24 +327,27 @@ jobs: env find ./enos -name "scenario.tf" -exec cat {} \; - name: Send Slack message if Run and Retry fails (or if something else went wrong) - uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 + uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # v1.26.0 # steps.run.outcome reports as failure when there is an error in `Run Enos scenario` # failure() captures errors before `Run Enos scenario` # failure() does not capture errors in `Run Enos scenario` due to continue-on-error if: ${{ failure() || (steps.run.outcome == 'failure' && steps.run_retry.outcome == 'failure') }} with: - method: chat.postMessage - token: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }} + channel-id: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }} payload: | - channel: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }} - text: ":x: e2e tests failed (${{ matrix.filter }}): ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.event.ref }}\n*SHA:* <${{ github.event.head_commit.url }}|${{ github.event.after }}>" + { + "text": ":x: e2e tests failed (${{ matrix.filter }}): ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.event.ref }}\n*SHA:* <${{ github.event.head_commit.url }}|${{ github.event.after }}>" + } + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }} - name: Send Slack message if Run but Retry passes - uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 + uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # v1.26.0 if: ${{ steps.run.outcome == 'failure' && steps.run_retry.outcome != 'failure' }} with: - method: chat.postMessage - token: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }} + channel-id: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }} payload: | - channel: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }} - text: ":warning: e2e tests passed, but needed retry (${{ matrix.filter }}): ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.event.ref }}\n*SHA:* <${{ github.event.head_commit.url }}|${{ github.event.after }}>" - + { + "text": ":warning: e2e tests passed, but needed retry (${{ matrix.filter }}): ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.event.ref }}\n*SHA:* <${{ github.event.head_commit.url }}|${{ github.event.after }}>" + } + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }} diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 6ff1baf925f..f4ab8316576 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -34,7 +34,7 @@ jobs: name: Fuzz grants.Parse runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Determine Go version id: get-go-version # We use .go-version as our source of truth for current Go @@ -42,14 +42,14 @@ jobs: run: | echo "Building with Go $(cat .go-version)" echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" - shell: bash run: go test ./internal/perms -fuzz=FuzzParse -fuzztime=30s - name: Upload fuzz failure seed corpus as run artifact if: failure() - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: fuzz-corpus path: ./internal/perms/testdata/fuzz diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 23e48b4162a..c2a5d3601b8 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -13,7 +13,7 @@ jobs: name: "Run Linter" runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Determine Go version @@ -24,7 +24,7 @@ jobs: echo "Building with Go $(cat .go-version)" echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" - name: Install Dependencies diff --git a/.github/workflows/make-gen-delta.yml b/.github/workflows/make-gen-delta.yml index cf604780b26..19476c02899 100644 --- a/.github/workflows/make-gen-delta.yml +++ b/.github/workflows/make-gen-delta.yml @@ -12,7 +12,7 @@ jobs: name: "Check for uncommitted changes from make gen" runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Determine Go version @@ -23,7 +23,7 @@ jobs: echo "Building with Go $(cat .go-version)" echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" - name: Running go mod tidy diff --git a/.github/workflows/schema-diff.yml b/.github/workflows/schema-diff.yml index 6dbecb7068b..a5ea449b014 100644 --- a/.github/workflows/schema-diff.yml +++ b/.github/workflows/schema-diff.yml @@ -30,7 +30,7 @@ jobs: if: '! github.event.pull_request.draft' runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Generate Schema Diff diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 3790d400b7d..eae85bd8062 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -17,7 +17,7 @@ jobs: github.actor != 'dependabot[bot]' && github.actor != 'hc-github-team-secure-boundary' steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Determine Go version id: get-go-version @@ -28,21 +28,21 @@ jobs: echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" cache: false - name: Set up Python - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 with: python-version: 3.x - name: Clone Security Scanner repo - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: repository: hashicorp/security-scanner - token: ${{ secrets.PRODSEC_SCANNER_READ_ONLY }} + token: ${{ secrets.HASHIBOT_PRODSEC_GITHUB_TOKEN }} path: security-scanner ref: main @@ -64,7 +64,7 @@ jobs: python3 -m pip install semgrep==1.45.0 # CodeQL - LATEST=$(gh release list --repo https://github.com/github/codeql-action | cut -f 3 | grep codeql-bundle- | sort --version-sort | tail -n1) + LATEST=$(gh release list --repo https://github.com/github/codeql-action | cut -f 3 | sort --version-sort | tail -n1) gh release download --repo https://github.com/github/codeql-action --pattern codeql-bundle-linux64.tar.gz "$LATEST" tar xf codeql-bundle-linux64.tar.gz -C "$HOME/.bin" @@ -79,7 +79,7 @@ jobs: repository: "$PWD" - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@cbe18979603527f12c7871a6eb04833ecf1548c7 # codeql-bundle-v2.19.3 + uses: github/codeql-action/upload-sarif@5c02493ebfd65b28fd3b082c65e5af2cd745d91f # codeql-bundle-v2.18.2 with: sarif_file: results.sarif diff --git a/.github/workflows/test-ci-bootstrap-oss.yml b/.github/workflows/test-ci-bootstrap-oss.yml index 54984daa9d7..d89734dc0df 100644 --- a/.github/workflows/test-ci-bootstrap-oss.yml +++ b/.github/workflows/test-ci-bootstrap-oss.yml @@ -27,7 +27,7 @@ jobs: TF_TOKEN_app_terraform_io: ${{ secrets.TF_API_TOKEN }} runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Terraform uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # TSCCR: loading action configs: failed to query HEAD reference: failed to get advertised references: authorization failed - name: Configure AWS credentials diff --git a/.github/workflows/test-ci-cleanup-oss.yml b/.github/workflows/test-ci-cleanup-oss.yml index ac792bae4c1..985ea52a531 100644 --- a/.github/workflows/test-ci-cleanup-oss.yml +++ b/.github/workflows/test-ci-cleanup-oss.yml @@ -53,7 +53,7 @@ jobs: role-skip-session-tagging: true role-duration-seconds: 3600 mask-aws-account-id: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Configure run: | cp enos/ci/aws-nuke.yml . diff --git a/.github/workflows/test-cli-ui_oss.yml b/.github/workflows/test-cli-ui_oss.yml index f47b4d237fc..5cf9d548b9f 100644 --- a/.github/workflows/test-cli-ui_oss.yml +++ b/.github/workflows/test-cli-ui_oss.yml @@ -16,10 +16,10 @@ jobs: runs-on: ${{ fromJSON(vars.RUNNER) }} name: CLI tests steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Import GPG key for Boundary pass keystore id: import_gpg - uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0 + uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0 with: gpg_private_key: ${{ secrets.ENOS_GPG_PRIVATE_KEY }} passphrase: ${{ secrets.ENOS_GPG_PASSPHRASE }} @@ -31,12 +31,12 @@ jobs: cat ~/.gnupg/gpg.conf - name: Set up Bats CLI UI tests dependency cache id: dep-cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: /tmp/bats-cli-ui-deps key: enos-bats-cli-ui-deps-jq-1.6-password-store-1.7.4-vault-1.12.2 - name: Set up Node for Bats install - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version: 16 - name: Install Bats via NPM @@ -112,10 +112,12 @@ jobs: make -C internal/tests/cli test-vault-down - name: Send Slack message if: ${{ failure() }} - uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 + uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # v1.26.0 with: - method: chat.postMessage - token: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }} + channel-id: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }} payload: | - channel: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }} - text: ":x: bats tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.event.ref }}\n*SHA:* <${{ github.event.head_commit.url }}|${{ github.event.after }}>" + { + "text": ":x: bats tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.event.ref }}\n*SHA:* <${{ github.event.head_commit.url }}|${{ github.event.after }}>" + } + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }} diff --git a/.github/workflows/test-race.yml b/.github/workflows/test-race.yml index 127e63bf478..3ca39bcc52e 100644 --- a/.github/workflows/test-race.yml +++ b/.github/workflows/test-race.yml @@ -25,7 +25,7 @@ jobs: plugin-cache-key: ${{ steps.plugin-cache-key.outputs.key }} runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Determine Go version @@ -36,7 +36,7 @@ jobs: echo "Building with Go $(cat .go-version)" echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" cache: false @@ -51,7 +51,7 @@ jobs: echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" echo "go-bin=$(go env GOPATH)/bin" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -74,7 +74,7 @@ jobs: echo "path=plugins/**/assets/*.gz" >> "$GITHUB_OUTPUT" - name: Set up plugin cache id: plugin-cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.plugin-cache-paths.outputs.path }} @@ -93,14 +93,14 @@ jobs: matrix: module: ["api", "sdk"] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ needs.setup.outputs.go-version }}" cache: false - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.cache-go-build }} @@ -125,14 +125,14 @@ jobs: ulimit -Sa echo "Hard limits" ulimit -Ha - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ needs.setup.outputs.go-version }}" cache: false - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.cache-go-build }} @@ -144,7 +144,7 @@ jobs: fail-on-cache-miss: false - name: Set up plugin cache id: plugin-cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.plugin-cache-path }} diff --git a/.github/workflows/test-sql.yml b/.github/workflows/test-sql.yml index 27007ebe279..3d974464570 100644 --- a/.github/workflows/test-sql.yml +++ b/.github/workflows/test-sql.yml @@ -18,7 +18,7 @@ jobs: postgres-version: [ latest, 12-alpine, 13-alpine, 14-alpine, 15-alpine ] name: SQL Tests ${{ matrix.postgres-version }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Run SQL PgTap Tests run: | make test-sql POSTGRES_DOCKER_IMAGE_BASE=docker.mirror.hashicorp.services/postgres PG_DOCKER_TAG=${{ matrix.postgres-version }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b7cc89c542..41b4bedbae3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: plugin-cache-key: ${{ steps.plugin-cache-key.outputs.key }} runs-on: ${{ fromJSON(vars.RUNNER) }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Determine Go version @@ -36,7 +36,7 @@ jobs: echo "Building with Go $(cat .go-version)" echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" - name: Set up Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ steps.get-go-version.outputs.go-version }}" cache: false @@ -51,7 +51,7 @@ jobs: echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" echo "go-bin=$(go env GOPATH)/bin" >> "$GITHUB_OUTPUT" - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.go-cache-paths.outputs.go-build }} @@ -74,7 +74,7 @@ jobs: echo "path=plugins/**/assets/*.gz" >> "$GITHUB_OUTPUT" - name: Set up plugin cache id: plugin-cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ steps.plugin-cache-paths.outputs.path }} @@ -93,14 +93,14 @@ jobs: matrix: module: ["api", "sdk"] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ needs.setup.outputs.go-version }}" cache: false - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.cache-go-build }} @@ -125,14 +125,14 @@ jobs: ulimit -Sa echo "Hard limits" ulimit -Ha - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "${{ needs.setup.outputs.go-version }}" cache: false - name: Set up Go modules cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.cache-go-build }} @@ -144,7 +144,7 @@ jobs: fail-on-cache-miss: false - name: Set up plugin cache id: plugin-cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | ${{ needs.setup.outputs.plugin-cache-path }} diff --git a/.github/workflows/trigger-merge-to-downstream.yml b/.github/workflows/trigger-merge-to-downstream.yml index aec3f938f39..000dcc043fc 100644 --- a/.github/workflows/trigger-merge-to-downstream.yml +++ b/.github/workflows/trigger-merge-to-downstream.yml @@ -18,7 +18,7 @@ jobs: DOWNSTREAM_TOK: ${{ secrets.DOWNSTREAM_TOK }} DOWNSTREAM_WORKFLOW: ${{ vars.DOWNSTREAM_WORKFLOW }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Trigger Merge run: | ./scripts/trigger-merge-to-downstream-gha ${{ github.ref_name }} diff --git a/.release/security-scan.hcl b/.release/security-scan.hcl index da2c1a239dd..afe49295c3d 100644 --- a/.release/security-scan.hcl +++ b/.release/security-scan.hcl @@ -5,6 +5,13 @@ container { dependencies = true alpine_secdb = true secrets = false + + triage { + suppress { + // Suppress wget vulnerability + vulnerabilities = ["CVE-2024-10524"] + } + } } binary { diff --git a/CHANGELOG.md b/CHANGELOG.md index 82520511382..9a1ea9fadf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,6 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. -## Next - -### New and Improved - -* Introduces soft-delete for users within the client cache. - ([PR](https://github.com/hashicorp/boundary/pull/5173)). - ## 0.18.1 (2024/11/21) ### New and Improved diff --git a/CODEOWNERS b/CODEOWNERS index 0f718113aa6..d896efc5916 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,7 +1,7 @@ # These owners will be the default owners for everything in # the repo, unless a later match takes precedence. -* @hashicorp/boundary +@hashicorp/boundary -# education +# web presence and education -/website/content/ @hashicorp/boundary-education-approvers +/website/ @hashicorp/boundary-education-approvers @hashicorp/web-presence @hashicorp/boundary \ No newline at end of file diff --git a/api/go.mod b/api/go.mod index 3df3f911c6a..76adc553eb4 100644 --- a/api/go.mod +++ b/api/go.mod @@ -19,7 +19,7 @@ require ( go.uber.org/atomic v1.11.0 golang.org/x/time v0.3.0 google.golang.org/grpc v1.61.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.33.0 nhooyr.io/websocket v1.8.10 ) @@ -37,8 +37,8 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/sys v0.28.0 // indirect google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/api/go.sum b/api/go.sum index 2380e4175bb..c9cb24465b1 100644 --- a/api/go.sum +++ b/api/go.sum @@ -143,8 +143,8 @@ go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -154,19 +154,19 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -189,8 +189,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/enos/ci/bootstrap/main.tf b/enos/ci/bootstrap/main.tf index 1b9f952fb66..3c778c49ce9 100644 --- a/enos/ci/bootstrap/main.tf +++ b/enos/ci/bootstrap/main.tf @@ -4,8 +4,7 @@ terraform { required_providers { aws = { - source = "hashicorp/aws" - version = "5.72.1" + source = "hashicorp/aws" } } diff --git a/enos/ci/service-user-iam/main.tf b/enos/ci/service-user-iam/main.tf index c52cc6e4dee..a8c2fd4d6e4 100644 --- a/enos/ci/service-user-iam/main.tf +++ b/enos/ci/service-user-iam/main.tf @@ -119,7 +119,6 @@ data "aws_iam_policy_document" "enos_policy_document" { "ec2:RevokeSecurityGroupIngress", "ec2:RunInstances", "ec2:TerminateInstances", - "ec2:UnassignIpv6Addresses", "elasticloadbalancing:AddTags", "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer", "elasticloadbalancing:AttachLoadBalancerToSubnets", @@ -133,7 +132,6 @@ data "aws_iam_policy_document" "enos_policy_document" { "elasticloadbalancing:DeleteRule", "elasticloadbalancing:DeleteTargetGroup", "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeListenerAttributes", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeLoadBalancerAttributes", "elasticloadbalancing:DescribeLoadBalancers", diff --git a/enos/enos.hcl b/enos/enos.hcl index d71352c566b..5bd1d82a534 100644 --- a/enos/enos.hcl +++ b/enos/enos.hcl @@ -14,8 +14,7 @@ terraform "default" { } aws = { - source = "hashicorp/aws" - version = "5.72.1" + source = "hashicorp/aws" } } } diff --git a/enos/modules/aws_bucket/main.tf b/enos/modules/aws_bucket/main.tf index 95578206682..20c7b1c3944 100644 --- a/enos/modules/aws_bucket/main.tf +++ b/enos/modules/aws_bucket/main.tf @@ -3,29 +3,10 @@ resource "random_pet" "default" {} -data "aws_caller_identity" "current" {} - resource "aws_s3_bucket" "default" { bucket_prefix = "enos-${random_pet.default.id}-" force_destroy = true - tags = merge( - local.common_tags, - { - User = "${split(":", data.aws_caller_identity.current.user_id)[1]}" - }, - ) -} - -resource "aws_s3_bucket_lifecycle_configuration" "example" { - bucket = aws_s3_bucket.default.id - - rule { - id = "file_retention" - expiration { - days = 30 - } - status = "Enabled" - } + tags = local.common_tags } data "aws_iam_policy_document" "default" { diff --git a/go.mod b/go.mod index 0f579611add..b4a7cf835e7 100644 --- a/go.mod +++ b/go.mod @@ -66,10 +66,10 @@ require ( github.com/stretchr/testify v1.9.0 github.com/zalando/go-keyring v0.2.3 go.uber.org/atomic v1.11.0 - golang.org/x/crypto v0.29.0 - golang.org/x/sync v0.9.0 - golang.org/x/sys v0.27.0 - golang.org/x/term v0.26.0 + golang.org/x/crypto v0.31.0 + golang.org/x/sync v0.10.0 + golang.org/x/sys v0.28.0 + golang.org/x/term v0.27.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 google.golang.org/grpc v1.61.1 @@ -102,7 +102,7 @@ require ( github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a github.com/sevlyar/go-daemon v0.1.6 golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 - golang.org/x/net v0.31.0 + golang.org/x/net v0.25.0 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 ) @@ -223,7 +223,7 @@ require ( github.com/xo/dburl v0.23.1 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/text v0.20.0 + golang.org/x/text v0.21.0 golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect diff --git a/go.sum b/go.sum index 068c5e08f14..b84eff74938 100644 --- a/go.sum +++ b/go.sum @@ -547,8 +547,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= @@ -583,8 +583,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= @@ -595,8 +595,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -625,8 +625,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -635,8 +635,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -647,8 +647,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/alias/target/alias_test.go b/internal/alias/target/alias_test.go index c9571b61b20..8bff6d08dc1 100644 --- a/internal/alias/target/alias_test.go +++ b/internal/alias/target/alias_test.go @@ -157,7 +157,7 @@ func TestCreate(t *testing.T) { a.PublicId, err = db.NewPublicId(ctx, globals.TargetAliasPrefix) require.NoError(t, err) - start := time.Now().UTC().Round(time.Second) + start := time.Now().UTC() err = rw.Create(ctx, a) if c.errContains != "" { @@ -169,8 +169,8 @@ func TestCreate(t *testing.T) { assert.Equal(t, a.Version, uint32(1)) assert.Equal(t, a.ScopeId, c.scope) assert.Equal(t, a.Value, c.value) - assert.GreaterOrEqual(t, a.CreateTime.AsTime().Round(time.Second), start) - assert.GreaterOrEqual(t, a.UpdateTime.AsTime().Round(time.Second), start) + assert.GreaterOrEqual(t, a.CreateTime.AsTime(), start) + assert.GreaterOrEqual(t, a.UpdateTime.AsTime(), start) if c.validate != nil { c.validate(t, a) } diff --git a/internal/clientcache/internal/cache/refresh_test.go b/internal/clientcache/internal/cache/refresh_test.go index 6f43e6b0284..38953761326 100644 --- a/internal/clientcache/internal/cache/refresh_test.go +++ b/internal/clientcache/internal/cache/refresh_test.go @@ -104,7 +104,7 @@ func testResolvableAliasStaticResourceRetrievalFunc(inFunc func(ctx context.Cont // testNoRefreshRetrievalFunc simulates a controller that doesn't support refresh // since it does not return any refresh token. -func testNoRefreshRetrievalFunc[T any](_ *testing.T) func(context.Context, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { +func testNoRefreshRetrievalFunc[T any](t *testing.T) func(context.Context, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { return func(_ context.Context, _, _ string, _ RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { return nil, nil, "", ErrRefreshNotSupported } @@ -113,7 +113,7 @@ func testNoRefreshRetrievalFunc[T any](_ *testing.T) func(context.Context, strin // testErroringForRefreshTokenRetrievalFunc returns a refresh token error when // the refresh token is not empty. This is useful for testing behavior when // the refresh token has expired or is otherwise invalid. -func testErroringForRefreshTokenRetrievalFunc[T any](_ *testing.T, ret []T) func(context.Context, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { +func testErroringForRefreshTokenRetrievalFunc[T any](t *testing.T, ret []T) func(context.Context, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { return func(ctx context.Context, s1, s2 string, refToken RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { if refToken != "" { return nil, nil, "", api.ErrInvalidListToken @@ -158,7 +158,7 @@ func testStaticResourceRetrievalFuncForId[T any](t *testing.T, ret [][]T, remove // since it does not return any refresh token. This is for retrieval // functions that require an id be provided for listing purposes like when // listing resolvable aliases. -func testNoRefreshRetrievalFuncForId[T any](_ *testing.T) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { +func testNoRefreshRetrievalFuncForId[T any](t *testing.T) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { return func(_ context.Context, _, _, _ string, _ RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { return nil, nil, "", ErrRefreshNotSupported } @@ -169,7 +169,7 @@ func testNoRefreshRetrievalFuncForId[T any](_ *testing.T) func(context.Context, // the refresh token has expired or is otherwise invalid. This is for retrieval // functions that require an id be provided for listing purposes like when // listing resolvable aliases. -func testErroringForRefreshTokenRetrievalFuncForId[T any](_ *testing.T, ret []T) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { +func testErroringForRefreshTokenRetrievalFuncForId[T any](t *testing.T, ret []T) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { return func(ctx context.Context, s1, s2, s3 string, refToken RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { if refToken != "" { return nil, nil, "", api.ErrInvalidListToken diff --git a/internal/clientcache/internal/cache/repository_refresh_token_test.go b/internal/clientcache/internal/cache/repository_refresh_token_test.go index cb092b6912f..e2c67ccabed 100644 --- a/internal/clientcache/internal/cache/repository_refresh_token_test.go +++ b/internal/clientcache/internal/cache/repository_refresh_token_test.go @@ -189,7 +189,7 @@ func TestLookupRefreshToken(t *testing.T) { }) t.Run("unknown user", func(t *testing.T) { - got, err := r.lookupRefreshToken(ctx, &user{Id: "unknownUser", Address: "addr"}, targetResourceType) + got, err := r.lookupRefreshToken(ctx, &user{Id: "unkonwnUser", Address: "addr"}, targetResourceType) assert.NoError(t, err) assert.Empty(t, got) }) @@ -209,11 +209,10 @@ func TestLookupRefreshToken(t *testing.T) { require.NoError(t, r.rw.Create(ctx, known)) before := time.Now().Truncate(time.Millisecond).UTC() - _, err := r.rw.DoTx(ctx, 1, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error { + r.rw.DoTx(ctx, 1, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error { require.NoError(t, upsertRefreshToken(ctx, w, known, targetResourceType, token)) return nil }) - require.NoError(t, err) got, err := r.lookupRefreshToken(ctx, known, targetResourceType) assert.NoError(t, err) diff --git a/internal/clientcache/internal/cache/repository_token.go b/internal/clientcache/internal/cache/repository_token.go index 1e7f8f7b275..055a1b7e32e 100644 --- a/internal/clientcache/internal/cache/repository_token.go +++ b/internal/clientcache/internal/cache/repository_token.go @@ -75,8 +75,7 @@ func upsertUserAndAuthToken(ctx context.Context, reader db.Reader, writer db.Wri } var users []*user - // we only want users that have not been soft deleted - if err := reader.SearchWhere(ctx, &users, "true", []any{}, db.WithLimit(-1), db.WithTable(activeUserTableName)); err != nil { + if err := reader.SearchWhere(ctx, &users, "true", []any{}, db.WithLimit(-1)); err != nil { return errors.Wrap(ctx, err, op) } if len(users) <= usersLimit { @@ -383,8 +382,6 @@ func cleanExpiredOrOrphanedAuthTokens(ctx context.Context, writer db.Writer, idT return nil } -const activeUserTableName = "user_active" // users that have not been soft deleted - // lookupUser returns a user if one is present in the repository or nil if not. func (r *Repository) lookupUser(ctx context.Context, id string) (*user, error) { const op = "cache.(Repository).lookupUser" @@ -393,8 +390,7 @@ func (r *Repository) lookupUser(ctx context.Context, id string) (*user, error) { return nil, errors.New(ctx, errors.InvalidParameter, op, "empty id") } ret := &user{Id: id} - // we only want users that have NOT been soft deleted - if err := r.rw.LookupById(ctx, ret, db.WithTable(activeUserTableName)); err != nil { + if err := r.rw.LookupById(ctx, ret); err != nil { if errors.IsNotFoundError(err) { return nil, nil } @@ -407,8 +403,7 @@ func (r *Repository) lookupUser(ctx context.Context, id string) (*user, error) { func (r *Repository) listUsers(ctx context.Context) ([]*user, error) { const op = "cache.(Repository).listUsers" var ret []*user - // we only want users that have NOT been soft deleted - if err := r.rw.SearchWhere(ctx, &ret, "true", nil, db.WithTable(activeUserTableName)); err != nil { + if err := r.rw.SearchWhere(ctx, &ret, "true", nil); err != nil { return nil, errors.Wrap(ctx, err, op) } return ret, nil @@ -487,31 +482,16 @@ func deleteUser(ctx context.Context, w db.Writer, u *user) (int, error) { case u.Id == "": return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing id") } - const ( - // delete the user if they don't have any refresh tokens which are - // newer than 20 days (the refresh token expiration time) - deleteStmt = "delete from user where id = ? and id not in (select user_id from refresh_token where DATETIME('now', '-20 days') < datetime(create_time) )" - - // fallback to soft deleting the user - softDeleteStmt = "update user set deleted_at = (strftime('%Y-%m-%d %H:%M:%f','now')) where id = ?" - ) - // see if we should delete the user - rowsAffected, err := w.Exec(ctx, deleteStmt, []any{u.Id}) - switch { - case err != nil: - return db.NoRowsAffected, errors.Wrap(ctx, err, op) - case rowsAffected > 0: - // if we deleted the user, we're done. - return rowsAffected, nil - } - - // fallback to soft delete - rowsAffected, err = w.Exec(ctx, softDeleteStmt, []any{u.Id}) + // TODO(https://github.com/go-gorm/gorm/issues/4879): Use the + // writer.Delete() function once the gorm bug is fixed. Until then + // the gorm driver for sqlite has an error which wont execute a + // delete correctly. as a work around we manually execute the + // query here. + n, err := w.Exec(ctx, "delete from user where id = ?", []any{u.Id}) if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op) + err = errors.Wrap(ctx, err, op) } - - return rowsAffected, nil + return n, err } // user is a gorm model for the user table. It represents a user diff --git a/internal/clientcache/internal/cache/repository_token_test.go b/internal/clientcache/internal/cache/repository_token_test.go index c41845f3162..7124e805ad1 100644 --- a/internal/clientcache/internal/cache/repository_token_test.go +++ b/internal/clientcache/internal/cache/repository_token_test.go @@ -5,21 +5,14 @@ package cache import ( "context" - "database/sql/driver" - stderrors "errors" "fmt" "sync" "testing" "time" - "github.com/hashicorp/boundary/api/aliases" "github.com/hashicorp/boundary/api/authtokens" - "github.com/hashicorp/boundary/api/sessions" - "github.com/hashicorp/boundary/api/targets" cachedb "github.com/hashicorp/boundary/internal/clientcache/internal/db" "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/go-dbw" - "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" @@ -617,7 +610,7 @@ func TestRepository_LookupToken(t *testing.T) { }) } -func TestRepository_lookupUpUser(t *testing.T) { +func TestRepository_lookupUpser(t *testing.T) { ctx := context.Background() s, err := cachedb.Open(ctx) require.NoError(t, err) @@ -657,250 +650,6 @@ func TestRepository_lookupUpUser(t *testing.T) { assert.NoError(t, err) assert.Equal(t, &user{Id: at.UserId, Address: addr}, u) }) - t.Run("soft-deleted", func(t *testing.T) { - at2 := &authtokens.AuthToken{ - Id: "at_2", - Token: "at_2_token", - UserId: "u_2", - ExpirationTime: time.Now().Add(1 * time.Minute), // not expired is required for this test - } - kt2 := KeyringToken{ - TokenName: "t2", - KeyringType: "k2", - AuthTokenId: at2.Id, - } - addr2 := "address2" - boundaryAuthTokens2 := []*authtokens.AuthToken{at2} - atMap2 := map[ringToken]*authtokens.AuthToken{ - {kt2.KeyringType, kt2.TokenName}: at2, - } - m := &sync.Map{} - r2, err := NewRepository(ctx, s, m, mapBasedAuthTokenKeyringLookup(atMap2), sliceBasedAuthTokenBoundaryReader(boundaryAuthTokens2)) - require.NoError(t, err) - assert.NoError(t, r2.AddKeyringToken(ctx, addr2, kt2)) - - rs, err := NewRefreshService(ctx, r2, hclog.NewNullLogger(), 0, 0) - require.NoError(t, err) - - retTargets := []*targets.Target{ - target("1"), - target("2"), - target("3"), - target("4"), - } - opts := []Option{ - WithAliasRetrievalFunc(testResolvableAliasStaticResourceRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil))), - WithSessionRetrievalFunc(testSessionStaticResourceRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil))), - WithTargetRetrievalFunc(testTargetStaticResourceRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, - [][]*targets.Target{ - retTargets[:3], - retTargets[3:], - }, - [][]string{ - nil, - {retTargets[0].Id, retTargets[1].Id}, - }, - ))), - } - assert.NoError(t, rs.RefreshForSearch(ctx, at2.Id, Targets, opts...)) - // Now load up a few resources and a token, and trying again should - // see the RefreshForSearch update more fields. - assert.NoError(t, rs.Refresh(ctx, opts...)) - cachedTargets, err := r.ListTargets(ctx, at2.Id) - assert.NoError(t, err) - assert.ElementsMatch(t, retTargets[:3], cachedTargets.Targets) - - // should be found in cache (user_active) - u2, err := r2.lookupUser(ctx, at2.UserId) - assert.NoError(t, err) - assert.Equal(t, &user{Id: at2.UserId, Address: addr2}, u2) - u2, err = r2.lookupUser(ctx, at2.UserId) - assert.NoError(t, err) - assert.Equal(t, &user{Id: at2.UserId, Address: addr2}, u2) - - // should be found in underlying user table as well - tu, err := testLookupUser(t, s, at2.UserId) - assert.NoError(t, err) - assert.Equal(t, &testUser{Id: at2.UserId, Address: addr2, DeletedAt: infinityValue}, tu) - - // there better be some refresh tokens - tks, err := r2.listRefreshTokens(ctx, u2) - assert.NoError(t, err) - assert.NotEmpty(t, tks) - - // now delete the user's auth_token and be sure the user is still found - // in the cache (table == "user" and not in "user_active") - err = r2.deleteKeyringToken(ctx, kt2) - require.NoError(t, err) - - currentTks, err := r2.listTokens(ctx, u2) - require.NoError(t, err) - assert.Empty(t, currentTks) - - // should no longer be an active user - u2, err = r2.lookupUser(ctx, tu.Id) - assert.NoError(t, err) - assert.Empty(t, u2) - - // should still be found in underlying user table - tu, err = testLookupUser(t, s, tu.Id) - assert.NoError(t, err) - assert.Equal(t, &testUser{Id: tu.Id, Address: tu.Address, DeletedAt: tu.DeletedAt}, tu) - }) - t.Run("hard-deleted", func(t *testing.T) { - at3 := &authtokens.AuthToken{ - Id: "at_3", - Token: "at_3_token", - UserId: "u_3", - ExpirationTime: time.Now().Add(1 * time.Minute), // not expired is required for this test - } - kt3 := KeyringToken{ - TokenName: "t3", - KeyringType: "k3", - AuthTokenId: at3.Id, - } - addr3 := "address3" - boundaryAuthTokens3 := []*authtokens.AuthToken{at3} - atMap3 := map[ringToken]*authtokens.AuthToken{ - {kt3.KeyringType, kt3.TokenName}: at3, - } - m := &sync.Map{} - r3, err := NewRepository(ctx, s, m, mapBasedAuthTokenKeyringLookup(atMap3), sliceBasedAuthTokenBoundaryReader(boundaryAuthTokens3)) - require.NoError(t, err) - assert.NoError(t, r3.AddKeyringToken(ctx, addr3, kt3)) - - // should be found in cache (user_active) - u3, err := r3.lookupUser(ctx, at3.UserId) - assert.NoError(t, err) - assert.Equal(t, &user{Id: at3.UserId, Address: addr3}, u3) - u3, err = r3.lookupUser(ctx, at3.UserId) - assert.NoError(t, err) - assert.Equal(t, &user{Id: at3.UserId, Address: addr3}, u3) - - // should be found in underlying user table as well - tu, err := testLookupUser(t, s, at3.UserId) - assert.NoError(t, err) - assert.Equal(t, &testUser{Id: at3.UserId, Address: addr3, DeletedAt: infinityValue}, tu) - - // there better be some refresh tokens - tks, err := r3.listRefreshTokens(ctx, u3) - assert.NoError(t, err) - assert.Empty(t, tks) - - // now delete the user's auth_token and be sure the user is not found - // in the cache (not in either the "user" or "user_active" tables) - err = r3.deleteKeyringToken(ctx, kt3) - require.NoError(t, err) - - currentTks, err := r3.listTokens(ctx, u3) - require.NoError(t, err) - assert.Empty(t, currentTks) - - // should no longer be an active user - u3, err = r3.lookupUser(ctx, tu.Id) - assert.NoError(t, err) - assert.Empty(t, u3) - - // should not be found in underlying user table - _, err = testLookupUser(t, s, tu.Id) - assert.Error(t, err) - assert.ErrorIs(t, err, dbw.ErrRecordNotFound) - }) -} - -// infinityValue represents a time.Time that is infinity -var infinityValue = infinityDate{ - Time: time.Time{}, - IsInfinity: true, -} - -// negInfinityValue represents a time.Time that is negative infinity -var negInfinityValue = infinityDate{ - Time: time.Time{}, - IsNegInfinity: true, -} - -// infinityDate is used to represent a time.Time that can be infinity, neg -// infinity or a regular time.Time -type infinityDate struct { - Time time.Time - IsInfinity bool - IsNegInfinity bool -} - -// sqliteDatetimeLayout defines the format for sqlite datetime ('YYYY-MM-DD HH:MM:SS.SSS') -const sqliteDatetimeLayout = "2006-01-02 15:04:05.999" - -// Scan implements the sql.Scanner interface for infinityDate -func (d *infinityDate) Scan(value any) error { - switch v := value.(type) { - case string: - if v == "infinity" { - d.IsInfinity = true - d.IsNegInfinity = false - return nil - } else if v == "-infinity" { - d.IsNegInfinity = true - d.IsInfinity = false - return nil - } else { - parsedTime, err := time.Parse(sqliteDatetimeLayout, v) - if err != nil { - return err - } - d.Time = parsedTime - d.IsInfinity = false - d.IsNegInfinity = false - return nil - } - case time.Time: - d.Time = v - d.IsInfinity = false - d.IsNegInfinity = false - return nil - } - return stderrors.New("unsupported data type for Date") -} - -// Value implements the driver.Valuer interface for infinityDate -func (d infinityDate) Value() (driver.Value, error) { - if d.IsInfinity { - return "infinity", nil - } else if d.IsNegInfinity { - return "-infinity", nil - } - return d.Time.Format(sqliteDatetimeLayout), nil -} - -// testUser is used by testLookupUser to lookup a user from the database and -// supports returning the user's DeletedAt time (soft delete). -type testUser struct { - Id string - Address string - DeletedAt infinityDate -} - -// testLookupUser is a helper function to lookup a user from the database in the -// underlying user table. -func testLookupUser(t *testing.T, conn any, id string) (*testUser, error) { - t.Helper() - var rw db.Reader - switch v := conn.(type) { - case *db.DB: - rw = db.New(v) - case db.Reader: - rw = v - } - u := &testUser{ - Id: id, - } - err := rw.LookupById(context.Background(), u, db.WithTable("user")) - switch { - case err == nil: - return u, nil - default: - return &testUser{}, err - } } func TestRepository_RemoveStaleTokens(t *testing.T) { @@ -1114,110 +863,4 @@ func TestUpsertUserAndAuthToken(t *testing.T) { return nil }) require.NoError(t, err) - t.Run("hard-and-soft-delete-oldest-user", func(t *testing.T) { - boundaryAuthTokens := make([]*authtokens.AuthToken, 0, usersLimit) - atMap := map[ringToken]*authtokens.AuthToken{} - m := &sync.Map{} - - // create usersLimit users to simulate the case where the user limit is - // reached. The Tx is required because upsertUserAndAuthToken requires - // an inflight transaction. - _, err = rw.DoTx(ctx, 1, db.ExpBackoff{}, func(txReader db.Reader, txWriter db.Writer) error { - for i := 1; i <= usersLimit; i++ { - u := &user{ - Id: fmt.Sprintf("u_%d", i), - Address: fmt.Sprintf("address_%d", i), - } - at := &authtokens.AuthToken{ - Id: fmt.Sprintf("at_%d", i), - Token: fmt.Sprintf("at_%d_token", i), - UserId: u.Id, - } - boundaryAuthTokens = append(boundaryAuthTokens, at) - atMap[ringToken{fmt.Sprintf("k_%d", i), fmt.Sprintf("t_%d", i)}] = at - err := upsertUserAndAuthToken(ctx, txReader, txWriter, u.Address, at) - require.NoError(t, err) - - } - return nil - }) - // verify that all the initial users were added - repo, err := NewRepository(ctx, s, m, mapBasedAuthTokenKeyringLookup(atMap), sliceBasedAuthTokenBoundaryReader(boundaryAuthTokens)) - require.NoError(t, err) - for i := 1; i <= usersLimit; i++ { - userId := fmt.Sprintf("u_%d", i) - foundUser, err := repo.lookupUser(ctx, userId) - require.NoError(t, err) - _, err = testLookupUser(t, s, foundUser.Id) - assert.NoError(t, err) - } - - { - // setup is done. Let's add a new user and verify that the oldest - // user is hard deleted - _, err = rw.DoTx(ctx, 1, db.ExpBackoff{}, func(txReader db.Reader, txWriter db.Writer) error { - // add a new user, which should trigger the hard deletion of the oldest user - newUser := &user{ - Id: "u_new", - Address: "address_new", - } - newUserAt := &authtokens.AuthToken{ - Id: "at_new", - Token: "at_new_token", - UserId: newUser.Id, - } - err := upsertUserAndAuthToken(ctx, txReader, txWriter, newUser.Address, newUserAt) - require.NoError(t, err) - return nil - }) - require.NoError(t, err) - - // verify that the oldest user was hard deleted - foundUser, err := repo.lookupUser(ctx, "u_1") - assert.NoError(t, err) - assert.Empty(t, foundUser) - foundTestUser, err := testLookupUser(t, s, "u_1") - assert.Error(t, err) - assert.Equal(t, &testUser{}, foundTestUser) - } - { - // Let's add a refresh token for the oldest user and then new user - // and verify that the oldest user is soft deleted - rt := &refreshToken{ - UserId: "u_2", - ResourceType: "target", - RefreshToken: "rt_2", - CreateTime: time.Now().Add(-24 * time.Hour), - UpdateTime: time.Now().Add(-24 * time.Hour), - } - err = repo.rw.Create(ctx, rt) - require.NoError(t, err) - - _, err = rw.DoTx(ctx, 1, db.ExpBackoff{}, func(txReader db.Reader, txWriter db.Writer) error { - // add a new user, which should trigger the soft deletion of the oldest user - newUser := &user{ - Id: "u_new_2", - Address: "address_new_2", - } - newUserAt := &authtokens.AuthToken{ - Id: "at_new_2", - Token: "at_new_token_2", - UserId: newUser.Id, - } - err := upsertUserAndAuthToken(ctx, txReader, txWriter, newUser.Address, newUserAt) - require.NoError(t, err) - return nil - }) - require.NoError(t, err) - - // verify that the oldest user was soft deleted - foundUser, err := repo.lookupUser(ctx, "u_2") - assert.NoError(t, err) - assert.Empty(t, foundUser) - // should not find the user in the underlying user table - foundTestUser, err := testLookupUser(t, s, "u_2") - assert.NoError(t, err) - assert.NotEqual(t, &testUser{}, foundTestUser) - } - }) } diff --git a/internal/clientcache/internal/db/db.go b/internal/clientcache/internal/db/db.go index 302b36f3703..9063cf37259 100644 --- a/internal/clientcache/internal/db/db.go +++ b/internal/clientcache/internal/db/db.go @@ -146,7 +146,7 @@ type schema struct { const ( schemaTableName = "schema_version" - schemaCurrentVersion = "v0.0.3" + schemaCurrentVersion = "v0.0.2" ) // TableName returns the table name diff --git a/internal/clientcache/internal/db/schema.sql b/internal/clientcache/internal/db/schema.sql index 4b20cd910f4..3806637716d 100644 --- a/internal/clientcache/internal/db/schema.sql +++ b/internal/clientcache/internal/db/schema.sql @@ -34,7 +34,7 @@ when end; -insert into schema_version(version) values('v0.0.3'); +insert into schema_version(version) values('v0.0.2'); -- user contains the boundary user information for the boundary user that owns -- the information in the cache. @@ -44,18 +44,9 @@ create table if not exists user ( check (length(id) > 0), -- The address of the boundary instance that this user id comes from address text not null - check (length(address) > 0), - -- deleted_at indicates when the user was soft-deleted because all - -- auth_tokens associated with the user were deleted. It is set to 'infinity' - -- for users that have not been soft-deleted. - deleted_at timestamp not null default 'infinity' + check (length(address) > 0) ); --- user_active is a view that contains only the active users in the cache. This --- view is used to prevent the cache from syncing data for users that have been --- soft-deleted. -create view user_active as select * from user where deleted_at = 'infinity'; - -- Contains the known resource types contained in the boundary client cache create table if not exists resource_type_enm( string text not null primary key @@ -120,46 +111,19 @@ create table if not exists auth_token ( ); -- *delete_orphaned_users triggers delete a user when it no longer has any --- auth tokens associated with them and they no longer have any refresh tokens --- that are less than 20 days old. This is to prevent the cache from syncing --- data for users that are no longer active. +-- auth tokens associated with them create trigger token_update_delete_orphaned_users after update on auth_token begin --- delete users that no longer have any auth tokens associated with them --- and they have no refresh tokens that are newer (less) than 20 days old. -delete from user -where - id not in (select user_id from auth_token) and - id not in (select user_id from refresh_token where DATETIME('now', '-20 days') < datetime(create_time) ); - --- soft delete users that no longer have any auth tokens associated with them --- and they haven't been previously soft deleted --- and they no longer have any refresh tokens that are newer (greater) than 20 days old. -update user set deleted_at = (strftime('%Y-%m-%d %H:%M:%f','now')) +delete from user where - id not in (select user_id from auth_token) and - deleted_at = 'infinity' and - id not in (select user_id from refresh_token where DATETIME('now', '-20 days') > datetime(create_time)); - + id not in (select user_id from auth_token); end; create trigger token_delete_delete_orphaned_users after delete on auth_token begin --- delete users that no longer have any auth tokens associated with them --- and they have no refresh tokens that are newer (less) than 20 days old. -delete from user -where - id not in (select user_id from auth_token) and - id not in (select user_id from refresh_token where DATETIME('now', '-20 days') < datetime(create_time) ); - --- soft delete users that no longer have any auth tokens associated with them --- and they haven't been previously soft deleted --- and they no longer have any refresh tokens that are newer (greater) than 20 days old. -update user set deleted_at = (strftime('%Y-%m-%d %H:%M:%f','now')) +delete from user where - id not in (select user_id from auth_token) and - deleted_at = 'infinity' and - id not in (select user_id from refresh_token where DATETIME('now', '-20 days') > datetime(create_time)); + id not in (select user_id from auth_token); end; create table if not exists keyring_token ( diff --git a/internal/cmd/base/base.go b/internal/cmd/base/base.go index 2e2c0618d19..e668743f312 100644 --- a/internal/cmd/base/base.go +++ b/internal/cmd/base/base.go @@ -38,7 +38,6 @@ const ( EnabledPluginAws EnabledPluginHostAzure EnabledPluginMinio - EnabledPluginGCP ) // MinioEnabled controls if the Minio storage plugin should be initiated or not @@ -54,8 +53,6 @@ func (e EnabledPlugin) String() string { return "Azure" case EnabledPluginMinio: return "MinIO" - case EnabledPluginGCP: - return "GCP" default: return "" } diff --git a/internal/cmd/base/dev.go b/internal/cmd/base/dev.go index e8881d5d3e5..f9300154449 100644 --- a/internal/cmd/base/dev.go +++ b/internal/cmd/base/dev.go @@ -23,7 +23,6 @@ import ( "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/boundary/testing/dbtest" capoidc "github.com/hashicorp/cap/oidc" "github.com/jimlambrt/gldap" @@ -243,9 +242,13 @@ func (b *Server) CreateDevLdapAuthMethod(ctx context.Context) error { if purpose != "api" { continue } - host, _, err = util.SplitHostPort(ln.Config.Address) + host, _, err = net.SplitHostPort(ln.Config.Address) if err != nil { - return fmt.Errorf("error splitting host/port: %w", err) + if strings.Contains(err.Error(), "missing port") { + host = ln.Config.Address + } else { + return fmt.Errorf("error splitting host/port: %w", err) + } } } if host == "" { @@ -256,16 +259,6 @@ func (b *Server) CreateDevLdapAuthMethod(ctx context.Context) error { tb := &oidcLogger{} port = testdirectory.FreePort(tb) - - // The util.SplitHostPort() method removes the square brackets that enclose the - // host address when the address type is ipv6. The square brackets must be - // added back, otherwise the gldap server will fail to start due to a parsing - // error. - if ip := net.ParseIP(host); ip != nil { - if ip.To16() != nil { - host = fmt.Sprintf("[%s]", host) - } - } b.DevLdapSetup.testDirectory = testdirectory.Start(tb, testdirectory.WithNoTLS(tb), testdirectory.WithHost(tb, host), @@ -462,12 +455,15 @@ func (b *Server) CreateDevOidcAuthMethod(ctx context.Context) error { if purpose != "api" { continue } - b.DevOidcSetup.hostAddr, b.DevOidcSetup.callbackPort, err = util.SplitHostPort(ln.Config.Address) + b.DevOidcSetup.hostAddr, b.DevOidcSetup.callbackPort, err = net.SplitHostPort(ln.Config.Address) if err != nil { - return fmt.Errorf("error splitting host/port: %w", err) - } - if b.DevOidcSetup.callbackPort == "" { - b.DevOidcSetup.callbackPort = "9200" + if strings.Contains(err.Error(), "missing port") { + b.DevOidcSetup.hostAddr = ln.Config.Address + // Use the default API port in the callback + b.DevOidcSetup.callbackPort = "9200" + } else { + return fmt.Errorf("error splitting host/port: %w", err) + } } } if b.DevOidcSetup.hostAddr == "" { diff --git a/internal/cmd/base/listener.go b/internal/cmd/base/listener.go index bfaad009def..49a32e9bce2 100644 --- a/internal/cmd/base/listener.go +++ b/internal/cmd/base/listener.go @@ -16,7 +16,6 @@ import ( _ "crypto/sha512" "crypto/tls" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-secure-stdlib/listenerutil" "github.com/hashicorp/go-secure-stdlib/reloadutil" "github.com/mitchellh/cli" @@ -138,22 +137,24 @@ func tcpListenerFactory(purpose string, l *listenerutil.ListenerConfig, ui cli.U } } - host, port, err := util.SplitHostPort(l.Address) + host, port, err := net.SplitHostPort(l.Address) if err != nil { - return "", nil, fmt.Errorf("error splitting host/port: %w", err) - } - if port == "" { - switch purpose { - case "api": - port = "9200" - case "cluster": - port = "9201" - case "proxy": - port = "9202" - case "ops": - port = "9203" - default: - return "", nil, errors.New("no purpose provided for listener and no port discoverable") + if strings.Contains(err.Error(), "missing port") { + switch purpose { + case "api": + port = "9200" + case "cluster": + port = "9201" + case "proxy": + port = "9202" + case "ops": + port = "9203" + default: + return "", nil, errors.New("no purpose provided for listener and no port discoverable") + } + host = l.Address + } else { + return "", nil, fmt.Errorf("error splitting host/port: %w", err) } } diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index 351f8a6f810..b5392a53b13 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -10,9 +10,11 @@ import ( "errors" "fmt" "io" + "net" "os" "os/signal" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -56,6 +58,10 @@ const ( WorkerAuthReqFile = "auth_request_token" ) +// This regular expression is used to find all instances of square brackets within a string. +// This regular expression is used to remove the square brackets from an IPv6 address. +var squareBrackets = regexp.MustCompile("\\[|\\]") + func init() { metric.InitializeBuildInfo(prometheus.DefaultRegisterer) } @@ -835,14 +841,20 @@ func (b *Server) SetupWorkerPublicAddress(conf *config.Config, flagValue string) } } - host, port, err := util.SplitHostPort(conf.Worker.PublicAddr) + host, port, err := net.SplitHostPort(conf.Worker.PublicAddr) if err != nil { - return fmt.Errorf("Error splitting public adddress host/port: %w", err) - } - if port == "" { - port = "9202" + if strings.Contains(err.Error(), "missing port") { + port = "9202" + host = conf.Worker.PublicAddr + } else { + return fmt.Errorf("Error splitting public adddress host/port: %w", err) + } } - conf.Worker.PublicAddr = util.JoinHostPort(host, port) + + // remove the square brackets from the ipv6 address because the method + // net.JoinHostPort() will add a second pair of square brackets. + host = squareBrackets.ReplaceAllString(host, "") + conf.Worker.PublicAddr = net.JoinHostPort(host, port) return nil } diff --git a/internal/cmd/commands/connect/connect.go b/internal/cmd/commands/connect/connect.go index aac30cac661..dbed3345dfd 100644 --- a/internal/cmd/commands/connect/connect.go +++ b/internal/cmd/commands/connect/connect.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "math" + "net" "net/netip" "os" "strconv" @@ -21,7 +22,6 @@ import ( apiproxy "github.com/hashicorp/boundary/api/proxy" "github.com/hashicorp/boundary/api/targets" "github.com/hashicorp/boundary/internal/cmd/base" - "github.com/hashicorp/boundary/internal/util" "github.com/mitchellh/cli" "github.com/posener/complete" "go.uber.org/atomic" @@ -476,10 +476,14 @@ func (c *Command) Run(args []string) (retCode int) { proxyAddr := clientProxy.ListenerAddress(context.Background()) var clientProxyHost, clientProxyPort string - clientProxyHost, clientProxyPort, err = util.SplitHostPort(proxyAddr) + clientProxyHost, clientProxyPort, err = net.SplitHostPort(proxyAddr) if err != nil { - c.PrintCliError(fmt.Errorf("error splitting listener addr: %w", err)) - return base.CommandCliError + if strings.Contains(err.Error(), "missing port") { + clientProxyHost = proxyAddr + } else { + c.PrintCliError(fmt.Errorf("error splitting listener addr: %w", err)) + return base.CommandCliError + } } c.sessInfo.Address = clientProxyHost @@ -601,11 +605,15 @@ func (c *Command) handleExec(clientProxy *apiproxy.ClientProxy, passthroughArgs addr := clientProxy.ListenerAddress(context.Background()) var host, port string var err error - host, port, err = util.SplitHostPort(addr) + host, port, err = net.SplitHostPort(addr) if err != nil { - c.PrintCliError(fmt.Errorf("Error splitting listener addr: %w", err)) - c.execCmdReturnValue.Store(int32(3)) - return + if strings.Contains(err.Error(), "missing port") { + host = addr + } else { + c.PrintCliError(fmt.Errorf("Error splitting listener addr: %w", err)) + c.execCmdReturnValue.Store(int32(3)) + return + } } var args []string diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index 6edf7369706..77bc225c69f 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "math/rand" + "net" "os" "runtime" "strings" @@ -26,7 +27,6 @@ import ( "github.com/hashicorp/boundary/internal/server" "github.com/hashicorp/boundary/internal/server/store" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-secure-stdlib/parseutil" "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/nodeenrollment" @@ -592,10 +592,13 @@ func (c *Command) Run(args []string) int { return base.CommandUserError } - host, port, err := util.SplitHostPort(c.flagHostAddress) + host, port, err := net.SplitHostPort(c.flagHostAddress) if err != nil { - c.UI.Error(fmt.Errorf("Invalid host address specified: %w", err).Error()) - return base.CommandUserError + if !strings.Contains(err.Error(), "missing port") { + c.UI.Error(fmt.Errorf("Invalid host address specified: %w", err).Error()) + return base.CommandUserError + } + host = c.flagHostAddress } if port != "" { c.UI.Error(`Port must not be specified as part of the dev host address`) @@ -821,7 +824,7 @@ func (c *Command) Run(args []string) int { } { - c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginAws, base.EnabledPluginHostAzure, base.EnabledPluginGCP) + c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginAws, base.EnabledPluginHostAzure) if base.MinioEnabled { c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginMinio) } diff --git a/internal/cmd/commands/server/controller_db_swap_test.go b/internal/cmd/commands/server/controller_db_swap_test.go index f6ee0f49e18..73abff3f662 100644 --- a/internal/cmd/commands/server/controller_db_swap_test.go +++ b/internal/cmd/commands/server/controller_db_swap_test.go @@ -115,7 +115,7 @@ func TestReloadControllerDatabase(t *testing.T) { exitCode := cmd.Run(args) if exitCode != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() @@ -241,6 +241,7 @@ func TestReloadControllerDatabase_InvalidNewDatabaseState(t *testing.T) { cfgHcl := fmt.Sprintf(dbSwapConfig, urlA, controllerKey, workerAuthKey, recoveryKey) require.NoError(t, os.WriteFile(td+"/config.hcl", []byte(cfgHcl), 0o644)) + errCh := make(chan error, 1) wg := &sync.WaitGroup{} wg.Add(1) go func() { @@ -250,12 +251,15 @@ func TestReloadControllerDatabase_InvalidNewDatabaseState(t *testing.T) { exitCode := cmd.Run(args) if exitCode != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + errCh <- fmt.Errorf("got a non-zero exit status: %s", output) + close(errCh) } }() // Wait until things are up and running (or timeout). select { + case err := <-errCh: + t.Fatal(err) case <-cmd.startedCh: case <-time.After(15 * time.Second): t.Fatal("timeout") diff --git a/internal/cmd/commands/server/controller_ratelimit_reload_test.go b/internal/cmd/commands/server/controller_ratelimit_reload_test.go index 2fce90741ea..278d00f1a6a 100644 --- a/internal/cmd/commands/server/controller_ratelimit_reload_test.go +++ b/internal/cmd/commands/server/controller_ratelimit_reload_test.go @@ -184,7 +184,7 @@ listener "tcp" { ` ) -func TestReloadControllerRateLimits(t *testing.T) { +func TestRealodControllerRateLimits(t *testing.T) { td := t.TempDir() controllerKey := config.DevKeyGeneration() @@ -209,7 +209,7 @@ func TestReloadControllerRateLimits(t *testing.T) { exitCode := cmd.Run(args) if exitCode != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() @@ -282,7 +282,7 @@ func TestReloadControllerRateLimits(t *testing.T) { wg.Wait() } -func TestReloadControllerRateLimitsSameConfig(t *testing.T) { +func TestRealodControllerRateLimitsSameConfig(t *testing.T) { td := t.TempDir() // Create and migrate database A and B. @@ -308,7 +308,7 @@ func TestReloadControllerRateLimitsSameConfig(t *testing.T) { exitCode := cmd.Run(args) if exitCode != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() @@ -377,7 +377,7 @@ func TestReloadControllerRateLimitsSameConfig(t *testing.T) { wg.Wait() } -func TestReloadControllerRateLimitsDisable(t *testing.T) { +func TestRealodControllerRateLimitsDisable(t *testing.T) { td := t.TempDir() controllerKey := config.DevKeyGeneration() @@ -402,7 +402,7 @@ func TestReloadControllerRateLimitsDisable(t *testing.T) { exitCode := cmd.Run(args) if exitCode != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() @@ -475,7 +475,7 @@ func TestReloadControllerRateLimitsDisable(t *testing.T) { wg.Wait() } -func TestReloadControllerRateLimitsEnable(t *testing.T) { +func TestRealodControllerRateLimitsEnable(t *testing.T) { td := t.TempDir() controllerKey := config.DevKeyGeneration() @@ -501,7 +501,7 @@ func TestReloadControllerRateLimitsEnable(t *testing.T) { exitCode := cmd.Run(args) if exitCode != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() diff --git a/internal/cmd/commands/server/listener_reload_test.go b/internal/cmd/commands/server/listener_reload_test.go index a5472f45013..809e6ca7cda 100644 --- a/internal/cmd/commands/server/listener_reload_test.go +++ b/internal/cmd/commands/server/listener_reload_test.go @@ -132,7 +132,7 @@ func TestServer_ReloadListener(t *testing.T) { defer wg.Done() if code := cmd.Run(args); code != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index 5badbfa4c76..a57c3b81371 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -26,7 +26,6 @@ import ( "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/event" "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-secure-stdlib/mlock" "github.com/hashicorp/go-secure-stdlib/parseutil" @@ -356,10 +355,14 @@ func (c *Command) Run(args []string) int { } } for _, upstream := range c.Config.Worker.InitialUpstreams { - host, _, err := util.SplitHostPort(upstream) + host, _, err := net.SplitHostPort(upstream) if err != nil { - c.UI.Error(fmt.Errorf("Invalid worker upstream address %q: %w", upstream, err).Error()) - return base.CommandUserError + if strings.Contains(err.Error(), globals.MissingPortErrStr) { + host = upstream + } else { + c.UI.Error(fmt.Errorf("Invalid worker upstream address %q: %w", upstream, err).Error()) + return base.CommandUserError + } } ip := net.ParseIP(host) if ip != nil { @@ -410,10 +413,14 @@ func (c *Command) Run(args []string) int { if purpose != "cluster" { continue } - host, _, err := util.SplitHostPort(ln.Address) + host, _, err := net.SplitHostPort(ln.Address) if err != nil { - c.UI.Error(fmt.Errorf("Invalid cluster listener address %q: %w", ln.Address, err).Error()) - return base.CommandUserError + if strings.Contains(err.Error(), globals.MissingPortErrStr) { + host = ln.Address + } else { + c.UI.Error(fmt.Errorf("Invalid cluster listener address %q: %w", ln.Address, err).Error()) + return base.CommandUserError + } } ip := net.ParseIP(host) if ip != nil { @@ -492,7 +499,7 @@ func (c *Command) Run(args []string) int { } } - c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginAws, base.EnabledPluginHostAzure, base.EnabledPluginGCP) + c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginAws, base.EnabledPluginHostAzure) if base.MinioEnabled { c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginMinio) } diff --git a/internal/cmd/commands/server/worker_initial_upstreams_reload_test.go b/internal/cmd/commands/server/worker_initial_upstreams_reload_test.go index a16935ce933..24b7b36fb11 100644 --- a/internal/cmd/commands/server/worker_initial_upstreams_reload_test.go +++ b/internal/cmd/commands/server/worker_initial_upstreams_reload_test.go @@ -75,7 +75,7 @@ func TestServer_ReloadInitialUpstreams(t *testing.T) { defer wg.Done() if code := cmd.Run(nil); code != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() diff --git a/internal/cmd/commands/server/worker_tags_reload_test.go b/internal/cmd/commands/server/worker_tags_reload_test.go index b6f8729c4ba..4159b9f181e 100644 --- a/internal/cmd/commands/server/worker_tags_reload_test.go +++ b/internal/cmd/commands/server/worker_tags_reload_test.go @@ -87,7 +87,7 @@ func TestServer_ReloadWorkerTags(t *testing.T) { defer wg.Done() if code := cmd.Run(nil); code != 0 { output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() - fmt.Printf("%s: got a non-zero exit status: %s", t.Name(), output) + t.Errorf("got a non-zero exit status: %s", output) } }() diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index b66ea720bcb..6b2dbbc1a4e 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -15,6 +15,7 @@ import ( "net" "os" "reflect" + "regexp" "strconv" "strings" "time" @@ -102,84 +103,6 @@ listener "tcp" { purpose = "ops" tls_disable = true } -` - - devIpv6ControllerExtraConfig = ` -controller { - name = "dev-controller" - description = "A default controller created in dev mode" -} - -kms "aead" { - purpose = "root" - aead_type = "aes-gcm" - key = "%s" - key_id = "global_root" -} - -kms "aead" { - purpose = "worker-auth" - aead_type = "aes-gcm" - key = "%s" - key_id = "global_worker-auth" -} - -kms "aead" { - purpose = "bsr" - aead_type = "aes-gcm" - key = "%s" - key_id = "global_bsr" -} - -kms "aead" { - purpose = "recovery" - aead_type = "aes-gcm" - key = "%s" - key_id = "global_recovery" -} - -listener "tcp" { - address = "[::1]" - purpose = "api" - tls_disable = true - cors_enabled = true - cors_allowed_origins = ["*"] -} - -listener "tcp" { - address = "[::1]" - purpose = "cluster" -} - -listener "tcp" { - address = "[::1]" - purpose = "ops" - tls_disable = true -} -` - - devIpv6WorkerExtraConfig = ` -listener "tcp" { - address = "[::1]" - purpose = "proxy" -} - -worker { - name = "w_1234567890" - description = "A default worker created in dev mode" - public_addr = "[::1]" - initial_upstreams = ["[::1]"] - tags { - type = ["dev", "local"] - } -} - -kms "aead" { - purpose = "worker-auth-storage" - aead_type = "aes-gcm" - key = "%s" - key_id = "worker-auth-storage" -} ` devWorkerExtraConfig = ` @@ -210,6 +133,10 @@ kms "aead" { defaultCsp = "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'" ) +// This regular expression is used to find all instances of square brackets within a string. +// This regular expression is used to remove the square brackets from an IPv6 address. +var squareBrackets = regexp.MustCompile("\\[|\\]") + // Config is the configuration for the boundary controller type Config struct { *configutil.SharedConfig `hcl:"-"` @@ -451,18 +378,15 @@ type License struct { // WithAuditEventsEnabled, TestWithErrorEventsEnabled func DevWorker(opt ...Option) (*Config, error) { workerAuthStorageKey := DevKeyGeneration() - opts, err := getOpts(opt...) - if err != nil { - return nil, fmt.Errorf("error parsing options: %w", err) - } hclStr := fmt.Sprintf(devConfig+devWorkerExtraConfig, workerAuthStorageKey) - if opts.withIPv6Enabled { - hclStr = fmt.Sprintf(devConfig+devIpv6WorkerExtraConfig, workerAuthStorageKey) - } parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) } + opts, err := getOpts(opt...) + if err != nil { + return nil, fmt.Errorf("error parsing options: %w", err) + } parsed.Eventing.AuditEnabled = opts.withAuditEventsEnabled parsed.Eventing.ObservationsEnabled = opts.withObservationsEnabled parsed.Eventing.SysEventsEnabled = opts.withSysEventsEnabled @@ -490,20 +414,12 @@ func DevKeyGeneration() string { // DevController is a Config that is used for dev mode of Boundary // controllers func DevController(opt ...Option) (*Config, error) { - opts, err := getOpts(opt...) - if err != nil { - return nil, fmt.Errorf("error parsing options: %w", err) - } - controllerKey := DevKeyGeneration() workerAuthKey := DevKeyGeneration() bsrKey := DevKeyGeneration() recoveryKey := DevKeyGeneration() hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey) - if opts.withIPv6Enabled { - hclStr = fmt.Sprintf(devConfig+devIpv6ControllerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey) - } parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) @@ -513,6 +429,10 @@ func DevController(opt ...Option) (*Config, error) { parsed.DevWorkerAuthKey = workerAuthKey parsed.DevBsrKey = bsrKey parsed.DevRecoveryKey = recoveryKey + opts, err := getOpts(opt...) + if err != nil { + return nil, fmt.Errorf("error parsing options: %w", err) + } parsed.Eventing.AuditEnabled = opts.withAuditEventsEnabled parsed.Eventing.ObservationsEnabled = opts.withObservationsEnabled parsed.Eventing.SysEventsEnabled = opts.withSysEventsEnabled @@ -520,22 +440,13 @@ func DevController(opt ...Option) (*Config, error) { return parsed, nil } -func DevCombined(opt ...Option) (*Config, error) { - opts, err := getOpts(opt...) - if err != nil { - return nil, fmt.Errorf("error parsing options: %w", err) - } - +func DevCombined() (*Config, error) { controllerKey := DevKeyGeneration() workerAuthKey := DevKeyGeneration() workerAuthStorageKey := DevKeyGeneration() bsrKey := DevKeyGeneration() recoveryKey := DevKeyGeneration() - hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey, workerAuthStorageKey) - if opts.withIPv6Enabled { - hclStr = fmt.Sprintf(devConfig+devIpv6ControllerExtraConfig+devIpv6WorkerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey, workerAuthStorageKey) - } parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) @@ -1344,14 +1255,20 @@ func (c *Config) SetupControllerPublicClusterAddress(flagValue string) error { } } - host, port, err := util.SplitHostPort(c.Controller.PublicClusterAddr) + host, port, err := net.SplitHostPort(c.Controller.PublicClusterAddr) if err != nil { - return fmt.Errorf("Error splitting public cluster adddress host/port: %w", err) - } - if port == "" { - port = "9201" + if strings.Contains(err.Error(), "missing port") { + port = "9201" + host = c.Controller.PublicClusterAddr + } else { + return fmt.Errorf("Error splitting public cluster adddress host/port: %w", err) + } } - c.Controller.PublicClusterAddr = util.JoinHostPort(host, port) + + // remove the square brackets from the ipv6 address because the method + // net.JoinHostPort() will add a second pair of square brackets. + host = squareBrackets.ReplaceAllString(host, "") + c.Controller.PublicClusterAddr = net.JoinHostPort(host, port) return nil } @@ -1405,7 +1322,11 @@ func (c *Config) SetupWorkerInitialUpstreams() error { break } // Best effort see if it's a domain name and if not assume it must match - host, _, err := util.SplitHostPort(c.Worker.InitialUpstreams[0]) + host, _, err := net.SplitHostPort(c.Worker.InitialUpstreams[0]) + if err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr) { + err = nil + host = c.Worker.InitialUpstreams[0] + } if err == nil { ip := net.ParseIP(host) if ip == nil { diff --git a/internal/cmd/config/config_test.go b/internal/cmd/config/config_test.go index 56f4d834b14..30449cc7baa 100644 --- a/internal/cmd/config/config_test.go +++ b/internal/cmd/config/config_test.go @@ -6,7 +6,6 @@ package config import ( "encoding/base64" "fmt" - "net" "net/http" "os" "testing" @@ -14,7 +13,6 @@ import ( "github.com/hashicorp/boundary/internal/event" "github.com/hashicorp/boundary/internal/ratelimit" - "github.com/hashicorp/boundary/internal/util" configutil "github.com/hashicorp/go-secure-stdlib/configutil/v2" "github.com/hashicorp/go-secure-stdlib/listenerutil" "github.com/hashicorp/go-secure-stdlib/parseutil" @@ -781,101 +779,6 @@ func TestDevWorkerRecordingStoragePath(t *testing.T) { } } -func TestDevControllerIpv6(t *testing.T) { - require, assert := require.New(t), assert.New(t) - // This test only validates that all listeners are utilizing an IPv6 address. - // Other dev controller configurations are validates in TestDevController. - actual, err := DevController(WithIPv6Enabled(true)) - require.NoError(err) - - // expected an error here because we purposely did not provide a port number - // to allow randomly assigned port values - _, _, err = net.SplitHostPort(actual.Controller.PublicClusterAddr) - require.Error(err) - - // assert the square brackets are removed from the host ipv6 address and that the port value is empty - publicAddr, port, err := util.SplitHostPort(actual.Controller.PublicClusterAddr) - require.NoError(err) - assert.Empty(port) - assert.Empty(publicAddr) - - require.NotEmpty(actual.Listeners) - for _, l := range actual.Listeners { - addr, _, err := util.SplitHostPort(l.Address) - require.NoError(err) - ip := net.ParseIP(addr) - assert.NotNil(ip, "failed to parse listener address for %v", l.Purpose) - assert.NotNil(ip.To16(), "failed to convert address to IPv6 for %v, found %v", l.Purpose, addr) - } -} - -func TestDevWorkerIpv6(t *testing.T) { - require, assert := require.New(t), assert.New(t) - // This test only validates that all listeners are utilizing an IPv6 address. - // Other dev worker configurations are validates in TestDevWorker. - actual, err := DevWorker(WithIPv6Enabled(true)) - require.NoError(err) - - // expected an error here because we purposely did not provide a port number - // to allow randomly assigned port values - _, _, err = net.SplitHostPort(actual.Worker.PublicAddr) - require.Error(err) - - // assert the square brackets are removed from the worker ipv6 address and that the port value is empty - publicAddr, port, err := util.SplitHostPort(actual.Worker.PublicAddr) - require.NoError(err) - assert.Empty(port) - ip := net.ParseIP(publicAddr) - assert.NotNil(ip, "failed to parse worker public address") - assert.NotNil(ip.To16(), "worker public address is not IPv6 %s", actual.Worker.PublicAddr) - - require.NotEmpty(actual.Listeners) - for _, l := range actual.Listeners { - addr, _, err := util.SplitHostPort(l.Address) - require.NoError(err) - ip := net.ParseIP(addr) - assert.NotNil(ip, "failed to parse listener address for %v", l.Purpose) - assert.NotNil(ip.To16(), "failed to convert address to IPv6 for %v, found %v", l.Purpose, addr) - } -} - -func TestDevCombinedIpv6(t *testing.T) { - require, assert := require.New(t), assert.New(t) - // This test only validates that all listeners are utilizing an IPv6 address. - actual, err := DevCombined(WithIPv6Enabled(true)) - require.NoError(err) - - // expected an error here because we purposely did not provide a port number - // to allow randomly assigned port values for the worker and controller - _, _, err = net.SplitHostPort(actual.Worker.PublicAddr) - require.Error(err) - _, _, err = net.SplitHostPort(actual.Controller.PublicClusterAddr) - require.Error(err) - - // assert the square brackets are removed from the host ipv6 address and that the port value is empty - publicAddr, port, err := util.SplitHostPort(actual.Worker.PublicAddr) - require.NoError(err) - assert.Empty(port) - ip := net.ParseIP(publicAddr) - assert.NotNil(ip, "failed to parse worker public address") - assert.NotNil(ip.To16(), "worker public address is not IPv6 %s", actual.Worker.PublicAddr) - - // assert the square brackets are removed from the controller ipv6 address and that the port value is empty - publicAddr, port, err = util.SplitHostPort(actual.Controller.PublicClusterAddr) - require.NoError(err) - assert.Empty(port) - assert.Empty(publicAddr) - - require.NotEmpty(actual.Listeners) - for _, l := range actual.Listeners { - addr, _, err := util.SplitHostPort(l.Address) - require.NoError(err) - ip := net.ParseIP(addr) - assert.NotNil(ip, "failed to parse listener address for %v", l.Purpose) - assert.NotNil(ip.To16(), "failed to convert address to IPv6 for %v, found %v", l.Purpose, addr) - } -} - func TestDevKeyGeneration(t *testing.T) { t.Parallel() dk := DevKeyGeneration() diff --git a/internal/cmd/config/options.go b/internal/cmd/config/options.go index e95564f7862..aed401b7a3e 100644 --- a/internal/cmd/config/options.go +++ b/internal/cmd/config/options.go @@ -35,7 +35,6 @@ type options struct { withSysEventsEnabled bool withAuditEventsEnabled bool withObservationsEnabled bool - withIPv6Enabled bool testWithErrorEventsEnabled bool } @@ -60,12 +59,6 @@ func getDefaultOptions() (options, error) { } opts.withObservationsEnabled = obs - ipv6, err := parseutil.ParseBool(os.Getenv("BOUNDARY_ENABLE_TEST_IPV6")) - if err != nil { - return opts, err - } - opts.withIPv6Enabled = ipv6 - errEvents, err := parseutil.ParseBool(os.Getenv("BOUNDARY_ENABLE_TEST_ERROR_EVENTS")) if err != nil { return opts, err @@ -99,14 +92,6 @@ func WithObservationsEnabled(enable bool) Option { } } -// WithIPv6Enabled provides an option for enabling network ipv6 addresses -func WithIPv6Enabled(enable bool) Option { - return func(o *options) error { - o.withIPv6Enabled = enable - return nil - } -} - // TestWithErrorEventsEnabled provides an option for enabling error events // during tests. func TestWithErrorEventsEnabled(_ testing.TB, enable bool) Option { diff --git a/internal/daemon/controller/controller.go b/internal/daemon/controller/controller.go index 57200a7a625..3ac24f483e6 100644 --- a/internal/daemon/controller/controller.go +++ b/internal/daemon/controller/controller.go @@ -45,6 +45,7 @@ import ( "github.com/hashicorp/boundary/internal/ratelimit" "github.com/hashicorp/boundary/internal/recording" "github.com/hashicorp/boundary/internal/scheduler" + "github.com/hashicorp/boundary/internal/scheduler/cleaner" "github.com/hashicorp/boundary/internal/scheduler/job" "github.com/hashicorp/boundary/internal/server" serversjob "github.com/hashicorp/boundary/internal/server/job" @@ -320,8 +321,6 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { if _, err := conf.RegisterPlugin(ctx, pluginType, client, []plugin.PluginType{plugin.PluginTypeHost}, plugin.WithDescription(fmt.Sprintf("Built-in %s host plugin", enabledPlugin.String()))); err != nil { return nil, fmt.Errorf("error registering %s host plugin: %w", pluginType, err) } - case enabledPlugin == base.EnabledPluginGCP && !c.conf.SkipPlugins: - fallthrough case enabledPlugin == base.EnabledPluginAws && !c.conf.SkipPlugins: pluginType := strings.ToLower(enabledPlugin.String()) client, cleanup, err := external_plugins.CreateHostPlugin( @@ -398,8 +397,8 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { jobRepoFn := func() (*job.Repository, error) { return job.NewRepository(ctx, dbase, dbase, c.kms) } - - schedulerOpts := []scheduler.Option{} + // TODO: Allow setting run jobs limit from config + schedulerOpts := []scheduler.Option{scheduler.WithRunJobsLimit(-1)} if c.conf.RawConfig.Controller.Scheduler.JobRunIntervalDuration > 0 { schedulerOpts = append(schedulerOpts, scheduler.WithRunJobsInterval(c.conf.RawConfig.Controller.Scheduler.JobRunIntervalDuration)) } @@ -638,6 +637,9 @@ func (c *Controller) registerJobs() error { if err := kmsjob.RegisterJobs(c.baseContext, c.scheduler, c.kms); err != nil { return err } + if err := cleaner.RegisterJob(c.baseContext, c.scheduler, rw); err != nil { + return err + } if err := snapshot.RegisterJob(c.baseContext, c.scheduler, rw, rw); err != nil { return err } diff --git a/internal/daemon/controller/controller_test.go b/internal/daemon/controller/controller_test.go index 1c6dd54aa92..0dfb72ab81f 100644 --- a/internal/daemon/controller/controller_test.go +++ b/internal/daemon/controller/controller_test.go @@ -257,7 +257,6 @@ func TestController_NewPluginsConfig(t *testing.T) { conf.EnabledPlugins = []base.EnabledPlugin{ base.EnabledPluginAws, base.EnabledPluginHostAzure, - base.EnabledPluginGCP, } _, err = New(testCtx, conf) @@ -266,15 +265,14 @@ func TestController_NewPluginsConfig(t *testing.T) { // Check that both plugins were written to the temp dir files, err := os.ReadDir(tmpDir) require.NoError(err) - require.Len(files, 3) + require.Len(files, 2) for _, file := range files { name := filepath.Base(file.Name()) // Remove random chars and hyphen name = name[0 : len(name)-6] switch name { case boundary_plugin_assets.PluginPrefix + "aws", - boundary_plugin_assets.PluginPrefix + "azure", - boundary_plugin_assets.PluginPrefix + "gcp": + boundary_plugin_assets.PluginPrefix + "azure": default: require.Fail("unexpected name", name) } diff --git a/internal/daemon/controller/handlers/targets/target_service.go b/internal/daemon/controller/handlers/targets/target_service.go index f6e92d28d1e..e05eeaec49b 100644 --- a/internal/daemon/controller/handlers/targets/target_service.go +++ b/internal/daemon/controller/handlers/targets/target_service.go @@ -42,7 +42,6 @@ import ( "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/types/scope" "github.com/hashicorp/boundary/internal/types/subtypes" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets" fm "github.com/hashicorp/boundary/version" @@ -968,10 +967,17 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession "No host was discovered after checking target address and host sources.") } - // Ensure we don't have a port from the address - _, err = util.ParseAddress(ctx, h) - if err != nil { + // Ensure we don't have a port from the address, which would be unexpected + _, _, err = net.SplitHostPort(h) + switch { + case err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr): + // This is what we expect + case err != nil: return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error when parsing the chosen endpoint host address")) + case err == nil: + return nil, handlers.ApiErrorWithCodeAndMessage( + codes.FailedPrecondition, + "Address specified for use unexpectedly contains a port.") } // Generate the endpoint URL diff --git a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go index 836c6a28b75..92274e83e1c 100644 --- a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go +++ b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go @@ -4409,104 +4409,57 @@ func TestAuthorizeSession_Errors(t *testing.T) { assert.Equal(t, 1, num) v.RevokeToken(t, tok1) - workerExists := func(tar target.Target) target.Target { + workerExists := func(tar target.Target) (version uint32) { server.TestKmsWorker(t, conn, wrapper) - return tar + return tar.GetVersion() } - hostSetNoHostExists := func(tar target.Target) target.Target { + hostSetNoHostExists := func(tar target.Target) (version uint32) { hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - _, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ - Id: tar.GetPublicId(), - Version: tar.GetVersion(), - HostSourceIds: []string{hs.GetPublicId()}, - }) - require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar - } - hostExists := func(tar target.Target) target.Target { - hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] - h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] - hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - _, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ + tr, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ Id: tar.GetPublicId(), Version: tar.GetVersion(), HostSourceIds: []string{hs.GetPublicId()}, }) require.NoError(t, err) - hostRepo, err := staticHostRepoFn() - require.NoError(t, err) - _, _, err = hostRepo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"}) - require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar + return tr.GetItem().GetVersion() } - hostWithoutPort := func(tar target.Target) target.Target { + hostExists := func(tar target.Target) (version uint32) { hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - _, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ - Id: tar.GetPublicId(), - Version: tar.GetVersion(), - HostSourceIds: []string{hs.GetPublicId()}, - }) - require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar - } - - ipv4HostWithHostPort := func(tar target.Target) target.Target { - hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] - h := static.TestHost(t, conn, hc.GetPublicId(), static.WithAddress("8.8.8.8:22")) - hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - _, err := s.SetTargetHostSources(ctx, &pbs.SetTargetHostSourcesRequest{ + apiTar, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ Id: tar.GetPublicId(), Version: tar.GetVersion(), HostSourceIds: []string{hs.GetPublicId()}, }) require.NoError(t, err) - repo, err := repoFn() + repo, err := staticHostRepoFn() require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + _, _, err = repo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"}) require.NoError(t, err) - return tar + return apiTar.GetItem().GetVersion() } - ipv6HostWithHostPort := func(tar target.Target) target.Target { + hostWithoutPort := func(tar target.Target) (version uint32) { hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] - h := static.TestHost(t, conn, hc.GetPublicId(), static.WithAddress("[2001:4860:4860:0:0:0:0:8888]:22")) + h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - _, err := s.SetTargetHostSources(ctx, &pbs.SetTargetHostSourcesRequest{ + apiTar, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ Id: tar.GetPublicId(), Version: tar.GetVersion(), HostSourceIds: []string{hs.GetPublicId()}, }) require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar + return apiTar.GetItem().GetVersion() } - libraryExists := func(tar target.Target) target.Target { + libraryExists := func(tar target.Target) (version uint32) { credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ @@ -4521,21 +4474,17 @@ func TestAuthorizeSession_Errors(t *testing.T) { }}) require.NoError(t, err) - _, err = s.AddTargetCredentialSources(ctx, + tr, err := s.AddTargetCredentialSources(ctx, &pbs.AddTargetCredentialSourcesRequest{ Id: tar.GetPublicId(), BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()}, Version: tar.GetVersion(), }) require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar + return tr.GetItem().GetVersion() } - misConfiguredlibraryExists := func(tar target.Target) target.Target { + misConfiguredlibraryExists := func(tar target.Target) (version uint32) { credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ @@ -4550,21 +4499,17 @@ func TestAuthorizeSession_Errors(t *testing.T) { }}) require.NoError(t, err) - _, err = s.AddTargetCredentialSources(ctx, + tr, err := s.AddTargetCredentialSources(ctx, &pbs.AddTargetCredentialSourcesRequest{ Id: tar.GetPublicId(), BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()}, Version: tar.GetVersion(), }) require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar + return tr.GetItem().GetVersion() } - expiredTokenLibrary := func(tar target.Target) target.Target { + expiredTokenLibrary := func(tar target.Target) (version uint32) { credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ @@ -4579,18 +4524,14 @@ func TestAuthorizeSession_Errors(t *testing.T) { }}) require.NoError(t, err) - _, err = s.AddTargetCredentialSources(ctx, + tr, err := s.AddTargetCredentialSources(ctx, &pbs.AddTargetCredentialSourcesRequest{ Id: tar.GetPublicId(), BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()}, Version: tar.GetVersion(), }) require.NoError(t, err) - repo, err := repoFn() - require.NoError(t, err) - tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) - require.NoError(t, err) - return tar + return tr.GetItem().GetVersion() } // Generate correlation Id and add it to the context @@ -4602,7 +4543,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { cases := []struct { name string ctx context.Context - setup []func(target.Target) target.Target + setup []func(target.Target) uint32 useTargetId bool wantErr bool wantErrContains string @@ -4611,100 +4552,70 @@ func TestAuthorizeSession_Errors(t *testing.T) { // This one must be run first since it relies on the DB not having any worker details name: "no worker", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) uint32{hostExists, libraryExists}, useTargetId: true, wantErrContains: "No workers are available to handle this session", }, { name: "success", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, libraryExists}, useTargetId: true, }, { name: "no target", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, libraryExists}, useTargetId: false, wantErrContains: "Resource not found", }, { name: "no host port", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostWithoutPort, libraryExists}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostWithoutPort, libraryExists}, useTargetId: true, }, { - name: "ipv4 target address host port", + name: "host port", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{ - workerExists, func(tcpTarget target.Target) target.Target { + setup: []func(tcpTarget target.Target) uint32{ + workerExists, func(tcpTarget target.Target) uint32 { + tcpTarget.SetAddress("127.0.0.1:22") repo, err := repoFn() require.NoError(t, err) - n, err := repo.DeleteTarget(ctx, tcpTarget.GetPublicId()) + tcpTarget, _, err = repo.UpdateTarget(ctx, tcpTarget, tcpTarget.GetVersion(), []string{"address"}) require.NoError(t, err) - assert.Equal(t, 1, n) - return tcp.TestTarget(ctx, t, conn, tcpTarget.GetProjectId(), tcpTarget.GetName(), target.WithAddress("127.0.0.1:22"), target.WithDefaultPort(22)) + return tcpTarget.GetVersion() }, }, - wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", - useTargetId: true, - }, - { - name: "ipv6 target address host port", - ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{ - workerExists, func(tcpTarget target.Target) target.Target { - repo, err := repoFn() - require.NoError(t, err) - n, err := repo.DeleteTarget(ctx, tcpTarget.GetPublicId()) - require.NoError(t, err) - assert.Equal(t, 1, n) - return tcp.TestTarget(ctx, t, conn, tcpTarget.GetProjectId(), tcpTarget.GetName(), target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:22"), target.WithDefaultPort(22)) - }, - }, - wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", - useTargetId: true, - }, - { - name: "ipv4 static host port", - ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{ipv4HostWithHostPort}, - wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", - useTargetId: true, - }, - { - name: "ipv6 static host port", - ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{ipv6HostWithHostPort}, - wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", + wantErrContains: "Address specified for use unexpectedly contains a port", useTargetId: true, }, { name: "no hosts", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostSetNoHostExists, libraryExists}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostSetNoHostExists, libraryExists}, useTargetId: true, wantErrContains: "No host sources or address found for given target", }, { name: "bad library configuration", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, misConfiguredlibraryExists}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, misConfiguredlibraryExists}, useTargetId: true, wantErrContains: "external system issue: error #3014: Error making API request", }, { name: "expired token library", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, expiredTokenLibrary}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, expiredTokenLibrary}, useTargetId: true, wantErrContains: "vault.newClient: invalid configuration", }, { name: "no correaltion id", ctx: ctx, - setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, libraryExists}, useTargetId: true, wantErrContains: "authorize session: missing correlation id", }, @@ -4715,7 +4626,8 @@ func TestAuthorizeSession_Errors(t *testing.T) { tar := tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), fmt.Sprintf("test-%d", i), target.WithDefaultPort(22)) for _, fn := range tc.setup { - tar = fn(tar) + ver := fn(tar) + tar.SetVersion(ver) } id := tar.GetPublicId() diff --git a/internal/daemon/controller/testing.go b/internal/daemon/controller/testing.go index abf2e767593..41dc57d2bae 100644 --- a/internal/daemon/controller/testing.go +++ b/internal/daemon/controller/testing.go @@ -503,8 +503,6 @@ type TestControllerOpts struct { WorkerAuthDebuggingEnabled *atomic.Bool DisableRateLimiting bool - - EnableIPv6 bool } func NewTestController(t testing.TB, opts *TestControllerOpts) *TestController { @@ -589,8 +587,7 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController, opts.Config = cfg case opts.Config == nil: - cfgOpts := append([]config.Option{}, config.WithIPv6Enabled(true)) - opts.Config, err = config.DevController(cfgOpts...) + opts.Config, err = config.DevController() if err != nil { t.Fatal(err) } diff --git a/internal/daemon/controller/testing_test.go b/internal/daemon/controller/testing_test.go index 52e0bc4eeb2..57af31cb5da 100644 --- a/internal/daemon/controller/testing_test.go +++ b/internal/daemon/controller/testing_test.go @@ -7,9 +7,7 @@ import ( "bytes" "context" "io" - "net" "os" - "strings" "testing" "github.com/hashicorp/boundary/globals" @@ -101,26 +99,3 @@ func Test_TestController(t *testing.T) { assert.NotNil(ws.Bsr()) }) } - -func Test_TestControllerIPv6(t *testing.T) { - require, assert := require.New(t), assert.New(t) - c := NewTestController(t, &TestControllerOpts{ - EnableIPv6: true, - }) - require.NotNil(c) - validateIPv6 := func(addr, name string) { - host, _, err := net.SplitHostPort(addr) - require.NoError(err) - require.NotEmpty(host, "missing host") - ip := net.ParseIP(host) - assert.NotNil(ip, "failed to parse %s", name) - assert.NotNil(ip.To16(), "%s is not IPv6 %s", name, addr) - } - for _, addr := range c.ClusterAddrs() { - validateIPv6(addr, "cluster addr") - } - for _, addr := range c.ApiAddrs() { - addr = strings.ReplaceAll(addr, "http://", "") - validateIPv6(addr, "api addr") - } -} diff --git a/internal/daemon/worker/controller_connection.go b/internal/daemon/worker/controller_connection.go index d766ae00c59..33bd766f4d0 100644 --- a/internal/daemon/worker/controller_connection.go +++ b/internal/daemon/worker/controller_connection.go @@ -14,6 +14,7 @@ import ( "sync/atomic" "time" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/daemon/cluster" "github.com/hashicorp/boundary/internal/daemon/cluster/handlers" @@ -49,14 +50,14 @@ func (w *Worker) StartControllerConnections() error { case strings.HasPrefix(addr, "/"): initialAddrs = append(initialAddrs, addr) default: - host, port, err := util.SplitHostPort(addr) + host, port, err := net.SplitHostPort(addr) + if err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr) { + host, port, err = net.SplitHostPort(net.JoinHostPort(addr, "9201")) + } if err != nil { return fmt.Errorf("error parsing upstream address: %w", err) } - if port == "" { - port = "9201" - } - initialAddrs = append(initialAddrs, util.JoinHostPort(host, port)) + initialAddrs = append(initialAddrs, net.JoinHostPort(host, port)) } } diff --git a/internal/daemon/worker/testing.go b/internal/daemon/worker/testing.go index db47dece74b..ad57f22b6c9 100644 --- a/internal/daemon/worker/testing.go +++ b/internal/daemon/worker/testing.go @@ -236,9 +236,6 @@ type TestWorkerOpts struct { // Enable observation events EnableObservationEvents bool - // Enable IPv6 - EnableIPv6 bool - // Enable error events EnableErrorEvents bool } @@ -275,7 +272,6 @@ func NewTestWorker(t testing.TB, opts *TestWorkerOpts) *TestWorker { configOpts = append(configOpts, config.WithAuditEventsEnabled(opts.EnableAuditEvents)) configOpts = append(configOpts, config.WithSysEventsEnabled(opts.EnableSysEvents)) configOpts = append(configOpts, config.WithObservationsEnabled(opts.EnableObservationEvents)) - configOpts = append(configOpts, config.WithIPv6Enabled(opts.EnableIPv6)) configOpts = append(configOpts, config.TestWithErrorEventsEnabled(t, opts.EnableErrorEvents)) opts.Config, err = config.DevWorker(configOpts...) if err != nil { @@ -565,7 +561,7 @@ func NewTestMultihopWorkers(t testing.TB, // NewAuthorizedPkiTestWorker creates a new test worker with the provided upstreams // and creates it in the provided repo as an authorized worker. It returns // The TestWorker and it's boundary id. -func NewAuthorizedPkiTestWorker(t *testing.T, repo *server.Repository, name string, upstreams []string, opt ...config.Option) (*TestWorker, string) { +func NewAuthorizedPkiTestWorker(t *testing.T, repo *server.Repository, name string, upstreams []string) (*TestWorker, string) { t.Helper() logger := hclog.New(&hclog.LoggerOptions{ Level: hclog.Trace, diff --git a/internal/daemon/worker/testing_test.go b/internal/daemon/worker/testing_test.go index 5742bbefc22..25ae99bdd00 100644 --- a/internal/daemon/worker/testing_test.go +++ b/internal/daemon/worker/testing_test.go @@ -209,30 +209,6 @@ func TestNewTestMultihopWorkers(t *testing.T) { require.NoError(t, c.WaitForNextWorkerStatusUpdate(childKmsWorker.Name())) } -func TestWorkerIPv6(t *testing.T) { - require, assert := require.New(t), assert.New(t) - w := NewTestWorker(t, &TestWorkerOpts{ - EnableIPv6: true, - }) - require.NotNil(w) - validateIPv6 := func(addr, name string) { - host, _, err := net.SplitHostPort(addr) - require.NoError(err) - require.NotEmpty(host, "missing host") - ip := net.ParseIP(host) - assert.NotNil(ip, "failed to parse %s", name) - assert.NotNil(ip.To16(), "%s is not IPv6 %s", name, addr) - } - for _, addr := range w.addrs { - validateIPv6(addr, "worker addr") - } - for _, addr := range w.ProxyAddrs() { - validateIPv6(addr, "proxy addr") - } - require.NotNil(w.Worker().proxyListener) - validateIPv6(w.Worker().proxyListener.ProxyListener.Addr().String(), "proxy listener addr") -} - func createTestCert(t *testing.T) ([]byte, ed25519.PublicKey, ed25519.PrivateKey) { pub, priv, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) diff --git a/internal/db/option.go b/internal/db/option.go index c260c4aa372..f590fc6af01 100644 --- a/internal/db/option.go +++ b/internal/db/option.go @@ -137,9 +137,6 @@ func getDbwOptions(ctx context.Context, rw *Db, i any, opType OpType, opt ...Opt if opts.withRowsAffected != nil { dbwOpts = append(dbwOpts, dbw.WithReturnRowsAffected(opts.withRowsAffected)) } - if opts.withTable != "" { - dbwOpts = append(dbwOpts, dbw.WithTable(opts.withTable)) - } return dbwOpts, nil } @@ -184,8 +181,6 @@ type Options struct { withOnConflict *OnConflict withRowsAffected *int64 - - withTable string } type oplogOpts struct { @@ -210,13 +205,6 @@ func getDefaultOptions() Options { } } -// WithTable provides an optional table name for the operation. -func WithTable(name string) Option { - return func(o *Options) { - o.withTable = name - } -} - // WithLookup enables a lookup. func WithLookup(enable bool) Option { return func(o *Options) { diff --git a/internal/db/option_test.go b/internal/db/option_test.go index 99feb9659ee..e953b2644ed 100644 --- a/internal/db/option_test.go +++ b/internal/db/option_test.go @@ -255,15 +255,4 @@ func Test_getOpts(t *testing.T) { testOpts.withRowsAffected = &rowsAffected assert.Equal(opts, testOpts) }) - t.Run("WithTable", func(t *testing.T) { - assert := assert.New(t) - // test default of "" - opts := GetOpts() - testOpts := getDefaultOptions() - assert.Equal(opts, testOpts) - - opts = GetOpts(WithTable("foo")) - testOpts.withTable = "foo" - assert.Equal(opts, testOpts) - }) } diff --git a/internal/db/read_writer.go b/internal/db/read_writer.go index 91d63e7b8c9..29f3da7b5ec 100644 --- a/internal/db/read_writer.go +++ b/internal/db/read_writer.go @@ -471,15 +471,14 @@ func (rw *Db) IsTx(_ context.Context) bool { } // LookupByPublicId will lookup resource by its public_id or private_id, which -// must be unique. WithTable and WithDebug are the only valid options, all other -// options are ignored. +// must be unique. WithDebug is the only valid option, all other options are ignored. func (rw *Db) LookupById(ctx context.Context, resourceWithIder any, opt ...Option) error { const op = "db.LookupById" if rw.underlying == nil { return errors.New(ctx, errors.InvalidParameter, op, "missing underlying db") } opts := GetOpts(opt...) - if err := dbw.New(rw.underlying.wrapped.Load()).LookupBy(ctx, resourceWithIder, dbw.WithDebug(opts.withDebug), dbw.WithTable(opts.withTable)); err != nil { + if err := dbw.New(rw.underlying.wrapped.Load()).LookupBy(ctx, resourceWithIder, dbw.WithDebug(opts.withDebug)); err != nil { var errOpts []errors.Option if errors.Is(err, dbw.ErrRecordNotFound) { // Not found is a common workflow in the application layer during lookup, suppress @@ -492,21 +491,20 @@ func (rw *Db) LookupById(ctx context.Context, resourceWithIder any, opt ...Optio } // LookupByPublicId will lookup resource by its public_id, which must be unique. -// WithTable and WithDebug are supported. +// WithDebug is supported. func (rw *Db) LookupByPublicId(ctx context.Context, resource ResourcePublicIder, opt ...Option) error { return rw.LookupById(ctx, resource, opt...) } // LookupWhere will lookup the first resource using a where clause with -// parameters (it only returns the first one). WithTable and WithDebug are -// supported. +// parameters (it only returns the first one). WithDebug is supported. func (rw *Db) LookupWhere(ctx context.Context, resource any, where string, args []any, opt ...Option) error { const op = "db.LookupWhere" if rw.underlying == nil { return errors.New(ctx, errors.InvalidParameter, op, "missing underlying db") } opts := GetOpts(opt...) - if err := dbw.New(rw.underlying.wrapped.Load()).LookupWhere(ctx, resource, where, args, dbw.WithDebug(opts.withDebug), dbw.WithTable(opts.withTable)); err != nil { + if err := dbw.New(rw.underlying.wrapped.Load()).LookupWhere(ctx, resource, where, args, dbw.WithDebug(opts.withDebug)); err != nil { var errOpts []errors.Option if errors.Is(err, dbw.ErrRecordNotFound) { // Not found is a common workflow in the application layer during lookup, suppress diff --git a/internal/db/schema/migrations/oss/postgres/7/03_job.up.sql b/internal/db/schema/migrations/oss/postgres/7/03_job.up.sql index cf7cb29de51..472762ca49a 100644 --- a/internal/db/schema/migrations/oss/postgres/7/03_job.up.sql +++ b/internal/db/schema/migrations/oss/postgres/7/03_job.up.sql @@ -20,7 +20,6 @@ begin; create trigger immutable_columns before update on job for each row execute procedure immutable_columns('plugin_id', 'name'); - -- updated in 93/01_job_run_clean.up.sql create table job_run_status_enm ( name text not null primary key constraint only_predefined_job_status_allowed @@ -29,7 +28,6 @@ begin; comment on table job_run_status_enm is 'job_run_status_enm is an enumeration table where each row contains a valid job run state.'; - -- updated in 93/01_job_run_clean.up.sql insert into job_run_status_enm (name) values ('running'), @@ -86,7 +84,6 @@ begin; create trigger immutable_columns before update on job_run for each row execute procedure immutable_columns('private_id', 'job_plugin_id', 'job_name', 'create_time'); - -- dropped in 93/02_drop_job_jobs_to_run.up.sql create view job_jobs_to_run as with running_jobs (job_plugin_id, job_name) as ( diff --git a/internal/db/schema/migrations/oss/postgres/93/01_job_run_clean.up.sql b/internal/db/schema/migrations/oss/postgres/93/01_job_run_clean.up.sql deleted file mode 100644 index d09a1977759..00000000000 --- a/internal/db/schema/migrations/oss/postgres/93/01_job_run_clean.up.sql +++ /dev/null @@ -1,37 +0,0 @@ --- Copyright (c) HashiCorp, Inc. --- SPDX-License-Identifier: BUSL-1.1 - --- Boundary's design on removing entries from job_run has changed from having a --- job that periodically cleans the table to a design where the scheduler --- handles this by itself if the job is successful. It is possible that some --- entries are left in the table with this change (eg: Boundary is stopped after --- some jobs run but before the cleaner job runs). --- --- These entries would forever be stored, so this migration cleans them to --- ensure no dangling rows are left behind. --- --- It also updates the valid statues enum to reflect the ones in use. - -begin; - delete from job_run where status = 'completed'; - - delete from job_run where job_name = 'job_run_cleaner'; - delete from job where name = 'job_run_cleaner'; - - comment on index job_run_status_ix is - 'the job_run_status_ix indexes the commonly-used status field'; - - comment on table job_run is - 'job_run is a table where each row represents an instance of a job run that is either actively running or has failed in some way.'; - - -- Since we don't set completed anymore, but rather remove the job_run entry, - -- remove 'completed' from the valid statuses. - -- updates 7/03_job.up.sql. - delete from job_run_status_enm where name = 'completed'; - - alter table job_run_status_enm - drop constraint only_predefined_job_status_allowed, - add constraint only_predefined_job_status_allowed - check(name in ('running', 'failed', 'interrupted')); - -commit; diff --git a/internal/db/schema/migrations/oss/postgres/93/02_drop_job_jobs_to_run.up.sql b/internal/db/schema/migrations/oss/postgres/93/02_drop_job_jobs_to_run.up.sql deleted file mode 100644 index a1be8736dc6..00000000000 --- a/internal/db/schema/migrations/oss/postgres/93/02_drop_job_jobs_to_run.up.sql +++ /dev/null @@ -1,10 +0,0 @@ --- Copyright (c) HashiCorp, Inc. --- SPDX-License-Identifier: BUSL-1.1 - --- This migration removes support for the job_jobs_to_run view as it is not used --- anymore by the job repository. - -begin; - -- drops view from 7/03_job.up.sql - drop view job_jobs_to_run; -commit; \ No newline at end of file diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index f4d8e62c9a0..a5577217fed 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -3,7 +3,7 @@ "info": { "title": "Boundary controller HTTP API", "description": "Welcome to the Boundary controller HTTP API documentation. This page provides a reference guide for using the Boundary controller API, a JSON-based HTTP API. The API implements commonly seen HTTP API patterns for status codes, paths, and errors. See the [API overview](https://developer.hashicorp.com/boundary/docs/api-clients/api) for more information.\n\nBefore you read this page, it is useful to understand Boundary's [domain model](https://developer.hashicorp.com/boundary/docs/concepts/domain-model) and to be aware of the terminology used here. To get started, search for the service you want to interact with in the sidebar to the left. Each resource in Boundary, such as accounts and credential stores, has its own service. Each service contains all the API endpoints for the resource.\n## Status codes\n- `2XX`: Boundary returns a code between `200` and `299` on success. Generally this is `200`, but implementations should be prepared to accept any `2XX` status code as indicating success. If a call returns a `2XX` code that is not `200`, it follows well-understood semantics for those status codes.\n- `400`: Boundary returns `400` when a command cannot be completed due to invalid user input, except for a properly-formatted identifier that does not map to an existing resource, which returns a `404` as discussed below.\n- `401`: Boundary returns `401` if no authentication token is provided or if the provided token is invalid. A valid token that simply does not have permission for a resource returns a `403` instead. A token that is invalid or missing, but where the anonymous user (`u_anon`) is able to successfully perform the action, will not return a `401` but instead will return the result of the action.\n- `403`: Boundary returns `403` if a provided token was valid but does not have the grants required to perform the requested action.\n- `404`: Boundary returns `404` if a resource cannot be found. Note that this happens _prior_ to authentication/authorization checking in nearly all cases as the resource information (such as its scope, available actions, etc.) is a required part of that check. As a result, an action against a resource that does not exist returns a `404` instead of a `401` or `403`. While this could be considered an information leak, since IDs are randomly generated and this only discloses whether an ID is valid, it's tolerable as it allows for far simpler and more robust client implementation.\n- `405`: Boundary returns a `405` to indicate that the method (HTTP verb or custom action) is not implemented for the given resource.\n- `429`: Boundary returns a `429` if any of the API rate limit quotas have been exhausted for the resource and action. It includes the `Retry-After` header so that the client knows how long to wait before making a new request.\n- `500`: Boundary returns `500` if an error occurred that is not (directly) tied to invalid user input. If a `500` is generated, information about the error is logged to Boundary's server log but is not generally provided to the client.\n- `503`: Boundary returns a `503` if it is unable to store a quota due to the API rate limit being exceeded. It includes the `Retry-After` header so that the client knows how long to wait before making a new request.\n## List pagination\nBoundary uses [API pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination) to support searching and filtering large lists of results efficiently.", - "version": "0.19.0", + "version": "0.18.3", "contact": { "name": "HashiCorp Boundary", "url": "https://www.boundaryproject.io/" diff --git a/internal/host/plugin/host_address_test.go b/internal/host/plugin/host_address_test.go index 599a4c9397c..b1afb5dda5b 100644 --- a/internal/host/plugin/host_address_test.go +++ b/internal/host/plugin/host_address_test.go @@ -211,7 +211,7 @@ func TestHostIpAddress_Create(t *testing.T) { wantDbErr: true, }, { - name: "valid-ipv4", + name: "valid", args: args{ hostId: host1.GetPublicId(), address: "1.2.3.4", @@ -223,64 +223,6 @@ func TestHostIpAddress_Create(t *testing.T) { }, }, }, - { - name: "valid-ipv6", - args: args{ - hostId: host1.GetPublicId(), - address: "2001:4860:4860:0:0:0:0:8888", - }, - want: &host.IpAddress{ - IpAddress: &store.IpAddress{ - HostId: host1.GetPublicId(), - Address: "2001:4860:4860:0:0:0:0:8888", - }, - }, - }, - { - name: "valid-abbreviated-ipv6", - args: args{ - hostId: host1.GetPublicId(), - address: "2001:4860:4860::8887", - }, - want: &host.IpAddress{ - IpAddress: &store.IpAddress{ - HostId: host1.GetPublicId(), - Address: "2001:4860:4860::8887", - }, - }, - }, - { - name: "invalid-abbreviated-[ipv6]", - args: args{ - hostId: host1.GetPublicId(), - address: "[2001:4860:4860::8886]", - }, - wantNewErr: true, - }, - { - name: "invalid-[ipv6]", - args: args{ - hostId: host1.GetPublicId(), - address: "[2001:4860:4860:0:0:0:0:8885]", - }, - wantNewErr: true, - }, - { - name: "invalid-abbreviated-[ipv6]:port", - args: args{ - hostId: host1.GetPublicId(), - address: "[2001:4860:4860::8884]:80", - }, - wantNewErr: true, - }, - { - name: "invalid-[ipv6]:port", - args: args{ - hostId: host1.GetPublicId(), - address: "[2001:4860:4860:0:0:0:0:8883]:80", - }, - wantNewErr: true, - }, { name: "duplicate-name", args: args{ diff --git a/internal/host/static/host.go b/internal/host/static/host.go index ece1cf832bd..1fe420c3a38 100644 --- a/internal/host/static/host.go +++ b/internal/host/static/host.go @@ -32,9 +32,8 @@ type Host struct { // Name and description are the only valid options. All other options are // ignored. func NewHost(ctx context.Context, catalogId string, opt ...Option) (*Host, error) { - const op = "static.NewHost" if catalogId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "no catalog id") + return nil, errors.New(ctx, errors.InvalidParameter, "static.NewHost", "no catalog id") } opts := getOpts(opt...) diff --git a/internal/host/static/host_test.go b/internal/host/static/host_test.go index db05ddcfc39..f26239c7da4 100644 --- a/internal/host/static/host_test.go +++ b/internal/host/static/host_test.go @@ -131,30 +131,30 @@ func TestHost_New(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - require, assert := require.New(t), assert.New(t) + assert := assert.New(t) got, err := NewHost(ctx, tt.args.catalogId, tt.args.opts...) if tt.wantCreateErr { - require.Error(err) + assert.Error(err) assert.Nil(got) - return - } - require.NoError(err) - require.NotNil(got) - assert.Emptyf(got.PublicId, "PublicId set") - assert.Equal(tt.want, got) + } else { + assert.NoError(err) + if assert.NotNil(got) { + assert.Emptyf(got.PublicId, "PublicId set") + assert.Equal(tt.want, got) + + id, err := newHostId(ctx) + assert.NoError(err) - id, err := newHostId(ctx) - require.NoError(err) - tt.want.PublicId = id - got.PublicId = id + tt.want.PublicId = id + got.PublicId = id - w := db.New(conn) - dbWriteErr := w.Create(ctx, got) - if tt.wantWriteErr { - require.Error(dbWriteErr) - return + w := db.New(conn) + err2 := w.Create(ctx, got) + if tt.wantWriteErr { + assert.Error(err2) + } + } } - require.NoError(dbWriteErr) }) } } diff --git a/internal/host/static/repository_host.go b/internal/host/static/repository_host.go index acf4e970c54..b4246fdf7f2 100644 --- a/internal/host/static/repository_host.go +++ b/internal/host/static/repository_host.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-dbw" ) @@ -45,10 +44,9 @@ func (r *Repository) CreateHost(ctx context.Context, projectId string, h *Host, if projectId == "" { return nil, errors.New(ctx, errors.InvalidParameter, op, "no project id") } - var err error - h.Address, err = util.ParseAddress(ctx, h.Address) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) + h.Address = strings.TrimSpace(h.Address) + if len(h.Address) < MinHostAddressLength || len(h.Address) > MaxHostAddressLength { + return nil, errors.New(ctx, errors.InvalidAddress, op, "invalid address") } h = h.clone() @@ -140,10 +138,9 @@ func (r *Repository) UpdateHost(ctx context.Context, projectId string, h *Host, case strings.EqualFold("Name", f): case strings.EqualFold("Description", f): case strings.EqualFold("Address", f): - var err error - h.Address, err = util.ParseAddress(ctx, h.Address) - if err != nil { - return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) + h.Address = strings.TrimSpace(h.Address) + if len(h.Address) < MinHostAddressLength || len(h.Address) > MaxHostAddressLength { + return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidAddress, op, "invalid address") } default: return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidFieldMask, op, fmt.Sprintf("invalid field mask: %s", f)) diff --git a/internal/host/static/repository_host_test.go b/internal/host/static/repository_host_test.go index cbec7485d16..88056ba1c25 100644 --- a/internal/host/static/repository_host_test.go +++ b/internal/host/static/repository_host_test.go @@ -69,21 +69,6 @@ func TestRepository_CreateHost(t *testing.T) { }, wantIsErr: errors.InvalidParameter, }, - { - name: "valid-dns-name", - in: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "www.google.com", - }, - }, - want: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "www.google.com", - }, - }, - }, { name: "valid-ipv4-address", in: &Host{ @@ -99,16 +84,6 @@ func TestRepository_CreateHost(t *testing.T) { }, }, }, - { - name: "invalid-ipv4-address-with-port", - in: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "127.0.0.1:80", - }, - }, - wantIsErr: errors.InvalidAddress, - }, { name: "valid-abbreviated-ipv6-address", in: &Host{ @@ -124,16 +99,6 @@ func TestRepository_CreateHost(t *testing.T) { }, }, }, - { - name: "invalid-abbreviated-ipv6-address-with-port", - in: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "[2001:4860:4860::8888]:80", - }, - }, - wantIsErr: errors.InvalidAddress, - }, { name: "valid-ipv6-address", in: &Host{ @@ -149,46 +114,6 @@ func TestRepository_CreateHost(t *testing.T) { }, }, }, - { - name: "invalid-ipv6-address-with-port", - in: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "[2001:4860:4860:0:0:0:0:8888]:80", - }, - }, - wantIsErr: errors.InvalidAddress, - }, - { - name: "valid-abbreviated-[ipv6]-address", - in: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "[2001:4860:4860::8888]", - }, - }, - want: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "[2001:4860:4860::8888]", - }, - }, - }, - { - name: "valid-[ipv6]-address", - in: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "[2001:4860:4860:0:0:0:0:8888]", - }, - }, - want: &Host{ - Host: &store.Host{ - CatalogId: catalog.PublicId, - Address: "[2001:4860:4860:0:0:0:0:8888]", - }, - }, - }, { name: "valid-with-name", in: &Host{ @@ -649,22 +574,6 @@ func TestRepository_UpdateHost(t *testing.T) { }, wantCount: 1, }, - { - name: "change-dns-name", - orig: &Host{ - Host: &store.Host{ - Address: "www.google.com", - }, - }, - chgFn: changeAddress("www.hashicorp.com"), - masks: []string{"Address"}, - want: &Host{ - Host: &store.Host{ - Address: "www.hashicorp.com", - }, - }, - wantCount: 1, - }, { name: "change-ipv4-address", orig: &Host{ @@ -681,39 +590,6 @@ func TestRepository_UpdateHost(t *testing.T) { }, wantCount: 1, }, - { - name: "change-invalid-ipv4-address", - orig: &Host{ - Host: &store.Host{ - Address: "127.0.0.1", - }, - }, - chgFn: changeAddress("10.0.0.1:80"), - masks: []string{"Address"}, - wantIsErr: errors.InvalidAddress, - }, - { - name: "change-invalid-abbreviated-ipv6-address", - orig: &Host{ - Host: &store.Host{ - Address: "127.0.0.1", - }, - }, - chgFn: changeAddress("[2001:4860:4860::8888]:80"), - masks: []string{"Address"}, - wantIsErr: errors.InvalidAddress, - }, - { - name: "change-invalid-ipv6-address", - orig: &Host{ - Host: &store.Host{ - Address: "127.0.0.1", - }, - }, - chgFn: changeAddress("[2001:4860:4860:0:0:0:0:8888]:80"), - masks: []string{"Address"}, - wantIsErr: errors.InvalidAddress, - }, { name: "change-abbreviated-ipv6-address", orig: &Host{ @@ -746,38 +622,6 @@ func TestRepository_UpdateHost(t *testing.T) { }, wantCount: 1, }, - { - name: "change-abbreviated-[ipv6]-address", - orig: &Host{ - Host: &store.Host{ - Address: "127.0.0.1", - }, - }, - chgFn: changeAddress("[2001:4860:4860::8888]"), - masks: []string{"Address"}, - want: &Host{ - Host: &store.Host{ - Address: "[2001:4860:4860::8888]", - }, - }, - wantCount: 1, - }, - { - name: "change-[ipv6]-address", - orig: &Host{ - Host: &store.Host{ - Address: "127.0.0.1", - }, - }, - chgFn: changeAddress("[2001:4860:4860:0:0:0:0:8888]"), - masks: []string{"Address"}, - want: &Host{ - Host: &store.Host{ - Address: "[2001:4860:4860:0:0:0:0:8888]", - }, - }, - wantCount: 1, - }, { name: "change-short-address", orig: &Host{ diff --git a/internal/host/static/testing.go b/internal/host/static/testing.go index a3dc7b1d58b..0e34bb7603a 100644 --- a/internal/host/static/testing.go +++ b/internal/host/static/testing.go @@ -37,30 +37,6 @@ func TestCatalogs(t testing.TB, conn *db.DB, projectId string, count int) []*Hos return cats } -// TestHost creates a static host to the provided DB with the provided catalog id. -// The catalog must have been created previously. If any errors are encountered -// during the creation of the host, the test will fail. -func TestHost(t testing.TB, conn *db.DB, catalogId string, opt ...Option) *Host { - t.Helper() - ctx := context.Background() - assert := assert.New(t) - - host, err := NewHost(ctx, catalogId, opt...) - assert.NoError(err) - assert.NotNil(host) - - id, err := newHostId(ctx) - assert.NoError(err) - assert.NotEmpty(id) - host.PublicId = id - - w := db.New(conn) - err2 := w.Create(ctx, host) - assert.NoError(err2) - - return host -} - // TestHosts creates count number of static hosts to the provided DB // with the provided catalog id. The catalog must have been created previously. // If any errors are encountered during the creation of the host, the test will fail. diff --git a/internal/iam/repository_principal_role_test.go b/internal/iam/repository_principal_role_test.go index f2c24563a0f..cd0f0e2cf59 100644 --- a/internal/iam/repository_principal_role_test.go +++ b/internal/iam/repository_principal_role_test.go @@ -141,12 +141,20 @@ func TestRepository_AddPrincipalRoles(t *testing.T) { if tt.args.wantUserIds { userIds = createUsersFn(orgs) u := TestUser(t, repo, staticOrg.PublicId) - userIds = append(userIds, u.PublicId) + if roleId == orgRole.PublicId { + userIds = append(userIds, u.PublicId) + } else { + userIds = append(userIds, u.PublicId) + } } if tt.args.wantGroupIds { groupIds = createGrpsFn(orgs, projects) g := TestGroup(t, conn, staticProj.PublicId) - groupIds = append(groupIds, g.PublicId) + if roleId == projRole.PublicId { + groupIds = append(groupIds, g.PublicId) + } else { + groupIds = append(groupIds, g.PublicId) + } } if len(tt.args.specificUserIds) > 0 { userIds = tt.args.specificUserIds diff --git a/internal/proto/controller/storage/job/store/v1/job.proto b/internal/proto/controller/storage/job/store/v1/job.proto index e362b79ff5a..949c2492701 100644 --- a/internal/proto/controller/storage/job/store/v1/job.proto +++ b/internal/proto/controller/storage/job/store/v1/job.proto @@ -72,7 +72,7 @@ message JobRun { // @inject_tag: `gorm:"default:0"` uint32 retries_count = 12; - // status of the job run (running, failed or interrupted). + // status of the job run (running, completed, failed or interrupted). // @inject_tag: `gorm:"not_null"` string status = 10; diff --git a/internal/scheduler/additional_verification_test.go b/internal/scheduler/additional_verification_test.go index 2d1bf498f86..cacab68ea19 100644 --- a/internal/scheduler/additional_verification_test.go +++ b/internal/scheduler/additional_verification_test.go @@ -35,7 +35,7 @@ func TestSchedulerWorkflow(t *testing.T) { }) err := event.InitSysEventer(testLogger, testLock, "TestSchedulerWorkflow", event.WithEventerConfig(testConfig)) require.NoError(err) - sched := TestScheduler(t, conn, wrapper, WithRunJobsInterval(time.Second)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithRunJobsInterval(time.Second)) job1Ch := make(chan error) job1Ready := make(chan struct{}) @@ -118,7 +118,7 @@ func TestSchedulerCancelCtx(t *testing.T) { err := event.InitSysEventer(testLogger, testLock, "TestSchedulerCancelCtx", event.WithEventerConfig(testConfig)) require.NoError(err) - sched := TestScheduler(t, conn, wrapper, WithRunJobsInterval(time.Second)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithRunJobsInterval(time.Second)) fn, jobReady, jobDone := testJobFn() tj := testJob{name: "name", description: "desc", fn: fn, nextRunIn: time.Hour} @@ -168,7 +168,7 @@ func TestSchedulerInterruptedCancelCtx(t *testing.T) { err := event.InitSysEventer(testLogger, testLock, "TestSchedulerInterruptedCancelCtx", event.WithEventerConfig(testConfig)) require.NoError(err) - sched := TestScheduler(t, conn, wrapper, WithRunJobsInterval(time.Second), WithMonitorInterval(time.Second)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithRunJobsInterval(time.Second), WithMonitorInterval(time.Second)) fn, job1Ready, job1Done := testJobFn() tj1 := testJob{name: "name1", description: "desc", fn: fn, nextRunIn: time.Hour} @@ -270,7 +270,7 @@ func TestSchedulerJobProgress(t *testing.T) { err := event.InitSysEventer(testLogger, testLock, "TestSchedulerJobProgress", event.WithEventerConfig(testConfig)) require.NoError(err) - sched := TestScheduler(t, conn, wrapper, WithRunJobsInterval(time.Second), WithMonitorInterval(time.Second)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithRunJobsInterval(time.Second), WithMonitorInterval(time.Second)) jobReady := make(chan struct{}) done := make(chan struct{}) @@ -380,7 +380,7 @@ func TestSchedulerMonitorLoop(t *testing.T) { err := event.InitSysEventer(testLogger, testLock, "TestSchedulerMonitorLoop", event.WithEventerConfig(testConfig)) require.NoError(err) - sched := TestScheduler(t, conn, wrapper, WithInterruptThreshold(time.Second), WithRunJobsInterval(time.Second), WithMonitorInterval(time.Second)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithInterruptThreshold(time.Second), WithRunJobsInterval(time.Second), WithMonitorInterval(time.Second)) jobReady := make(chan struct{}) jobDone := make(chan struct{}) @@ -446,7 +446,7 @@ func TestSchedulerFinalStatusUpdate(t *testing.T) { err := event.InitSysEventer(testLogger, testLock, "TestSchedulerFinalStatusUpdate", event.WithEventerConfig(testConfig)) require.NoError(err) - sched := TestScheduler(t, conn, wrapper, WithRunJobsInterval(time.Second)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithRunJobsInterval(time.Second)) jobReady := make(chan struct{}) jobErr := make(chan error) @@ -489,7 +489,7 @@ func TestSchedulerFinalStatusUpdate(t *testing.T) { repo, err := job.NewRepository(ctx, rw, rw, kmsCache) require.NoError(err) - run := waitForRunStatus(t, repo, runId, job.Failed) + run := waitForRunStatus(t, repo, runId, string(job.Failed)) assert.Equal(uint32(10), run.TotalCount) assert.Equal(uint32(10), run.CompletedCount) @@ -502,9 +502,17 @@ func TestSchedulerFinalStatusUpdate(t *testing.T) { runId = runJob.(*runningJob).runId // Complete job without error so CompleteRun is called - completeFn := waitForRunComplete(t, sched, repo, runId, tj.name) jobErr <- nil - completeFn() + + // Report status + jobStatus <- JobStatus{Total: 20, Completed: 20} + + repo, err = job.NewRepository(ctx, rw, rw, kmsCache) + require.NoError(err) + + run = waitForRunStatus(t, repo, runId, string(job.Completed)) + assert.Equal(uint32(20), run.TotalCount) + assert.Equal(uint32(20), run.CompletedCount) baseCnl() close(testDone) @@ -530,7 +538,7 @@ func TestSchedulerRunNow(t *testing.T) { require.NoError(err) // Create test scheduler that only runs jobs every hour - sched := TestScheduler(t, conn, wrapper, WithRunJobsInterval(time.Hour)) + sched := TestScheduler(t, conn, wrapper, WithRunJobsLimit(10), WithRunJobsInterval(time.Hour)) jobCh := make(chan struct{}) jobReady := make(chan struct{}) @@ -562,13 +570,12 @@ func TestSchedulerRunNow(t *testing.T) { require.True(ok) runId := runJob.(*runningJob).runId - repo, err := job.NewRepository(ctx, rw, rw, kmsCache) - require.NoError(err) - // Complete job - completeFn := waitForRunComplete(t, sched, repo, runId, tj.name) jobCh <- struct{}{} - completeFn() + + repo, err := job.NewRepository(ctx, rw, rw, kmsCache) + require.NoError(err) + waitForRunStatus(t, repo, runId, string(job.Completed)) // Update job to run immediately once scheduling loop is called err = sched.UpdateJobNextRunInAtLeast(context.Background(), tj.name, 0) @@ -593,9 +600,9 @@ func TestSchedulerRunNow(t *testing.T) { runId = runJob.(*runningJob).runId // Complete job - completeFn = waitForRunComplete(t, sched, repo, runId, tj.name) jobCh <- struct{}{} - completeFn() + + waitForRunStatus(t, repo, runId, string(job.Completed)) // Update job to run again with RunNow option err = sched.UpdateJobNextRunInAtLeast(context.Background(), tj.name, 0, WithRunNow(true)) @@ -613,34 +620,7 @@ func TestSchedulerRunNow(t *testing.T) { close(jobCh) } -func waitForRunComplete(t *testing.T, sched *Scheduler, repo *job.Repository, runId, jobName string) func() { - r, err := repo.LookupRun(context.Background(), runId) - require.NoError(t, err) - require.EqualValues(t, job.Running, r.Status) - - return func() { - timeout := time.NewTimer(5 * time.Second) - for { - select { - case <-timeout.C: - t.Fatal(fmt.Errorf("timed out waiting for job run %q to be completed", runId)) - case <-time.After(100 * time.Millisecond): - } - - // A run is complete when we don't find it in the scheduler's - // running jobs list and also not in the job_run table. - _, ok := sched.runningJobs.Load(jobName) - if !ok { - r, err = repo.LookupRun(context.Background(), runId) - require.Nil(t, r) - require.Nil(t, err) - break - } - } - } -} - -func waitForRunStatus(t *testing.T, repo *job.Repository, runId string, status job.Status) *job.Run { +func waitForRunStatus(t *testing.T, repo *job.Repository, runId, status string) *job.Run { t.Helper() var run *job.Run @@ -656,7 +636,7 @@ func waitForRunStatus(t *testing.T, repo *job.Repository, runId string, status j var err error run, err = repo.LookupRun(context.Background(), runId) require.NoError(t, err) - if run.Status == string(status) { + if run.Status == status { break } } diff --git a/internal/scheduler/batch/batch_test.go b/internal/scheduler/batch/batch_test.go index 8fc60f40547..b82352b6aff 100644 --- a/internal/scheduler/batch/batch_test.go +++ b/internal/scheduler/batch/batch_test.go @@ -7,7 +7,6 @@ import ( "context" "errors" "fmt" - "sync" "testing" "time" @@ -301,25 +300,18 @@ type recorder struct { execBatchSize int storeBatchSize int status scheduler.JobStatus - mu sync.Mutex } func (r *recorder) setup(c *Config) { - r.mu.Lock() - defer r.mu.Unlock() c.Store = r.Store } func (r *recorder) Store(ctx context.Context, batchSize int) error { - r.mu.Lock() - defer r.mu.Unlock() r.storeBatchSize = batchSize return nil } func (r *recorder) Exec(ctx context.Context, batchSize int) (int, error) { - r.mu.Lock() - defer r.mu.Unlock() r.execBatchSize = batchSize return 0, nil } @@ -328,7 +320,6 @@ type testRun struct { ret func(context.Context, int, *Config) (int, error) chk func(*testing.T, *recorder) rec *recorder - mu sync.Mutex } func (tr *testRun) validate(t *testing.T) { @@ -338,8 +329,6 @@ func (tr *testRun) validate(t *testing.T) { } func (tr *testRun) recorder(cf *Config) *recorder { - tr.mu.Lock() - defer tr.mu.Unlock() if tr.rec == nil { tr.rec = &recorder{} tr.rec.setup(cf) diff --git a/internal/scheduler/cleaner/cleaner.go b/internal/scheduler/cleaner/cleaner.go new file mode 100644 index 00000000000..86358cb5866 --- /dev/null +++ b/internal/scheduler/cleaner/cleaner.go @@ -0,0 +1,30 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package cleaner + +import ( + "context" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/scheduler" + "github.com/hashicorp/boundary/internal/util" +) + +// RegisterJob registers the cleaner job with the provided scheduler. +func RegisterJob(ctx context.Context, s *scheduler.Scheduler, w db.Writer) error { + const op = "cleaner.RegisterJob" + if s == nil { + return errors.New(ctx, errors.Internal, "nil scheduler", op, errors.WithoutEvent()) + } + if util.IsNil(w) { + return errors.New(ctx, errors.Internal, "nil DB writer", op, errors.WithoutEvent()) + } + + if err := s.RegisterJob(ctx, newCleanerJob(w)); err != nil { + return errors.Wrap(ctx, err, op) + } + + return nil +} diff --git a/internal/scheduler/cleaner/cleaner_job.go b/internal/scheduler/cleaner/cleaner_job.go new file mode 100644 index 00000000000..a7fa39abd95 --- /dev/null +++ b/internal/scheduler/cleaner/cleaner_job.go @@ -0,0 +1,57 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package cleaner + +import ( + "context" + "time" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/scheduler" +) + +type cleanerJob struct { + w db.Writer +} + +func newCleanerJob(w db.Writer) *cleanerJob { + return &cleanerJob{ + w: w, + } +} + +// Status reports the job’s current status. +func (c *cleanerJob) Status() scheduler.JobStatus { + return scheduler.JobStatus{} +} + +// Run performs the required work depending on the implementation. +// The context is used to notify the job that it should exit early. +func (c *cleanerJob) Run(ctx context.Context, _ time.Duration) error { + const op = "cleaner.(cleanerJob).Run" + + if _, err := c.w.Exec(ctx, "delete from job_run where status='completed'", nil); err != nil { + return errors.Wrap(ctx, err, op) + } + + return nil +} + +// NextRunIn returns the duration until the next job run should be scheduled. +// We report as ready immediately after a successful run. This doesn't mean that +// this job will run immediately, only about as often as the configured scheduler interval. +func (c *cleanerJob) NextRunIn(_ context.Context) (time.Duration, error) { + return 0, nil +} + +// Name is the unique name of the job. +func (c *cleanerJob) Name() string { + return "job_run_cleaner" +} + +// Description is the human readable description of the job. +func (c *cleanerJob) Description() string { + return "Cleans completed job runs" +} diff --git a/internal/scheduler/cleaner/cleaner_test.go b/internal/scheduler/cleaner/cleaner_test.go new file mode 100644 index 00000000000..13eb4bbbdf2 --- /dev/null +++ b/internal/scheduler/cleaner/cleaner_test.go @@ -0,0 +1,64 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package cleaner_test + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/scheduler" + "github.com/hashicorp/boundary/internal/scheduler/cleaner" + "github.com/hashicorp/boundary/internal/scheduler/job" + "github.com/stretchr/testify/require" +) + +func TestCleanerJob(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + s := scheduler.TestScheduler(t, conn, wrapper, scheduler.WithMonitorInterval(10*time.Millisecond)) + err := cleaner.RegisterJob(context.Background(), s, rw) + require.NoError(t, err) + wg := &sync.WaitGroup{} + err = s.Start(context.Background(), wg) + require.NoError(t, err) + + // Trigger some runs, waiting for the cleaner to run + for i := 0; i < 10; i++ { + s.RunNow() + // Wait to allow for the job to finish + time.Sleep(50 * time.Millisecond) + } + + var jobRuns []*job.Run + err = rw.SearchWhere(context.Background(), &jobRuns, "", nil) + require.NoError(t, err) + + // We should have run 10 times, as long as some of them + // have been cleaned we should succeed. + require.True(t, len(jobRuns) < 10, "expected fewer than 10 job_run rows, found %d", len(jobRuns)) +} + +func TestRegisterJob(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + s := scheduler.TestScheduler(t, conn, wrapper) + + t.Run("succeeds", func(t *testing.T) { + err := cleaner.RegisterJob(context.Background(), s, rw) + require.NoError(t, err) + }) + t.Run("fails-on-nil-scheduler", func(t *testing.T) { + err := cleaner.RegisterJob(context.Background(), nil, rw) + require.Error(t, err) + }) + t.Run("fails-on-nil-db-writer", func(t *testing.T) { + err := cleaner.RegisterJob(context.Background(), s, nil) + require.Error(t, err) + }) +} diff --git a/internal/scheduler/job/additional_verification_test.go b/internal/scheduler/job/additional_verification_test.go index 6ec748efe64..0e9c351fd29 100644 --- a/internal/scheduler/job/additional_verification_test.go +++ b/internal/scheduler/job/additional_verification_test.go @@ -54,8 +54,9 @@ func TestJobWorkflow(t *testing.T) { require.NoError(err) assert.Nil(newRuns) - err = repo.CompleteRun(ctx, run.PrivateId, time.Hour) + run, err = repo.CompleteRun(ctx, run.PrivateId, time.Hour, 0, 0, 0) require.NoError(err) + assert.Equal(Completed.string(), run.Status) job, err = repo.LookupJob(ctx, job.Name) require.NoError(err) diff --git a/internal/scheduler/job/doc.go b/internal/scheduler/job/doc.go index b67e53e9996..dce76363e98 100644 --- a/internal/scheduler/job/doc.go +++ b/internal/scheduler/job/doc.go @@ -45,5 +45,5 @@ // nextJobRun = time.Now().Add(time.Hour) // // repo, _ = job.NewRepository(db, db, wrapper) -// _ = repo.CompleteRun(ctx, run.PrivateId nextJobRun) +// run, _ = repo.CompleteRun(ctx, run.PrivateId, job.Completed, nextJobRun) package job diff --git a/internal/scheduler/job/options.go b/internal/scheduler/job/options.go index 4d68ca4b6af..9dd8521333a 100644 --- a/internal/scheduler/job/options.go +++ b/internal/scheduler/job/options.go @@ -8,7 +8,8 @@ import ( ) const ( - defaultPluginId = "pi_system" + defaultRunJobsLimit = 1 + defaultPluginId = "pi_system" ) // getOpts - iterate the inbound Options and return a struct @@ -26,13 +27,16 @@ type Option func(*options) // options = how options are represented type options struct { withNextRunIn time.Duration + withRunJobsLimit int withLimit int withName string withControllerId string } func getDefaultOptions() options { - return options{} // No default options. + return options{ + withRunJobsLimit: defaultRunJobsLimit, + } } // WithNextRunIn provides an option to provide the duration until the next run is scheduled. @@ -44,6 +48,18 @@ func WithNextRunIn(d time.Duration) Option { } } +// WithRunJobsLimit provides an option to provide the number of jobs to run. +// If WithRunJobsLimit == 0, then default run jobs limit is used. +// If WithRunJobsLimit < 0, then no limit is used. +func WithRunJobsLimit(l int) Option { + return func(o *options) { + o.withRunJobsLimit = l + if o.withRunJobsLimit == 0 { + o.withRunJobsLimit = defaultRunJobsLimit + } + } +} + // WithLimit provides an option to provide a limit for ListJobs. Intentionally // allowing negative integers. If WithLimit < 0, then unlimited results are // returned. If WithLimit == 0, then default limits are used for results. diff --git a/internal/scheduler/job/options_test.go b/internal/scheduler/job/options_test.go index 115381b6e4f..ca0a53c88a9 100644 --- a/internal/scheduler/job/options_test.go +++ b/internal/scheduler/job/options_test.go @@ -21,6 +21,21 @@ func Test_GetOpts(t *testing.T) { testOpts.withNextRunIn = time.Hour assert.Equal(opts, testOpts) }) + t.Run("WithRunJobsLimit", func(t *testing.T) { + assert := assert.New(t) + opts := getOpts(WithRunJobsLimit(10)) + testOpts := getDefaultOptions() + assert.NotEqual(opts, testOpts) + testOpts.withRunJobsLimit = 10 + assert.Equal(opts, testOpts) + }) + t.Run("WithZeroRunJobsLimit", func(t *testing.T) { + assert := assert.New(t) + opts := getOpts(WithRunJobsLimit(0)) + testOpts := getDefaultOptions() + assert.Equal(opts, testOpts) + assert.Equal(defaultRunJobsLimit, opts.withRunJobsLimit) + }) t.Run("WithLimit", func(t *testing.T) { assert := assert.New(t) opts := getOpts(WithLimit(100)) diff --git a/internal/scheduler/job/query.go b/internal/scheduler/job/query.go index 686fb9b9cc0..41bd0c3185b 100644 --- a/internal/scheduler/job/query.go +++ b/internal/scheduler/job/query.go @@ -7,13 +7,13 @@ const runJobsQuery = ` insert into job_run ( job_plugin_id, job_name, controller_id ) - select - j.plugin_id, j."name", ? - from job j - where next_scheduled_run <= current_timestamp + select + job_plugin_id, job_name, ? + from job_jobs_to_run order by next_scheduled_run asc - on conflict - (job_plugin_id, job_name) + %s + on conflict + (job_plugin_id, job_name) where status = 'running' do nothing returning *; @@ -74,7 +74,14 @@ const updateProgressQuery = ` ` const completeRunQuery = ` - delete from job_run + update + job_run + set + completed_count = ?, + total_count = ?, + retries_count = ?, + status = 'completed', + end_time = current_timestamp where private_id = ? and status = 'running' diff --git a/internal/scheduler/job/repository_run.go b/internal/scheduler/job/repository_run.go index b5c0eec4195..e31044e9954 100644 --- a/internal/scheduler/job/repository_run.go +++ b/internal/scheduler/job/repository_run.go @@ -17,17 +17,29 @@ import ( // If there are not jobs to run, an empty slice will be returned with a nil error. // // • serverId is required and is the private_id of the server that will run the jobs. -// No options are supported. -func (r *Repository) RunJobs(ctx context.Context, serverId string, _ ...Option) ([]*Run, error) { +// +// The only valid option is WithRunJobsLimit, if not provided RunJobs will run only 1 job. +func (r *Repository) RunJobs(ctx context.Context, serverId string, opt ...Option) ([]*Run, error) { const op = "job.(Repository).RunJobs" if serverId == "" { return nil, errors.New(ctx, errors.InvalidParameter, op, "missing server id") } + opts := getOpts(opt...) + var limit string + switch { + case opts.withRunJobsLimit == 0: + // zero signals the defaults should be used. + limit = fmt.Sprintf("limit %d", defaultRunJobsLimit) + case opts.withRunJobsLimit > 0: + limit = fmt.Sprintf("limit %d", opts.withRunJobsLimit) + } + + query := fmt.Sprintf(runJobsQuery, limit) var runs []*Run _, err := r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error { - rows, err := w.Query(ctx, runJobsQuery, []any{serverId}) + rows, err := w.Query(ctx, query, []any{serverId}) if err != nil { return errors.Wrap(ctx, err, op) } @@ -56,7 +68,7 @@ func (r *Repository) RunJobs(ctx context.Context, serverId string, _ ...Option) // UpdateProgress updates the repository entry's completed and total counts for the provided runId. // -// Once a run has been persisted with a final run status (failed or interrupted), +// Once a run has been persisted with a final run status (completed, failed or interrupted), // any future UpdateProgress attempts will return an error with Code errors.InvalidJobRunState. // All options are ignored. func (r *Repository) UpdateProgress(ctx context.Context, runId string, completed, total, retries int, _ ...Option) (*Run, error) { @@ -111,26 +123,32 @@ func (r *Repository) UpdateProgress(ctx context.Context, runId string, completed return run, nil } -// CompleteRun is intended to be called when a job completes successfully. It -// deletes the job_run entry for the provided runId. It also updates the Job -// repository entry that is associated with this run, setting the job's -// NextScheduledRun to the current database time incremented by the nextRunIn +// CompleteRun updates the Run repository entry for the provided runId. +// It sets the status to 'completed', updates the run's EndTime to the current database +// time, and sets the completed and total counts. +// CompleteRun also updates the Job repository entry that is associated with this run, +// setting the job's NextScheduledRun to the current database time incremented by the nextRunIn // parameter. // -// If a run is persisted with a final run status (failed or interrupted), any -// calls to CompleteRun will return an error with Code -// errors.InvalidJobRunState. All options are ignored. -func (r *Repository) CompleteRun(ctx context.Context, runId string, nextRunIn time.Duration, _ ...Option) error { +// Once a run has been persisted with a final run status (completed, failed +// or interrupted), any future calls to CompleteRun will return an error with Code +// errors.InvalidJobRunState. +// All options are ignored. +func (r *Repository) CompleteRun(ctx context.Context, runId string, nextRunIn time.Duration, completed, total, retries int, _ ...Option) (*Run, error) { const op = "job.(Repository).CompleteRun" if runId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing run id") + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing run id") } run := allocRun() run.PrivateId = runId _, err := r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error { - rows, err := w.Query(ctx, completeRunQuery, []any{runId}) + // TODO (lcr 07/2021) this can potentially overwrite completed and total values + // persisted by the scheduler's monitor jobs loop. + // Add an on update sql trigger to protect the job_run table, once progress + // values are used in the critical path. + rows, err := w.Query(ctx, completeRunQuery, []any{completed, total, retries, runId}) if err != nil { return errors.Wrap(ctx, err, op) } @@ -151,8 +169,7 @@ func (r *Repository) CompleteRun(ctx context.Context, runId string, nextRunIn ti return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get next row for job run")) } if rowCnt == 0 { - // No rows returned from the query: Either it's already been - // removed or was in a final state (not 'running'). + // Failed to update run, either it does not exist or was in an invalid state if err = r.LookupById(ctx, run); err != nil { if errors.IsNotFoundError(err) { return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("job run %q does not exist", runId))) @@ -189,17 +206,17 @@ func (r *Repository) CompleteRun(ctx context.Context, runId string, nextRunIn ti }, ) if err != nil { - return errors.Wrap(ctx, err, op) + return nil, errors.Wrap(ctx, err, op) } - return nil + return run, nil } // FailRun updates the Run repository entry for the provided runId. // It sets the status to 'failed' and updates the run's EndTime to the current database // time, and sets the completed and total counts. // -// Once a run has been persisted with a final run status (failed +// Once a run has been persisted with a final run status (completed, failed // or interrupted), any future calls to FailRun will return an error with Code // errors.InvalidJobRunState. // All options are ignored. @@ -263,7 +280,7 @@ func (r *Repository) FailRun(ctx context.Context, runId string, completed, total // updated for the provided interruptThreshold. It sets the status to 'interrupted' and // updates the run's EndTime to the current database time. // -// Once a run has been persisted with a final run status (failed +// Once a run has been persisted with a final run status (completed, failed // or interrupted), any future calls to InterruptRuns will return an error with Code // errors.InvalidJobRunState. // WithControllerId is the only valid option diff --git a/internal/scheduler/job/repository_run_test.go b/internal/scheduler/job/repository_run_test.go index a5565520a34..fcc415e2514 100644 --- a/internal/scheduler/job/repository_run_test.go +++ b/internal/scheduler/job/repository_run_test.go @@ -5,6 +5,7 @@ package job import ( "context" + "fmt" "sort" "testing" "time" @@ -119,6 +120,73 @@ func TestRepository_RunJobs(t *testing.T) { } } +func TestRepository_RunJobs_Limits(t *testing.T) { + t.Parallel() + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + kms := kms.TestKms(t, conn, wrapper) + iam.TestRepo(t, conn, wrapper) + + numJobs := 20 + server := testController(t, conn, wrapper) + + tests := []struct { + name string + opts []Option + wantLen int + }{ + { + name: "with-more-than-available", + opts: []Option{WithRunJobsLimit(numJobs * 2)}, + wantLen: numJobs, + }, + { + name: "with-no-option", + wantLen: defaultRunJobsLimit, + }, + { + name: "with-limit", + opts: []Option{WithRunJobsLimit(3)}, + wantLen: 3, + }, + { + name: "with-zero-limit", + opts: []Option{WithRunJobsLimit(0)}, + wantLen: defaultRunJobsLimit, + }, + { + name: "unlimited", + opts: []Option{WithRunJobsLimit(-1)}, + wantLen: numJobs, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + repo, err := NewRepository(ctx, rw, rw, kms) + assert.NoError(err) + require.NotNil(repo) + + for i := 0; i < numJobs; i++ { + testJob(t, conn, fmt.Sprintf("%v-%d", tt.name, i), "description", wrapper) + } + + got, err := repo.RunJobs(ctx, server.PrivateId, tt.opts...) + require.NoError(err) + assert.Len(got, tt.wantLen) + + // Clean up jobs for next run + rows, err := rw.Query(ctx, "delete from job", nil) + require.NoError(err) + _ = rows.Close() + }) + } +} + func TestRepository_RunJobsOrder(t *testing.T) { t.Parallel() ctx := context.Background() @@ -142,18 +210,41 @@ func TestRepository_RunJobsOrder(t *testing.T) { runs, err := repo.RunJobs(ctx, server.PrivateId) require.NoError(err) - require.Len(runs, 3) + require.Len(runs, 1) + run := runs[0] + assert.Equal(run.JobName, firstJob.Name) + assert.Equal(run.JobPluginId, firstJob.PluginId) + + // End first job with time between last and middle + _, err = repo.CompleteRun(ctx, run.PrivateId, -6*time.Hour, 0, 0, 0) + require.NoError(err) + + runs, err = repo.RunJobs(ctx, server.PrivateId) + require.NoError(err) + require.Len(runs, 1) + run = runs[0] + assert.Equal(run.JobName, middleJob.Name) + assert.Equal(run.JobPluginId, middleJob.PluginId) - // We should see the job runs ordered by scheduled time. - // firstJob > middleJob > lastJob - assert.Equal(firstJob.Name, runs[0].JobName) - assert.Equal(firstJob.PluginId, runs[0].JobPluginId) + // firstJob should be up again, as it is scheduled before lastJob + runs, err = repo.RunJobs(ctx, server.PrivateId) + require.NoError(err) + require.Len(runs, 1) + run = runs[0] + assert.Equal(run.JobName, firstJob.Name) + assert.Equal(run.JobPluginId, firstJob.PluginId) - assert.Equal(middleJob.Name, runs[1].JobName) - assert.Equal(middleJob.PluginId, runs[1].JobPluginId) + runs, err = repo.RunJobs(ctx, server.PrivateId) + require.NoError(err) + require.Len(runs, 1) + run = runs[0] + assert.Equal(run.JobName, lastJob.Name) + assert.Equal(run.JobPluginId, lastJob.PluginId) - assert.Equal(lastJob.Name, runs[2].JobName) - assert.Equal(lastJob.PluginId, runs[2].JobPluginId) + // All jobs are running no work should be returned + runs, err = repo.RunJobs(ctx, server.PrivateId) + require.NoError(err) + require.Len(runs, 0) } func TestRepository_UpdateProgress(t *testing.T) { @@ -215,6 +306,20 @@ func TestRepository_UpdateProgress(t *testing.T) { wantErrCode: errors.InvalidJobRunState, wantErrMsg: "job.(Repository).UpdateProgress: db.DoTx: job.(Repository).UpdateProgress: job run was in a final run state: failed: integrity violation: error #115", }, + { + name: "status-already-completed", + orig: &Run{ + JobRun: &store.JobRun{ + JobName: job.Name, + JobPluginId: job.PluginId, + ControllerId: server.PrivateId, + Status: Completed.string(), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidJobRunState, + wantErrMsg: "job.(Repository).UpdateProgress: db.DoTx: job.(Repository).UpdateProgress: job run was in a final run state: completed: integrity violation: error #115", + }, { name: "valid-no-changes", orig: &Run{ @@ -374,10 +479,14 @@ func TestRepository_CompleteRun(t *testing.T) { server := testController(t, conn, wrapper) job := testJob(t, conn, "name", "description", wrapper) + type args struct { + completed, total, retries int + } tests := []struct { name string orig *Run nextRunIn time.Duration + args args wantErr bool wantErrCode errors.Code wantErrMsg string @@ -416,6 +525,20 @@ func TestRepository_CompleteRun(t *testing.T) { wantErrCode: errors.InvalidJobRunState, wantErrMsg: "job.(Repository).CompleteRun: db.DoTx: job.(Repository).CompleteRun: job run was in a final run state: failed: integrity violation: error #115", }, + { + name: "status-already-completed", + orig: &Run{ + JobRun: &store.JobRun{ + JobName: job.Name, + JobPluginId: job.PluginId, + ControllerId: server.PrivateId, + Status: Completed.string(), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidJobRunState, + wantErrMsg: "job.(Repository).CompleteRun: db.DoTx: job.(Repository).CompleteRun: job run was in a final run state: completed: integrity violation: error #115", + }, { name: "valid", orig: &Run{ @@ -438,6 +561,7 @@ func TestRepository_CompleteRun(t *testing.T) { Status: Running.string(), }, }, + args: args{completed: 10, total: 20, retries: 1}, }, } @@ -455,13 +579,9 @@ func TestRepository_CompleteRun(t *testing.T) { require.NoError(err) assert.Empty(tt.orig.EndTime) privateId = tt.orig.PrivateId - - r, err := repo.LookupRun(ctx, privateId) - require.NoError(err) - require.NotNil(r) } - err = repo.CompleteRun(ctx, privateId, tt.nextRunIn) + got, err := repo.CompleteRun(ctx, privateId, tt.nextRunIn, tt.args.completed, tt.args.total, tt.args.retries) if tt.wantErr { require.Error(err) assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "Unexpected error %s", err) @@ -476,21 +596,27 @@ func TestRepository_CompleteRun(t *testing.T) { return } assert.NoError(err) + require.NotNil(got) + assert.NotEmpty(got.EndTime) + assert.Equal(Completed.string(), got.Status) + assert.Equal(tt.args.completed, int(got.CompletedCount)) + assert.Equal(tt.args.total, int(got.TotalCount)) + assert.Equal(tt.args.retries, int(got.RetriesCount)) updatedJob, err := repo.LookupJob(ctx, tt.orig.JobName) assert.NoError(err) require.NotNil(updatedJob) - // The next run is expected to be ~ now + whatever duration was - // passed into CompleteRun. - expectedNextRunIn := time.Now().Add(tt.nextRunIn).Round(time.Minute).UTC() - actualNextRunIn := updatedJob.NextScheduledRun.AsTime().Round(time.Minute).UTC() - require.EqualValues(expectedNextRunIn, actualNextRunIn) + // The previous run is ended before the next run is scheduled, therefore the previous + // run end time incremented by the nextRunIn duration, should be less than or equal to the + // NextScheduledRun time that is persisted in the repo. + nextRunAt := updatedJob.NextScheduledRun.AsTime() + previousRunEnd := got.EndTime.AsTime() + assert.Equal(nextRunAt.Round(time.Minute), previousRunEnd.Add(tt.nextRunIn).Round(time.Minute)) - // If we can't find the run, it means it was complete. - r, err := repo.LookupRun(ctx, privateId) - require.NoError(err) - require.Nil(r) + // Delete job run so it does not clash with future runs + _, err = repo.deleteRun(ctx, privateId) + assert.NoError(err) }) } @@ -500,8 +626,9 @@ func TestRepository_CompleteRun(t *testing.T) { require.NoError(err) require.NotNil(repo) - err = repo.CompleteRun(ctx, "fake-run-id", time.Hour) + got, err := repo.CompleteRun(ctx, "fake-run-id", time.Hour, 0, 0, 0) require.Error(err) + require.Nil(got) assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "Unexpected error %s", err) assert.Equal("job.(Repository).CompleteRun: db.DoTx: job.(Repository).CompleteRun: job run \"fake-run-id\" does not exist: db.LookupById: record not found, search issue: error #1100: dbw.LookupById: record not found", err.Error()) }) @@ -564,6 +691,20 @@ func TestRepository_FailRun(t *testing.T) { wantErrCode: errors.InvalidJobRunState, wantErrMsg: "job.(Repository).FailRun: db.DoTx: job.(Repository).FailRun: job run was in a final run state: failed: integrity violation: error #115", }, + { + name: "status-already-completed", + orig: &Run{ + JobRun: &store.JobRun{ + JobName: job.Name, + JobPluginId: job.PluginId, + ControllerId: server.PrivateId, + Status: Completed.string(), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidJobRunState, + wantErrMsg: "job.(Repository).FailRun: db.DoTx: job.(Repository).FailRun: job run was in a final run state: completed: integrity violation: error #115", + }, { name: "valid", orig: &Run{ @@ -771,6 +912,7 @@ func TestRepository_InterruptServerRuns(t *testing.T) { runs: []args{ { ControllerId: server1.PrivateId, + opts: []Option{WithRunJobsLimit(3)}, expectedJobs: []*Job{job1, job2, job3}, }, }, @@ -785,6 +927,7 @@ func TestRepository_InterruptServerRuns(t *testing.T) { runs: []args{ { ControllerId: server2.PrivateId, + opts: []Option{WithRunJobsLimit(3)}, expectedJobs: []*Job{job1, job2, job3}, }, }, @@ -830,6 +973,124 @@ func TestRepository_InterruptServerRuns(t *testing.T) { }, }, }, + { + name: "multiple-servers-interrupt-all", + runs: []args{ + { + ControllerId: server1.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job1}, + }, + { + ControllerId: server2.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job2}, + }, + { + ControllerId: server3.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job3}, + }, + }, + interrupts: []args{ + { + expectedJobs: []*Job{job1, job2, job3}, + }, + }, + }, + { + name: "multiple-servers-with-server-id", + runs: []args{ + { + ControllerId: server1.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job1}, + }, + { + ControllerId: server2.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job2}, + }, + { + ControllerId: server3.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job3}, + }, + }, + interrupts: []args{ + { + opts: []Option{WithControllerId(server1.PrivateId)}, + expectedJobs: []*Job{job1}, + }, + { + opts: []Option{WithControllerId(server2.PrivateId)}, + expectedJobs: []*Job{job2}, + }, + { + opts: []Option{WithControllerId(server3.PrivateId)}, + expectedJobs: []*Job{job3}, + }, + }, + }, + { + name: "multiple-servers-distributed-runs", + runs: []args{ + { + ControllerId: server1.PrivateId, + opts: []Option{WithRunJobsLimit(2)}, + expectedJobs: []*Job{job1, job2}, + }, + { + ControllerId: server2.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job3}, + }, + { + ControllerId: server3.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{}, + }, + }, + interrupts: []args{ + { + opts: []Option{WithControllerId(server1.PrivateId)}, + expectedJobs: []*Job{job1, job2}, + }, + { + opts: []Option{WithControllerId(server2.PrivateId)}, + expectedJobs: []*Job{job3}, + }, + { + opts: []Option{WithControllerId(server3.PrivateId)}, + expectedJobs: []*Job{}, + }, + }, + }, + { + name: "multiple-servers-distributed-runs-interrupt-all", + runs: []args{ + { + ControllerId: server1.PrivateId, + opts: []Option{WithRunJobsLimit(2)}, + expectedJobs: []*Job{job1, job2}, + }, + { + ControllerId: server2.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{job3}, + }, + { + ControllerId: server3.PrivateId, + opts: []Option{WithRunJobsLimit(1)}, + expectedJobs: []*Job{}, + }, + }, + interrupts: []args{ + { + expectedJobs: []*Job{job1, job2, job3}, + }, + }, + }, } for _, tt := range tests { tt := tt @@ -838,7 +1099,7 @@ func TestRepository_InterruptServerRuns(t *testing.T) { require.NoError(err) for _, r := range tt.runs { - runs, err := repo.RunJobs(ctx, r.ControllerId) + runs, err := repo.RunJobs(ctx, r.ControllerId, r.opts...) require.NoError(err) assert.Len(runs, len(r.expectedJobs)) sort.Slice(runs, func(i, j int) bool { return runs[i].JobName < runs[j].JobName }) diff --git a/internal/scheduler/job/run.go b/internal/scheduler/job/run.go index 0229c18fe06..2128af7b486 100644 --- a/internal/scheduler/job/run.go +++ b/internal/scheduler/job/run.go @@ -8,7 +8,7 @@ import ( "google.golang.org/protobuf/proto" ) -// Run represents an instance of a job that is either actively running or has failed in some way. +// Run represents an instance of a job that is either actively running or has already completed. type Run struct { *store.JobRun tableName string `gorm:"-"` diff --git a/internal/scheduler/job/status.go b/internal/scheduler/job/status.go index 4fe5df00771..5db19ff0d09 100644 --- a/internal/scheduler/job/status.go +++ b/internal/scheduler/job/status.go @@ -9,6 +9,9 @@ const ( // Running represents that the job run is actively running on a server Running Status = "running" + // Completed represents that the job run has successfully finished + Completed Status = "completed" + // Failed represent that the job run had an error during execution Failed Status = "failed" diff --git a/internal/scheduler/job/store/job.pb.go b/internal/scheduler/job/store/job.pb.go index f64fae2c2ca..c6d4020a84f 100644 --- a/internal/scheduler/job/store/job.pb.go +++ b/internal/scheduler/job/store/job.pb.go @@ -138,7 +138,7 @@ type JobRun struct { // a job has retried work. // @inject_tag: `gorm:"default:0"` RetriesCount uint32 `protobuf:"varint,12,opt,name=retries_count,json=retriesCount,proto3" json:"retries_count,omitempty" gorm:"default:0"` - // status of the job run (running, failed or interrupted). + // status of the job run (running, completed, failed or interrupted). // @inject_tag: `gorm:"not_null"` Status string `protobuf:"bytes,10,opt,name=status,proto3" json:"status,omitempty" gorm:"not_null"` // The controller_id of the controller running the job and must be set. diff --git a/internal/scheduler/options.go b/internal/scheduler/options.go index 056ced18617..c9a3c1d4247 100644 --- a/internal/scheduler/options.go +++ b/internal/scheduler/options.go @@ -6,6 +6,7 @@ package scheduler import "time" const ( + defaultRunJobsLimit = 1 defaultRunJobsInterval = time.Minute defaultMonitorInterval = 30 * time.Second defaultInterruptThreshold = 5 * time.Minute @@ -26,6 +27,7 @@ type Option func(*options) // options = how options are represented type options struct { withNextRunIn time.Duration + withRunJobsLimit int withRunJobInterval time.Duration withMonitorInterval time.Duration withInterruptThreshold time.Duration @@ -34,12 +36,26 @@ type options struct { func getDefaultOptions() options { return options{ + withRunJobsLimit: defaultRunJobsLimit, withRunJobInterval: defaultRunJobsInterval, withMonitorInterval: defaultMonitorInterval, withInterruptThreshold: defaultInterruptThreshold, } } +// WithRunJobsLimit provides an option to provide the number of jobs that will be requested +// by the scheduler when querying for jobs to run. +// If WithRunJobsLimit == 0, then default run jobs limit is used. +// If WithRunJobsLimit < 0, then no limit is used. +func WithRunJobsLimit(l int) Option { + return func(o *options) { + o.withRunJobsLimit = l + if o.withRunJobsLimit == 0 { + o.withRunJobsLimit = defaultRunJobsLimit + } + } +} + // WithRunJobsInterval provides an option to provide the interval at which the scheduler // will query the repository for jobs to run. // If WithRunJobsInterval == 0, then default interval is used. diff --git a/internal/scheduler/options_test.go b/internal/scheduler/options_test.go index 5b3fc4733ae..d5e872a67cc 100644 --- a/internal/scheduler/options_test.go +++ b/internal/scheduler/options_test.go @@ -13,6 +13,20 @@ import ( // Test_GetOpts provides unit tests for GetOpts and all the options func Test_GetOpts(t *testing.T) { t.Parallel() + t.Run("WithRunJobsLimit", func(t *testing.T) { + assert := assert.New(t) + opts := getOpts(WithRunJobsLimit(10)) + testOpts := getDefaultOptions() + assert.NotEqual(opts, testOpts) + testOpts.withRunJobsLimit = 10 + assert.Equal(opts, testOpts) + }) + t.Run("WithZeroRunJobsLimit", func(t *testing.T) { + assert := assert.New(t) + opts := getOpts(WithRunJobsLimit(0)) + testOpts := getDefaultOptions() + assert.Equal(opts, testOpts) + }) t.Run("WithRunJobsInterval", func(t *testing.T) { assert := assert.New(t) opts := getOpts(WithRunJobsInterval(time.Hour)) diff --git a/internal/scheduler/scheduler.go b/internal/scheduler/scheduler.go index 66592fe7b86..b71f77b93d0 100644 --- a/internal/scheduler/scheduler.go +++ b/internal/scheduler/scheduler.go @@ -32,6 +32,7 @@ type Scheduler struct { runningJobs *sync.Map started ua.Bool + runJobsLimit int runJobsInterval time.Duration monitorInterval time.Duration interruptThreshold time.Duration @@ -44,7 +45,7 @@ type Scheduler struct { // // • jobRepoFn must be provided and is a function that returns the job repository // -// WithRunJobsInterval, WithMonitorInterval and WithInterruptThreshold are +// WithRunJobsLimit, WithRunJobsInterval, WithMonitorInterval and WithInterruptThreshold are // the only valid options. func New(ctx context.Context, serverId string, jobRepoFn jobRepoFactory, opt ...Option) (*Scheduler, error) { const op = "scheduler.New" @@ -61,6 +62,7 @@ func New(ctx context.Context, serverId string, jobRepoFn jobRepoFactory, opt ... jobRepoFn: jobRepoFn, registeredJobs: new(sync.Map), runningJobs: new(sync.Map), + runJobsLimit: opts.withRunJobsLimit, runJobsInterval: opts.withRunJobInterval, monitorInterval: opts.withMonitorInterval, interruptThreshold: opts.withInterruptThreshold, @@ -188,7 +190,7 @@ func (s *Scheduler) start(ctx context.Context) { event.WriteSysEvent(ctx, op, "scheduling loop running", "server id", s.serverId, "run interval", s.runJobsInterval.String(), - ) + "run limit", s.runJobsLimit) timer := time.NewTimer(0) var wg sync.WaitGroup for { @@ -216,7 +218,7 @@ func (s *Scheduler) schedule(ctx context.Context, wg *sync.WaitGroup) { return } - runs, err := repo.RunJobs(ctx, s.serverId) + runs, err := repo.RunJobs(ctx, s.serverId, job.WithRunJobsLimit(s.runJobsLimit)) if err != nil { event.WriteError(ctx, op, err, event.WithInfoMsg("error getting jobs to run from repo")) return @@ -260,6 +262,8 @@ func (s *Scheduler) runJob(ctx context.Context, wg *sync.WaitGroup, r *job.Run) defer wg.Done() runErr := j.Run(jobContext, s.interruptThreshold) + // Get final status report to update run progress with + status := j.Status() var updateErr error switch { case ctx.Err() != nil: @@ -269,11 +273,9 @@ func (s *Scheduler) runJob(ctx context.Context, wg *sync.WaitGroup, r *job.Run) if inner != nil { event.WriteError(ctx, op, inner, event.WithInfoMsg("error getting next run time", "name", j.Name())) } - updateErr = repo.CompleteRun(ctx, r.PrivateId, nextRun) + _, updateErr = repo.CompleteRun(ctx, r.PrivateId, nextRun, status.Completed, status.Total, status.Retries) default: event.WriteError(ctx, op, runErr, event.WithInfoMsg("job run failed", "run id", r.PrivateId, "name", j.Name())) - - status := j.Status() // Get final status report to update run progress with _, updateErr = repo.FailRun(ctx, r.PrivateId, status.Completed, status.Total, status.Retries) } diff --git a/internal/scheduler/scheduler_test.go b/internal/scheduler/scheduler_test.go index b96a55cdb3a..c9b22bcbcb8 100644 --- a/internal/scheduler/scheduler_test.go +++ b/internal/scheduler/scheduler_test.go @@ -34,6 +34,7 @@ func TestScheduler_New(t *testing.T) { type args struct { serverId string jobRepo jobRepoFactory + runLimit int runInterval time.Duration monitorInterval time.Duration } @@ -69,6 +70,7 @@ func TestScheduler_New(t *testing.T) { }, want: args{ serverId: "test-server", + runLimit: defaultRunJobsLimit, runInterval: defaultRunJobsInterval, monitorInterval: defaultMonitorInterval, }, @@ -84,6 +86,7 @@ func TestScheduler_New(t *testing.T) { }, want: args{ serverId: "test-server", + runLimit: defaultRunJobsLimit, monitorInterval: defaultMonitorInterval, runInterval: time.Hour, }, @@ -94,9 +97,12 @@ func TestScheduler_New(t *testing.T) { serverId: "test-server", jobRepo: jobRepoFn, }, - opts: []Option{}, + opts: []Option{ + WithRunJobsLimit(-1), + }, want: args{ serverId: "test-server", + runLimit: -1, runInterval: defaultRunJobsInterval, monitorInterval: defaultMonitorInterval, }, @@ -107,9 +113,12 @@ func TestScheduler_New(t *testing.T) { serverId: "test-server", jobRepo: jobRepoFn, }, - opts: []Option{}, + opts: []Option{ + WithRunJobsLimit(20), + }, want: args{ serverId: "test-server", + runLimit: 20, runInterval: defaultRunJobsInterval, monitorInterval: defaultMonitorInterval, }, @@ -125,6 +134,7 @@ func TestScheduler_New(t *testing.T) { }, want: args{ serverId: "test-server", + runLimit: defaultRunJobsLimit, runInterval: defaultRunJobsInterval, monitorInterval: time.Hour, }, @@ -137,10 +147,12 @@ func TestScheduler_New(t *testing.T) { }, opts: []Option{ WithRunJobsInterval(time.Hour), + WithRunJobsLimit(20), WithMonitorInterval(2 * time.Hour), }, want: args{ serverId: "test-server", + runLimit: 20, runInterval: time.Hour, monitorInterval: 2 * time.Hour, }, @@ -162,6 +174,7 @@ func TestScheduler_New(t *testing.T) { require.NoError(err) assert.Equal(tt.want.serverId, got.serverId) + assert.Equal(tt.want.runLimit, got.runJobsLimit) assert.Equal(tt.want.runInterval, got.runJobsInterval) assert.Equal(tt.want.monitorInterval, got.monitorInterval) assert.NotNil(got.jobRepoFn) diff --git a/internal/server/repository_controller.go b/internal/server/repository_controller.go index 4ecc2298942..5e5ac77cba6 100644 --- a/internal/server/repository_controller.go +++ b/internal/server/repository_controller.go @@ -46,7 +46,7 @@ func (r *Repository) listControllersWithReader(ctx context.Context, reader db.Re } func (r *Repository) UpsertController(ctx context.Context, controller *store.Controller) (int, error) { - const op = "server.(Repository).UpsertController" + const op = "server.UpsertController" if controller == nil { return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "controller is nil") diff --git a/internal/server/repository_nonce.go b/internal/server/repository_nonce.go index 90626f0e289..c72fe659e4a 100644 --- a/internal/server/repository_nonce.go +++ b/internal/server/repository_nonce.go @@ -30,7 +30,7 @@ const ( // AddNonce adds a nonce func (r *Repository) AddNonce(ctx context.Context, nonce, purpose string, opt ...Option) error { - const op = "server.(Repository).AddNonce" + const op = "server.AddNonce" if nonce == "" { return errors.New(ctx, errors.InvalidParameter, op, "empty nonce") } diff --git a/internal/server/repository_worker.go b/internal/server/repository_worker.go index fbb9af0ee5a..f3e95b161ca 100644 --- a/internal/server/repository_worker.go +++ b/internal/server/repository_worker.go @@ -303,7 +303,7 @@ func ListWorkers(ctx context.Context, reader db.Reader, scopeIds []string, opt . // the only ones used. All others are ignored. // Workers are intentionally not oplogged. func (r *Repository) UpsertWorkerStatus(ctx context.Context, worker *Worker, opt ...Option) (*Worker, error) { - const op = "server.(Repository).UpsertWorkerStatus" + const op = "server.UpsertWorkerStatus" opts := GetOpts(opt...) switch { @@ -519,10 +519,10 @@ func setWorkerTags(ctx context.Context, w db.Writer, id string, ts TagSource, ta // via the old registration method or pki-kms) name updates will be disallowed. func (r *Repository) UpdateWorker(ctx context.Context, worker *Worker, version uint32, fieldMaskPaths []string, opt ...Option) (*Worker, int, error) { const ( - op = "server.(Repository).UpdateWorker" nameField = "name" descField = "description" ) + const op = "server.(Repository).UpdateWorker" switch { case worker == nil: return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "worker is nil") @@ -631,7 +631,7 @@ func (r *Repository) UpdateWorker(ctx context.Context, worker *Worker, version u // WithCreateControllerLedActivationToken. The latter two are mutually // exclusive. func (r *Repository) CreateWorker(ctx context.Context, worker *Worker, opt ...Option) (*Worker, error) { - const op = "server.(Repository).CreateWorker" + const op = "server.CreateWorker" opts := GetOpts(opt...) diff --git a/internal/server/worker_auth.go b/internal/server/worker_auth.go index 490986bb3ff..08b91c3f4f4 100644 --- a/internal/server/worker_auth.go +++ b/internal/server/worker_auth.go @@ -215,7 +215,7 @@ func (w *WorkerCertBundle) clone() *WorkerCertBundle { // Validate is called before storing a WorkerCertBundle in the db func (w *WorkerCertBundle) ValidateNewWorkerCertBundle(ctx context.Context) error { - const op = "server.(WorkerCertBundle).validateNewWorkerCertBundle" + const op = "server.(WorkerAuth).validateNewWorkerCertBundle" if w.RootCertificatePublicKey == nil { return errors.New(ctx, errors.InvalidParameter, op, "missing CertificatePublicKey") } diff --git a/internal/session/connection.go b/internal/session/connection.go index 3941b349045..b4697ad7f99 100644 --- a/internal/session/connection.go +++ b/internal/session/connection.go @@ -5,7 +5,6 @@ package session import ( "context" - "net" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/db/timestamp" @@ -186,14 +185,5 @@ func (c *Connection) validateNewConnection(ctx context.Context) error { if c.UserClientIp == "" { return errors.New(ctx, errors.InvalidParameter, op, "missing user client ip") } - if ip := net.ParseIP(c.ClientTcpAddress); ip == nil { - return errors.New(ctx, errors.InvalidParameter, op, "given client tcp address is not an ip address") - } - if ip := net.ParseIP(c.EndpointTcpAddress); ip == nil { - return errors.New(ctx, errors.InvalidParameter, op, "given endpoint tcp address is not an ip address") - } - if ip := net.ParseIP(c.UserClientIp); ip == nil { - return errors.New(ctx, errors.InvalidParameter, op, "given user client ip is not an ip address") - } return nil } diff --git a/internal/session/connection_test.go b/internal/session/connection_test.go index b5f515b1add..0dbe2f8c93d 100644 --- a/internal/session/connection_test.go +++ b/internal/session/connection_test.go @@ -31,24 +31,23 @@ func TestConnection_Create(t *testing.T) { userClientIp string } tests := []struct { - name string - args args - want *Connection - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - expectedErrMsg string + name string + args args + want *Connection + wantErr bool + wantIsErr errors.Code + create bool + wantCreateErr bool }{ { - name: "valid-ipv4", + name: "valid", args: args{ sessionId: s.PublicId, clientTcpAddress: "127.0.0.1", clientTcpPort: 22, endpointTcpAddress: "127.0.0.1", endpointTcpPort: 2222, - userClientIp: "127.0.0.2", + userClientIp: "::1", }, want: &Connection{ SessionId: s.PublicId, @@ -56,134 +55,10 @@ func TestConnection_Create(t *testing.T) { ClientTcpPort: 22, EndpointTcpAddress: "127.0.0.1", EndpointTcpPort: 2222, - UserClientIp: "127.0.0.2", + UserClientIp: "::1", }, create: true, }, - { - name: "valid-ipv6", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "2001:4860:4860:0:0:0:0:8887", - clientTcpPort: 22, - endpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", - endpointTcpPort: 2222, - userClientIp: "2001:4860:4860:0:0:0:0:8885", - }, - want: &Connection{ - SessionId: s.PublicId, - ClientTcpAddress: "2001:4860:4860:0:0:0:0:8887", - ClientTcpPort: 22, - EndpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", - EndpointTcpPort: 2222, - UserClientIp: "2001:4860:4860:0:0:0:0:8885", - }, - create: true, - }, - { - name: "valid-abbreviated-ipv6", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "2001:4860:4860::8887", - clientTcpPort: 22, - endpointTcpAddress: "2001:4860:4860::8886", - endpointTcpPort: 2222, - userClientIp: "2001:4860:4860::8885", - }, - want: &Connection{ - SessionId: s.PublicId, - ClientTcpAddress: "2001:4860:4860::8887", - ClientTcpPort: 22, - EndpointTcpAddress: "2001:4860:4860::8886", - EndpointTcpPort: 2222, - UserClientIp: "2001:4860:4860::8885", - }, - create: true, - }, - { - name: "invalid-[ipv6]-client-tcp-address", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "[2001:4860:4860:0:0:0:0:8887]", - clientTcpPort: 22, - endpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", - endpointTcpPort: 2222, - userClientIp: "2001:4860:4860:0:0:0:0:8885", - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - expectedErrMsg: "given client tcp address is not an ip address", - }, - { - name: "invalid-[ipv6]-endpoint-tcp-address", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "2001:4860:4860:0:0:0:0:8887", - clientTcpPort: 22, - endpointTcpAddress: "[2001:4860:4860:0:0:0:0:8886]", - endpointTcpPort: 2222, - userClientIp: "2001:4860:4860:0:0:0:0:8885", - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - expectedErrMsg: "given endpoint tcp address is not an ip address", - }, - { - name: "invalid-[ipv6]-user-client-ip", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "2001:4860:4860:0:0:0:0:8887", - clientTcpPort: 22, - endpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", - endpointTcpPort: 2222, - userClientIp: "[2001:4860:4860:0:0:0:0:8885]", - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - expectedErrMsg: "given user client ip is not an ip address", - }, - { - name: "invalid-abbreviated-[ipv6]-client-tcp-address", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "[2001:4860:4860::8887]", - clientTcpPort: 22, - endpointTcpAddress: "2001:4860:4860::8886", - endpointTcpPort: 2222, - userClientIp: "2001:4860:4860::8885", - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - expectedErrMsg: "given client tcp address is not an ip address", - }, - { - name: "invalid-abbreviated-[ipv6]-endpoint-tcp-address", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "2001:4860:4860::8887", - clientTcpPort: 22, - endpointTcpAddress: "[2001:4860:4860::8886]", - endpointTcpPort: 2222, - userClientIp: "2001:4860:4860::8885", - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - expectedErrMsg: "given endpoint tcp address is not an ip address", - }, - { - name: "invalid-abbreviated-[ipv6]-user-client-ip", - args: args{ - sessionId: s.PublicId, - clientTcpAddress: "2001:4860:4860::8887", - clientTcpPort: 22, - endpointTcpAddress: "2001:4860:4860::8886", - endpointTcpPort: 2222, - userClientIp: "[2001:4860:4860::8885]", - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - expectedErrMsg: "given user client ip is not an ip address", - }, { name: "empty-session-id", args: args{ @@ -272,9 +147,6 @@ func TestConnection_Create(t *testing.T) { if tt.wantErr { require.Error(err) assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - if tt.expectedErrMsg != "" { - assert.ErrorContains(err, tt.expectedErrMsg) - } return } require.NoError(err) diff --git a/internal/session/session.go b/internal/session/session.go index 5f8b7b9994e..6cbf75fb60d 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -472,9 +472,13 @@ func newCert(ctx context.Context, jobId string, addresses []string, exp time.Tim for _, addr := range addresses { // First ensure we aren't looking at ports, regardless of IP or not - host, _, err := util.SplitHostPort(addr) + host, _, err := net.SplitHostPort(addr) if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) + if strings.Contains(err.Error(), "missing port") { + host = addr + } else { + return nil, nil, errors.Wrap(ctx, err, op) + } } // Now figure out if it's an IP address or not. If ParseIP likes it, add // to IP SANs. Otherwise DNS SANs. diff --git a/internal/target/repository.go b/internal/target/repository.go index d1ec66708c3..c91624dba51 100644 --- a/internal/target/repository.go +++ b/internal/target/repository.go @@ -22,7 +22,6 @@ import ( "github.com/hashicorp/boundary/internal/types/action" "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-dbw" ) @@ -551,11 +550,7 @@ func (r *Repository) CreateTarget(ctx context.Context, target Target, opt ...Opt var address *Address var err error if t.GetAddress() != "" { - host, err := util.ParseAddress(ctx, t.GetAddress()) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) - } - t.SetAddress(host) + t.SetAddress(strings.TrimSpace(t.GetAddress())) address, err = NewAddress(ctx, t.GetPublicId(), t.GetAddress()) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -655,6 +650,7 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui return nil, db.NoRowsAffected, err } + var addressEndpoint string for _, f := range fieldMaskPaths { switch { case strings.EqualFold("name", f): @@ -667,6 +663,8 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui case strings.EqualFold("egressworkerfilter", f): case strings.EqualFold("ingressworkerfilter", f): case strings.EqualFold("address", f): + target.SetAddress(strings.TrimSpace(target.GetAddress())) + addressEndpoint = target.GetAddress() case strings.EqualFold("storagebucketid", f): case strings.EqualFold("enablesessionrecording", f): default: @@ -700,19 +698,12 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui // The Address field is not a part of the target schema in the database. It // is a part of a different table called target_address, which is why the // Address field must be filtered out of the dbMask & nullFields slices. - var addressEndpoint string var updateAddress, deleteAddress bool var filteredDbMask, filteredNullFields []string for _, f := range dbMask { switch { case strings.EqualFold("Address", f): updateAddress = true - address, err := util.ParseAddress(ctx, target.GetAddress()) - if err != nil { - return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) - } - target.SetAddress(address) - addressEndpoint = target.GetAddress() default: filteredDbMask = append(filteredDbMask, f) } diff --git a/internal/target/tcp/repository_tcp_target_test.go b/internal/target/tcp/repository_tcp_target_test.go index 807578e3182..6341c86dbf5 100644 --- a/internal/target/tcp/repository_tcp_target_test.go +++ b/internal/target/tcp/repository_tcp_target_test.go @@ -70,23 +70,6 @@ func TestRepository_CreateTarget(t *testing.T) { }, wantErr: false, }, - { - name: "with-dns-name", - args: args{ - target: func() *tcp.Target { - target, err := target.New(ctx, tcp.Subtype, proj.PublicId, - target.WithName("with-dns-name"), - target.WithDescription("with-dns-name"), - target.WithDefaultPort(uint32(22)), - target.WithAddress("www.google.com"), - ) - require.NoError(t, err) - return target.(*tcp.Target) - }(), - }, - wantErr: false, - wantAddress: "www.google.com", - }, { name: "with-ipv4-address", args: args{ @@ -100,24 +83,7 @@ func TestRepository_CreateTarget(t *testing.T) { return target }(), }, - wantErr: false, - wantAddress: "8.8.8.8", - }, - { - name: "with-invalid-ipv4-address-with-port", - args: args{ - target: func() target.Target { - target, err := target.New(ctx, tcp.Subtype, proj.PublicId, - target.WithName("with-invalid-ipv4-address-with-port"), - target.WithDescription("with-invalid-ipv4-address-with-port"), - target.WithDefaultPort(80), - target.WithAddress("8.8.8.8:80")) - require.NoError(t, err) - return target - }(), - }, - wantErr: true, - wantIsError: errors.InvalidAddress, + wantErr: false, }, { name: "with-abbreviated-ipv6-address", @@ -132,8 +98,7 @@ func TestRepository_CreateTarget(t *testing.T) { return target }(), }, - wantErr: false, - wantAddress: "2001:4860:4860::8888", + wantErr: false, }, { name: "with-ipv6-address", @@ -148,72 +113,7 @@ func TestRepository_CreateTarget(t *testing.T) { return target }(), }, - wantErr: false, - wantAddress: "2001:4860:4860::8888", - }, - { - name: "with-abbreviated-[ipv6]-address", - args: args{ - target: func() target.Target { - target, err := target.New(ctx, tcp.Subtype, proj.PublicId, - target.WithName("with-abbreviated-[ipv6]-address"), - target.WithDescription("with-abbreviated-[ipv6]-address"), - target.WithDefaultPort(80), - target.WithAddress("[2001:4860:4860::8888]")) - require.NoError(t, err) - return target - }(), - }, - wantErr: false, - wantAddress: "2001:4860:4860::8888", - }, - { - name: "with-invalid-abbreviated-[ipv6]-address-with-port", - args: args{ - target: func() target.Target { - target, err := target.New(ctx, tcp.Subtype, proj.PublicId, - target.WithName("with-invalid-abbreviated-[ipv6]-address-with-port"), - target.WithDescription("with-invalid-abbreviated-[ipv6]-address-with-port"), - target.WithDefaultPort(80), - target.WithAddress("[2001:4860:4860::8888]:80")) - require.NoError(t, err) - return target - }(), - }, - wantErr: true, - wantIsError: errors.InvalidAddress, - }, - { - name: "with-[ipv6]-address", - args: args{ - target: func() target.Target { - target, err := target.New(ctx, tcp.Subtype, proj.PublicId, - target.WithName("with-[ipv6]-address"), - target.WithDescription("with-[ipv6]-address"), - target.WithDefaultPort(80), - target.WithAddress("[2001:4860:4860:0:0:0:0:8888]")) - require.NoError(t, err) - return target - }(), - }, - wantErr: false, - wantAddress: "2001:4860:4860:0:0:0:0:8888", - }, - { - name: "with-invalid-[ipv6]-address-with-port", - args: args{ - target: func() target.Target { - target, err := target.New(ctx, tcp.Subtype, proj.PublicId, - target.WithName("with-invalid-[ipv6]-address-with-port"), - target.WithDescription("with-invalid-[ipv6]-address-with-port"), - target.WithDefaultPort(80), - target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:80")) - require.NoError(t, err) - return target - }(), - }, - wantErr: true, - wantIsError: errors.InvalidAddress, + wantErr: false, }, { name: "with-address-whitespace", @@ -488,6 +388,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantRowsUpdate: 1, wantHostSources: true, }, + { name: "valid-ipv4-address", args: args{ @@ -500,20 +401,6 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantErr: false, wantRowsUpdate: 1, wantHostSources: false, - wantAddress: "8.8.8.8", - }, - { - name: "invalid-ipv4-address-with-port", - args: args{ - name: "invalid-ipv4-address-with-port" + id, - fieldMaskPaths: []string{"Name", "Address"}, - ProjectId: proj.PublicId, - address: "8.8.8.8:80", - }, - newProjectId: proj.PublicId, - wantErr: true, - wantIsError: errors.InvalidAddress, - wantErrMsg: "invalid address", }, { name: "valid-abbreviated-ipv6-address", @@ -527,7 +414,6 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantErr: false, wantRowsUpdate: 1, wantHostSources: false, - wantAddress: "2001:4860:4860::8888", }, { name: "valid-ipv6-address", @@ -541,61 +427,6 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantErr: false, wantRowsUpdate: 1, wantHostSources: false, - wantAddress: "2001:4860:4860::8888", - }, - { - name: "valid-abbreviated-[ipv6]-address", - args: args{ - name: "valid-abbreviated-[ipv6]-address" + id, - fieldMaskPaths: []string{"Name", "Address"}, - ProjectId: proj.PublicId, - address: "[2001:4860:4860::8888]", - }, - newProjectId: proj.PublicId, - wantErr: false, - wantRowsUpdate: 1, - wantHostSources: false, - wantAddress: "2001:4860:4860::8888", - }, - { - name: "invalid-abbreviated-[ipv6]-address-with-port", - args: args{ - name: "invalid-abbreviated-[ipv6]-address-with-port" + id, - fieldMaskPaths: []string{"Name", "Address"}, - ProjectId: proj.PublicId, - address: "[2001:4860:4860::8888]:80", - }, - newProjectId: proj.PublicId, - wantErr: true, - wantIsError: errors.InvalidAddress, - wantErrMsg: "invalid address", - }, - { - name: "valid-[ipv6]-address", - args: args{ - name: "valid-[ipv6]-address" + id, - fieldMaskPaths: []string{"Name", "Address"}, - ProjectId: proj.PublicId, - address: "[2001:4860:4860:0:0:0:0:8888]", - }, - newProjectId: proj.PublicId, - wantErr: false, - wantRowsUpdate: 1, - wantHostSources: false, - wantAddress: "2001:4860:4860:0:0:0:0:8888", - }, - { - name: "invalid-[ipv6]-address-with-port", - args: args{ - name: "invalid-[ipv6]-address-with-port" + id, - fieldMaskPaths: []string{"Name", "Address"}, - ProjectId: proj.PublicId, - address: "[2001:4860:4860:0:0:0:0:8888]:80", - }, - newProjectId: proj.PublicId, - wantErr: true, - wantIsError: errors.InvalidAddress, - wantErrMsg: "invalid address", }, { name: "null-address", diff --git a/internal/target/tcp/testing_test.go b/internal/target/tcp/testing_test.go index 24dc2a8b040..757657cc1e6 100644 --- a/internal/target/tcp/testing_test.go +++ b/internal/target/tcp/testing_test.go @@ -19,116 +19,39 @@ import ( ) func Test_TestTcpTarget(t *testing.T) { - t.Parallel() - + require := require.New(t) conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) testKms := kms.TestKms(t, conn, wrapper) iamRepo := iam.TestRepo(t, conn, wrapper) + _, proj := iam.TestScopes(t, iamRepo) + ctx := context.Background() repo, err := target.NewRepository(ctx, rw, rw, testKms) - require.NoError(t, err) - - t.Run("with-host-source", func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - _, proj := iam.TestScopes(t, iamRepo) - cats := static.TestCatalogs(t, conn, proj.PublicId, 1) - hsets := static.TestSets(t, conn, cats[0].GetPublicId(), 2) - var sets []string - for _, s := range hsets { - sets = append(sets, s.PublicId) - } - name := tcp.TestTargetName(t, proj.PublicId) - tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, name, target.WithHostSources(sets)) - require.NotNil(t) - assert.NotEmpty(tar.GetPublicId()) - assert.Equal(name, tar.GetName()) - assert.Empty(tar.GetAddress()) + require.NoError(err) - foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) - require.NoError(err) + cats := static.TestCatalogs(t, conn, proj.PublicId, 1) + hsets := static.TestSets(t, conn, cats[0].GetPublicId(), 2) + var sets []string + for _, s := range hsets { + sets = append(sets, s.PublicId) + } + name := tcp.TestTargetName(t, proj.PublicId) + tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, name, target.WithHostSources(sets)) + require.NotNil(t) + require.NotEmpty(tar.GetPublicId()) + require.Equal(name, tar.GetName()) - foundSources := foundTarget.GetHostSources() - foundIds := make([]string, 0, len(foundSources)) - for _, s := range foundSources { - foundIds = append(foundIds, s.Id()) - } - assert.ElementsMatch(sets, foundIds) - }) + foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) + foundSources := foundTarget.GetHostSources() - tests := []struct { - name string - opt []target.Option - wantAddress string - }{ - { - name: "dns-name", - opt: []target.Option{ - target.WithAddress("www.google.com"), - }, - wantAddress: "www.google.com", - }, - { - name: "ipv4-address", - opt: []target.Option{ - target.WithAddress("8.8.8.8"), - }, - wantAddress: "8.8.8.8", - }, - { - name: "ipv4-address-with-port", - opt: []target.Option{ - target.WithAddress("8.8.8.8:80"), - }, - wantAddress: "8.8.8.8:80", - }, - { - name: "ipv6-address", - opt: []target.Option{ - target.WithAddress("2001:4860:4860:0:0:0:0:8888"), - }, - wantAddress: "2001:4860:4860:0:0:0:0:8888", - }, - { - name: "ipv6-address-with-port", - opt: []target.Option{ - target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:80"), - }, - wantAddress: "[2001:4860:4860:0:0:0:0:8888]:80", - }, - { - name: "abbreviated-ipv6-address", - opt: []target.Option{ - target.WithAddress("2001:4860:4860::8888"), - }, - wantAddress: "2001:4860:4860::8888", - }, - { - name: "abbreviated-ipv6-address-with-port", - opt: []target.Option{ - target.WithAddress("[2001:4860:4860::8888]:80"), - }, - wantAddress: "[2001:4860:4860::8888]:80", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - _, proj := iam.TestScopes(t, iamRepo) - name := tcp.TestTargetName(t, proj.PublicId) - tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, name, tt.opt...) - require.NotNil(t) - assert.NotEmpty(tar.GetPublicId()) - assert.Equal(name, tar.GetName()) - if tt.wantAddress != "" { - assert.Equal(tt.wantAddress, tar.GetAddress()) - assert.Empty(tar.GetHostSources()) - } else { - assert.Empty(tar.GetAddress()) - } - }) + require.NoError(err) + foundIds := make([]string, 0, len(foundSources)) + for _, s := range foundSources { + foundIds = append(foundIds, s.Id()) } + require.ElementsMatch(sets, foundIds) } func Test_TestCredentialLibrary(t *testing.T) { diff --git a/internal/tests/api/targets/target_test.go b/internal/tests/api/targets/target_test.go index d00cc28d95b..72a6bb1ea95 100644 --- a/internal/tests/api/targets/target_test.go +++ b/internal/tests/api/targets/target_test.go @@ -383,7 +383,7 @@ func TestTarget_AddressMutualExclusiveRelationship(t *testing.T) { targets.WithName("test-address"), targets.WithAddress("[::1]"), targets.WithTcpTargetDefaultPort(22)) require.NoError(t, err) require.NotNil(t, targetResp) - require.Equal(t, "::1", targetResp.GetItem().Address) + require.Equal(t, "[::1]", targetResp.GetItem().Address) // Setup host catalog, host set, & host resources hc, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId()) @@ -477,7 +477,7 @@ func TestTarget_HostSourceMutualExclusiveRelationship(t *testing.T) { updateResp, err = tClient.Update(tc.Context(), targetId, version, targets.WithAddress("[::1]")) require.NoError(t, err) require.NotNil(t, updateResp) - require.Equal(t, "::1", updateResp.GetItem().Address) + require.Equal(t, "[::1]", updateResp.GetItem().Address) require.Empty(t, updateResp.GetItem().HostSourceIds) } @@ -491,29 +491,24 @@ func TestCreateTarget_DirectlyAttachedAddress(t *testing.T) { tClient := targets.NewClient(client) tests := []struct { - name string - address string - expectedAddress string + name string + address string }{ { - name: "target-ipv4-address", - address: "127.0.0.1", - expectedAddress: "127.0.0.1", + name: "target-ipv4-address", + address: "127.0.0.1", }, { - name: "target-ipv6-address", - address: "[2001:4860:4860:0:0:0:0:8888]", - expectedAddress: "2001:4860:4860:0:0:0:0:8888", + name: "target-ipv6-address", + address: "[2001:4860:4860:0:0:0:0:8888]", }, { - name: "target-abbreviated-ipv6-address", - address: "[2001:4860:4860::8888]", - expectedAddress: "2001:4860:4860::8888", + name: "target-abbreviated-ipv6-address", + address: "[2001:4860:4860::8888]", }, { - name: "target-dns-address", - address: "www.google.com", - expectedAddress: "www.google.com", + name: "target-dns-address", + address: "null", }, } for _, tt := range tests { @@ -523,14 +518,14 @@ func TestCreateTarget_DirectlyAttachedAddress(t *testing.T) { targets.WithName(tt.name), targets.WithAddress(tt.address), targets.WithTcpTargetDefaultPort(22)) require.NoError(err) require.NotNil(createResp) - assert.Equal(tt.expectedAddress, createResp.GetItem().Address) + assert.Equal(tt.address, createResp.GetItem().Address) targetId := createResp.GetItem().Id version := createResp.GetItem().Version readResp, err := tClient.Read(tc.Context(), targetId) require.NoError(err) require.NotNil(readResp) - assert.Equal(tt.expectedAddress, readResp.GetItem().Address) + assert.Equal(tt.address, readResp.GetItem().Address) updateResp, err := tClient.Update(tc.Context(), targetId, version, targets.DefaultAddress()) require.NoError(err) diff --git a/internal/tests/cluster/ipv6_listener_test.go b/internal/tests/cluster/ipv6_listener_test.go index 9d454221933..8274de0e163 100644 --- a/internal/tests/cluster/ipv6_listener_test.go +++ b/internal/tests/cluster/ipv6_listener_test.go @@ -5,8 +5,8 @@ package cluster import ( "context" - "sync" "testing" + "time" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/scopes" @@ -19,73 +19,58 @@ import ( ) func TestIPv6Listener(t *testing.T) { - t.Parallel() require := require.New(t) logger := hclog.New(&hclog.LoggerOptions{ Level: hclog.Trace, }) - conf, err := config.DevController(config.WithIPv6Enabled(true)) + conf, err := config.DevController() require.NoError(err) + for _, l := range conf.Listeners { + switch l.Purpose[0] { + case "api": + l.Address = "[::1]:9200" + + case "cluster": + l.Address = "[::1]:9201" + } + } + c1 := controller.NewTestController(t, &controller.TestControllerOpts{ Config: conf, Logger: logger.Named("c1"), }) defer c1.Shutdown() - c2 := c1.AddClusterControllerMember(t, &controller.TestControllerOpts{ - Config: conf, - Logger: c1.Config().Logger.ResetNamed("c2"), - }) - defer c2.Shutdown() + helper.ExpectWorkers(t, c1) - wg := new(sync.WaitGroup) - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2) - }() - wg.Wait() - - wconf, err := config.DevWorker(config.WithIPv6Enabled(true)) + wconf, err := config.DevWorker() require.NoError(err) w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ Config: wconf, WorkerAuthKms: c1.Config().WorkerAuthKms, - InitialUpstreams: append(c1.ClusterAddrs(), c2.ClusterAddrs()...), + InitialUpstreams: c1.ClusterAddrs(), Logger: logger.Named("w1"), }) defer w1.Shutdown() - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w1) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2, w1) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w1) - require.NoError(w1.Worker().Shutdown()) + c2 := c1.AddClusterControllerMember(t, &controller.TestControllerOpts{ + Logger: c1.Config().Logger.ResetNamed("c2"), + }) + defer c2.Shutdown() + + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c2, w1) - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2) - }() - wg.Wait() + require.NoError(w1.Worker().Shutdown()) + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1) + helper.ExpectWorkers(t, c2) client, err := api.NewClient(nil) require.NoError(err) diff --git a/internal/tests/cluster/multi_controller_worker_test.go b/internal/tests/cluster/multi_controller_worker_test.go index 9380fda0b91..80b3c6613fe 100644 --- a/internal/tests/cluster/multi_controller_worker_test.go +++ b/internal/tests/cluster/multi_controller_worker_test.go @@ -5,7 +5,6 @@ package cluster import ( "context" - "sync" "testing" "time" @@ -39,64 +38,33 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { }) defer c2.Shutdown() - wg := new(sync.WaitGroup) - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2) - }() - wg.Wait() + helper.ExpectWorkers(t, c1) + helper.ExpectWorkers(t, c2) w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ WorkerAuthKms: c1.Config().WorkerAuthKms, - InitialUpstreams: append(c1.ClusterAddrs(), c2.ClusterAddrs()...), + InitialUpstreams: c1.ClusterAddrs(), Logger: logger.Named("w1"), }) defer w1.Shutdown() - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w1) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2, w1) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w1) + helper.ExpectWorkers(t, c2, w1) w2 := w1.AddClusterWorkerMember(t, &worker.TestWorkerOpts{ Logger: logger.Named("w2"), }) defer w2.Shutdown() - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w1, w2) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2, w1, w2) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w1, w2) + helper.ExpectWorkers(t, c2, w1, w2) require.NoError(w1.Worker().Shutdown()) - - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w2) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2, w2) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w2) + helper.ExpectWorkers(t, c2, w2) w1 = worker.NewTestWorker(t, &worker.TestWorkerOpts{ WorkerAuthKms: c1.Config().WorkerAuthKms, @@ -105,41 +73,22 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { }) defer w1.Shutdown() - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w1, w2) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2, w1, w2) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w1, w2) + helper.ExpectWorkers(t, c2, w1, w2) require.NoError(c2.Controller().Shutdown()) - - wg.Add(1) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w1, w2) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w1, w2) c2 = c1.AddClusterControllerMember(t, &controller.TestControllerOpts{ Logger: c1.Config().Logger.ResetNamed("c2"), }) defer c2.Shutdown() - wg.Add(2) - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c1, w1, w2) - }() - go func() { - defer wg.Done() - helper.ExpectWorkers(t, c2, w1, w2) - }() - wg.Wait() + time.Sleep(10 * time.Second) + helper.ExpectWorkers(t, c1, w1, w2) + helper.ExpectWorkers(t, c2, w1, w2) } func TestWorkerAppendInitialUpstreams(t *testing.T) { diff --git a/internal/tests/cluster/worker_bytesupdown_test.go b/internal/tests/cluster/worker_bytesupdown_test.go index 77e734587f3..e9867074cb1 100644 --- a/internal/tests/cluster/worker_bytesupdown_test.go +++ b/internal/tests/cluster/worker_bytesupdown_test.go @@ -31,23 +31,16 @@ func TestWorkerBytesUpDown(t *testing.T) { Level: hclog.Trace, }) - conf, err := config.DevController(config.WithIPv6Enabled(true)) + conf, err := config.DevController() require.NoError(err) - pl, err := net.Listen("tcp", "[::1]:") + pl, err := net.Listen("tcp", "localhost:0") require.NoError(err) - - // update cluster listener to utilize proxy listener address - for _, l := range conf.Listeners { - if l.Purpose[0] == "cluster" { - l.Address = pl.Addr().String() - } - } - c1 := controller.NewTestController(t, &controller.TestControllerOpts{ Config: conf, InitialResourcesSuffix: "1234567890", Logger: logger.Named("c1"), + PublicClusterAddr: pl.Addr().String(), WorkerStatusGracePeriodDuration: helper.DefaultWorkerStatusGracePeriod, }) @@ -69,9 +62,10 @@ func TestWorkerBytesUpDown(t *testing.T) { InitialUpstreams: []string{proxy.ListenerAddr()}, Logger: logger.Named("w1"), SuccessfulStatusGracePeriodDuration: helper.DefaultSuccessfulStatusGracePeriod, - EnableIPv6: true, }) + require.NoError(w1.Worker().WaitForNextSuccessfulStatusUpdate()) + require.NoError(c1.WaitForNextWorkerStatusUpdate(w1.Name())) helper.ExpectWorkers(t, c1, w1) // Use an independent context for test things that take a context so @@ -96,12 +90,7 @@ func TestWorkerBytesUpDown(t *testing.T) { require.NotNil(tgt) // Authorize a session, connect and send/recv some traffic - workerInfo := []*targets.WorkerInfo{ - { - Address: w1.ProxyAddrs()[0], - }, - } - sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890", helper.WithWorkerInfo(workerInfo)) + sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890") conn := sess.Connect(ctx, t) conn.TestSendRecvAll(t) diff --git a/internal/tests/cluster/worker_proxy_test.go b/internal/tests/cluster/worker_proxy_test.go index 7948aebf2ca..585d6452f01 100644 --- a/internal/tests/cluster/worker_proxy_test.go +++ b/internal/tests/cluster/worker_proxy_test.go @@ -32,23 +32,16 @@ func TestWorkerSessionProxyMultipleConnections(t *testing.T) { Level: hclog.Trace, }) - pl, err := net.Listen("tcp", "[::1]:") + conf, err := config.DevController() require.NoError(err) - conf, err := config.DevController(config.WithIPv6Enabled(true)) + pl, err := net.Listen("tcp", "localhost:0") require.NoError(err) - - // update cluster listener to utilize proxy listener address - for _, l := range conf.Listeners { - if l.Purpose[0] == "cluster" { - l.Address = pl.Addr().String() - } - } - c1 := controller.NewTestController(t, &controller.TestControllerOpts{ Config: conf, InitialResourcesSuffix: "1234567890", Logger: logger.Named("c1"), + PublicClusterAddr: pl.Addr().String(), WorkerStatusGracePeriodDuration: helper.DefaultWorkerStatusGracePeriod, }) t.Cleanup(c1.Shutdown) @@ -73,10 +66,13 @@ func TestWorkerSessionProxyMultipleConnections(t *testing.T) { InitialUpstreams: []string{proxy.ListenerAddr()}, Logger: logger.Named("w1"), SuccessfulStatusGracePeriodDuration: helper.DefaultWorkerStatusGracePeriod, - EnableIPv6: true, }) t.Cleanup(w1.Shutdown) + err = w1.Worker().WaitForNextSuccessfulStatusUpdate() + require.NoError(err) + err = c1.WaitForNextWorkerStatusUpdate(w1.Name()) + require.NoError(err) helper.ExpectWorkers(t, c1, w1) // Use an independent context for test things that take a context so @@ -103,12 +99,7 @@ func TestWorkerSessionProxyMultipleConnections(t *testing.T) { require.NotNil(tgt) // Authorize and connect - workerInfo := []*targets.WorkerInfo{ - { - Address: w1.ProxyAddrs()[0], - }, - } - sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890", helper.WithWorkerInfo(workerInfo)) + sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890") sConn := sess.Connect(ctx, t) // Run initial send/receive test, make sure things are working diff --git a/internal/tests/helper/option.go b/internal/tests/helper/option.go index 4ce8e321b2c..28e9b8be5f4 100644 --- a/internal/tests/helper/option.go +++ b/internal/tests/helper/option.go @@ -3,8 +3,6 @@ package helper -import "github.com/hashicorp/boundary/api/targets" - // getOpts iterates the inbound Options and returns a struct and any errors func getOpts(opt ...Option) (*Options, error) { opts := getDefaultOptions() @@ -24,7 +22,6 @@ func getOpts(opt ...Option) (*Options, error) { // are parsed in various other packages. type Options struct { WithSkipSessionTeardown bool - WithWorkerInfo []*targets.WorkerInfo } // Option is a function that takes in an options struct and sets values or @@ -46,13 +43,3 @@ func WithSkipSessionTeardown(with bool) Option { return nil } } - -// WithWorkerInfo can be used to override the default worker address localhost:9202 -// for SessionAuthroizationData. This is useful when testing session connection with -// dev workers that are not utilizing default addresses. -func WithWorkerInfo(workerInfo []*targets.WorkerInfo) Option { - return func(o *Options) error { - o.WithWorkerInfo = workerInfo - return nil - } -} diff --git a/internal/tests/helper/testing_helper.go b/internal/tests/helper/testing_helper.go index ed916a44214..0392eb3f62b 100644 --- a/internal/tests/helper/testing_helper.go +++ b/internal/tests/helper/testing_helper.go @@ -11,7 +11,6 @@ import ( "net" "reflect" "strconv" - "sync" "testing" "time" @@ -77,18 +76,11 @@ func NewTestSession( sessAuth, err := sar.GetSessionAuthorization() require.NoError(err) - sessAuthData, err := sessAuth.GetSessionAuthorizationData() - if len(opts.WithWorkerInfo) != 0 { - sessAuthData.WorkerInfo = opts.WithWorkerInfo - } - require.NoError(err) - proxy, err := apiproxy.New( ctx, sessAuth.AuthorizationToken, apiproxy.WithWorkerHost(sessAuth.SessionId), apiproxy.WithSkipSessionTeardown(opts.WithSkipSessionTeardown), - apiproxy.WithSessionAuthorizationData(sessAuthData), ) require.NoError(err) @@ -439,36 +431,23 @@ func NewTestTcpServer(t *testing.T) *TestTcpServer { return ts } -// ExpectWorkers is a blocking call, where the method validates that the expected workers -// can be found in the controllers status update. If the provided list of workers is empty, -// this method will sleep for 10 seconds and then validate that the controller worker status -// is empty. func ExpectWorkers(t *testing.T, c *controller.TestController, workers ...*worker.TestWorker) { - // validate the controller has no reported workers - if len(workers) == 0 { - c.Controller().WorkerStatusUpdateTimes().Clear() - time.Sleep(10 * time.Second) - assert.Eventually(t, func() bool { - empty := true - c.Controller().WorkerStatusUpdateTimes().Range(func(k, v any) bool { - empty = false - return false - }) - return empty - }, 30*time.Second, 2*time.Second) - return - } - - // validate the controller has expected workers - wg := new(sync.WaitGroup) + updateTimes := c.Controller().WorkerStatusUpdateTimes() + workerMap := map[string]*worker.TestWorker{} for _, w := range workers { - wg.Add(1) - go func() { - defer wg.Done() - require.NoError(t, c.WaitForNextWorkerStatusUpdate(w.Name())) - _, ok := c.Controller().WorkerStatusUpdateTimes().Load(w.Name()) - assert.True(t, ok) - }() + workerMap[w.Name()] = w } - wg.Wait() + updateTimes.Range(func(k, v any) bool { + require.NotNil(t, k) + require.NotNil(t, v) + if workerMap[k.(string)] == nil { + // We don't remove from updateTimes currently so if we're not + // expecting it we'll see an out-of-date entry + return true + } + assert.WithinDuration(t, time.Now(), v.(time.Time), 30*time.Second) + delete(workerMap, k.(string)) + return true + }) + assert.Empty(t, workerMap) } diff --git a/internal/util/net.go b/internal/util/net.go deleted file mode 100644 index 874929906af..00000000000 --- a/internal/util/net.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package util - -import ( - "context" - "errors" - "net" - "regexp" - "strings" - - "github.com/hashicorp/boundary/globals" -) - -const ( - // MinAddressLength - MinAddressLength = 3 - // MaxAddressLength - MaxAddressLength = 255 -) - -// This regular expression is used to find all instances of square brackets within a string. -// This regular expression is used to remove the square brackets from an IPv6 address. -var squareBrackets = regexp.MustCompile("\\[|\\]") - -// JoinHostPort combines host and port into a network address of the form "host:port". -// If host contains a colon, as found in literal IPv6 addresses, then JoinHostPort returns "[host]:port". -func JoinHostPort(host, port string) string { - host = squareBrackets.ReplaceAllString(host, "") - return net.JoinHostPort(host, port) -} - -// SplitHostPort splits a network address of the form "host:port", "host%zone:port", "[host]:port" or "[host%zone]:port" into host or host%zone and port. -// -// A literal IPv6 address in hostport must be enclosed in square brackets, as in "[::1]:80", "[::1%lo0]:80". -func SplitHostPort(hostport string) (host string, port string, err error) { - host, port, err = net.SplitHostPort(hostport) - // use the hostport value as a backup when we have a missing port error - if err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr) { - // incase the hostport value is an ipv6, we must remove the enclosed square - // brackets to retain the same behavior as the net.SplitHostPort() method - host = squareBrackets.ReplaceAllString(hostport, "") - err = nil - } - return -} - -// ParseAddress trims and validates the input address string. It checks whether -// the address is within the allowed length and attempts to split it into a host and -// port. If the address contains a port, it returns an error. The function supports -// both valid IP addresses (IPv4 or IPv6) and DNS names. If the address is valid -// and does not include a port, it returns the host (either an IP or a DNS name). -func ParseAddress(ctx context.Context, address string) (string, error) { - const op = "util.ParseAddress" - address = strings.TrimSpace(address) - if len(address) < MinAddressLength || len(address) > MaxAddressLength { - return "", errors.New("invalid address length") - } - host, port, err := SplitHostPort(address) - if err != nil { - ip := net.ParseIP(address) - if ip.To4() == nil && ip.To16() == nil { - return "", err - } - host = ip.String() - } - if port != "" { - return "", errors.New("address contains a port") - } - return host, nil -} diff --git a/internal/util/net_test.go b/internal/util/net_test.go deleted file mode 100644 index 1767a9bfe95..00000000000 --- a/internal/util/net_test.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package util - -import ( - "context" - "net" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_JoinHostPort(t *testing.T) { - t.Parallel() - - // The wrapper function is used to ensure that the - // host input value is not already enclosed with - // square brackets for ipv6 addresses. This is because - // the underlying JoinHostPort() method will enclose the - // existing square brackets with another pair of square - // brackets. - t.Run("ensure-net.JoinHostPort()-behavior", func(t *testing.T) { - assert := assert.New(t) - hostport := net.JoinHostPort("[2001:4860:4860:0:0:0:0:8888]", "80") - assert.Equal("[[2001:4860:4860:0:0:0:0:8888]]:80", hostport) - }) - - tests := []struct { - name string - host string - port string - expectedAddress string - }{ - { - name: "local-ipv4", - host: "127.0.0.1", - port: "80", - expectedAddress: "127.0.0.1:80", - }, - { - name: "ipv4", - host: "8.8.8.8", - port: "80", - expectedAddress: "8.8.8.8:80", - }, - { - name: "ipv4-empty-port", - host: "8.8.8.8", - expectedAddress: "8.8.8.8:", - }, - { - name: "ipv4-square-brackets", - host: "[8.8.8.8]", - port: "80", - expectedAddress: "8.8.8.8:80", - }, - { - name: "missing-left-square-bracket", - host: "::1]", - port: "80", - expectedAddress: "[::1]:80", - }, - { - name: "missing-right-square-bracket", - host: "[::1", - port: "80", - expectedAddress: "[::1]:80", - }, - { - name: "local-no-square-brackets", - host: "::1", - port: "80", - expectedAddress: "[::1]:80", - }, - { - name: "local-no-square-brackets-missing-port", - host: "::1", - expectedAddress: "[::1]:", - }, - { - name: "ipv6-no-square-brackets", - host: "2001:4860:4860:0:0:0:0:8888", - port: "80", - expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:80", - }, - { - name: "ipv6-no-square-brackets-missing-port", - host: "2001:4860:4860:0:0:0:0:8888", - expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:", - }, - { - name: "abbreviated-ipv6-no-square-brackets", - host: "2001:4860:4860::8888", - port: "80", - expectedAddress: "[2001:4860:4860::8888]:80", - }, - { - name: "abbreviated-ipv6-no-square-brackets-missing-port", - host: "2001:4860:4860::8888", - expectedAddress: "[2001:4860:4860::8888]:", - }, - { - name: "local-square-brackets", - host: "[::1]", - port: "80", - expectedAddress: "[::1]:80", - }, - { - name: "local-double-square-brackets", - host: "[[::1]]", - port: "80", - expectedAddress: "[::1]:80", - }, - { - name: "local-square-brackets-missing-port", - host: "[::1]", - expectedAddress: "[::1]:", - }, - { - name: "local-double-square-brackets-missing-port", - host: "[[::1]]", - expectedAddress: "[::1]:", - }, - { - name: "ipv6-square-brackets", - host: "[2001:4860:4860:0:0:0:0:8888]", - port: "80", - expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:80", - }, - { - name: "ipv6-dobule-square-brackets", - host: "[[2001:4860:4860:0:0:0:0:8888]]", - port: "80", - expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:80", - }, - { - name: "ipv6-square-brackets-missing-port", - host: "[2001:4860:4860:0:0:0:0:8888]", - expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:", - }, - { - name: "ipv6-double-square-brackets-missing-port", - host: "[[2001:4860:4860:0:0:0:0:8888]]", - expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:", - }, - { - name: "abbreviated-ipv6-square-brackets", - host: "[2001:4860:4860::8888]", - port: "80", - expectedAddress: "[2001:4860:4860::8888]:80", - }, - { - name: "abbreviated-ipv6-double-square-brackets", - host: "[[2001:4860:4860::8888]]", - port: "80", - expectedAddress: "[2001:4860:4860::8888]:80", - }, - { - name: "abbreviated-ipv6-square-brackets-missing-port", - host: "[2001:4860:4860::8888]", - expectedAddress: "[2001:4860:4860::8888]:", - }, - { - name: "abbreviated-ipv6-double-square-brackets-missing-port", - host: "[[2001:4860:4860::8888]]", - expectedAddress: "[2001:4860:4860::8888]:", - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - actualAddress := JoinHostPort(tt.host, tt.port) - assert.Equal(tt.expectedAddress, actualAddress) - }) - } -} - -func Test_SplitHostPort(t *testing.T) { - t.Parallel() - - // The wrapper function is used to ignore missing port error. - // We need to validate the behavior of the underlying - // SplitHostPort() method hasn't changed. - t.Run("ensure-net.SplitHostPort()-behavior", func(t *testing.T) { - require, assert := require.New(t), assert.New(t) - host, port, err := net.SplitHostPort("[2001:4860:4860:0:0:0:0:8888]") - require.Error(err) - assert.ErrorContains(err, "missing port in address") - assert.Empty(host) - assert.Empty(port) - }) - - tests := []struct { - name string - hostport string - expectedHost string - expectedPort string - expectedErrMsg string - }{ - { - name: "local-ipv4", - hostport: "127.0.0.1:80", - expectedHost: "127.0.0.1", - expectedPort: "80", - }, - { - name: "ipv4", - hostport: "8.8.8.8:80", - expectedHost: "8.8.8.8", - expectedPort: "80", - }, - { - name: "ipv4-ignore-missing-port", - hostport: "8.8.8.8", - expectedHost: "8.8.8.8", - }, - { - name: "ipv4-empty-port", - hostport: "8.8.8.8:", - expectedHost: "8.8.8.8", - }, - { - name: "ipv4-square-bracket", - hostport: "[8.8.8.8]:80", - expectedHost: "8.8.8.8", - expectedPort: "80", - }, - { - name: "ipv6-missing-square-brackets", - hostport: "::1:80", - expectedErrMsg: "address ::1:80: too many colons in address", - }, - { - name: "ipv6-ignore-missing-port", - hostport: "[::1]", - expectedHost: "::1", - }, - { - name: "ipv6-empty-port", - hostport: "[::1]:", - expectedHost: "::1", - }, - { - name: "local-ipv6", - hostport: "[::1]:80", - expectedHost: "::1", - expectedPort: "80", - }, - { - name: "ipv6", - hostport: "[2001:4860:4860:0:0:0:0:8888]:80", - expectedHost: "2001:4860:4860:0:0:0:0:8888", - expectedPort: "80", - }, - { - name: "abbreviated-ipv6", - hostport: "[2001:4860:4860::8888]:80", - expectedHost: "2001:4860:4860::8888", - expectedPort: "80", - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - require, assert := require.New(t), assert.New(t) - actualHost, actualPort, err := SplitHostPort(tt.hostport) - if tt.expectedErrMsg != "" { - require.Error(err) - assert.ErrorContains(err, tt.expectedErrMsg) - return - } - require.NoError(err) - assert.Equal(tt.expectedHost, actualHost) - assert.Equal(tt.expectedPort, actualPort) - }) - } -} - -func Test_ParseAddress(t *testing.T) { - t.Parallel() - tests := []struct { - name string - address string - expectedAddress string - expectedErrMsg string - }{ - { - name: "empty-address", - expectedErrMsg: "invalid address length", - }, - { - name: "empty-spaces", - address: " ", - expectedErrMsg: "invalid address length", - }, - { - name: "invalid-short-address", - address: "ab", - expectedErrMsg: "invalid address length", - }, - { - name: "invalid-long-address", - address: strings.Repeat("a", 256), - expectedErrMsg: "invalid address length", - }, - { - name: "valid-dns-name", - address: "www.google.com", - expectedAddress: "www.google.com", - }, - { - name: "valid-dns-name-trim-empty-spaces", - address: " www.google.com ", - expectedAddress: "www.google.com", - }, - { - name: "valid-ipv4", - address: "127.0.0.1", - expectedAddress: "127.0.0.1", - }, - { - name: "invalid-ipv4-with-port", - address: "127.0.0.1:80", - expectedErrMsg: "address contains a port", - }, - { - name: "valid-ipv6", - address: "2001:4860:4860:0:0:0:0:8888", - expectedAddress: "2001:4860:4860::8888", - }, - { - name: "valid-[ipv6]", - address: "[2001:4860:4860:0:0:0:0:8888]", - expectedAddress: "2001:4860:4860:0:0:0:0:8888", - }, - { - name: "valid-[ipv6]:", - address: "[2001:4860:4860:0:0:0:0:8888]:", - expectedAddress: "2001:4860:4860:0:0:0:0:8888", - }, - { - name: "invalid-ipv6-with-port", - address: "[2001:4860:4860:0:0:0:0:8888]:80", - expectedErrMsg: "address contains a port", - }, - { - name: "valid-abbreviated-ipv6", - address: "2001:4860:4860::8888", - expectedAddress: "2001:4860:4860::8888", - }, - { - name: "valid-abbreviated-[ipv6]", - address: "[2001:4860:4860::8888]", - expectedAddress: "2001:4860:4860::8888", - }, - { - name: "valid-abbreviated-[ipv6]:", - address: "[2001:4860:4860::8888]:", - expectedAddress: "2001:4860:4860::8888", - }, - { - name: "invalid-abbreviated-[ipv6]-with-port", - address: "[2001:4860:4860::8888]:80", - expectedErrMsg: "address contains a port", - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - require, assert := require.New(t), assert.New(t) - actualAddress, err := ParseAddress(context.Background(), tt.address) - if tt.expectedErrMsg != "" { - require.Error(err) - assert.ErrorContains(err, tt.expectedErrMsg) - return - } - require.NoError(err) - assert.Equal(tt.expectedAddress, actualAddress) - }) - } -} diff --git a/plugins/boundary/mains/aws/go.mod b/plugins/boundary/mains/aws/go.mod index d2223cd225f..b92719c3a95 100644 --- a/plugins/boundary/mains/aws/go.mod +++ b/plugins/boundary/mains/aws/go.mod @@ -3,65 +3,67 @@ module github.com/hashicorp/boundary/plugins/boundary/mains/aws go 1.23.3 require ( - github.com/hashicorp/boundary-plugin-aws v0.4.1 + github.com/hashicorp/boundary-plugin-aws v0.4.2 github.com/hashicorp/boundary/sdk v0.0.49 ) require ( - github.com/aws/aws-sdk-go-v2 v1.32.5 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect - github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 // indirect - github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect - github.com/aws/smithy-go v1.22.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.20.1 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 // indirect + github.com/aws/aws-sdk-go-v2/config v1.18.33 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.32 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0 // indirect + github.com/aws/aws-sdk-go-v2/service/iam v1.22.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 // indirect + github.com/aws/smithy-go v1.14.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.18.0 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/eventlogger v0.2.10 // indirect + github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0 // indirect github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.6.2 // indirect - github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.1.0 // indirect + github.com/hashicorp/go-plugin v1.5.2 // indirect + github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.0.0 // indirect github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect - github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7 // indirect + github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/yamux v0.1.2 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.10.0 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/grpc v1.68.0 // indirect - google.golang.org/protobuf v1.35.2 // indirect + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/grpc v1.61.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/boundary/mains/aws/go.sum b/plugins/boundary/mains/aws/go.sum index d633899e8ca..c75a596f9f9 100644 --- a/plugins/boundary/mains/aws/go.sum +++ b/plugins/boundary/mains/aws/go.sum @@ -6,46 +6,51 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= -github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc= -github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0= -github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o= -github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24 h1:JX70yGKLj25+lMC5Yyh8wBtvB01GDilyRuJvXJ4piD0= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24/go.mod h1:+Ln60j9SUTD0LEwnhEB0Xhg61DHqplBrbZpLgyjoEHg= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 h1:RhSoBFT5/8tTmIseJUXM6INTXTQDF8+0oyxWBnozIms= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0/go.mod h1:mzj8EEjIHSN2oZRXiw1Dd+uB4HZTl7hC8nBzX9IZMWw= -github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 h1:hfkzDZHBp9jAT4zcd5mtqckpU4E3Ax0LQaEWWk1VgN8= -github.com/aws/aws-sdk-go-v2/service/iam v1.38.1/go.mod h1:u36ahDtZcQHGmVm/r+0L1sfKX4fzLEMdCqiKRKkUMVM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5 h1:gvZOjQKPxFXy1ft3QnEyXmT+IqneM9QAUWlM3r0mfqw= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5/go.mod h1:DLWnfvIcm9IET/mmjdxeXbBKmTCm0ZB8p1za9BVteM8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 h1:P1doBzv5VEg1ONxnJss1Kh5ZG/ewoIE4MQtKKc6Crgg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5/go.mod h1:NOP+euMW7W3Ukt28tAxPuoWao4rhhqJD3QEBk7oCg7w= -github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 h1:Q2ax8S21clKOnHhhr933xm3JxdJebql+R7aNo7p7GBQ= -github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0/go.mod h1:ralv4XawHjEMaHOWnTFushl0WRqim/gQWesAMF6hTow= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= -github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= -github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.20.1 h1:rZBf5DWr7YGrnlTK4kgDQGn1ltqOg5orCYb/UhOFZkg= +github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 h1:lN6L3LrYHeZ6xCxaIYtoWCx4GMLk4nRknsh29OMSqHY= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12/go.mod h1:TDCkEAkMTXxTs0oLBGBKpBZbk3NLh8EvAfF0Q3x8/0c= +github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= +github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.32 h1:lIH1eKPcCY1ylR4B6PkBGRWMHO3aVenOKJHWiS4/G2w= +github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 h1:DK/9C+UN/X+1+Wm8pqaDksQr2tSLzq+8X1/rI/ZxKEQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 h1:c8ed/T9T2K5I+h/JzmF5tpI46+OODQ74dzmdo+QnaMg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 h1:hNeAAymUY5gu11WrrmFb3CVIp9Dar9hbo44yzzcQpzA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 h1:fc0ukRAiP1syoSGZYu+DaE+FulSYhTiJ8WpVu5jElU4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1 h1:vUh7dBFNS3oFCtVv6CiYKh5hP9ls8+kIpKLeFruIBLk= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1/go.mod h1:sFMeinkhj/SZKQM8BxtvNtSPjJEo0Xrz+w3g2e4FSKI= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0 h1:NXi4pNJWjAaiI56P1Rl8DC9A4jMNRE00WNBsDua5WRg= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0/go.mod h1:L3ZT0N/vBsw77mOAawXmRnREpEjcHd2v5Hzf7AkIH8M= +github.com/aws/aws-sdk-go-v2/service/iam v1.22.2 h1:DPFxx/6Zwes/MiadlDteVqDKov7yQ5v9vuwfhZuJm1s= +github.com/aws/aws-sdk-go-v2/service/iam v1.22.2/go.mod h1:cQTMNdo/Z5t1DDRsUnx0a2j6cPnytMBidUYZw2zks28= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 h1:iV/W5OMBys+66OeXJi/7xIRrKZNsu0ylsLGu+6nbmQE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13/go.mod h1:ReJb6xYmtGyu9KoFtRreWegbN9dZqvZIIv4vWnhcsyI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33 h1:QviNkc+vGSuEHx8P+pVNKOdWLXBPIwMFv7p0fphgE4U= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33/go.mod h1:fABTUmOrAgAalG2i9WJpjBvlnk7UK8YmnYaxN+Q2CwE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 h1:dGAseBFEYxth10V23b5e2mAS+tX7oVbfYHD6dnDdAsg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1 h1:PT6PBCycRwhpEW5hJnRiceCeoWJ+r3bdgXtV+VKG7Pk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1/go.mod h1:TqoxCLwT2nrxrBGA+z7t6OWM7LBkgRckK3gOjYE+7JA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2 h1:v346f1h8sUBKXnEbrv43L37MTBlFHyKXQPIZHNAaghA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2/go.mod h1:cwCATiyNrXK9P2FsWdZ89g9mpsYv2rhk0UA/KByl5fY= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 h1:A2RlEMo4SJSwbNoUUgkxTAEMduAy/8wG3eB2b2lP4gY= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 h1:OJELEgyaT2kmaBGZ+myyZbTTLobfe3ox3FSh5eYK9Qs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 h1:ympg1+Lnq33XLhcK/xTG4yZHPs1Oyxu+6DEWbl7qOzA= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs= +github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -55,41 +60,46 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= -github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/boundary-plugin-aws v0.4.1 h1:I64eZcRLhndx5PnuaCFNt9B30Bb0c9WV1S+HaZzBHhE= -github.com/hashicorp/boundary-plugin-aws v0.4.1/go.mod h1:LLNJ6K149OTGteink8xatHKsWohT1cZ8lqLM0kfGolQ= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/boundary-plugin-aws v0.4.2 h1:qPBl61Oow/f8UZLeXYqrxsq1ggeLmqepeM/9VwRzRYI= +github.com/hashicorp/boundary-plugin-aws v0.4.2/go.mod h1:iDTNMMJ7mfmaWSUIML65uphXTUJYNRbm683exxQ/x7w= github.com/hashicorp/boundary/sdk v0.0.49 h1:XOb6mSKyrU/wI20+5xTYBHQUP7eIeKcLxKSCpCs4yzM= github.com/hashicorp/boundary/sdk v0.0.49/go.mod h1:IHP79to8aIi22FiY58pgBqJL96/U9D8ZAUhS2DdC+Us= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/eventlogger v0.2.10 h1:Dddth3KVSribGE1rInGToM30tRNblvL0G1OG6N+i2pk= -github.com/hashicorp/eventlogger v0.2.10/go.mod h1:imHMTfJH4qfb8Knh9nZw4iLfL9J1bX6TJKEurSB4t+U= +github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0 h1:f9oX8/3zxiQrfrWnBeyjDm4S02GAU02OBtCRoZOUwlo= +github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0/go.mod h1://CHt6/j+Q2lc0NlUB5af4aS2M0c0aVBg9/JfcpAyhM= github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 h1:iAb287bq0TaWTnhDYuN/zVqdD2EwanQg9ncVelC60Xc= github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0/go.mod h1:tMywUTIvdB/FXhwm6HMTt61C8/eODY6gitCHhXtyojg= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= -github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= -github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= -github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.1.0 h1:V3TJFolOHYSDqQLbTUBygXtbX4jKXyBcDoU+KNZE1Ak= -github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.1.0/go.mod h1:OeRwM2eWNW62L1Z+8GvoZM5nQJMRWBewHSoo77qmb4Y= +github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= +github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= +github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.0.0 h1:ca5TSI4AgaOncPpyzLDtCGjVEtKukONpeM95vFxXCOQ= +github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.0.0/go.mod h1:7CUvZtfTp2U0CYQCLzMtS2ngckjAZePSfwrE2aeDP1M= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11 h1:uPW2Wn0YlmI9RGSkZpcIplnVRwJ7BCiGpk1vnF2TMw4= @@ -98,10 +108,11 @@ github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.9 h1:0S0ctJ7Ra8O7ap+/3fZ github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.9/go.mod h1:TNNdgtjLgVDbrgFcyCKrlAicIl3dZF94swJltyGUX2M= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0= -github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7 h1:oYEPhztZRmZCETTxxIo5MNa+I+DDqSDZ+biJt2o4Ncw= -github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7/go.mod h1:ggFN8dlaLWS2R1gymBbCrvXM/bkZP7hEAa4seqDwhyg= +github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 h1:ZYv2XA+tEfFXIToR2jmBgVqQU9gERt0APbWqmUoNGnY= +github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6/go.mod h1:ggFN8dlaLWS2R1gymBbCrvXM/bkZP7hEAa4seqDwhyg= github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 h1:SMGUnbpAcat8rIKHkBPjfv81yC46a8eCNZ2hsR2l1EI= github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1/go.mod h1:Ch/bf00Qnx77MZd49JRgHYqHQjtEmTgGU2faufpVZb0= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 h1:xbrxd0U9XQW8qL1BAz2XrAjAF/P2vcqUTAues9c24B8= @@ -113,8 +124,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= -github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= @@ -123,8 +134,16 @@ github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f h1:E87tDTVS5W github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f/go.mod h1:3J2qVK16Lq8V+wfiL2lPeDZ7UWMxk5LemerHa1p6N00= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -134,12 +153,14 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -153,6 +174,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= @@ -162,36 +184,80 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= -google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= -google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= -google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= diff --git a/plugins/boundary/mains/azure/go.mod b/plugins/boundary/mains/azure/go.mod index a9a433228a6..8e11ea4eea5 100644 --- a/plugins/boundary/mains/azure/go.mod +++ b/plugins/boundary/mains/azure/go.mod @@ -21,8 +21,8 @@ require ( github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect - github.com/fatih/color v1.16.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect + github.com/fatih/color v1.14.1 // indirect + github.com/golang-jwt/jwt/v4 v4.2.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0 // indirect @@ -32,7 +32,7 @@ require ( github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect @@ -40,7 +40,7 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/manicminer/hamilton v0.46.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -51,14 +51,14 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/stretchr/testify v1.8.4 // indirect - golang.org/x/crypto v0.29.0 // indirect - golang.org/x/net v0.31.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/boundary/mains/azure/go.sum b/plugins/boundary/mains/azure/go.sum index 1742abc9909..d7e75fe4411 100644 --- a/plugins/boundary/mains/azure/go.sum +++ b/plugins/boundary/mains/azure/go.sum @@ -88,17 +88,16 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -173,17 +172,14 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1 github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= @@ -244,8 +240,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -306,8 +302,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -370,8 +366,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -423,9 +419,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -433,8 +428,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -567,8 +562,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/plugins/boundary/mains/gcp/go.mod b/plugins/boundary/mains/gcp/go.mod deleted file mode 100644 index 29b6aa2f8a1..00000000000 --- a/plugins/boundary/mains/gcp/go.mod +++ /dev/null @@ -1,70 +0,0 @@ -module github.com/hashicorp/boundary/plugins/boundary/mains/gcp - -go 1.23.1 - -require ( - github.com/hashicorp/boundary-plugin-gcp v0.0.0-20241120152221-baa2c7a2e742 - github.com/hashicorp/boundary/sdk v0.0.47 -) - -require ( - cloud.google.com/go v0.115.1 // indirect - cloud.google.com/go/auth v0.9.3 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect - cloud.google.com/go/compute v1.28.0 // indirect - cloud.google.com/go/compute/metadata v0.5.0 // indirect - cloud.google.com/go/iam v1.2.0 // indirect - cloud.google.com/go/longrunning v0.6.0 // indirect - cloud.google.com/go/resourcemanager v1.10.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/s2a-go v0.1.8 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.3 // indirect - github.com/googleapis/gax-go/v2 v2.13.0 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/eventlogger v0.2.9 // indirect - github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.5.2 // indirect - github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect - github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 // indirect - github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/yamux v0.1.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/pointerstructure v1.2.1 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/oklog/run v1.1.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.9.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect - golang.org/x/crypto v0.29.0 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/time v0.6.0 // indirect - google.golang.org/api v0.196.0 // indirect - google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.66.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/plugins/boundary/mains/gcp/go.sum b/plugins/boundary/mains/gcp/go.sum deleted file mode 100644 index ce777b66379..00000000000 --- a/plugins/boundary/mains/gcp/go.sum +++ /dev/null @@ -1,327 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= -cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= -cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= -cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= -cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= -cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= -cloud.google.com/go/compute v1.28.0 h1:OPtBxMcheSS+DWfci803qvPly3d4w7Eu5ztKBcFfzwk= -cloud.google.com/go/compute v1.28.0/go.mod h1:DEqZBtYrDnD5PvjsKwb3onnhX+qjdCVM7eshj1XdjV4= -cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= -cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8= -cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= -cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkBZr+aI= -cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= -cloud.google.com/go/resourcemanager v1.10.1 h1:fO/QoSJ1lepmTM9dCbSXYWgTIhecmQkpY0mM1X9OGN0= -cloud.google.com/go/resourcemanager v1.10.1/go.mod h1:A/ANV/Sv7y7fcjd4LSH7PJGTZcWRkO/69yN5UhYUmvE= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= -github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= -github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.3 h1:QRje2j5GZimBzlbhGA2V2QlGNgL8G6e+wGo/+/2bWI0= -github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= -github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= -github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= -github.com/hashicorp/boundary-plugin-gcp v0.0.0-20241120152221-baa2c7a2e742 h1:c4pftmjCNl8E58gxRo1pNmY63pGVz8qHDejeKKDtq34= -github.com/hashicorp/boundary-plugin-gcp v0.0.0-20241120152221-baa2c7a2e742/go.mod h1:HC8FEkYf/kC0m1w0UiGcxDG6DsmEaVSNDSqFPWyspHc= -github.com/hashicorp/boundary/sdk v0.0.47 h1:h5AXOASS2duHkCYEmNKnI9AR6YBZxD7VbFPV8BoE0z0= -github.com/hashicorp/boundary/sdk v0.0.47/go.mod h1:9iOT7kDM6mYcSkKxNuZlv8rP7U5BG1kXoevjLLL8lNQ= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/eventlogger v0.2.9 h1:QO8hPXNngadMp72FVNTwIduLAG9fcLP7t59bSFd7gDY= -github.com/hashicorp/eventlogger v0.2.9/go.mod h1://CHt6/j+Q2lc0NlUB5af4aS2M0c0aVBg9/JfcpAyhM= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 h1:iAb287bq0TaWTnhDYuN/zVqdD2EwanQg9ncVelC60Xc= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0/go.mod h1:tMywUTIvdB/FXhwm6HMTt61C8/eODY6gitCHhXtyojg= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= -github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= -github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= -github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= -github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= -github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11 h1:uPW2Wn0YlmI9RGSkZpcIplnVRwJ7BCiGpk1vnF2TMw4= -github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11/go.mod h1:uis9dCmOzXuOaRyXq+1Foh31kcvXKoWogjNnhfjHfW8= -github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.9 h1:0S0ctJ7Ra8O7ap+/3fZUnzJ3VzJyirWS/WnNCuOYtZY= -github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.9/go.mod h1:TNNdgtjLgVDbrgFcyCKrlAicIl3dZF94swJltyGUX2M= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0= -github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 h1:ZYv2XA+tEfFXIToR2jmBgVqQU9gERt0APbWqmUoNGnY= -github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6/go.mod h1:ggFN8dlaLWS2R1gymBbCrvXM/bkZP7hEAa4seqDwhyg= -github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 h1:SMGUnbpAcat8rIKHkBPjfv81yC46a8eCNZ2hsR2l1EI= -github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1/go.mod h1:Ch/bf00Qnx77MZd49JRgHYqHQjtEmTgGU2faufpVZb0= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= -github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 h1:xbrxd0U9XQW8qL1BAz2XrAjAF/P2vcqUTAues9c24B8= -github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3/go.mod h1:LWq2Sy8UoKKuK4lFuCNWSjJj57MhNNf2zzBWMtkAIX4= -github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2wMvfPJU= -github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= -github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f h1:E87tDTVS5W65euzixn7clSzK66puSt1H4I5SC0EmHH4= -github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f/go.mod h1:3J2qVK16Lq8V+wfiL2lPeDZ7UWMxk5LemerHa1p6N00= -github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= -github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= -github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= -github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= -github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.196.0 h1:k/RafYqebaIJBO3+SMnfEGtFVlvp5vSgqTUF54UN/zg= -google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= -google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= diff --git a/plugins/boundary/mains/gcp/main.go b/plugins/boundary/mains/gcp/main.go deleted file mode 100644 index 813d553184c..00000000000 --- a/plugins/boundary/mains/gcp/main.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package main - -import ( - "fmt" - "os" - - gcp "github.com/hashicorp/boundary-plugin-gcp/plugin" - hp "github.com/hashicorp/boundary/sdk/plugins" -) - -func main() { - if err := hp.ServePlugin(gcp.NewGCPPlugin()); err != nil { - fmt.Println("Error serving plugin", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/plugins/boundary/mains/minio/go.mod b/plugins/boundary/mains/minio/go.mod index 59912e27f69..b30a4b80f14 100644 --- a/plugins/boundary/mains/minio/go.mod +++ b/plugins/boundary/mains/minio/go.mod @@ -12,7 +12,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/uuid v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -63,16 +63,16 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect - golang.org/x/crypto v0.22.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.24.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect google.golang.org/grpc v1.61.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/boundary/mains/minio/go.sum b/plugins/boundary/mains/minio/go.sum index a26482ca35d..bcde77fecf9 100644 --- a/plugins/boundary/mains/minio/go.sum +++ b/plugins/boundary/mains/minio/go.sum @@ -43,8 +43,8 @@ github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -75,8 +75,6 @@ github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -263,8 +261,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -272,8 +270,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -288,8 +286,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -313,8 +311,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -322,8 +320,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -332,8 +330,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -348,8 +346,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/plugins/kms/mains/alicloudkms/go.mod b/plugins/kms/mains/alicloudkms/go.mod index 3d3c0405e4f..13bd65cac2e 100644 --- a/plugins/kms/mains/alicloudkms/go.mod +++ b/plugins/kms/mains/alicloudkms/go.mod @@ -30,12 +30,12 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/stretchr/testify v1.8.4 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/kms/mains/alicloudkms/go.sum b/plugins/kms/mains/alicloudkms/go.sum index e11880cd6fd..3200d2a167e 100644 --- a/plugins/kms/mains/alicloudkms/go.sum +++ b/plugins/kms/mains/alicloudkms/go.sum @@ -18,16 +18,10 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 h1:gM4OwbF16Cmfxt2QMkoGMQbRTfYFZLvDMPgU3rM3KIo= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7/go.mod h1:7ZMHVluyqgHgEuTADeDzFNWoA9mnyPfdiK8Tk2Bct1c= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= -github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2 v2.0.2 h1:j/2W4nWgzUMGrtRnfvFj60PdwooKBGDY4/fec7vvjhc= -github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2 v2.0.2/go.mod h1:heY2PS1SGU0cMamgv+zId/sKT+XFHaf61bLOSnP1Gb8= github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2 v2.0.3 h1:36Pxy8BQd7DAJ2Mk6vuJlIjqQ80e20vlO7a4Ep3RTOg= github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2 v2.0.3/go.mod h1:heY2PS1SGU0cMamgv+zId/sKT+XFHaf61bLOSnP1Gb8= github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= @@ -96,18 +90,18 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= @@ -117,8 +111,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/plugins/kms/mains/awskms/go.mod b/plugins/kms/mains/awskms/go.mod index 39f76062ef0..3d761b5d18b 100644 --- a/plugins/kms/mains/awskms/go.mod +++ b/plugins/kms/mains/awskms/go.mod @@ -31,11 +31,11 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/stretchr/testify v1.8.4 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/kms/mains/awskms/go.sum b/plugins/kms/mains/awskms/go.sum index 2eeff3cd0cc..6ab9416f707 100644 --- a/plugins/kms/mains/awskms/go.sum +++ b/plugins/kms/mains/awskms/go.sum @@ -92,8 +92,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -104,11 +104,11 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= @@ -116,8 +116,8 @@ google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/plugins/kms/mains/azurekeyvault/go.mod b/plugins/kms/mains/azurekeyvault/go.mod index 3207391c3d6..ae279deb07b 100644 --- a/plugins/kms/mains/azurekeyvault/go.mod +++ b/plugins/kms/mains/azurekeyvault/go.mod @@ -8,9 +8,9 @@ require ( ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect @@ -20,13 +20,13 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.15.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect - github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect @@ -38,15 +38,16 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/oklog/run v1.1.0 // indirect - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.9.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + github.com/rogpeppe/go-internal v1.8.1 // indirect + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/kms/mains/azurekeyvault/go.sum b/plugins/kms/mains/azurekeyvault/go.sum index 29252a82e06..a7b0712ee27 100644 --- a/plugins/kms/mains/azurekeyvault/go.sum +++ b/plugins/kms/mains/azurekeyvault/go.sum @@ -1,11 +1,9 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= -github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= @@ -28,48 +26,37 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= -github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 h1:gM4OwbF16Cmfxt2QMkoGMQbRTfYFZLvDMPgU3rM3KIo= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7/go.mod h1:7ZMHVluyqgHgEuTADeDzFNWoA9mnyPfdiK8Tk2Bct1c= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= -github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault/v2 v2.0.10 h1:g4F+mrwvfCJJIrLHbKhClClFLz/+T42zASm6S1Av38s= -github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault/v2 v2.0.10/go.mod h1:+nZqburV15IZlvfxk29XUdwWour3PkYxRaOFesx37OI= github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault/v2 v2.0.11 h1:/7SKkYIhA8cr3l8m1EKT6Q90bPoSVqqVBuQ6HgoMIkw= github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault/v2 v2.0.11/go.mod h1:LepS5s6ESGE0qQMpYaui5lX+mQYeiYiy06VzwWRioO8= github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= @@ -83,10 +70,11 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -104,14 +92,13 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= -github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -119,23 +106,23 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -144,17 +131,17 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -163,8 +150,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -176,11 +163,15 @@ google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/plugins/kms/mains/gcpckms/go.mod b/plugins/kms/mains/gcpckms/go.mod index cf6622c4df1..b2ae3e312a8 100644 --- a/plugins/kms/mains/gcpckms/go.mod +++ b/plugins/kms/mains/gcpckms/go.mod @@ -21,7 +21,6 @@ require ( github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect - github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.8 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect @@ -30,24 +29,22 @@ require ( github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/oklog/run v1.1.0 // indirect - github.com/oracle/oci-go-sdk/v60 v60.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect - github.com/sony/gobreaker v0.5.0 // indirect github.com/stretchr/testify v1.8.4 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.29.0 // indirect - golang.org/x/net v0.31.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/kms/mains/gcpckms/go.sum b/plugins/kms/mains/gcpckms/go.sum index 7c491bcbade..2471d98d6ae 100644 --- a/plugins/kms/mains/gcpckms/go.sum +++ b/plugins/kms/mains/gcpckms/go.sum @@ -61,20 +61,12 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 h1:gM4OwbF16Cmfxt2QMkoGMQbRTfYFZLvDMPgU3rM3KIo= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7/go.mod h1:7ZMHVluyqgHgEuTADeDzFNWoA9mnyPfdiK8Tk2Bct1c= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= -github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.10 h1:/HAAj2i/jeo2GqdWO1XjlutpaKzZaeBe3scvuujAJPg= -github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.10/go.mod h1:HSaOaX/lv3ShCdilUYbOTPnSvmoZ9xtQhgw+8hYcZkg= github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.12 h1:PCqWzT/Hii0KL07JsBZ3lJbv/wx02IAHYlhWQq8rxRY= github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.12/go.mod h1:HSaOaX/lv3ShCdilUYbOTPnSvmoZ9xtQhgw+8hYcZkg= -github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.8 h1:F2RNYvXq9yJKbXRxfHBSzOCx0YxRdkaQ8qu0EECeu5U= -github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.8/go.mod h1:ULlMyM1QKNuq1JIENcNCRAkgo/RYxxCkm26pjR6w/ko= github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= @@ -106,22 +98,15 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/oracle/oci-go-sdk/v60 v60.0.0 h1:EJAWjEi4SY5Raha6iUzq4LTQ0uM5YFw/wat/L1ehIEM= -github.com/oracle/oci-go-sdk/v60 v60.0.0/go.mod h1:krz+2gkSzlSL/L4PvP0Z9pZpag9HYLNtsMd1PmxlA2w= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= -github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -132,8 +117,8 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -145,16 +130,16 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -165,13 +150,13 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -211,8 +196,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/plugins/kms/mains/ocikms/go.mod b/plugins/kms/mains/ocikms/go.mod index 0fc7ae1ecee..1e5d3724ac1 100644 --- a/plugins/kms/mains/ocikms/go.mod +++ b/plugins/kms/mains/ocikms/go.mod @@ -26,11 +26,11 @@ require ( github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/stretchr/testify v1.8.4 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/kms/mains/ocikms/go.sum b/plugins/kms/mains/ocikms/go.sum index 3f59802c771..5e498bd82df 100644 --- a/plugins/kms/mains/ocikms/go.sum +++ b/plugins/kms/mains/ocikms/go.sum @@ -14,12 +14,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 h1:gM4OwbF16Cmfxt2QMkoGMQbRTfYFZLvDMPgU3rM3KIo= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7/go.mod h1:7ZMHVluyqgHgEuTADeDzFNWoA9mnyPfdiK8Tk2Bct1c= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.8 h1:F2RNYvXq9yJKbXRxfHBSzOCx0YxRdkaQ8qu0EECeu5U= @@ -73,18 +69,18 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= @@ -92,8 +88,8 @@ google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/plugins/kms/mains/transit/go.mod b/plugins/kms/mains/transit/go.mod index 516e2e0cacc..54e994aa31b 100644 --- a/plugins/kms/mains/transit/go.mod +++ b/plugins/kms/mains/transit/go.mod @@ -10,7 +10,7 @@ require ( require ( github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -19,7 +19,7 @@ require ( github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect @@ -30,7 +30,7 @@ require ( github.com/hashicorp/vault/api v1.10.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -38,13 +38,13 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/stretchr/testify v1.8.4 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/kms/mains/transit/go.sum b/plugins/kms/mains/transit/go.sum index bdf7f927e72..95cd12042ac 100644 --- a/plugins/kms/mains/transit/go.sum +++ b/plugins/kms/mains/transit/go.sum @@ -9,8 +9,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= @@ -26,18 +26,13 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 h1:gM4OwbF16Cmfxt2QMkoGMQbRTfYFZLvDMPgU3rM3KIo= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7/go.mod h1:7ZMHVluyqgHgEuTADeDzFNWoA9mnyPfdiK8Tk2Bct1c= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= -github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.12-0.20240510224000-05c77e842118 h1:Znp4cktSGpDSk3CQvdmluVoozB8VsgUDKEUNrmzy/Uk= -github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.12-0.20240510224000-05c77e842118/go.mod h1:YRqguGarF7kbHeojTPkanH3qvjbEP2pelq5b0ifaQ1M= github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.12 h1:E8pzzF7i44OZCYDol+U7VbTBmHe65/6dx1nYxS0P1k0= github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.12/go.mod h1:YRqguGarF7kbHeojTPkanH3qvjbEP2pelq5b0ifaQ1M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= @@ -45,8 +40,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= @@ -83,8 +78,8 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -105,6 +100,7 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -113,8 +109,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -140,11 +136,10 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -155,8 +150,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -173,8 +169,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/sdk/go.mod b/sdk/go.mod index 9d16eebf0b4..c93696b9b39 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -13,7 +13,7 @@ require ( github.com/stretchr/testify v1.8.4 google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe google.golang.org/grpc v1.61.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.33.0 nhooyr.io/websocket v1.8.10 ) @@ -65,9 +65,9 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/posener/complete v1.2.3 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - golang.org/x/crypto v0.29.0 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sdk/go.sum b/sdk/go.sum index 5c0c59d086b..4e7aab18ebf 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -47,8 +47,6 @@ github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0/go.mod h1:tMywUTIvdB/FXhwm6HMTt61C8/eODY6gitCHhXtyojg= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= -github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 h1:gM4OwbF16Cmfxt2QMkoGMQbRTfYFZLvDMPgU3rM3KIo= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7/go.mod h1:7ZMHVluyqgHgEuTADeDzFNWoA9mnyPfdiK8Tk2Bct1c= github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= @@ -171,8 +169,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -188,8 +186,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -211,8 +209,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -220,8 +218,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -244,8 +242,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/testing/internal/e2e/tests/base/search_test.go b/testing/internal/e2e/tests/base/search_test.go index 5a1c9e8aad1..56594ece797 100644 --- a/testing/internal/e2e/tests/base/search_test.go +++ b/testing/internal/e2e/tests/base/search_test.go @@ -33,11 +33,11 @@ func TestCliSearch(t *testing.T) { ctx := context.Background() - // If cache is already running, stop it so that we can start it with a + // If daemon is already running, stop it so that we can start it with a // shorter refresh interval output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "status", "-format", "json")) if output.Err == nil { - t.Log("Stopping cache...") + t.Log("Stopping daemon...") output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "stop")) require.NoError(t, output.Err, string(output.Stderr)) } @@ -54,8 +54,8 @@ func TestCliSearch(t *testing.T) { require.NoError(t, output.Err, string(output.Stderr)) }) - // Wait for cache to be up and running - t.Log("Waiting for cache to start...") + // Wait for daemon to be up and running + t.Log("Waiting for daemon to start...") var statusResult clientcache.StatusResult err = backoff.RetryNotify( func() error { @@ -80,7 +80,7 @@ func TestCliSearch(t *testing.T) { require.Equal(t, statusResult.StatusCode, 200) require.GreaterOrEqual(t, statusResult.Item.Uptime, 0*time.Second) - // Confirm cache version matches CLI version + // Confirm daemon version matches CLI version output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("version", "-format", "json")) require.NoError(t, output.Err, string(output.Stderr)) var versionResult version.Info @@ -102,48 +102,19 @@ func TestCliSearch(t *testing.T) { require.NoError(t, err) // Get current number of targets - var currentCount int - err = backoff.RetryNotify( - func() error { - output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "status", "-format", "json")) - if output.Err != nil { - return backoff.Permanent(errors.New(string(output.Stderr))) - } - - statusResult = clientcache.StatusResult{} - err = json.Unmarshal(output.Stdout, &statusResult) - if err != nil { - return errors.New("Failed to unmarshal status result") - } - - if len(statusResult.Item.Users) == 0 { - output = e2e.RunCommand(ctx, "cat", e2e.WithArgs(statusResult.Item.LogLocation)) - t.Log("Printing cache log...") - t.Log(string(output.Stdout)) - return errors.New("No users are appearing in the status") - } - idx := slices.IndexFunc( - statusResult.Item.Users[0].Resources, - func(r clientcache.ResourceStatus) bool { - return r.Name == "target" - }, - ) - if idx == -1 { - output = e2e.RunCommand(ctx, "cat", e2e.WithArgs(statusResult.Item.LogLocation)) - t.Log("Printing cache log...") - t.Log(string(output.Stdout)) - return errors.New("Targets not found in cache") - } - currentCount = statusResult.Item.Users[0].Resources[idx].Count - - return nil - }, - backoff.WithMaxRetries(backoff.NewConstantBackOff(3*time.Second), 5), - func(err error, td time.Duration) { - t.Logf("%s. Retrying...", err.Error()) + output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "status", "-format", "json")) + require.NoError(t, output.Err, string(output.Stderr)) + statusResult = clientcache.StatusResult{} + err = json.Unmarshal(output.Stdout, &statusResult) + require.Len(t, statusResult.Item.Users, 1) + idx := slices.IndexFunc( + statusResult.Item.Users[0].Resources, + func(r clientcache.ResourceStatus) bool { + return r.Name == "target" }, ) - require.NoError(t, err) + require.NotEqual(t, idx, -1) + currentCount := statusResult.Item.Users[0].Resources[idx].Count // Create enough targets to overflow a single page. // Use the API to make creation faster. @@ -195,9 +166,6 @@ func TestCliSearch(t *testing.T) { } if len(statusResult.Item.Users) == 0 { - output = e2e.RunCommand(ctx, "cat", e2e.WithArgs(statusResult.Item.LogLocation)) - t.Log("Printing cache log...") - t.Log(string(output.Stdout)) return errors.New("No users are appearing in the status") } @@ -208,9 +176,6 @@ func TestCliSearch(t *testing.T) { }, ) if idx == -1 { - output = e2e.RunCommand(ctx, "cat", e2e.WithArgs(statusResult.Item.LogLocation)) - t.Log("Printing cache log...") - t.Log(string(output.Stdout)) return errors.New("No targets are appearing in the status") } @@ -235,7 +200,7 @@ func TestCliSearch(t *testing.T) { require.NoError(t, err) // Search for targets that contain the target prefix. - // This requests data from the client cache. + // This requests data from the client cache daemon. t.Log("Searching targets...") output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs( diff --git a/version/VERSION b/version/VERSION index 3f46c4d1821..de564aec2e9 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -0.19.0 \ No newline at end of file +0.18.3 \ No newline at end of file diff --git a/website/content/docs/concepts/connection-workflows/multi-hop.mdx b/website/content/docs/concepts/connection-workflows/multi-hop.mdx index 869bf5dbe3c..84d6889e1ec 100644 --- a/website/content/docs/concepts/connection-workflows/multi-hop.mdx +++ b/website/content/docs/concepts/connection-workflows/multi-hop.mdx @@ -69,6 +69,63 @@ traffic to a target. Ingress worker filters determine which workers you connect with to initiate a session, and egress worker filters determine which workers are used to access targets. +## Use HCP-managed workers as ingress workers + +Many organizations have strict network policies that prohibit all inbound traffic into their networks. In these scenarios, you can use HCP-managed workers as the ingress workers. To establish a connection into the network, a self-managed worker configured as an egress worker initiates an outbound connection to the HCP-managed worker, creating a persistent connection. As a result, when end users connect to a target, the end user's connection would hop from the Boundary client to the HCP-managed worker (ingress worker) to the self-managed worker (egress worker) to the target (or other intermediary workers if needed). + +### Configure HCP-managed workers for ingress + +To configure end user traffic to ingress through HCP-managed workers, you must configure the self-managed worker (enterprise version). On your self-managed worker that you use for egress to the HCP-managed worker, set the configuration file with the following parameters: +- `hcp_boundary_cluster_id` - The HCP Boundary cluster ID, which can be found in the HCP Boundary cluster's URL. +- Omit the `public_addr` parameter. A public address is not needed since the self-managed worker initiates the connection to HCP-managed workers. +- Omit the `initial_upstreams` parameter. This is not needed because the `hcp_boundary_cluster_id` parameter is sufficent to indicate the HCP-managed workers as the upstream. +- Include a [worker tag](/boundary/docs/concepts/filtering/worker-tags#target-worker-filtering) in the `worker` stanza which will be used to select multi-hop routes for each target. + +### Example self-managed worker configuration: +``` +hcp_boundary_cluster_id = "7acdefe2c-1234-4ff1-b710-123456789876" + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +worker { + auth_storage_path = "/home/ubuntu/boundary/worker1" + tags { + tag = ["multihop"] + } + recording_storage_path = "/tmp/worker1" +} +``` +### Allow-list outbound network traffic to HCP-managed workers + +Some organizations require explicit destination addresses set in their network firewall rules for any outbound traffic. In this scenario, you should use the fully qualified domain name (FQDN) of the HCP-managed workers: + +``` +.proxy.boundary.hashicorp.cloud +``` + +where the `cluster_uuid` is the HCP Boundary cluster ID. You can find your HCP Boundary cluster ID in the HCP Boundary cluster's URL. + + + + The Boundary cluster ID is derived from the Boundary address. For example, if + your cluster URL is: + + `https://abcd1234-e567-f890-1ab2-cde345f6g789.boundary.hashicorp.cloud` + + Then your cluster id is `abcd1234-e567-f890-1ab2-cde345f6g789`. + + + +### Route end user traffic to targets through HCP-managed workers + +To route traffic through the HCP-managed workers, you should set the egress filters of each target to match the tag set in the self-managed worker's configuration file. You do not need to set additional ingress filters on the targets. + +![Multi-hop egress worker filter](/img/ui/multi-hop-egress-filter_light.png#light-theme-only) +![Multi-hop egress worker filter](/img/ui/multi-hop-egress-filter_dark.png#dark-theme-only) + ## Multi-hop worker requirements When you configure multi-hop sessions, there is an "ingress" worker, an "egress" diff --git a/website/content/docs/concepts/security/data-encryption.mdx b/website/content/docs/concepts/security/data-encryption.mdx index d066779635e..646dac467f5 100644 --- a/website/content/docs/concepts/security/data-encryption.mdx +++ b/website/content/docs/concepts/security/data-encryption.mdx @@ -20,7 +20,7 @@ methods](/boundary/docs/configuration/worker/worker-configuration) for storage o keys. It is optional for workers; if not specified the authentication keys will not be encrypted on disk. This can not used by workers registered using an external KMS. -## The `root` KMS key and per-scope KEK/DEKs Community Edition only +## The `root` KMS key and per-scope KEK/DEKs Following best practices of using different encryption keys for different purposes, Boundary has a number of encryption keys generated within each scope. @@ -35,6 +35,8 @@ and the various DEKs (Data Encryption Keys) are created when a scope is created. The DEKs are encrypted with the scope's `root` KEK, and this is in turn encrypted with the KMS key marked for the `root` purpose. +You can configure `root` KMS keys for self-managed Enterprise or Community edition deployments. + The current scoped DEKs and their purposes are detailed below: - `audit`: This is used to encrypt secret values in the event log. For more @@ -113,14 +115,16 @@ The `bsr` KMS key is required for [session recording](/boundary/docs/configurati If you do not add a `bsr` key to your controller configuration, you will receive an error when you attempt to enable session recording. The key is used for encrypting data and checking the integrity of recordings. -## The `previous-root` KMS key Community Edition only +## The `previous-root` KMS key The `previous-root` KMS key is used when migrating to a new `root` key. Adding the `previous-root` KMS key to your configuration informs the Controller to use it for decrypting the existing information in the database, allowing you to rotate and rewrap the KEKs to complete the migration to the new root key. -## The `worker-auth` KMS key Community Edition only +You can configure `previous-root` KMS keys for self-managed Enterprise or Community edition deployments. + +## The `worker-auth` KMS key The `worker-auth` KMS key is a key shared by the Controller and Worker in order to authenticate a Worker to the Controller. Specifics of this mechanism can be @@ -128,7 +132,10 @@ found on the [Connections/TLS page](/boundary/docs/concepts/security/connections a worker is registered with [worker-led or controller-led methods](/boundary/docs/configuration/worker/worker-configuration) this is unnecessary. -## The `recovery` KMS key Community Edition only +You can configure `worker-auth` KMS keys for HCP, Enterprise, and Community edition deployments. +However, you cannot configure `worker-auth` keys for the first set of workers that connect to your HCP workers. + +## The `recovery` KMS key The `recovery` KMS key is used for rescue/recovery operations that can be used by a client to authenticate almost any operation within Boundary. Its mechanism @@ -140,17 +147,23 @@ cannot be replayed by an adversary, and also to ensure that each operation must be individually authenticated by a client so that revoking access to the KMS has an immediate result. -~> **Note:** It is not required for this `kms` configuration block to exist in the +You can configure `recovery` KMS keys for self-managed Enterprise or Community edition deployments. + + + +It is not required for this `kms` configuration block to exist in the Controller's configuration file. It's best practice to leave it out except when actually needed, and to use change control capabilities to ensure that the configuration file modification is authorized. After it's no longer needed, the block should be removed. + + On the client side, a user can use the `-recovery-config` flag with any operation on the CLI to specify a configuration file containing a suitable `kms` block. This functionality is also accessible via the Go SDK. -~> **Note:** Requests authorized via this mechanism will show a user of `u_recovery`. This +Requests authorized via this mechanism will show a user of `u_recovery`. This mechanism _cannot_ be used to authorize a session, as there is no uniquely identifying user information available. @@ -164,7 +177,7 @@ with the options to skip creating default resources, Terraform can be used to create the specific resources needed instead, with the `recovery` KMS used to authenticate setting up the initial auth method(s). -## The `config` KMS key Community Edition only +## The `config` KMS key This key can be used to encrypt values within Boundary's configuration file. By sharing this block between Boundary and an operator, the operator can put @@ -174,3 +187,5 @@ safely pass the file to a change control system. Only another operator or system with access to that KMS can decrypt the values. Boundary will check for a `config` KMS block on startup, and if it exists, will use it to decrypt any encrypted values found at startup time. + +You can configure `config` KMS keys for self-managed Enterprise or Community edition deployments. diff --git a/website/content/docs/release-notes/v0_16_0.mdx b/website/content/docs/release-notes/v0_16_0.mdx index e1faa92704f..581f1fafd72 100644 --- a/website/content/docs/release-notes/v0_16_0.mdx +++ b/website/content/docs/release-notes/v0_16_0.mdx @@ -312,6 +312,27 @@ description: >- + + + 0.8.0 - 0.16.3 +

+ (Fixed in Boundary Community Edition and Boundary Enterprise 0.16.4) + + + Boundary controller incorrectly handles HTTP requests and stops prematurely (HCSEC-2024-28) + + + Boundary Community Edition and Boundary Enterprise incorrectly handle HTTP requests while the Boundary controller is starting up, which may cause the controller to stop prematurely. Boundary is only vulnerable to this flaw during the controller's initialization, which usually occurs in milliseconds during Boundary's startup process. +

+ This vulnerability, HCSEC-2024-28, is fixed in Boundary Community Edition and Boundary Enterprise versions 0.16.4, 0.17.3, and 0.18.2. +

+ Learn more: HCSEC-2024-28: Boundary controller incorrectly handles http requests on initialization which may lead to a denial of service +

+ Upgrade to the latest version of Boundary + + + + diff --git a/website/content/docs/release-notes/v0_17_0.mdx b/website/content/docs/release-notes/v0_17_0.mdx index 5a6add742dc..391adbbe016 100644 --- a/website/content/docs/release-notes/v0_17_0.mdx +++ b/website/content/docs/release-notes/v0_17_0.mdx @@ -184,7 +184,9 @@ description: >- - 0.17.0 (Fixed in 0.17.1) + 0.17.0 +

+ (Fixed in 0.17.1) Using an invalid alias results in a 401 message @@ -202,7 +204,9 @@ description: >- - 0.17.0 (Fixed in 0.17.1) + 0.17.0 +

+ (Fixed in 0.17.1) Session recording fails when you use Secure File Copy (SCP) @@ -218,5 +222,26 @@ description: >- + + + 0.8.0 - 0.17.2 +

+ (Fixed in Boundary Community Edition and Boundary Enterprise 0.17.3) + + + Boundary controller incorrectly handles HTTP requests and stops prematurely (HCSEC-2024-28) + + + Boundary Community Edition and Boundary Enterprise incorrectly handle HTTP requests while the Boundary controller is starting up, which may cause the controller to stop prematurely. Boundary is only vulnerable to this flaw during the controller's initialization, which usually occurs in milliseconds during Boundary's startup process. +

+ This vulnerability, HCSEC-2024-28, is fixed in Boundary Community Edition and Boundary Enterprise versions 0.16.4, 0.17.3, and 0.18.2. +

+ Learn more: HCSEC-2024-28: Boundary controller incorrectly handles http requests on initialization which may lead to a denial of service +

+ Upgrade to the latest version of Boundary + + + + \ No newline at end of file diff --git a/website/content/docs/release-notes/v0_18_0.mdx b/website/content/docs/release-notes/v0_18_0.mdx index 8f7754237e5..4c1735ce57e 100644 --- a/website/content/docs/release-notes/v0_18_0.mdx +++ b/website/content/docs/release-notes/v0_18_0.mdx @@ -170,7 +170,9 @@ description: >- - 0.18.0 (Fixed in 0.18.1) + 0.18.0 +

+ (Fixed in 0.18.1) Users are incorrectly removed from managed groups @@ -186,5 +188,45 @@ description: >- + + + 0.18.0 +

+ (Fixed in 0.18.2) + + + Session recordings fail with an error + + + When large numbers of sessions were created around the same time using the AssumeRole API, the AWS STS (Security Token Service) credentials sometimes failed to refresh and session recordings would fail. The failure occurred due to throttling from AWS. +

+ Version 0.18.2 adds a cache for Amazon S3 clients to store temporary credentials and prevent AWS resources from being overwhelmed. This issue is now resolved. +

+ Learn more:  Configure Amazon S3 as a storage provider +

+ Upgrade to the latest version of Boundary + + + + + + 0.8.0 - 0.18.1 +

+ (Fixed in Boundary Community Edition and Boundary Enterprise 0.18.2) + + + Boundary controller incorrectly handles HTTP requests and stops prematurely (HCSEC-2024-28) + + + Boundary Community Edition and Boundary Enterprise incorrectly handle HTTP requests while the Boundary controller is starting up, which may cause the controller to stop prematurely. Boundary is only vulnerable to this flaw during the controller's initialization, which usually occurs in milliseconds during Boundary's startup process. +

+ This vulnerability, HCSEC-2024-28, is fixed in Boundary Community Edition and Boundary Enterprise versions 0.16.4, 0.17.3, and 0.18.2. +

+ Learn more: HCSEC-2024-28: Boundary controller incorrectly handles http requests on initialization which may lead to a denial of service +

+ Upgrade to the latest version of Boundary + + + \ No newline at end of file diff --git a/website/public/img/ui/multi-hop-egress-filter_dark.png b/website/public/img/ui/multi-hop-egress-filter_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..7887e78226fe5cfc82b4bda2533b4e5c9ec0c649 GIT binary patch literal 136499 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

ch*2@V#Kw%hMyzGTOP#%3s|N!TM? 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 Gp8Q`mqxO{m literal 0 HcmV?d00001