pax_global_header00006660000000000000000000000064145247360500014520gustar00rootroot0000000000000052 comment=2dbca720e7c87ebe0af635d9dc638152807f8dc4 cloud-sql-proxy-1.33.14/000077500000000000000000000000001452473605000147535ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/.build/000077500000000000000000000000001452473605000161305ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/.build/alpine.yaml000066400000000000000000000032461452473605000202710ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. steps: - name: gcr.io/cloud-builders/docker args: - run - '--privileged' - 'linuxkit/binfmt:v0.7' id: 'initialize-qemu' - name: gcr.io/cloud-builders/docker args: - buildx - create - '--name' - multiarch-builder id: 'create-builder' - name: gcr.io/cloud-builders/docker args: - buildx - use - multiarch-builder id: 'select-builder' - name: gcr.io/cloud-builders/docker args: - buildx - inspect - '--bootstrap' id: 'show-target-build-platforms' - name: 'gcr.io/cloud-builders/docker' args: - 'buildx' - 'build' - '--platform' - $_DOCKER_BUILDX_PLATFORMS - '--tag=gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-alpine' - '--tag=us.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-alpine' - '--tag=eu.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-alpine' - '--tag=asia.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-alpine' - '-f=Dockerfile.alpine' - '--push' - '.' id: 'build-multi-architecture-container-image' options: env: - DOCKER_CLI_EXPERIMENTAL=enabled substitutions: _DOCKER_BUILDX_PLATFORMS: 'linux/amd64,linux/arm64' cloud-sql-proxy-1.33.14/.build/bullseye.yaml000066400000000000000000000032421452473605000206410ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. steps: - name: gcr.io/cloud-builders/docker args: - run - '--privileged' - 'linuxkit/binfmt:v0.7' id: 'initialize-qemu' - name: gcr.io/cloud-builders/docker args: - buildx - create - '--name' - multiarch-builder id: 'create-builder' - name: gcr.io/cloud-builders/docker args: - buildx - use - multiarch-builder id: 'select-builder' - name: gcr.io/cloud-builders/docker args: - buildx - inspect - '--bootstrap' id: 'show-target-build-platforms' - name: 'gcr.io/cloud-builders/docker' args: - 'buildx' - 'build' - '--platform' - $_DOCKER_BUILDX_PLATFORMS - '--tag=gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-bullseye' - '--tag=us.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-bullseye' - '--tag=eu.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-bullseye' - '--tag=asia.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-bullseye' - '-f=Dockerfile.bullseye' - '--push' - '.' id: 'build-multi-architecture-container-image' options: env: - DOCKER_CLI_EXPERIMENTAL=enabled substitutions: _DOCKER_BUILDX_PLATFORMS: 'linux/amd64' cloud-sql-proxy-1.33.14/.build/buster.yaml000066400000000000000000000032461452473605000203250ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. steps: - name: gcr.io/cloud-builders/docker args: - run - '--privileged' - 'linuxkit/binfmt:v0.7' id: 'initialize-qemu' - name: gcr.io/cloud-builders/docker args: - buildx - create - '--name' - multiarch-builder id: 'create-builder' - name: gcr.io/cloud-builders/docker args: - buildx - use - multiarch-builder id: 'select-builder' - name: gcr.io/cloud-builders/docker args: - buildx - inspect - '--bootstrap' id: 'show-target-build-platforms' - name: 'gcr.io/cloud-builders/docker' args: - 'buildx' - 'build' - '--platform' - $_DOCKER_BUILDX_PLATFORMS - '--tag=gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-buster' - '--tag=us.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-buster' - '--tag=eu.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-buster' - '--tag=asia.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}-buster' - '-f=Dockerfile.buster' - '--push' - '.' id: 'build-multi-architecture-container-image' options: env: - DOCKER_CLI_EXPERIMENTAL=enabled substitutions: _DOCKER_BUILDX_PLATFORMS: 'linux/amd64,linux/arm64' cloud-sql-proxy-1.33.14/.build/default.yaml000066400000000000000000000031551452473605000204440ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. steps: - name: gcr.io/cloud-builders/docker args: - run - '--privileged' - 'linuxkit/binfmt:v0.7' id: 'initialize-qemu' - name: gcr.io/cloud-builders/docker args: - buildx - create - '--name' - multiarch-builder id: 'create-builder' - name: gcr.io/cloud-builders/docker args: - buildx - use - multiarch-builder id: 'select-builder' - name: gcr.io/cloud-builders/docker args: - buildx - inspect - '--bootstrap' id: 'show-target-build-platforms' - name: 'gcr.io/cloud-builders/docker' args: - 'buildx' - 'build' - '--platform' - $_DOCKER_BUILDX_PLATFORMS - '--tag=gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}' - '--tag=us.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}' - '--tag=eu.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}' - '--tag=asia.gcr.io/$PROJECT_ID/gce-proxy:${_VERSION}' - '--push' - '.' id: 'build-multi-architecture-container-image' options: env: - DOCKER_CLI_EXPERIMENTAL=enabled substitutions: _DOCKER_BUILDX_PLATFORMS: 'linux/amd64,linux/arm64' cloud-sql-proxy-1.33.14/.build/gcs_upload.yaml000066400000000000000000000061661452473605000211450ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. timeout: 1800s options: env: - "GOPATH=/workspace/GOPATH" - "CGO_ENABLED=0" steps: - id: linux.amd64 name: "golang:1.21" env: - "GOOS=linux" - "GOARCH=amd64" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy.$$GOOS.$$GOARCH ./cmd/cloud_sql_proxy' - id: linux.386 name: "golang:1.21" env: - "GOOS=linux" - "GOARCH=386" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy.$$GOOS.$$GOARCH ./cmd/cloud_sql_proxy' - id: linux.arm64 name: "golang:1.21" env: - "GOOS=linux" - "GOARCH=arm64" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy.$$GOOS.$$GOARCH ./cmd/cloud_sql_proxy' - id: linux.arm name: "golang:1.21" env: - "GOOS=linux" - "GOARCH=arm" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy.$$GOOS.$$GOARCH ./cmd/cloud_sql_proxy' - id: darwin.amd64 name: "golang:1.21" env: - "GOOS=darwin" - "GOARCH=amd64" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy.$$GOOS.$$GOARCH ./cmd/cloud_sql_proxy' - id: darwin.arm64 name: "golang:1.21" env: - "GOOS=darwin" - "GOARCH=arm64" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy.$$GOOS.$$GOARCH ./cmd/cloud_sql_proxy' - id: windows.amd64 name: "golang:1.21" env: - "GOOS=windows" - "GOARCH=amd64" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy_x64.exe ./cmd/cloud_sql_proxy' - id: windows.386 name: "golang:1.21" env: - "GOOS=windows" - "GOARCH=386" entrypoint: "bash" args: - "-c" - 'go build -ldflags "-X main.versionString=${_VERSION} -X main.metadataString=$$GOOS.$$GOARCH" -o cloud_sql_proxy_x86.exe ./cmd/cloud_sql_proxy' artifacts: objects: location: "gs://cloudsql-proxy/v${_VERSION}/" paths: - "cloud_sql_proxy*" cloud-sql-proxy-1.33.14/.build/release_artifacts.sh000077500000000000000000000104701452473605000221510ustar00rootroot00000000000000#! /bin/bash # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This script distributes the artifacts for the Cloud SQL proxy to their different channels. set -e # exit immediatly if any step fails PROJ_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. >/dev/null 2>&1 && pwd )" cd $PROJ_ROOT # get the current version export VERSION=$(cat proxy/util/version.txt) if [ -z "$VERSION" ]; then echo "error: No version.txt found in $PROJ_ROOT" exit 1 fi read -p "This will release new Cloud SQL proxy artifacts for \"$VERSION\", even if they already exist. Are you sure (y/Y)? " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]] then exit 1 fi # Build and push the container images gcloud builds submit --async --config .build/default.yaml --substitutions _VERSION=$VERSION gcloud builds submit --async --config .build/alpine.yaml --substitutions _VERSION=$VERSION gcloud builds submit --async --config .build/buster.yaml --substitutions _VERSION=$VERSION gcloud builds submit --async --config .build/bullseye.yaml --substitutions _VERSION=$VERSION # Build the binarys and upload to GCS gcloud builds submit --config .build/gcs_upload.yaml --substitutions _VERSION=$VERSION # clean up any artifacts.json left by previous builds gsutil rm -f gs://cloudsql-proxy/v$VERSION/*.json 2> /dev/null || true # Generate sha256 hashes for authentication echo -e "Add the following table to the release notes on GitHub: \n\n" echo "| filename | sha256 hash |" echo "|----------|-------------|" for f in $(gsutil ls "gs://cloudsql-proxy/v$VERSION/cloud_sql_proxy*"); do file=$(basename $f) sha=$(gsutil cat $f | sha256sum --binary | head -c 64) echo "| [$file](https://storage.googleapis.com/cloudsql-proxy/v$VERSION/$file) | $sha |" done tag_latest() { local new_version=$1 # strip patch version from version, x.y.z -> x.y # https://stackoverflow.com/questions/49252680/bash-get-major-minor-version-from-string local major_minor_version=${new_version%.*} # strip minor and patch version from version, x.y.z -> x local major_version=${new_version%.*.*} for registry in "gcr.io" "us.gcr.io" "eu.gcr.io" "asia.gcr.io" do local base_image="$registry/cloudsql-docker/gce-proxy" echo "Tagging $new_version as latest in $registry" gcloud container images add-tag --quiet "$base_image:$new_version" "$base_image:latest" gcloud container images add-tag --quiet "$base_image:$new_version" "$base_image:$major_minor_version" gcloud container images add-tag --quiet "$base_image:$new_version" "$base_image:$major_version" echo "Addings tags to $new_version-alpine image in $registry" gcloud container images add-tag --quiet "$base_image:$new_version-alpine" "$base_image:alpine" gcloud container images add-tag --quiet "$base_image:$new_version-alpine" "$base_image:$major_minor_version-alpine" gcloud container images add-tag --quiet "$base_image:$new_version-alpine" "$base_image:$major_version-alpine" echo "Addings tags to $new_version-buster image in $registry" gcloud container images add-tag --quiet "$base_image:$new_version-buster" "$base_image:buster" gcloud container images add-tag --quiet "$base_image:$new_version-buster" "$base_image:$major_minor_version-buster" gcloud container images add-tag --quiet "$base_image:$new_version-buster" "$base_image:$major_version-buster" echo "Addings tags to $new_version-bullseye image in $registry" gcloud container images add-tag --quiet "$base_image:$new_version-bullseye" "$base_image:bullseye" gcloud container images add-tag --quiet "$base_image:$new_version-bullseye" "$base_image:$major_minor_version-bullseye" gcloud container images add-tag --quiet "$base_image:$new_version-bullseye" "$base_image:$major_version-bullseye" done } tag_latest "$VERSION" cloud-sql-proxy-1.33.14/.envrc.example000066400000000000000000000011521452473605000175220ustar00rootroot00000000000000export GOOGLE_CLOUD_PROJECT="project-name" export MYSQL_CONNECTION_NAME="project:region:instance" export MYSQL_USER="mysql-user" export MYSQL_PASS="mysql-password" export MYSQL_DB="mysql-db-name" export POSTGRES_CONNECTION_NAME="project:region:instance" export POSTGRES_USER="postgres-user" export POSTGRES_PASS="postgres-password" export POSTGRES_DB="postgres-db-name" export POSTGRES_USER_IAM="some-user-with-db-access@example.com" export SQLSERVER_CONNECTION_NAME="project:region:instance" export SQLSERVER_USER="sqlserver-user" export SQLSERVER_PASS="sqlserver-password" export SQLSERVER_DB="sqlserver-db-name" cloud-sql-proxy-1.33.14/.github/000077500000000000000000000000001452473605000163135ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/.github/CODEOWNERS000066400000000000000000000000451452473605000177050ustar00rootroot00000000000000* @GoogleCloudPlatform/infra-db-dpes cloud-sql-proxy-1.33.14/.github/ISSUE_TEMPLATE/000077500000000000000000000000001452473605000204765ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/.github/ISSUE_TEMPLATE/bug-report.md000066400000000000000000000024411452473605000231070ustar00rootroot00000000000000--- name: Bug Report about: Report defective or unintentional behavior you've experienced. title: "Brief summary of what bug or error was observed" labels: 'type: bug' --- ## Bug Description Please enter a detailed description of the bug, and any information about what behavior you noticed and how it differs from what you expected. ## Example code (or command) ``` // example ``` ## Stacktrace ``` Any relevant stacktrace here. Be sure to filter sensitive information. ``` ## How to reproduce 1. ? 2. ? ## Environment 1. OS type and version: 2. Cloud SQL Proxy version (`./cloud_sql_proxy -version`): cloud-sql-proxy-1.33.14/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000006021452473605000224640ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: Cloud SQL Issue tracker url: https://issuetracker.google.com/savedsearches/559773 about: Please use the Cloud SQL Issue tracker for problems with Cloud SQL itself. - name: StackOverflow url: https://stackoverflow.com/questions/tagged/google-cloud-sql about: Please use the `google-cloud-sql` tag for questions on StackOverflow.cloud-sql-proxy-1.33.14/.github/ISSUE_TEMPLATE/documentation-issue.md000066400000000000000000000022731452473605000250230ustar00rootroot00000000000000--- name: Documentation Issue about: Report wrong or missing information with the documentation in the repo. title: "Brief summary of what is missing or incorrect" labels: 'type: docs' --- ## Description Provide a short description of what is missing or incorrect, as well as a link to the specific location of the information. ## Solution What would you prefer the documentation say? Why would this information be more accurate or helpful? ## Additional Context Please reference any other relevant issues, PRs, descriptions, or screenshots here. cloud-sql-proxy-1.33.14/.github/ISSUE_TEMPLATE/feature-request.md000066400000000000000000000022751452473605000241470ustar00rootroot00000000000000--- name: Feature Request about: Suggest an idea for new or improved behavior. title: "Brief summary of the proposed feature" labels: 'type: feature request' --- ## Feature Description A clear and concise description of what feature you would like to see, and why it would be useful to have added. ## Alternatives Considered Are there any workaround or third party tools to replicate this behavior? Why would adding this feature be preferred over them? ## Additional Context Please reference any other issues, PRs, descriptions, or screenshots here. cloud-sql-proxy-1.33.14/.github/ISSUE_TEMPLATE/question.md000066400000000000000000000020321452473605000226640ustar00rootroot00000000000000--- name: Question about: Questions on how something works or the best way to do something. title: "Breif summary of your question" labels: 'type: question' --- ## Question What's your question? Please provide as much relevant information as possible to reduce turnaround time. ## Additional Context Please reference any other relevant issues, PRs, descriptions, or screenshots here. cloud-sql-proxy-1.33.14/.github/auto-label.yaml000066400000000000000000000011171452473605000212240ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. enabled: false cloud-sql-proxy-1.33.14/.github/blunderbuss.yml000066400000000000000000000013401452473605000213640ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. assign_issues: # - shubha-rajan - enocom # - jackwotherspoon # - kurtisvg assign_prs: # - shubha-rajan - enocom # - jackwotherspoon # - kurtisvg cloud-sql-proxy-1.33.14/.github/flakybot.yaml000066400000000000000000000011221452473605000210060ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. issuePriority: p2 cloud-sql-proxy-1.33.14/.github/header-checker-lint.yml000066400000000000000000000013001452473605000226260ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. allowedCopyrightHolders: - 'Google LLC' allowedLicenses: - 'Apache-2.0' sourceFileExtensions: - 'go' - 'yaml' - 'yml' cloud-sql-proxy-1.33.14/.github/renovate.json000066400000000000000000000006241452473605000210330ustar00rootroot00000000000000{ "extends": [ "config:base", ":semanticCommitTypeAll(chore)" ], "ignorePresets": [":semanticPrefixFixDepsChoreOthers"], "prConcurrentLimit": 0, "rebaseStalePrs": true, "dependencyDashboard": true, "semanticCommits": true, "postUpdateOptions": [ "gomodTidy" ], "ignoreDeps": [ "golang.org/x/net" ], "force": { "constraints": { "go": "1.16" } } } cloud-sql-proxy-1.33.14/.github/trusted-contribution.yml000066400000000000000000000011641452473605000232470ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. annotations: - type: label text: "tests: run" cloud-sql-proxy-1.33.14/.github/workflows/000077500000000000000000000000001452473605000203505ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/.github/workflows/coverage.yaml000066400000000000000000000034651452473605000230370ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: code coverage on: [pull_request] jobs: build: runs-on: ubuntu-latest steps: - name: Setup Go uses: actions/setup-go@v3 with: go-version: "1.21" - name: Checkout base branch uses: actions/checkout@v3 with: ref: ${{ github.base_ref }} - name: Calculate base code coverage run: | go test -short -coverprofile current_cover.out ./... || true export CUR_COVER=$(go tool cover -func current_cover.out | grep total | awk '{print substr($3, 1, length($3)-1)}') echo "CUR_COVER=$CUR_COVER" >> $GITHUB_ENV - name: Checkout PR branch uses: actions/checkout@v3 - name: Calculate PR code coverage run: | go test -short -coverprofile pr_cover.out ./... || true export PR_COVER=$(go tool cover -func pr_cover.out | grep total | awk '{print substr($3, 1, length($3)-1)}') echo "PR_COVER=$PR_COVER" >> $GITHUB_ENV - name: Verify code coverage. If your reading this and the step has failed, please add tests to cover your changes. run: | go tool cover -func pr_cover.out if [ "${{ env.PR_COVER }}" -lt "${{ env.CUR_COVER }}" ]; then exit 1; fi cloud-sql-proxy-1.33.14/.github/workflows/lint.yaml000066400000000000000000000040111452473605000221760ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: lint on: pull_request: pull_request_target: types: [labeled] jobs: lint: if: "${{ github.event.action != 'labeled' || github.event.label.name == 'tests: run' }}" name: run lint runs-on: ubuntu-latest steps: - name: Setup Go uses: actions/setup-go@v3 with: go-version: "1.21" - name: Install goimports run: go install golang.org/x/tools/cmd/goimports@latest - name: Checkout code uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} - run: goimports -w . - run: go mod tidy - name: Verify no changes from goimports and go mod tidy. If you're reading this and the check has failed, run `goimports -w . && go mod tidy`. run: git diff --exit-code - name: Remove PR Label if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}" uses: actions/github-script@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | try { await github.rest.issues.removeLabel({ name: 'tests: run', owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number }); } catch (e) { console.log('Failed to remove label. Another job may have already removed it!'); } cloud-sql-proxy-1.33.14/.github/workflows/tests.yaml000066400000000000000000000226741452473605000224110ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: tests on: push: branches: - 'v1' pull_request: pull_request_target: types: [labeled] jobs: unit: # run job on proper workflow event triggers (skip job for pull_request event from forks and only run pull_request_target for "tests: run" label) if: "${{ (github.event.action != 'labeled' && github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) || github.event.label.name == 'tests: run' }}" name: unit tests runs-on: "ubuntu-latest" strategy: matrix: go-version: ["1.19", "1.21"] fail-fast: false permissions: contents: 'read' id-token: 'write' steps: - name: Remove PR label if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}" uses: actions/github-script@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | try { await github.rest.issues.removeLabel({ name: 'tests: run', owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number }); } catch (e) { console.log('Failed to remove label. Another job may have already removed it!'); } - name: Checkout code uses: 'actions/checkout@v3' with: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} - name: Setup Go ${{ matrix.go-version }} uses: actions/setup-go@v3 with: go-version: ${{ matrix.go-version }} - id: 'auth' name: 'Authenticate to Google Cloud' uses: 'google-github-actions/auth@v0.8.0' with: workload_identity_provider: ${{ secrets.PROVIDER_NAME }} service_account: ${{ secrets.SERVICE_ACCOUNT }} access_token_lifetime: 600s - name: Run tests # specifying bash shell ensures a failure in a piped process isn't lost by using `set -eo pipefail` shell: bash run: | go install github.com/jstemmer/go-junit-report/v2@latest go test -short -race -v ./... | tee test_results.txt go-junit-report -in test_results.txt -set-exit-code -out unit_sponge_log.xml - name: FlakyBot if: ${{ (github.event_name == 'schedule' || github.event_name == 'push') && always() }} run: | curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L chmod +x ./flakybot ./flakybot --repo ${{github.repository}} --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} integration: # run job on proper workflow event triggers (skip job for pull_request event from forks and only run pull_request_target for "tests: run" label) if: "${{ (github.event.action != 'labeled' && github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) || github.event.label.name == 'tests: run' }}" name: integration tests runs-on: ${{ matrix.os }} strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] fail-fast: false permissions: contents: 'read' id-token: 'write' steps: - name: Remove PR label if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}" uses: actions/github-script@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | try { await github.rest.issues.removeLabel({ name: 'tests: run', owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number }); } catch (e) { console.log('Failed to remove label. Another job may have already removed it!'); } - name: Checkout code uses: 'actions/checkout@v3' with: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} - name: Setup Go uses: actions/setup-go@v3 with: go-version: "1.21" - id: 'auth' name: 'Authenticate to Google Cloud' uses: 'google-github-actions/auth@v0.8.0' with: workload_identity_provider: ${{ secrets.PROVIDER_NAME }} service_account: ${{ secrets.SERVICE_ACCOUNT }} access_token_lifetime: 600s - id: 'secrets' name: Get secrets uses: 'google-github-actions/get-secretmanager-secrets@v0.5.0' with: secrets: |- MYSQL_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_CONNECTION_NAME MYSQL_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER MYSQL_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_PASS MYSQL_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB POSTGRES_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME POSTGRES_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER POSTGRES_USER_IAM:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER_IAM POSTGRES_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_PASS POSTGRES_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_DB SQLSERVER_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_CONNECTION_NAME SQLSERVER_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_USER SQLSERVER_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_PASS SQLSERVER_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_DB - name: Enable fuse config (Linux) if: runner.os == 'Linux' run: | sudo sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf - name: Run tests env: GOOGLE_CLOUD_PROJECT: '${{ secrets.GOOGLE_CLOUD_PROJECT }}' MYSQL_CONNECTION_NAME: '${{ steps.secrets.outputs.MYSQL_CONNECTION_NAME }}' MYSQL_USER: '${{ steps.secrets.outputs.MYSQL_USER }}' MYSQL_PASS: '${{ steps.secrets.outputs.MYSQL_PASS }}' MYSQL_DB: '${{ steps.secrets.outputs.MYSQL_DB }}' POSTGRES_CONNECTION_NAME: '${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}' POSTGRES_USER: '${{ steps.secrets.outputs.POSTGRES_USER }}' POSTGRES_USER_IAM: '${{ steps.secrets.outputs.POSTGRES_USER_IAM }}' POSTGRES_PASS: '${{ steps.secrets.outputs.POSTGRES_PASS }}' POSTGRES_DB: '${{ steps.secrets.outputs.POSTGRES_DB }}' SQLSERVER_CONNECTION_NAME: '${{ steps.secrets.outputs.SQLSERVER_CONNECTION_NAME }}' SQLSERVER_USER: '${{ steps.secrets.outputs.SQLSERVER_USER }}' SQLSERVER_PASS: '${{ steps.secrets.outputs.SQLSERVER_PASS }}' SQLSERVER_DB: '${{ steps.secrets.outputs.SQLSERVER_DB }}' TMPDIR: "/tmp" run: | go install github.com/jstemmer/go-junit-report/v2@latest go test -race -v ./... | tee test_results.txt go-junit-report -in test_results.txt -set-exit-code -out integration_sponge_log.xml - name: FlakyBot (Linux) # only run flakybot on periodic (schedule) and continuous (push) events if: ${{ (github.event_name == 'schedule' || github.event_name == 'push') && runner.os == 'Linux' && always() }} run: | curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L chmod +x ./flakybot ./flakybot --repo ${{github.repository}} --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} - name: FlakyBot (Windows) # only run flakybot on periodic (schedule) and continuous (push) events if: ${{ (github.event_name == 'schedule' || github.event_name == 'push') && runner.os == 'Windows' && always() }} run: | curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot.exe -o flakybot.exe -s -L ./flakybot.exe --repo ${{github.repository}} --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} - name: FlakyBot (macOS) # only run flakybot on periodic (schedule) and continuous (push) events if: ${{ (github.event_name == 'schedule' || github.event_name == 'push') && runner.os == 'macOS' && always() }} run: | curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot-darwin-amd64 -o flakybot -s -L chmod +x ./flakybot ./flakybot --repo ${{github.repository}} --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} cloud-sql-proxy-1.33.14/.gitignore000066400000000000000000000002021452473605000167350ustar00rootroot00000000000000# direnv .envrc # IDEs .idea/ .vscode/ # Compiled binary /cmd/cloud_sql_proxy/cloud_sql_proxy /cloud_sql_proxy /cloud-sql-proxy cloud-sql-proxy-1.33.14/CHANGELOG.md000066400000000000000000000632061452473605000165730ustar00rootroot00000000000000# Changelog ## [1.33.14](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.13...v1.33.14) (2023-11-14) ### Bug Fixes * update deps to latest ([#2028](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/2028)) ([684fad0](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/684fad02f88c1d2c1f781109c86a8ffde5d10c3d)) ## [1.33.13](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.12...v1.33.13) (2023-10-25) ### Bug Fixes * upgrade google.golang.org/grpc ([#2009](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/2009)) ([ac9255b](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/ac9255bf029474f0d8cce7c2e148db28dcfa2852)) ## [1.33.12](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.11...v1.33.12) (2023-10-17) ### Bug Fixes * bump dependencies to latest ([#2001](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/2001)) ([2aa1924](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/2aa192419abfb63c78b001946d43d9802e7584d8)) * update supported Go versions ([#2002](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/2002)) ([68b85b6](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/68b85b6646e0eec39b42cf578695abcf9b6538bb)) ## [1.33.11](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.10...v1.33.11) (2023-09-19) ### Bug Fixes * bump dependencies to latest ([#1961](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1961)) ([82c13cb](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/82c13cb59a9af54de870b20080546efca2c20487)) ## [1.33.10](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.9...v1.33.10) (2023-08-16) ### Bug Fixes * replace the hardcoded default version string ([#1836](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1836)) ([#1900](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1900)) ([f945798](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/f945798b9c12daea5c318a14c5320a8fa18c4ec3)) ## [1.33.9](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.8...v1.33.9) (2023-07-18) ### Bug Fixes * update dependencies to latest versions ([#1873](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1873)) ([1978c11](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/1978c11bac70858eca1dc31bf67e3e19a326a456)) ## [1.33.8](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.7...v1.33.8) (2023-06-20) ### Bug Fixes * update dependencies to latest versions ([#1846](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1846)) ([d7b43c0](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/d7b43c0ca1a696025211f2242e2b9342c068d14d)) ## [1.33.7](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.6...v1.33.7) (2023-05-16) ### Bug Fixes * update dependencies to latest versions ([#1798](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1798)) ([e652120](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/e652120b0f46dfb2246cccdb482ff3639b25f9a9)) ## [1.33.6](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.5...v1.33.6) (2023-04-18) ### Bug Fixes * update dependencies to latest versions ([#1752](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1752)) ([f0b3cbd](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/f0b3cbd11d88cc1a1d38da233ac04a929747eb17)) ## [1.33.5](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.4...v1.33.5) (2023-03-22) ### Bug Fixes * bump all dependencies to latest ([#1706](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1706)) ([7ff4c4f](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/7ff4c4f65a5156ff08625a0ce2fb533e839dd9ee)) ## [1.33.4](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.3...v1.33.4) (2023-02-23) ### Bug Fixes * build statically linked binaries ([#1681](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1681)) ([ccb9bfa](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/ccb9bfae0138596dd91b73e27a0c39f4aa8a2480)) ## [1.33.3](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.2...v1.33.3) (2023-02-22) ### Bug Fixes * add support for Go 1.20 ([#1668](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1668)) ([c3d0c6b](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/c3d0c6b9c483140b316d22aafa5bef39e0ad235d)) * bump deps to latest ([#1671](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1671)) ([084b72e](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/084b72ed77379003039cb87df6f7d374505b6f69)) * require login_token with token and enable_iam_login ([#1641](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1641)) ([48a2fe5](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/48a2fe5f2c0e5487d3d5ccfa29023ac7d4a77600)) ## [1.33.2](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.1...v1.33.2) (2022-12-19) ### Bug Fixes * update dependencies to latest versions ([#1581](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1581)) ([e23ccb4](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/e23ccb404df2f4291429ea3d5d65c0aa8cf8cfac)) ## [1.33.1](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.33.0...v1.33.1) (2022-11-15) ### Bug Fixes * update dependencies to latest versions ([#1546](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1546)) ([a3aba9a](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/a3aba9a2552831b5aa1935af9a4ef4371d30a37c)) ## [1.33.0](https://github.com/googlecloudplatform/cloudsql-proxy/compare/v1.32.0...v1.33.0) (2022-10-25) ### Features * add bullseye container image ([#1467](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1467)) ([5a5d0a1](https://github.com/googlecloudplatform/cloudsql-proxy/commit/5a5d0a1c342ec57027921f43c4a40e02865a5b12)) * add support for Go 1.19 ([#1441](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1441)) ([1b16ff8](https://github.com/googlecloudplatform/cloudsql-proxy/commit/1b16ff8324b74a8d62f70286837d3b4a3af6d056)) * deprecate proxy drivers ([#1500](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1500)) ([2b460ea](https://github.com/googlecloudplatform/cloudsql-proxy/commit/2b460ea07ddfdc658b52f275c0e5550ce553c872)) * Downscope OAuth2 token included in ephemeral certificate ([#1450](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1450)) ([7557a35](https://github.com/googlecloudplatform/cloudsql-proxy/commit/7557a354ee26fa842025b0c2a811cb6175484e6d)) ### Bug Fixes * don't build fuse on freebsd ([#1439](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1439)) ([87863a1](https://github.com/googlecloudplatform/cloudsql-proxy/commit/87863a1b326e31fb3d3f4474fb2223010c6207e9)) * restore Go 1.16 support ([#1408](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1408)) ([618cb12](https://github.com/googlecloudplatform/cloudsql-proxy/commit/618cb129e3591aba072a01b420d18cc7dce26a68)) * update all direct deps to latest ([#1497](https://github.com/googlecloudplatform/cloudsql-proxy/issues/1497)) ([b15f78a](https://github.com/googlecloudplatform/cloudsql-proxy/commit/b15f78a569dc4bd7e113e9739a24240f5a7b4036)) ## [1.32.0](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/compare/v1.31.2...v1.32.0) (2022-09-08) ### Bug Fixes * update dependencies to latest versions ([#1383](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/1383)) ([8b6b137](https://github.com/GoogleCloudPlatform/cloud-sql-proxy/commit/8b6b13732a6ff0b6fb1b595b41e926da7d27353d)) ## [1.31.2](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.31.1...v1.31.2) (2022-08-02) ### Bug Fixes * update dependencies to latest versions ([#1286](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1286)) ([d3f9dcb](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/d3f9dcbe81bb43a0602e35359a262b2920f1915e)) ## [1.31.1](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.31.0...v1.31.1) (2022-07-12) ### Bug Fixes * strip monotonic clock reading during refresh ([#1223](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1223)) ([957d160](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/957d1609ad96bfed77b3744f1c11a762010bc06e)) ## [1.31.0](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.30.1...v1.31.0) (2022-06-02) ### Features * make Docker images ARM-friendly ([#1193](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1193)) ([6a98a04](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/6a98a0407785db7085532ea242b7079ceba756e3)) ### [1.30.1](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.30.0...v1.30.1) (2022-05-03) ### Bug Fixes * update dependencies to latest versions ([#1187](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1187)) ([f915180](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/f9151809664e1847db94b0e4da905aece000d8fa)) ## [1.30.0](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.29.0...v1.30.0) (2022-04-04) ### Features * drop support and testing for Go 1.13, 1.14, 1.15 ([#1148](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1148)) ([158b0d5](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/158b0d57d46054be6a0d1600d5030b23be69dc9b)) ## [1.29.0](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.28.1...v1.29.0) (2022-03-01) ### Features * add Go version support policy ([#1109](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1109)) ([ae6f4a1](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/ae6f4a1a534df8a273c0ea96880154b90bc65e77)) ### [1.28.1](https://github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.28.0...v1.28.1) (2022-01-31) ### Bug Fixes * invalidated config should retain error ([#1068](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1068)) ([49d3003](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/49d3003c018afdc0cde54340d5be808f9dcd5c84)) * remove unnecessary token parsing ([#1074](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1074)) ([e138611](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/e1386118ad239e6c1ff16df6f2be1351a6432bb3)) * return error from instance version ([#1069](https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1069)) ([d9fc819](https://github.com/GoogleCloudPlatform/cloudsql-proxy/commit/d9fc819a197bd75d0060bd46b8e06da6bdd6630c)) ## [1.28.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.27.1...v1.28.0) (2022-01-04) ### Features * add support for ReadTime in Admin API requests ([#1040](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1040)) ([a7c8b5c](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/a7c8b5cf4d10c17bea405ce67ee642232b43fdec)) * add support for specifying a quota project ([#1044](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1044)) ([dc66aca](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/dc66aca88190ae3f6d39f191489fdfb280146ed9)) * allow multiple -instances flags ([#1046](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1046)) ([1972693](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/1972693b8ac65c912bb719dc23d4f578cb6ff9e2)), closes [#1030](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1030) ### Bug Fixes * increase rateLimit burst size to 2 ([#1048](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1048)) ([df6b6f9](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/df6b6f9ed8860d28f5e934db495257d288c42f2b)) ### [1.27.1](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.27.0...v1.27.1) (2021-12-07) ### Bug Fixes * update dependencies to latest versions ([#1034](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1034)) ([8954d24](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/8954d241a71b59d9bf82cb47469e6652d3f379e7)) ## [1.27.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.26.0...v1.27.0) (2021-11-02) ### Features * switch to supported FUSE library ([#953](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/953)) ([10f2133](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/10f2133010f3bf7ef8a13b43e0bfa16bdca8cedb)) * verify FUSE is installed on macOS / linux ([#959](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/959)) ([9ab868e](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/9ab868ef344b9a82c06f97928420f98a4d37c5ce)) ### Bug Fixes * fail fast on invalid config ([#999](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/999)) ([18a0960](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/18a096037d9ceb2ca71218984b65fe342fc2a778)) * respect context deadline for TLS handshakes ([#987](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/987)) ([12ff12c](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/12ff12c9f87459dc40e2e6e4a2d08bebb0786ee7)), closes [#986](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/986) * validate instance connections in liveness probe ([#995](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/995)) ([e5cc8d4](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/e5cc8d4f8676fed2013cc491578a1aaf7416ec3e)) ## [1.26.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.25.0...v1.26.0) (2021-10-05) ### Features * improve reliability of refresh operations ([#883](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/883)) ([480992a](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/480992a7671abe9b76f940175f4ed17f5271d3f8)) ## [1.25.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.24.0...v1.25.0) (2021-09-07) ### Features * add health checks to proxy ([#859](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/859)) ([ea62bdd](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/ea62bddaaf3aa7df79250d045ba2f5f3fe7edaea)) * add instance dialing to health check ([#871](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/871)) ([eca3793](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/eca37935e7cd54efcd612c170e46f45c1d8e3556)) * require TLS v1.3 at minimum ([#906](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/906)) ([cafa966](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/cafa966e50170ad94f12f067549ba3aedf8ecdca)) ### Bug Fixes * ensure proxy shuts down gracefully on SIGTERM ([#877](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/877)) ([9793555](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/97935551ac44cb7a92e2901def1938d604dfeecb)) * validate instances in fuse mode ([#875](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/875)) ([96f8b65](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/96f8b655b09b711fd9adfcb486626b64d3b917f3)) ## [1.24.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.23.1...v1.24.0) (2021-08-02) ### Features * Add option to delay key generation until first connect ([#841](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/841)) ([4999ffd](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/4999ffd0c3406e91874648630f9805b2d5f0ac50)) * stop building darwin 386 binaries ([#846](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/846)) ([77d7c40](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/77d7c40ff79cf99a10d2dbae39b737625a08582f)), closes [#780](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/780) ### Bug Fixes * invalidate cached config on handshake error ([#817](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/817)) ([5d98f5c](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/5d98f5c40e0b58da479bf6897712d53e6846f613)) * strip padding from access tokens if present ([#851](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/851)) ([1f195e5](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/1f195e500c1a8989dcf4d73c429620ddd5b20891)) * structured_logs compatibility with Google Cloud Logging ([#861](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/861)) ([74a6ec7](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/74a6ec70b63f4f0488470164fa4da68a26779fb2)) ### [1.23.1](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.23.0...v1.23.1) (2021-07-12) ### Bug Fixes * improve log message when refresh is throttled ([#830](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/830)) ([4ffee2a](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/4ffee2a1950fd6fb6703647d178a436b566b8a80)) ## [1.23.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.22.0...v1.23.0) (2021-06-01) ### Features * add deprecation warning for Darwin 386 ([#781](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/781)) ([cdc552b](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/cdc552b8da7abb3378d43c060acb019de7e12fcc)) ### Bug Fixes * change to static base container ([#791](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/791)) ([d66233e](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/d66233e2a0aecb6e80a4f802b0dc6a5cd2fa9041)) ## [1.22.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.21.0...v1.22.0) (2021-04-21) ### Features * Add support for systemd notify ([#719](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/719)) ([4305eff](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/4305eff05f1d33da4251a7b512b723cb086e4ce5)) ### Bug Fixes * Allow combined use of structured logs and -log_debug_stdout ([#726](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/726)) ([45bda77](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/45bda776fc964a3464a1703035b4f2a719779bc6)) * return early when cert refresh fails ([#748](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/748)) ([fd21f66](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/fd21f66f2d8dc3b8e787ab0b467db4d4b85921cb)) * structured logging respects the -verbose flag ([#737](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/737)) ([f35422f](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/f35422f449a0c79f6b2225de21c26c2da04d3528)) ## [1.21.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.20.2...v1.21.0) (2021-04-05) ### Features * add support for structured logs ([#650](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/650)) ([ca8993a](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/ca8993a2110affa0b0cbbfdebf6f6bdd86004e9f)) ### Bug Fixes * improve cache to prevent multiple concurrent refreshes ([#674](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/674)) ([c5ffa69](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/c5ffa69952eba713e7acc688841f9b448a180625)) * lower refresh buffer and config throttle when IAM authn is enabled ([#680](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/680)) ([58acab3](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/58acab3b03375032501f17c85949db493af7a292)) * prevent refreshCfg from scheduling multiple refreshes ([#666](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/666)) ([52db349](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/52db3492ac78a9a68218c2a12840c4016b1d0b99)) ### [1.20.2](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.20.1...v1.20.2) (2021-03-05) ### Bug Fixes * ensure certificate expiration is correct ([#659](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/659)) ([2fd2504](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/2fd2504381405b0d5fe7cc81d3c55a15f949df99)) * perform initial gcloud check and reuse token ([#657](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/657)) ([f3bf3f9](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/f3bf3f931621285875363fab5fe3563bc82a3d94)) ### [1.20.1](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.20.0...v1.20.1) (2021-03-04) ### Bug Fixes * prevent untrusted gcloud exe's from running ([#649](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/649)) ([0f0ff49](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/0f0ff49a0fac990ba1ec05a6cbd4e666e3141c08)) * use new oauth2 token with cert refresh ([#648](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/648)) ([6d5e455](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/6d5e4558a63957714f6347c9768e671586c0a605)) * verify TokenSource exists in TokenExpiration() ([#642](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/642)) ([d01d7eb](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/d01d7eb78652cf83f713b5d47bb696378929e8a6)) ## [1.20.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.19.2...v1.20.0) (2021-02-24) ### Features * add ARM releases ([#631](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/631)) ([d3fb7f6](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/d3fb7f6394f2c641f0ba7339ab29a1c02d82e396)) * Added '-enable_iam_login' flag for IAM db authentication ([#583](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/583)) ([470f92d](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/470f92d29d7a32f7903a3cb6d49fb09363185866)) ### [1.19.2](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.19.1...v1.19.2) (2021-02-16) ### Bug Fixes * improve logging for file descriptor limits ([#609](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/609)) ([b42b681](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/b42b68134543fbee7da4fbb9a8d667fd9153bec2)), closes [#413](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/413) ### [1.19.1](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.19.0...v1.19.1) (2020-12-02) ### Bug Fixes * Ensure necessary fields are 64-bit aligned ([#550](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/550)) ([4575c8f](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/4575c8f8cb496ac3069208e446c47fb6c6acb868)) ## [1.19.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.18.0...v1.19.0) (2020-11-18) ### Features * Added DialContext to Client and proxy package ([#483](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/483)) ([c84aa50](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/c84aa5079668e07e3d2dc8f254d30e1103a6ead3)) * use regionalized instance ids to prevent global conflicts with sqladmin v1 ([#504](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/504)) ([6c45513](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/6c455136a24b841dbfc015a1f8ed7505f9e77dec)) ### Bug Fixes * **containers:** Allow non-root users to mount fuse filesystems for alpine and buster images ([#540](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/540)) ([5b653f5](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/5b653f5df6d9c4c226e3c4f6036d5e7d4c43c699)) * only allow fuse mode to unmount if an error occurs first ([#537](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/537)) ([6caef36](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/6caef36968d23b931c824450e418e29ac6277191)) * refreshCfg no longer caches error over valid cert ([#521](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/521)) ([4a6b3d8](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/4a6b3d8c895e2634afd8cee2341db668f20b9a33)) ## [1.18.0](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/compare/v1.17.0...v1.18.0) (2020-09-08) ### Features * **containers:** Add "-alpine" and "-buster" based images. ([#415](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/415)) ([ebcf294](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/ebcf294b9ee028340695868fb6f4cc4bbe09d849)) * **containers:** Add fuse to alpine and buster images ([#459](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/459)) ([0f28fcd](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/0f28fcd008a5bb863ec2ca1402c31ae81d7dae5d)) ### Bug Fixes * Print out any errors during SIGTERM-caused shutdown ([#389](https://github.com/GoogleCloudPlatform/cloudsql-proxy/pull/389)) * Optimize `-term-timeout` wait ([#391](https://github.com/GoogleCloudPlatform/cloudsql-proxy/pull/391)) * Add socket suffix for Postgres instances when running in `-fuse` mode ([#426](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/426)) ([20ffaec](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/20ffaec2f0f00a2516206a0453bd0d1c6e62770c)) * **containers:** Specify nonroot user by uid to work with runAsNonRoot ([#402](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/issues/402)) ([c5c0be1](https://www.github.com/GoogleCloudPlatform/cloudsql-proxy/commit/c5c0be1b60bfc1c3fa862039619908a328066e5e)) * Releases are now tagged using `vMAJOR.MINOR.PATCH` for correct compatibility with go-modules. Please note that this will effect container image tags (which were previously only `vMAJOR.MINOR`), since these tags correspond directly to the release on GitHub. cloud-sql-proxy-1.33.14/CONTRIBUTING.md000066400000000000000000000160451452473605000172120ustar00rootroot00000000000000# Contributing 1. **Please sign one of the contributor license agreements below!** 1. Fork the repo, develop and test your code changes, add docs. 1. Make sure that your commit messages clearly describe the changes. 1. Send a pull request. ## Table of contents * [Opening an issue](#opening-an-issue) * [How to run tests](#how-to-run-tests) * [Contributor License Agreements](#contributor-license-agreements) * [Contributor Code of Conduct](#contributor-code-of-conduct) ## Opening an issue If you find a bug in the proxy code or an inaccuracy in the documentation, please open an issue. GitHub provides a guide, [Mastering Issues](https://guides.github.com/features/issues/), that is useful if you are unfamiliar with the process. Here are the specific steps for opening an issue: 1. Go to the project issues page on GitHub. 1. Click the green `New Issue` button located in the upper right corner. 1. In the title field, write a single phrase that identifies your issue. 1. In the main editor, describe your issue. 1. Click the submit button. Thank you. We will do our best to triage your issue within one business day, and attempt to categorize your issues with an estimate of the priority and issue type. We will try to respond with regular updates based on its priority: * **Critical** respond and update daily, resolve with a week * **High** respond and update weekly, resolve within six weeks * **Medium** respond and update every three months, best effort resolution * **Low** respond and update every six months, best effort resolution The priority we assign will be roughly a function of the number of users we expect to be impacted, as well as its severity. As a rule of thumb:
Severity Number of users
Handful Some Most All
Easy, obvious workaround Low Low Medium High
Non-obvious workaround available Low Medium High Critical
Functionality blocked High High Critical Critical
## How to run tests The test suite includes both unit and integration tests. For macOS and Linux, there is a depenency on [FUSE][] that must be present on the system. ### Test Dependencies When running tests on macOS and Linux, users will need to first install [FUSE][]. Windows users may skip this step. On Debian, use: ``` sudo apt-get install fuse ``` On macOS, use: ``` brew install --cask macfuse ``` ### How to run just unit tests ``` go test -short ./... ``` ### How to run all tests To run all integration tests, users will need a Google Cloud project with a MySQL, PostgreSQL, and SQL Server database, in addition to installing FUSE support. Note: Pull Requests will run these tests and as a result may be skipped locally if necessary. A sample `.envrc.example` file is included in the root directory which documents which environment variables must be set to run the integration tests. Copy this example file to `.envrc` at the root of the project, supply all the correct values for each variable, source the file (`source .envrc`, or consider using [direnv][]), and then run: ``` go test ./... ``` ## Contributor License Agreements Open-source software licensing is a wonderful arrangement that benefits everyone, but in an imperfect world, we all need to exercise some legal prudence. In order to protect you, Google, and most of all, everyone who comes to depend on these libraries, we require that all contributors sign our short and human-readable Contributor License Agreement (CLA). We don't want to open the door to patent trolls, predatory lawyers, or anyone else who isn't on board with creating value and making the world a better place. We hope you will agree that the CLA offers very important protection and is easy to understand. Take a moment to read it carefully, and if you agree with what you read, please sign it now. If you believe you've already signed the appropriate CLA already for this or any other Google open-source project, you shouldn't have to do so again. You can review your signed CLAs at [cla.developers.google.com/clas](https://cla.developers.google.com/clas). First, check that you are signed in to a [Google Account](https://accounts.google.com) that matches your [local Git email address](https://help.github.com/articles/setting-your-email-in-git/). Then choose one of the following: * If you are **an individual writing original source code** and **you own the intellectual property**, sign the [Individual CLA](https://developers.google.com/open-source/cla/individual). * If you work for **a company that wants to allow you to contribute**, sign the [Corporate CLA](https://developers.google.com/open-source/cla/corporate). You (and your authorized signer, if corporate) can sign the CLA electronically. After that, we'll be able to accept your contributions. ## Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) [FUSE]: https://www.kernel.org/doc/html/latest/filesystems/fuse.html [direnv]: https://direnv.net/ cloud-sql-proxy-1.33.14/CONTRIBUTORS000066400000000000000000000027451452473605000166430ustar00rootroot00000000000000# This is the official list of people who can contribute # (and typically have contributed) code to the repository. # The AUTHORS file lists the copyright holders; this file # lists people. For example, Google employees are listed here # but not in AUTHORS, because Google holds the copyright. # # The submission process automatically checks to make sure # that people submitting code are listed in this file (by email address). # # Names should be added to this file only after verifying that # the individual or the individual's organization has agreed to # the appropriate Contributor License Agreement, found here: # # https://cla.developers.google.com/about/google-individual # https://cla.developers.google.com/about/google-corporate # # The CLA can be filled out on the web: # # https://cla.developers.google.com/ # # When adding J Random Contributor's name to this file, # either J's name or J's organization's name should be # added to the AUTHORS file, depending on whether the # individual or corporate CLA was used. # Names should be added to this file like so: # Name # # An entry with two email addresses specifies that the # first address should be used in the submit logs and # that the second address should be recognized as the # same person when interacting with Rietveld. # Please keep the list sorted. Ben Brown Frank van Rest Kevin Malachowski Mykola Smith cloud-sql-proxy-1.33.14/Dockerfile000066400000000000000000000022071452473605000167460ustar00rootroot00000000000000# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Use the latest stable golang 1.x to compile to a binary FROM --platform=$BUILDPLATFORM golang:1 as build WORKDIR /go/src/cloudsql-proxy COPY . . ARG TARGETOS ARG TARGETARCH RUN go get ./... RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ go build -ldflags "-X main.metadataString=container" -o cloud_sql_proxy ./cmd/cloud_sql_proxy # Final Stage FROM gcr.io/distroless/static:nonroot COPY --from=build --chown=nonroot /go/src/cloudsql-proxy/cloud_sql_proxy /cloud_sql_proxy # set the uid as an integer for compatibility with runAsNonRoot in Kubernetes USER 65532 cloud-sql-proxy-1.33.14/Dockerfile.alpine000066400000000000000000000027521452473605000202220ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Use the latest stable golang 1.x to compile to a binary FROM --platform=$BUILDPLATFORM golang:1-alpine as build WORKDIR /go/src/cloudsql-proxy COPY . . ARG TARGETOS ARG TARGETARCH RUN go get ./... RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ go build -ldflags "-X main.metadataString=container.alpine" -o cloud_sql_proxy ./cmd/cloud_sql_proxy # Final stage FROM alpine:3 RUN apk add --no-cache \ ca-certificates \ libc6-compat # Install fuse and allow enable non-root users to mount RUN apk add --no-cache fuse && sed -i 's/^#user_allow_other$/user_allow_other/g' /etc/fuse.conf # Add a non-root user matching the nonroot user from the main container RUN addgroup -g 65532 -S nonroot && adduser -u 65532 -S nonroot -G nonroot # Set the uid as an integer for compatibility with runAsNonRoot in Kubernetes USER 65532 COPY --from=build --chown=nonroot /go/src/cloudsql-proxy/cloud_sql_proxy /cloud_sql_proxy cloud-sql-proxy-1.33.14/Dockerfile.bullseye000066400000000000000000000027641452473605000206010ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Use the latest stable golang 1.x to compile to a binary FROM --platform=$BUILDPLATFORM golang:1 as build WORKDIR /go/src/cloudsql-proxy COPY . . ARG TARGETOS ARG TARGETARCH RUN go get ./... RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ go build -ldflags "-X main.metadataString=container.bullseye" -o cloud_sql_proxy ./cmd/cloud_sql_proxy # Final stage FROM debian:bullseye RUN apt-get update && apt-get install -y ca-certificates # Install fuse and allow enable non-root users to mount RUN apt-get update && apt-get install -y fuse && sed -i 's/^#user_allow_other$/user_allow_other/g' /etc/fuse.conf # Add a non-root user matching the nonroot user from the main container RUN groupadd -g 65532 -r nonroot && useradd -u 65532 -g 65532 -r nonroot # Set the uid as an integer for compatibility with runAsNonRoot in Kubernetes USER 65532 COPY --from=build --chown=nonroot /go/src/cloudsql-proxy/cloud_sql_proxy /cloud_sql_proxy cloud-sql-proxy-1.33.14/Dockerfile.buster000066400000000000000000000027601452473605000202550ustar00rootroot00000000000000# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Use the latest stable golang 1.x to compile to a binary FROM --platform=$BUILDPLATFORM golang:1 as build WORKDIR /go/src/cloudsql-proxy COPY . . ARG TARGETOS ARG TARGETARCH RUN go get ./... RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ go build -ldflags "-X main.metadataString=container.buster" -o cloud_sql_proxy ./cmd/cloud_sql_proxy # Final stage FROM debian:buster RUN apt-get update && apt-get install -y ca-certificates # Install fuse and allow enable non-root users to mount RUN apt-get update && apt-get install -y fuse && sed -i 's/^#user_allow_other$/user_allow_other/g' /etc/fuse.conf # Add a non-root user matching the nonroot user from the main container RUN groupadd -g 65532 -r nonroot && useradd -u 65532 -g 65532 -r nonroot # Set the uid as an integer for compatibility with runAsNonRoot in Kubernetes USER 65532 COPY --from=build --chown=nonroot /go/src/cloudsql-proxy/cloud_sql_proxy /cloud_sql_proxy cloud-sql-proxy-1.33.14/LICENSE000066400000000000000000000261361452473605000157700ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cloud-sql-proxy-1.33.14/README.md000066400000000000000000000367131452473605000162440ustar00rootroot00000000000000# Cloud SQL Auth proxy [![CI][ci-badge]][ci-build] [![Go Reference][pkg-badge]][pkg-docs] The [Cloud SQL Auth proxy][proxy-page] is a binary that provides IAM-based authorization and encryption when connecting to a Cloud SQL instance. See the [Connecting Overview][connection-overview] page for more information on connecting to a Cloud SQL instance, or the [About the proxy][about-proxy] page for details on how the Cloud SQL proxy works. Note: The Proxy *cannot* provide a network path to a Cloud SQL instance if one is not already present (e.g., the proxy cannot access a VPC if it does not already have access to it). ## Installation For 64-bit Linux, run: ``` VERSION=v1.21.0 # see Releases for other versions wget "https://storage.googleapis.com/cloudsql-proxy/$VERSION/cloud_sql_proxy.linux.amd64" -O cloud_sql_proxy chmod +x cloud_sql_proxy ``` Releases for additional OS's and architectures and be found on the [releases page][releases]. For alternative distributions, see below under [third party](#third-party). ### Container Images There are containerized versions of the proxy available from the following Google Cloud Container Registry repositories: * `gcr.io/cloudsql-docker/gce-proxy` * `us.gcr.io/cloudsql-docker/gce-proxy` * `eu.gcr.io/cloudsql-docker/gce-proxy` * `asia.gcr.io/cloudsql-docker/gce-proxy` Each image is tagged with the associated proxy version. The following tags are currently supported: * `$VERSION` - default image (recommended) * `$VERSION-alpine` - uses [`alpine:3`](https://hub.docker.com/_/alpine) as a base image (only supported from v1.17 up) * `$VERSION-buster` - uses [`debian:buster`](https://hub.docker.com/_/debian) as a base image (only supported from v1.17 up) * `$VERSION-bullseye` - uses [`debian:bullseye`](https://hub.docker.com/_/debian) as a base image (only supported from v1.17 up) We recommend using the latest version of the proxy and updating the version regularly. However, we also recommend pinning to a specific tag and avoid the latest tag. Note: the tagged version is only that of the proxy. Changes in base images may break specific setups, even on non-major version increments. As such, it's a best practice to test changes before deployment, and use automated rollbacks to revert potential failures. **NOTE**: As of v1.16, the default container image uses [distroless][]. If you require a shell or similar tools, use the Alpine or Buster images listed above. [distroless]: https://github.com/GoogleContainerTools/distroless ### Install from Source To install from source, ensure you have the latest version of [Go installed](https://go.dev/doc/install). Then, simply run: ``` go install github.com/GoogleCloudPlatform/cloudsql-proxy/cmd/cloud_sql_proxy@latest ``` The `cloud_sql_proxy` will be placed in `$GOPATH/bin` or `$HOME/go/bin`. ## Usage All the following invocations assume valid credentials are present in the environment. The following examples all reference an `INSTANCE_CONNECTION_NAME`, which takes the form: `myproject:myregion:myinstance`. To find the `INSTANCE_CONNECTION_NAME`, run `gcloud sql instances describe ` where `INSTANCE_NAME` is the name of the database instance. ### TCP socket example ``` bash # Starts the proxy listening on 127.0.0.1:5432 cloud_sql_proxy -instances==tcp:5432 ``` ``` bash # Starts the proxy listening on port 5432 on *all* interfaces cloud_sql_proxy -instances==tcp:0.0.0.0:5432 ``` ### Unix socket example ``` bash # The proxy will mount a Unix domain socket at /cloudsql/ # Note: The directory specified by `-dir` must exist and the socket file path # (i.e., dir plus INSTANCE_CONNECTION_NAME) must be under your platform's # limit (typically 108 characters on many Unix systems, but varies by platform). cloud_sql_proxy -dir=/cloudsql -instances= ``` ### Private IP example ``` cloud_sql_proxy -instances==tcp:5432 -ip_address_types=PRIVATE ``` In order to connect using Private IP, you must have access through your project's VPC. For more details, see [Private IP Requirements][private-ip]. ## Credentials The Cloud SQL proxy uses a Cloud IAM account to authorize connections against a Cloud SQL instance. The proxy sources the credentials for these accounts in the following order: 1. The `-credential_file` flag 2. The `-token` flag 3. The service account key at the path stored in the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. 4. The gcloud user credentials (set from `gcloud auth login`) 5. The [Application Default Credentials](https://cloud.google.com/docs/authentication/production) Note: Any account connecting to a Cloud SQL database will need one of the following IAM roles: - Cloud SQL Client (preferred) - Cloud SQL Editor - Cloud SQL Admin Or one may manually assign the following IAM permissions: - `cloudsql.instances.connect` - `cloudsql.instances.get` See [Roles and Permissions in Cloud SQL][roles-and-permissions] for details. When the proxy authenticates under the Compute Engine VM's default service account, the VM must have at least the `sqlservice.admin` API scope (i.e., "https://www.googleapis.com/auth/sqlservice.admin") and the associated project must have the SQL Admin API enabled. The default service account must also have at least writer or editor privileges to any projects of target SQL instances. ## CLI Flags The Cloud SQL Auth proxy takes a few arguments to configure what instances to connect to and connection behavior. For a full list of flags supported by the proxy, use `cloud_sql_proxy -help`. ### Authentication Flags #### `-credential_file` Specifies the path to a JSON [service account][service-account] key the proxy uses to authorize or authenticate connections. #### `-token` When set, the proxy uses this Bearer token for authorization. #### `-enable_iam_login` Enables the proxy to use Cloud SQL IAM database authentication. This will cause the proxy to use IAM account credentials for database user authentication. For details, see [Overview of Cloud SQL IAM database authentication][iam-auth]. NOTE: This feature only works with Postgres database instances. ### Connection Flags #### `-instances="project1:region:instance1,project3:region:instance1"` A comma-separated list of instances to open inside `-dir`. Also supports exposing a TCP port and renaming the default Unix Domain Sockets; see examples below. Same list can be provided via INSTANCES environment variable, in case when both are provided - proxy will use command line flag. **Example** Using TCP sockets: ``` ./cloud_sql_proxy -instances=my-project:us-central1:sql-inst=tcp:3306 & mysql -u root -h 127.0.0.1 ``` Using Unix sockets: ``` ./cloud_sql_proxy -dir=/cloudsql -instances=my-project:us-central1:sql-inst & mysql -u root -S /cloudsql/my-project:us-central1:sql-inst ``` To specify a custom Unix socket name: ``` ./cloud_sql_proxy -dir=/cloudsql \ -instances=my-project:us-central1:sql-inst=unix:custom_socket_name & mysql -u root -S /cloudsql/custom_socket_name ``` To specify a custom location for a Unix socket (overrides `-dir`): ``` ./cloud_sql_proxy -dir=/cloudsql \ -instances=my-project:us-central1:sql-inst=unix:/my/custom/sql-socket & mysql -u root -S /my/custom/sql-socket ``` #### `-fuse` Requires access to `/dev/fuse` as well as the `fusermount` binary. An optional `-fuse_tmp` flag can specify where to place temporary files. The directory indicated by `-dir` is mounted. **Example** Using `-fuse`, you do not need to specify instance names ahead of time: ``` ./cloud_sql_proxy -dir=/cloudsql -fuse & mysql -u root -S /cloudsql/my-project:us-central1:sql-inst ``` #### `-instances_metadata=metadata_key` Usable on [GCE](https://cloud.google.com/compute/docs/quickstart) only. The given [GCE metadata](https://cloud.google.com/compute/docs/metadata) key will be polled for a list of instances to open in `-dir`. The metadata key is relative from `computeMetadata/v1/`. The format for the value is the same as the 'instances' flag. A hanging-poll strategy is used, meaning that changes to the metadata value will be reflected in the `-dir` even while the proxy is running. When an instance is removed from the list the corresponding socket will be removed from `-dir` as well (unless it was also specified in `-instances`), but any existing connections to this instance will NOT be terminated. **Example** ``` ./cloud_sql_proxy -dir=/cloudsql \ -instances_metadata instance/attributes/ & mysql -u root -S /cloudsql/my-project:us-central1:sql-inst ``` Note: `-instances` and `-instances_metadata` may be used at the same time but are not compatible with the `-fuse` flag. #### `-max_connections` If provided, the maximum number of connections to establish before refusing new connections. Defaults to 0 (no limit). ### Additional Flags #### `-ip_address_types=PUBLIC,PRIVATE` A comma-delimited list of preferred IP types for connecting to an instance. For example, setting this to PRIVATE will force the proxy to connect to instances using an instance's associated private IP. Defaults to `PUBLIC,PRIVATE` #### `-term_timeout=30s` How long to wait for connections to close after receiving a SIGTERM before shutting down the proxy. Defaults to 0. If all connections close before the duration, the proxy will shutdown early. #### `-skip_failed_instance_config` Setting this flag will prevent the proxy from terminating if any errors occur during instance configuration. Please note that this means some instances may fail to be set up correctly while others may work if the proxy restarts. #### `-log_debug_stdout=true` This is to log non-error output to standard out instead of standard error. For example, if you don't want connection related messages to log as errors, set this flag to true. Defaults to false. #### `-structured_logs` Writes all logging output as JSON with the following keys: severity, timestamp, caller, message and optionally stacktrace. For example, the startup message looks like: ```json {"severity":"INFO","timestamp":"2020-10-12T07:20:50.52Z","caller":"cloud_sql_proxy/cloud_sql_proxy.go:510","message":"Using gcloud's active project: [my-project-id]"} ``` #### `-use_http_health_check` Enables HTTP health checks for the proxy, including startup, liveness, and readiness probing. Requires that you configure the Kubernetes container with HTTP probes ([instructions][health-check-example]). #### `-health_check_port=8090` Specifies the port that the health check server listens and serves on. Defaults to 8090. ## Running as a Kubernetes Sidecar See the [example here][sidecar-example] as well as [Connecting from Google Kubernetes Engine][connect-to-k8s]. ## Running behind a Socks5 proxy The Cloud SQL Auth Proxy includes support for sending requests through a SOCKS5 proxy. If a SOCKS5 proxy is running on `localhost:8000`, the command to start the Cloud SQL Auth Proxy would look like: ``` ALL_PROXY=socks5://localhost:8000 \ HTTPS_PROXY=socks5://localhost:8000 \ cloud_sql_proxy -instances=$INSTANCE_CONNECTION_NAME=tcp:5432 ``` The `ALL_PROXY` environment variable specifies the proxy for all TCP traffic to and from a Cloud SQL instance. The `ALL_PROXY` environment variable supports `socks5` and `socks5h` protocols. To route DNS lookups through a proxy, use the `socks5h` protocol. The `HTTPS_PROXY` (or `HTTP_PROXY`) specifies the proxy for all HTTP(S) traffic to the SQL Admin API. Specifying `HTTPS_PROXY` or `HTTP_PROXY` is only necessary when you want to proxy this traffic. Otherwise, it is optional. See [`http.ProxyFromEnvironment`](https://pkg.go.dev/net/http@go1.17.3#ProxyFromEnvironment) for possible values. ## Reference Documentation - [Cloud SQL][cloud-sql] - [Cloud SQL Auth proxy Documentation][proxy-page] - [Cloud SQL Auth proxy Quickstarts][quickstarts] - [Cloud SQL Code Samples][code-samples] - [Cloud SQL Auth proxy Package Documentation][pkg-docs] ## Support policy ### Major version lifecycle This project uses [semantic versioning](https://semver.org/), and uses the following lifecycle regarding support for a major version: **Active** - Active versions get all new features and security fixes (that wouldn’t otherwise introduce a breaking change). New major versions are guaranteed to be "active" for a minimum of 1 year. **Deprecated** - Deprecated versions continue to receive security and critical bug fixes, but do not receive new features. Deprecated versions will be publicly supported for 1 year. **Unsupported** - Any major version that has been deprecated for >=1 year is considered publicly unsupported. ### Supported Go Versions We follow the [Go Version Support Policy][go-policy] used by Google Cloud Libraries for Go. [go-policy]: https://github.com/googleapis/google-cloud-go#supported-versions ### Release cadence The Cloud SQL Auth proxy aims for a minimum monthly release cadence. If no new features or fixes have been added, a new PATCH version with the latest dependencies is released. ## Contributing Contributions are welcome. Please, see the [CONTRIBUTING][contributing] document for details. Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. See [Contributor Code of Conduct][code-of-conduct] for more information. ## Third Party __WARNING__: _These distributions are not officially supported by Google._ ### Homebrew There is Homebrew formula for Cloud SQL Auth proxy [here](https://github.com/tclass/homebrew-cloud_sql_proxy). ### Kubernetes Cluster Service using Helm Follow these [instructions](https://github.com/rimusz/charts/tree/master/stable/gcloud-sqlproxy). This chart creates a Deployment and a Service, but we recommend deploying the proxy as a sidecar container in your pods. ### .Net Proxy Wrapper (Nuget Package) Install via Nuget, follow these [instructions](https://github.com/expert1-pty-ltd/cloudsql-proxy#install-via-nuget). [about-proxy]: https://cloud.google.com/sql/docs/mysql/sql-proxy [ci-badge]: https://github.com/GoogleCloudPlatform/cloudsql-proxy/actions/workflows/tests.yaml/badge.svg?event=push [ci-build]: https://github.com/GoogleCloudPlatform/cloudsql-proxy/actions/workflows/tests.yaml?query=event%3Apush+branch%3Amain [cloud-sql]: https://cloud.google.com/sql [code-samples]: https://cloud.google.com/sql/docs/mysql/samples [code-of-conduct]: CONTRIBUTING.md#contributor-code-of-conduct [connect-to-k8s]: https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine [connection-overview]: https://cloud.google.com/sql/docs/mysql/connect-overview [contributing]: CONTRIBUTING.md [health-check-example]: https://github.com/GoogleCloudPlatform/cloudsql-proxy/tree/main/examples/k8s-health-check#cloud-sql-proxy-health-checks [iam-auth]: https://cloud.google.com/sql/docs/postgres/authentication [pkg-badge]: https://pkg.go.dev/badge/github.com/GoogleCloudPlatform/cloudsql-proxy.svg [pkg-docs]: https://pkg.go.dev/github.com/GoogleCloudPlatform/cloudsql-proxy [private-ip]: https://cloud.google.com/sql/docs/mysql/private-ip#requirements_for_private_ip [proxy-page]: https://cloud.google.com/sql/docs/mysql/sql-proxy [quickstarts]: https://cloud.google.com/sql/docs/mysql/quickstarts [releases]: https://github.com/GoogleCloudPlatform/cloudsql-proxy/releases [roles-and-permissions]: https://cloud.google.com/sql/docs/mysql/roles-and-permissions [service-account]: https://cloud.google.com/iam/docs/service-accounts [sidecar-example]: https://github.com/GoogleCloudPlatform/cloudsql-proxy/tree/master/examples/k8s-sidecar#run-the-cloud-sql-proxy-as-a-sidecar [source-install]: docs/install-from-source.md cloud-sql-proxy-1.33.14/cmd/000077500000000000000000000000001452473605000155165ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/000077500000000000000000000000001452473605000207445ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/cloud_sql_proxy.go000066400000000000000000000630041452473605000245240ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // cloudsql-proxy can be used as a proxy to Cloud SQL databases. It supports // connecting to many instances and authenticating via different means. // Specifically, a list of instances may be provided on the command line, in // GCE metadata (for VMs), or provided during connection time via a // FUSE-mounted directory. See flags for a more specific explanation. package main import ( _ "embed" "errors" "flag" "fmt" "io/ioutil" "net/http" "os" "os/signal" "path/filepath" "strings" "sync" "syscall" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/cmd/cloud_sql_proxy/internal/healthcheck" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/certs" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/fuse" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/limits" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/util" "cloud.google.com/go/compute/metadata" "github.com/coreos/go-systemd/v22/daemon" "golang.org/x/net/context" "golang.org/x/oauth2" goauth "golang.org/x/oauth2/google" sqladmin "google.golang.org/api/sqladmin/v1beta4" ) var ( version = flag.Bool("version", false, "Print the version of the proxy and exit") verbose = flag.Bool("verbose", true, `If false, verbose output such as information about when connections are created/closed without error are suppressed`, ) quiet = flag.Bool("quiet", false, "Disable log messages") logDebugStdout = flag.Bool("log_debug_stdout", false, "If true, log messages that are not errors will output to stdout instead of stderr") structuredLogs = flag.Bool("structured_logs", false, "Configures all log messages to be emitted as JSON.") refreshCfgThrottle = flag.Duration("refresh_config_throttle", proxy.DefaultRefreshCfgThrottle, `If set, this flag specifies the amount of forced sleep between successive API calls in order to protect client API quota. Minimum allowed value is `+minimumRefreshCfgThrottle.String(), ) checkRegion = flag.Bool("check_region", false, `If specified, the 'region' portion of the connection string is required for Unix socket-based connections.`) // Settings for how to choose which instance to connect to. dir = flag.String("dir", "", "Directory to use for placing Unix sockets representing database instances") projects = flag.String("projects", "", `Open sockets for each Cloud SQL Instance in the projects specified (comma-separated list)`, ) instances stringListValue // -instances flag is defined in runProxy() instanceSrc = flag.String("instances_metadata", "", `If provided, it is treated as a path to a metadata value which is polled for a comma-separated list of instances to connect to. For example, to use the instance metadata value named 'cloud-sql-instances' you would provide 'instance/attributes/cloud-sql-instances'. Not compatible with -fuse`) useFuse = flag.Bool("fuse", false, `Mount a directory at 'dir' using FUSE for accessing instances. Note that the directory at 'dir' must be empty before this program is started.`) fuseTmp = flag.String("fuse_tmp", defaultTmp, `Used as a temporary directory if -fuse is set. Note that files in this directory can be removed automatically by this program.`) // Settings for limits maxConnections = flag.Uint64("max_connections", 0, `If provided, the maximum number of connections to establish before refusing new connections. Defaults to 0 (no limit)`, ) fdRlimit = flag.Uint64("fd_rlimit", limits.ExpectedFDs, `Sets the rlimit on the number of open file descriptors for the proxy to the provided value. If set to zero, disables attempts to set the rlimit. Defaults to a value which can support 4K connections to one instance`, ) termTimeout = flag.Duration("term_timeout", 0, `When set, the proxy will wait for existing connections to close before terminating. Any connections that haven't closed after the timeout will be dropped`, ) // Settings for authentication. token = flag.String("token", "", "When set, the proxy uses this Bearer token for authorization.") loginToken = flag.String("login_token", "", "Used in conjunction with --token and --enable_iam_login only") tokenFile = flag.String("credential_file", "", `If provided, this json file will be used to retrieve Service Account credentials. You may set the GOOGLE_APPLICATION_CREDENTIALS environment variable for the same effect.`, ) ipAddressTypes = flag.String("ip_address_types", "PUBLIC,PRIVATE", `Default to be 'PUBLIC,PRIVATE'. Options: a list of strings separated by ',', e.g. 'PUBLIC,PRIVATE' `, ) // Settings for IAM db proxy authentication enableIAMLogin = flag.Bool("enable_iam_login", false, "Enables database user authentication using Cloud SQL's IAM DB Authentication (Postgres only).") skipInvalidInstanceConfigs = flag.Bool("skip_failed_instance_config", false, `Setting this flag will allow you to prevent the proxy from terminating when some instance configurations could not be parsed and/or are unavailable.`, ) // Setting to choose what API to connect to host = flag.String("host", "", `When set, the proxy uses this host as the base API path. Example: https://sqladmin.googleapis.com`, ) quotaProject = flag.String("quota_project", "", `Specifies the project to use for Cloud SQL Admin API quota tracking.`) // Settings for healthcheck useHTTPHealthCheck = flag.Bool("use_http_health_check", false, "When set, creates an HTTP server that checks and communicates the health of the proxy client.") healthCheckPort = flag.String("health_check_port", "8090", "When applicable, health checks take place on this port number. Defaults to 8090.") ) const ( minimumRefreshCfgThrottle = time.Second port = 3307 ) func init() { flag.Usage = func() { fmt.Fprintf(os.Stderr, ` The Cloud SQL Auth proxy allows simple, secure connectivity to Google Cloud SQL. It is a long-running process that opens local sockets (either TCP or Unix sockets) according to the parameters passed to it. A local application connects to a Cloud SQL instance by using the corresponding socket. Authorization: * On Google Compute Engine, the default service account is used. The Cloud SQL API must be enabled for the VM. * When the gcloud command-line tool is installed on the local machine, the "active account" is used for authentication. Run 'gcloud auth list' to see which accounts are installed on your local machine and 'gcloud config list account' to view the active account. * To configure the proxy using a service account, pass the -credential_file parameter or set the GOOGLE_APPLICATION_CREDENTIALS environment variable. This will override gcloud or GCE (Google Compute Engine) credentials, if they exist. * To configure the proxy using IAM authentication, pass the -enable_iam_login flag. This will cause the proxy to use IAM account credentials for database user authentication. General: -quiet Disable log messages (e.g. when new connections are established). WARNING: this option disables ALL logging output (including connection errors), which will likely make debugging difficult. The -quiet flag takes precedence over the -verbose flag. -log_debug_stdout When explicitly set to true, verbose and info log messages will be directed to stdout as opposed to the default stderr. -verbose When explicitly set to false, disable log messages that are not errors nor first-time startup messages (e.g. when new connections are established). -structured_logs When set to true, all log messages are written out as JSON. -term_timeout How long to wait for connections to close after receiving a SIGTERM before shutting down the proxy. Defaults to 0. If all connections close before the duration, the proxy will shutdown early. Connection: -instances To connect to a specific list of instances, set the instances parameter to a comma-separated list of instance connection strings. For example: -instances=my-project:my-region:my-instance For convenience, this flag may be specified multiple times. For connectivity over TCP, you must specify a tcp port as part of the instance string. For example, the following example opens a loopback TCP socket on port 3306, which will be proxied to connect to the instance 'my-instance' in project 'my-project'. To listen on other interfaces than localhost, a custom bind address (e.g., 0.0.0.0) may be provided. For example: -instances=my-project:my-region:my-instance=tcp:3306 or -instances=my-project:my-region:my-instance=tcp:0.0.0.0:3306 When connecting over TCP, the -instances parameter is required. To set a custom socket name, you can specify it as part of the instance string. The following example opens a unix socket in the directory specified by -dir, which will be proxied to connect to the instance 'my-instance' in project 'my-project': -instances=my-project:my-region:my-instance=unix:custom-socket-name Note: The directory specified by -dir must exist and the socket file path (i.e., dir plus INSTANCE_CONNECTION_NAME) must be under your platform's limit (typically 108 characters on many Unix systems, but varies by platform). To override the -dir parameter, specify an absolute path as shown in the following example: -instances=my-project:my-region:my-instance=unix:/my/custom/sql-socket Supplying INSTANCES environment variable achieves the same effect. One can use that to keep k8s manifest files constant across multiple environments -instances_metadata When running on GCE (Google Compute Engine) you can avoid the need to specify the list of instances on the command line by using the Metadata server. This parameter specifies a path to a metadata value which is then interpreted as a list of instances in the exact same way as the -instances parameter. Updates to the metadata value will be observed and acted on by the Proxy. -projects To direct the proxy to allow connections to all instances in specific projects, set the projects parameter: -projects=my-project -fuse If your local environment has FUSE installed, you can specify the -fuse flag to avoid the requirement to specify instances in advance. With FUSE, any attempts to open a Unix socket in the directory specified by -dir automatically creates that socket and connects to the corresponding instance. -dir When using Unix sockets (the default for systems which support them), the Proxy places the sockets in the directory specified by the -dir parameter. Automatic instance discovery: If the Google Cloud SQL is installed on the local machine and no instance connection flags are specified, the proxy connects to all instances in the gcloud tool's active project. Run 'gcloud config list project' to display the active project. Information for all flags: `) flag.VisitAll(func(f *flag.Flag) { usage := strings.Replace(f.Usage, "\n", "\n ", -1) fmt.Fprintf(os.Stderr, " -%s\n %s\n\n", f.Name, usage) }) } } var defaultTmp = filepath.Join(os.TempDir(), "cloudsql-proxy-tmp") const accountErrorSuffix = `Please create a new VM with Cloud SQL access (scope) enabled under "Identity and API access". Alternatively, create a new "service account key" and specify it using the -credential_file parameter` type stringListValue []string func (i *stringListValue) String() string { return strings.Join(*i, ",") } func (i *stringListValue) Set(s string) error { *i = append(*i, stringList(s)...) return nil } func checkFlags(onGCE bool) error { if !onGCE { if *instanceSrc != "" { return errors.New("-instances_metadata unsupported outside of Google Compute Engine") } return nil } if *token != "" || *tokenFile != "" || os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") != "" { return nil } // Check if gcloud credentials are available and if so, skip checking the GCE VM service account scope. _, err := util.GcloudConfig() if err == nil { return nil } scopes, err := metadata.Scopes("default") if err != nil { if _, ok := err.(metadata.NotDefinedError); ok { return errors.New("no service account found for this Compute Engine VM. " + accountErrorSuffix) } return fmt.Errorf("error checking scopes: %T %v | %+v", err, err, err) } ok := false for _, sc := range scopes { if sc == proxy.SQLScope || sc == "https://www.googleapis.com/auth/cloud-platform" { ok = true break } } if !ok { return errors.New(`the default Compute Engine service account is not configured with sufficient permissions to access the Cloud SQL API from this VM. ` + accountErrorSuffix) } return nil } // iamLoginScope is the OAuth2 scope attached to tokens which are used for // database login only. This scope is only applicable when auto IAM authn is // being used. const iamLoginScope = "https://www.googleapis.com/auth/sqlservice.login" func authenticatedClientFromPath(ctx context.Context, f string) (*http.Client, oauth2.TokenSource, error) { all, err := ioutil.ReadFile(f) if err != nil { return nil, nil, fmt.Errorf("invalid json file %q: %v", f, err) } // First try and load this as a service account config, which allows us to see the service account email: if cfg, err := goauth.JWTConfigFromJSON(all, proxy.SQLScope); err == nil { logging.Infof("using credential file for authentication; email=%s", cfg.Email) // Created a downscoped token source using the same credentials. scoped, err := goauth.JWTConfigFromJSON(all, iamLoginScope) if err != nil { return nil, nil, err } return cfg.Client(ctx), scoped.TokenSource(ctx), nil } cred, err := goauth.CredentialsFromJSON(ctx, all, proxy.SQLScope) if err != nil { return nil, nil, fmt.Errorf("invalid json file %q: %v", f, err) } // Created a downscoped token source using the same credentials. scoped, err := goauth.CredentialsFromJSON(ctx, all, iamLoginScope) if err != nil { return nil, nil, fmt.Errorf("invalid json file %q: %v", f, err) } logging.Infof("using credential file for authentication; path=%q", f) return oauth2.NewClient(ctx, cred.TokenSource), scoped.TokenSource, nil } var errLoginToken = errors.New("login_token must be used with token and enable_iam_login") func authenticatedClient(ctx context.Context) (*http.Client, oauth2.TokenSource, error) { if *tokenFile != "" { return authenticatedClientFromPath(ctx, *tokenFile) } // If login token has been set, but there is no token or // enable_iam_login has not been set, error. if *loginToken != "" && (*token == "" || !(*enableIAMLogin)) { return nil, nil, errLoginToken } if tok := *token; tok != "" { src := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: tok}) cl := oauth2.NewClient(ctx, src) if *enableIAMLogin { if *loginToken == "" { return nil, nil, errLoginToken } lts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: *loginToken}) return cl, lts, nil } return cl, src, nil } if f := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"); f != "" { return authenticatedClientFromPath(ctx, f) } // If flags or env don't specify an auth source, try either gcloud or application default // credentials. src, err := util.GcloudTokenSource(ctx) scoped := src if err != nil { src, err = goauth.DefaultTokenSource(ctx, proxy.SQLScope) if err != nil { return nil, nil, err } // Created a downscoped token source using the same credentials. scoped, err = goauth.DefaultTokenSource(ctx, iamLoginScope) if err != nil { return nil, nil, err } } return oauth2.NewClient(ctx, src), scoped, nil } // quotaProjectTransport is an http.RoundTripper that adds an X-Goog-User-Project // header to all requests for quota and billing purposes. // // For details, see: // https://cloud.google.com/apis/docs/system-parameters#definitions type quotaProjectTransport struct { base http.RoundTripper project string } var _ http.RoundTripper = quotaProjectTransport{} // RoundTrip adds a X-Goog-User-Project header to each request. func (t quotaProjectTransport) RoundTrip(req *http.Request) (*http.Response, error) { if req.Header == nil { req.Header = make(http.Header) } req.Header.Add("X-Goog-User-Project", t.project) return t.base.RoundTrip(req) } // configureQuotaProject configures an HTTP client to use the provided project // for quota calculations for all requests. func configureQuotaProject(c *http.Client, project string) { // Copy the given client's tripper. Note that tripper can be nil, which is equivalent to // http.DefaultTransport. (See https://golang.org/pkg/net/http/#Client) base := c.Transport if base == nil { base = http.DefaultTransport } c.Transport = quotaProjectTransport{ base: base, project: project, } } func stringList(s string) []string { spl := strings.Split(s, ",") if len(spl) == 1 && spl[0] == "" { return nil } return spl } func listInstances(ctx context.Context, cl *http.Client, projects []string) ([]string, error) { if len(projects) == 0 { // No projects requested. return nil, nil } sql, err := sqladmin.New(cl) if err != nil { return nil, err } if *host != "" { sql.BasePath = *host } ch := make(chan string) var wg sync.WaitGroup wg.Add(len(projects)) for _, proj := range projects { proj := proj go func() { err := sql.Instances.List(proj).Pages(ctx, func(r *sqladmin.InstancesListResponse) error { for _, in := range r.Items { // The Proxy is only support on Second Gen if in.BackendType == "SECOND_GEN" { ch <- in.ConnectionName } } return nil }) if err != nil { logging.Errorf("Error listing instances in %v: %v", proj, err) } wg.Done() }() } go func() { wg.Wait() close(ch) }() var ret []string for x := range ch { ret = append(ret, x) } if len(ret) == 0 { return nil, fmt.Errorf("no Cloud SQL Instances found in these projects: %v", projects) } return ret, nil } func gcloudProject() ([]string, error) { cfg, err := util.GcloudConfig() if err != nil { return nil, err } if cfg.Configuration.Properties.Core.Project == "" { return nil, fmt.Errorf("gcloud has no active project, you can set it by running `gcloud config set project `") } return []string{cfg.Configuration.Properties.Core.Project}, nil } func runProxy() int { flag.Var(&instances, "instances", `Comma-separated list of fully qualified instances (project:region:name) to connect to. If the name has the suffix '=tcp:port', a TCP server is opened on the specified port on localhost to proxy to that instance. It is also possible to listen on a custom address by providing a host, e.g., '=tcp:0.0.0.0:port'. If no value is provided for 'tcp', one socket file per instance is opened in 'dir'. For convenience, this flag may be specified multiple times. You may use the INSTANCES environment variable for the same effect. Using both will use the value from the flag, Not compatible with -fuse.`, ) flag.Parse() if *version { fmt.Println("Cloud SQL Auth proxy:", util.SemanticVersion()) return 0 } if *logDebugStdout { logging.LogDebugToStdout() } if !*verbose { logging.LogVerboseToNowhere() } if *structuredLogs { cleanup, err := logging.EnableStructuredLogs(*logDebugStdout, *verbose) if err != nil { logging.Errorf("failed to enable structured logs: %v", err) return 1 } defer cleanup() } if *quiet { logging.Infof("Cloud SQL Auth proxy logging has been disabled by the -quiet flag. All messages (including errors) will be suppressed.") logging.DisableLogging() } // Split the input ipAddressTypes to the slice of string ipAddrTypeOptsInput := strings.Split(*ipAddressTypes, ",") if *fdRlimit != 0 { if err := limits.SetupFDLimits(*fdRlimit); err != nil { logging.Infof("failed to setup file descriptor limits: %v", err) } } if *host != "" && !strings.HasSuffix(*host, "/") { logging.Errorf("Flag host should always end with /") flag.PrintDefaults() return 0 } // TODO: needs a better place for consolidation // if instances is blank and env var INSTANCES is supplied use it if envInstances := os.Getenv("INSTANCES"); len(instances) == 0 && envInstances != "" { instances.Set(envInstances) } projList := stringList(*projects) // TODO: it'd be really great to consolidate flag verification in one place. if len(instances) == 0 && *instanceSrc == "" && len(projList) == 0 && !*useFuse { var err error projList, err = gcloudProject() if err == nil { logging.Infof("Using gcloud's active project: %v", projList) } else if gErr, ok := err.(*util.GcloudError); ok && gErr.Status == util.GcloudNotFound { logging.Errorf("gcloud is not in the path and -instances and -projects are empty") return 1 } else { logging.Errorf("unable to retrieve the active gcloud project and -instances and -projects are empty: %v", err) return 1 } } onGCE := metadata.OnGCE() if err := checkFlags(onGCE); err != nil { logging.Errorf(err.Error()) return 1 } ctx, cancel := context.WithCancel(context.Background()) client, tokSrc, err := authenticatedClient(ctx) if err != nil { logging.Errorf(err.Error()) return 1 } if *quotaProject != "" { logging.Infof("Using the project %q for SQL Admin API quota", *quotaProject) configureQuotaProject(client, *quotaProject) } ins, err := listInstances(ctx, client, projList) if err != nil { logging.Errorf(err.Error()) return 1 } instances = append(instances, ins...) cfgs, err := CreateInstanceConfigs(*dir, *useFuse, instances, *instanceSrc, client, *skipInvalidInstanceConfigs) if err != nil { logging.Errorf(err.Error()) return 1 } // We only need to store connections in a ConnSet if FUSE is used; otherwise // it is not efficient to do so. var connset *proxy.ConnSet if *useFuse { connset = proxy.NewConnSet() } // Create proxy client first; fuse uses its cache to resolve database version. refreshCfgThrottle := *refreshCfgThrottle if refreshCfgThrottle < minimumRefreshCfgThrottle { refreshCfgThrottle = minimumRefreshCfgThrottle } refreshCfgBuffer := proxy.DefaultRefreshCfgBuffer if *enableIAMLogin { refreshCfgThrottle = proxy.IAMLoginRefreshThrottle refreshCfgBuffer = proxy.IAMLoginRefreshCfgBuffer } proxyClient := &proxy.Client{ Port: port, MaxConnections: *maxConnections, Certs: certs.NewCertSourceOpts(client, certs.RemoteOpts{ APIBasePath: *host, IgnoreRegion: !*checkRegion, UserAgent: util.UserAgentFromVersionString(), IPAddrTypeOpts: ipAddrTypeOptsInput, EnableIAMLogin: *enableIAMLogin, TokenSource: tokSrc, }), Conns: connset, RefreshCfgThrottle: refreshCfgThrottle, RefreshCfgBuffer: refreshCfgBuffer, } var hc *healthcheck.Server if *useHTTPHealthCheck { // Extract a list of all instances specified statically. List is empty when in fuse mode. var insts []string for _, cfg := range cfgs { insts = append(insts, cfg.Instance) } hc, err = healthcheck.NewServer(proxyClient, *healthCheckPort, insts) if err != nil { logging.Errorf("[Health Check] Could not initialize health check server: %v", err) return 1 } defer hc.Close(ctx) } // Initialize a source of new connections to Cloud SQL instances. var connSrc <-chan proxy.Conn if *useFuse { c, fuse, err := fuse.NewConnSrc(*dir, *fuseTmp, proxyClient, connset) if err != nil { logging.Errorf("Could not start fuse directory at %q: %v", *dir, err) return 1 } connSrc = c defer fuse.Close() } else { updates := make(chan string) if *instanceSrc != "" { go func() { for { err := metadata.Subscribe(*instanceSrc, func(v string, ok bool) error { if ok { updates <- v } return nil }) if err != nil { logging.Errorf("Error on receiving new instances from metadata: %v", err) } time.Sleep(5 * time.Second) } }() } c, err := WatchInstances(*dir, cfgs, updates, client) if err != nil { logging.Errorf(err.Error()) return 1 } connSrc = c } logging.Infof("Ready for new connections") if hc != nil { hc.NotifyStarted() } signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) shutdown := make(chan int, 1) go func() { defer func() { cancel(); close(shutdown) }() <-signals logging.Infof("Received TERM signal. Waiting up to %s before terminating.", *termTimeout) go func() { if _, err := daemon.SdNotify(false, daemon.SdNotifyStopping); err != nil { logging.Errorf("Failed to notify systemd of termination: %v", err) } }() err := proxyClient.Shutdown(*termTimeout) if err != nil { logging.Errorf("Error during SIGTERM shutdown: %v", err) shutdown <- 2 return } }() // If running under systemd with Type=notify, we'll send a message to the // service manager that we are ready to handle connections now, and any other // units that are waiting for us can start. go func() { if _, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil { logging.Errorf("Failed to notify systemd of readiness: %v", err) } }() proxyClient.RunContext(ctx, connSrc) if code, ok := <-shutdown; ok { return code } return 0 } func main() { code := runProxy() os.Exit(code) } cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/cloud_sql_proxy_test.go000066400000000000000000000036371452473605000255710ustar00rootroot00000000000000// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "testing" "golang.org/x/net/context" ) func TestAuthenticatedClient(t *testing.T) { tcs := []struct { desc string setup func() func() wantErr bool }{ { desc: "when just token is set", setup: func() func() { *token = "MYTOKEN" return func() { *token = "" } }, wantErr: false, }, { desc: "when just login_token is set", setup: func() func() { *loginToken = "MYTOKEN" return func() { *loginToken = "" } }, wantErr: true, }, { desc: "when token and enable_iam_login are set", setup: func() func() { *token = "MYTOKEN" *enableIAMLogin = true return func() { *token = "" *enableIAMLogin = false } }, wantErr: true, }, { desc: "when token, login_token, and enable_iam_login are set", setup: func() func() { *token = "MYTOKEN" *loginToken = "MYLOGINTOKEN" *enableIAMLogin = true return func() { *token = "" *loginToken = "" *enableIAMLogin = false } }, wantErr: false, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { cleanup := tc.setup() defer cleanup() _, _, err := authenticatedClient(context.Background()) gotErr := err != nil if tc.wantErr != gotErr { t.Fatalf("err: want = %v, got = %v", tc.wantErr, gotErr) } }) } } cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/internal/000077500000000000000000000000001452473605000225605ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/internal/healthcheck/000077500000000000000000000000001452473605000250235ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/internal/healthcheck/healthcheck.go000066400000000000000000000124641452473605000276240ustar00rootroot00000000000000// Copyright 2021 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package healthcheck tests and communicates the health of the Cloud SQL Auth proxy. package healthcheck import ( "context" "errors" "net" "net/http" "sync" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" ) const ( startupPath = "/startup" livenessPath = "/liveness" readinessPath = "/readiness" ) // Server is a type used to implement health checks for the proxy. type Server struct { // started is used to indicate whether the proxy has finished starting up. // If started is open, startup has not finished. If started is closed, // startup is complete. started chan struct{} // once ensures that started can only be closed once. once *sync.Once // port designates the port number on which Server listens and serves. port string // srv is a pointer to the HTTP server used to communicate proxy health. srv *http.Server // instances is a list of all instances specified statically (e.g. as flags to the binary) instances []string } // NewServer initializes a Server and exposes HTTP endpoints used to // communicate proxy health. func NewServer(c *proxy.Client, port string, staticInst []string) (*Server, error) { mux := http.NewServeMux() srv := &http.Server{ Addr: ":" + port, Handler: mux, } hcServer := &Server{ started: make(chan struct{}), once: &sync.Once{}, port: port, srv: srv, instances: staticInst, } mux.HandleFunc(startupPath, func(w http.ResponseWriter, _ *http.Request) { if !hcServer.proxyStarted() { w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte("error")) return } w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) }) mux.HandleFunc(readinessPath, func(w http.ResponseWriter, _ *http.Request) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() if !isReady(ctx, c, hcServer) { w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte("error")) return } w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) }) mux.HandleFunc(livenessPath, func(w http.ResponseWriter, _ *http.Request) { if !isLive(c) { w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte("error")) return } w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) }) ln, err := net.Listen("tcp", srv.Addr) if err != nil { return nil, err } go func() { if err := srv.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) { logging.Errorf("[Health Check] Failed to serve: %v", err) } }() return hcServer, nil } // Close gracefully shuts down the HTTP server belonging to the Server. func (s *Server) Close(ctx context.Context) error { return s.srv.Shutdown(ctx) } // NotifyStarted tells the Server that the proxy has finished startup. func (s *Server) NotifyStarted() { s.once.Do(func() { close(s.started) }) } // proxyStarted returns true if started is closed, false otherwise. func (s *Server) proxyStarted() bool { select { case <-s.started: return true default: return false } } // isLive returns true as long as the proxy Client has all valid connections. func isLive(c *proxy.Client) bool { invalid := c.InvalidInstances() alive := len(invalid) == 0 if !alive { for _, err := range invalid { logging.Errorf("[Health Check] Liveness failed: %v", err) } } return alive } // isReady will check the following criteria: // 1. Finished starting up / been sent the 'Ready for Connections' log. // 2. Not yet hit the MaxConnections limit, if set. // 3. Able to dial all specified instances without error. func isReady(ctx context.Context, c *proxy.Client, s *Server) bool { // Not ready until we reach the 'Ready for Connections' log. if !s.proxyStarted() { logging.Errorf("[Health Check] Readiness failed because proxy has not finished starting up.") return false } // Not ready if the proxy is at the optional MaxConnections limit. if !c.AvailableConn() { logging.Errorf("[Health Check] Readiness failed because proxy has reached the maximum connections limit (%v).", c.MaxConnections) return false } // Not ready if one or more instances cannot be dialed. instances := s.instances if s.instances == nil { // Proxy is in fuse mode. instances = c.GetInstances() } canDial := true var once sync.Once var wg sync.WaitGroup for _, inst := range instances { wg.Add(1) go func(inst string) { defer wg.Done() conn, err := c.DialContext(ctx, inst) if err != nil { logging.Errorf("[Health Check] Readiness failed because proxy couldn't connect to %q: %v", inst, err) once.Do(func() { canDial = false }) return } err = conn.Close() if err != nil { logging.Errorf("[Health Check] Readiness: error while closing connection: %v", err) } }(inst) } wg.Wait() return canDial } cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/internal/healthcheck/healthcheck_test.go000066400000000000000000000170461452473605000306640ustar00rootroot00000000000000// Copyright 2021 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package healthcheck_test import ( "context" "crypto/tls" "crypto/x509" "errors" "net" "net/http" "testing" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/cmd/cloud_sql_proxy/internal/healthcheck" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" ) const ( startupPath = "/startup" livenessPath = "/liveness" readinessPath = "/readiness" testPort = "8090" ) type fakeCertSource struct{} func (cs *fakeCertSource) Local(instance string) (tls.Certificate, error) { return tls.Certificate{ Leaf: &x509.Certificate{ NotAfter: time.Date(9999, 0, 0, 0, 0, 0, 0, time.UTC), }, }, nil } func (cs *fakeCertSource) Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) { return &x509.Certificate{}, "fake address", "fake name", "fake version", nil } type failingCertSource struct{} func (cs *failingCertSource) Local(instance string) (tls.Certificate, error) { return tls.Certificate{}, errors.New("failed") } func (cs *failingCertSource) Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) { return nil, "", "", "", errors.New("failed") } // Test to verify that when the proxy client is up, the liveness endpoint writes http.StatusOK. func TestLivenessPasses(t *testing.T) { s, err := healthcheck.NewServer(&proxy.Client{}, testPort, nil) if err != nil { t.Fatalf("Could not initialize health check: %v", err) } defer s.Close(context.Background()) resp, err := http.Get("http://localhost:" + testPort + livenessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusOK { t.Errorf("want %v, got %v", http.StatusOK, resp.StatusCode) } } func TestLivenessFails(t *testing.T) { c := &proxy.Client{ Certs: &failingCertSource{}, Dialer: func(string, string) (net.Conn, error) { return nil, errors.New("error") }, } // ensure cache has errored config _, err := c.Dial("proj:region:instance") if err == nil { t.Fatalf("expected Dial to fail, but it succeeded") } s, err := healthcheck.NewServer(c, testPort, []string{"proj:region:instance"}) if err != nil { t.Fatalf("Could not initialize health check: %v", err) } defer s.Close(context.Background()) resp, err := http.Get("http://localhost:" + testPort + livenessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } defer resp.Body.Close() want := http.StatusServiceUnavailable if got := resp.StatusCode; got != want { t.Errorf("want %v, got %v", want, got) } } // Test to verify that when startup HAS finished (and MaxConnections limit not specified), // the startup and readiness endpoints write http.StatusOK. func TestStartupPass(t *testing.T) { s, err := healthcheck.NewServer(&proxy.Client{}, testPort, nil) if err != nil { t.Fatalf("Could not initialize health check: %v", err) } defer s.Close(context.Background()) // Simulate the proxy client completing startup. s.NotifyStarted() resp, err := http.Get("http://localhost:" + testPort + startupPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusOK { t.Errorf("%v: want %v, got %v", startupPath, http.StatusOK, resp.StatusCode) } resp, err = http.Get("http://localhost:" + testPort + readinessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusOK { t.Errorf("%v: want %v, got %v", readinessPath, http.StatusOK, resp.StatusCode) } } // Test to verify that when startup has NOT finished, the startup and readiness endpoints write // http.StatusServiceUnavailable. func TestStartupFail(t *testing.T) { s, err := healthcheck.NewServer(&proxy.Client{}, testPort, nil) if err != nil { t.Fatalf("Could not initialize health check: %v", err) } defer s.Close(context.Background()) resp, err := http.Get("http://localhost:" + testPort + startupPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusServiceUnavailable { t.Errorf("%v: want %v, got %v", startupPath, http.StatusOK, resp.StatusCode) } resp, err = http.Get("http://localhost:" + testPort + readinessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusServiceUnavailable { t.Errorf("%v: want %v, got %v", readinessPath, http.StatusOK, resp.StatusCode) } } // Test to verify that when startup has finished, but MaxConnections has been reached, // the readiness endpoint writes http.StatusServiceUnavailable. func TestMaxConnectionsReached(t *testing.T) { c := &proxy.Client{ MaxConnections: 1, } s, err := healthcheck.NewServer(c, testPort, nil) if err != nil { t.Fatalf("Could not initialize health check: %v", err) } defer s.Close(context.Background()) s.NotifyStarted() c.ConnectionsCounter = c.MaxConnections // Simulate reaching the limit for maximum number of connections resp, err := http.Get("http://localhost:" + testPort + readinessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusServiceUnavailable { t.Errorf("want %v, got %v", http.StatusServiceUnavailable, resp.StatusCode) } } // Test to verify that when dialing instance(s) returns an error, the readiness endpoint // writes http.StatusServiceUnavailable. func TestDialFail(t *testing.T) { tests := map[string]struct { insts []string }{ "Single instance": {insts: []string{"project:region:instance"}}, "Multiple instances": {insts: []string{"project:region:instance-1", "project:region:instance-2", "project:region:instance-3"}}, } c := &proxy.Client{ Certs: &fakeCertSource{}, Dialer: func(string, string) (net.Conn, error) { return nil, errors.New("error") }, } for name, test := range tests { func() { s, err := healthcheck.NewServer(c, testPort, test.insts) if err != nil { t.Fatalf("%v: Could not initialize health check: %v", name, err) } defer s.Close(context.Background()) s.NotifyStarted() resp, err := http.Get("http://localhost:" + testPort + readinessPath) if err != nil { t.Fatalf("%v: HTTP GET failed: %v", name, err) } if resp.StatusCode != http.StatusServiceUnavailable { t.Errorf("want %v, got %v", http.StatusServiceUnavailable, resp.StatusCode) } }() } } // Test to verify that after closing a healthcheck, its liveness endpoint serves // an error. func TestCloseHealthCheck(t *testing.T) { s, err := healthcheck.NewServer(&proxy.Client{}, testPort, nil) if err != nil { t.Fatalf("Could not initialize health check: %v", err) } defer s.Close(context.Background()) resp, err := http.Get("http://localhost:" + testPort + livenessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusOK { t.Errorf("want %v, got %v", http.StatusOK, resp.StatusCode) } err = s.Close(context.Background()) if err != nil { t.Fatalf("Failed to close health check: %v", err) } _, err = http.Get("http://localhost:" + testPort + livenessPath) if err == nil { t.Fatalf("HTTP GET did not return error after closing health check server.") } } cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/proxy.go000066400000000000000000000277121452473605000224650ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main // This file contains code for supporting local sockets for the Cloud SQL Auth proxy. import ( "bytes" "errors" "fmt" "net" "net/http" "os" "path/filepath" "runtime" "strings" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/fuse" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" sqladmin "google.golang.org/api/sqladmin/v1beta4" ) // WatchInstances handles the lifecycle of local sockets used for proxying // local connections. Values received from the updates channel are // interpretted as a comma-separated list of instances. The set of sockets in // 'dir' is the union of 'instances' and the most recent list from 'updates'. func WatchInstances(dir string, cfgs []instanceConfig, updates <-chan string, cl *http.Client) (<-chan proxy.Conn, error) { ch := make(chan proxy.Conn, 1) // Instances specified statically (e.g. as flags to the binary) will always // be available. They are ignored if also returned by the GCE metadata since // the socket will already be open. staticInstances := make(map[string]net.Listener, len(cfgs)) for _, v := range cfgs { l, err := listenInstance(ch, v) if err != nil { return nil, err } staticInstances[v.Instance] = l } if updates != nil { go watchInstancesLoop(dir, ch, updates, staticInstances, cl) } return ch, nil } func watchInstancesLoop(dir string, dst chan<- proxy.Conn, updates <-chan string, static map[string]net.Listener, cl *http.Client) { dynamicInstances := make(map[string]net.Listener) for instances := range updates { // All instances were legal when we started, so we pass false below to ensure we don't skip them // later if they became unhealthy for some reason; this would be a serious enough problem. list, err := parseInstanceConfigs(dir, strings.Split(instances, ","), cl, false) if err != nil { logging.Errorf("%v", err) // If we do not have a valid list of instances, skip this update continue } stillOpen := make(map[string]net.Listener) for _, cfg := range list { instance := cfg.Instance // If the instance is specified in the static list don't do anything: // it's already open and should stay open forever. if _, ok := static[instance]; ok { continue } if l, ok := dynamicInstances[instance]; ok { delete(dynamicInstances, instance) stillOpen[instance] = l continue } l, err := listenInstance(dst, cfg) if err != nil { logging.Errorf("Couldn't open socket for %q: %v", instance, err) continue } stillOpen[instance] = l } // Any instance in dynamicInstances was not in the most recent metadata // update. Clean up those instances' sockets by closing them; note that // this does not affect any existing connections instance. for instance, listener := range dynamicInstances { logging.Infof("Closing socket for instance %v", instance) listener.Close() } dynamicInstances = stillOpen } for _, v := range static { if err := v.Close(); err != nil { logging.Errorf("Error closing %q: %v", v.Addr(), err) } } for _, v := range dynamicInstances { if err := v.Close(); err != nil { logging.Errorf("Error closing %q: %v", v.Addr(), err) } } } func remove(path string) { if err := os.Remove(path); err != nil && !os.IsNotExist(err) { logging.Infof("Remove(%q) error: %v", path, err) } } // listenInstance starts listening on a new unix socket in dir to connect to the // specified instance. New connections to this socket are sent to dst. func listenInstance(dst chan<- proxy.Conn, cfg instanceConfig) (net.Listener, error) { unix := cfg.Network == "unix" if unix { remove(cfg.Address) } l, err := net.Listen(cfg.Network, cfg.Address) if err != nil { return nil, err } if unix { if err := os.Chmod(cfg.Address, 0777|os.ModeSocket); err != nil { logging.Errorf("couldn't update permissions for socket file %q: %v; other users may not be unable to connect", cfg.Address, err) } } go func() { for { start := time.Now() c, err := l.Accept() if err != nil { logging.Errorf("Error in accept for %q on %v: %v", cfg, cfg.Address, err) if nerr, ok := err.(net.Error); ok && nerr.Temporary() { d := 10*time.Millisecond - time.Since(start) if d > 0 { time.Sleep(d) } continue } l.Close() return } logging.Verbosef("New connection for %q", cfg.Instance) switch clientConn := c.(type) { case *net.TCPConn: clientConn.SetKeepAlive(true) clientConn.SetKeepAlivePeriod(1 * time.Minute) } dst <- proxy.Conn{cfg.Instance, c} } }() logging.Infof("Listening on %s for %s", cfg.Address, cfg.Instance) return l, nil } type instanceConfig struct { Instance string Network, Address string } // loopbackForNet maps a network (e.g. tcp6) to the loopback address for that // network. It is updated during the initialization of validNets to include a // valid loopback address for "tcp". var loopbackForNet = map[string]string{ "tcp4": "127.0.0.1", "tcp6": "::1", } // validNets tracks the networks that are valid for this platform and machine. var validNets = func() map[string]bool { m := map[string]bool{ "unix": runtime.GOOS != "windows", } anyTCP := false for _, n := range []string{"tcp4", "tcp6"} { host, ok := loopbackForNet[n] if !ok { // This is effectively a compile-time error. panic(fmt.Sprintf("no loopback address found for %v", n)) } // Open any port to see if the net is valid. x, err := net.Listen(n, net.JoinHostPort(host, "0")) if err != nil { // Error is too verbose to be useful. continue } x.Close() m[n] = true if !anyTCP { anyTCP = true // Set the loopback value for generic tcp if it hasn't already been // set. (If both tcp4/tcp6 are supported the first one in the list // (tcp4's 127.0.0.1) is used. loopbackForNet["tcp"] = host } } if anyTCP { m["tcp"] = true } return m }() func parseInstanceConfig(dir, instance string, cl *http.Client) (instanceConfig, error) { var ret instanceConfig proj, region, name, args, err := proxy.ParseInstanceConnectionName(instance) if err != nil { return instanceConfig{}, err } ret.Instance = args[0] regionName := fmt.Sprintf("%s~%s", region, name) if len(args) == 1 { // Default to listening via unix socket in specified directory ret.Network = "unix" ret.Address = filepath.Join(dir, instance) } else { // Parse the instance options if present. opts := strings.SplitN(args[1], ":", 2) if len(opts) != 2 { return instanceConfig{}, fmt.Errorf("invalid instance options: must be in the form `unix:/path/to/socket`, `tcp:port`, `tcp:host:port`; invalid option was %q", strings.Join(opts, ":")) } ret.Network = opts[0] var err error if ret.Network == "unix" { if strings.HasPrefix(opts[1], "/") { ret.Address = opts[1] // Root path. } else { ret.Address = filepath.Join(dir, opts[1]) } } else { ret.Address, err = parseTCPOpts(opts[0], opts[1]) } if err != nil { return instanceConfig{}, err } } // Use the SQL Admin API to verify compatibility with the instance. sql, err := sqladmin.New(cl) if err != nil { return instanceConfig{}, err } if *host != "" { sql.BasePath = *host } inst, err := sql.Connect.Get(proj, regionName).Do() if err != nil { return instanceConfig{}, err } if inst.BackendType == "FIRST_GEN" { logging.Errorf("WARNING: proxy client does not support first generation Cloud SQL instances.") return instanceConfig{}, fmt.Errorf("%q is a first generation instance", instance) } // Postgres instances use a special suffix on the unix socket. // See https://www.postgresql.org/docs/11/runtime-config-connection.html if ret.Network == "unix" && strings.HasPrefix(strings.ToLower(inst.DatabaseVersion), "postgres") { // Verify the directory exists. if err := os.MkdirAll(ret.Address, 0755); err != nil { return instanceConfig{}, err } ret.Address = filepath.Join(ret.Address, ".s.PGSQL.5432") } if !validNets[ret.Network] { return ret, fmt.Errorf("invalid %q: unsupported network: %v", instance, ret.Network) } return ret, nil } // parseTCPOpts parses the instance options when specifying tcp port options. func parseTCPOpts(ntwk, addrOpt string) (string, error) { if strings.Contains(addrOpt, ":") { return addrOpt, nil // User provided a host and port; use that. } // No "host" part of the address. Be safe and assume that they want a loopback address. addr, ok := loopbackForNet[ntwk] if !ok { return "", fmt.Errorf("invalid %q:%q: unrecognized network %v", ntwk, addrOpt, ntwk) } return net.JoinHostPort(addr, addrOpt), nil } // parseInstanceConfigs calls parseInstanceConfig for each instance in the // provided slice, collecting errors along the way. There may be valid // instanceConfigs returned even if there's an error. func parseInstanceConfigs(dir string, instances []string, cl *http.Client, skipFailedInstanceConfigs bool) ([]instanceConfig, error) { errs := new(bytes.Buffer) var cfg []instanceConfig for _, v := range instances { if v == "" { continue } if c, err := parseInstanceConfig(dir, v, cl); err != nil { if skipFailedInstanceConfigs { logging.Infof("There was a problem when parsing an instance configuration but ignoring due to the configuration. Error: %v", err) } else { fmt.Fprintf(errs, "\n\t%v", err) } } else { cfg = append(cfg, c) } } var err error if errs.Len() > 0 { err = fmt.Errorf("errors parsing config:%s", errs) } return cfg, err } // CreateInstanceConfigs verifies that the parameters passed to it are valid // for the proxy for the platform and system and then returns a slice of valid // instanceConfig. It is possible for the instanceConfig to be empty if no valid // configurations were specified, however `err` will be set. func CreateInstanceConfigs(dir string, useFuse bool, instances []string, instancesSrc string, cl *http.Client, skipFailedInstanceConfigs bool) ([]instanceConfig, error) { if useFuse && !fuse.Supported() { return nil, errors.New("FUSE not supported on this system") } cfgs, err := parseInstanceConfigs(dir, instances, cl, skipFailedInstanceConfigs) if err != nil { return nil, err } if dir == "" { // Reasons to set '-dir': // - Using -fuse // - Using the metadata to get a list of instances // - Having an instance that uses a 'unix' network if useFuse { return nil, errors.New("must set -dir because -fuse was set") } else if instancesSrc != "" { return nil, errors.New("must set -dir because -instances_metadata was set") } else { for _, v := range cfgs { if v.Network == "unix" { return nil, fmt.Errorf("must set -dir: using a unix socket for %v", v.Instance) } } } // Otherwise it's safe to not set -dir } if useFuse { if len(instances) != 0 || instancesSrc != "" { return nil, errors.New("-fuse is not compatible with -projects, -instances, or -instances_metadata") } return nil, nil } // FUSE disabled. if len(instances) == 0 && instancesSrc == "" { // Failure to specifying instance can be caused by following reasons. // 1. not enough information is provided by flags // 2. failed to invoke gcloud var flags string if fuse.Supported() { flags = "-projects, -fuse, -instances or -instances_metadata" } else { flags = "-projects, -instances or -instances_metadata" } errStr := fmt.Sprintf("no instance selected because none of %s is specified", flags) return nil, errors.New(errStr) } return cfgs, nil } cloud-sql-proxy-1.33.14/cmd/cloud_sql_proxy/proxy_test.go000066400000000000000000000225471452473605000235250ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "bytes" "fmt" "io/ioutil" "net" "net/http" "os" "runtime" "testing" ) type mockTripper struct { } func (m *mockTripper) RoundTrip(r *http.Request) (*http.Response, error) { return &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader([]byte("{}")))}, nil } var mockClient = &http.Client{Transport: &mockTripper{}} func TestCreateInstanceConfigs(t *testing.T) { for _, v := range []struct { desc string //inputs dir string useFuse bool instances []string instancesSrc string // We don't need to check the []instancesConfig return value, we already // have a TestParseInstanceConfig. wantErr bool skipFailedInstanceConfig bool }{ { desc: "setting -fuse and -dir", dir: "dir", useFuse: true, instances: nil, instancesSrc: "", wantErr: false, skipFailedInstanceConfig: false, }, { desc: "setting -fuse", dir: "", useFuse: true, instances: nil, instancesSrc: "", wantErr: true, skipFailedInstanceConfig: false, }, { desc: "setting -fuse, -dir, and -instances", dir: "dir", useFuse: true, instances: []string{"proj:reg:x"}, instancesSrc: "", wantErr: true, skipFailedInstanceConfig: false, }, { desc: "setting -fuse, -dir, and -instances_metadata", dir: "dir", useFuse: true, instances: nil, instancesSrc: "md", wantErr: true, skipFailedInstanceConfig: false, }, { desc: "setting -dir and -instances (unix socket)", dir: "dir", useFuse: false, instances: []string{"proj:reg:x"}, instancesSrc: "", wantErr: false, skipFailedInstanceConfig: false, }, { // tests for the case where invalid configs can still exist, when skipped desc: "setting -dir and -instances (unix socket) w/ something invalid", dir: "dir", useFuse: false, instances: []string{"proj:reg:x", "INVALID_PROJECT_STRING"}, instancesSrc: "", wantErr: false, skipFailedInstanceConfig: true, }, { desc: "Seting -instance (unix socket)", dir: "", useFuse: false, instances: []string{"proj:reg:x"}, instancesSrc: "", wantErr: true, skipFailedInstanceConfig: false, }, { desc: "setting -instance (tcp socket)", dir: "", useFuse: false, instances: []string{"proj:reg:x=tcp:1234"}, instancesSrc: "", wantErr: false, skipFailedInstanceConfig: false, }, { desc: "setting -instance (tcp socket) and -instances_metadata", dir: "", useFuse: false, instances: []string{"proj:reg:x=tcp:1234"}, instancesSrc: "md", wantErr: true, skipFailedInstanceConfig: false, }, { desc: "setting -dir, -instance (tcp socket), and -instances_metadata", dir: "dir", useFuse: false, instances: []string{"proj:reg:x=tcp:1234"}, instancesSrc: "md", wantErr: false, skipFailedInstanceConfig: false, }, { desc: "setting -dir, -instance (unix socket), and -instances_metadata", dir: "dir", useFuse: false, instances: []string{"proj:reg:x"}, instancesSrc: "md", wantErr: false, skipFailedInstanceConfig: false, }, { desc: "setting -dir and -instances_metadata", dir: "dir", useFuse: false, instances: nil, instancesSrc: "md", wantErr: false, skipFailedInstanceConfig: false, }, { desc: "setting -instances_metadata", dir: "", useFuse: false, instances: nil, instancesSrc: "md", wantErr: true, skipFailedInstanceConfig: false, }, } { t.Run(v.desc, func(t *testing.T) { // fuse is not supported in CI for darwin if runtime.GOOS == "darwin" && v.useFuse { t.Skip("skipping Darwin and FUSE test") } // fuse and unix sockets are not supported on windows if runtime.GOOS == "windows" && (v.useFuse || v.dir != "") { t.Skip("skipping Windows and FUSE/Unix socket test") } if v.useFuse && testing.Short() { t.Skip("skipping fuse tests in short mode.") } _, err := CreateInstanceConfigs(v.dir, v.useFuse, v.instances, v.instancesSrc, mockClient, v.skipFailedInstanceConfig) if v.wantErr { if err == nil { t.Errorf("CreateInstanceConfigs passed when %s, wanted error", v.desc) } return } if err != nil { t.Errorf("CreateInstanceConfigs gave error when %s: %v", v.desc, err) } }) } } func TestParseInstanceConfig(t *testing.T) { // sentinel values var ( anyLoopbackAddress = "" wantErr = instanceConfig{"", "", ""} ) tcs := []struct { // inputs dir, instance string wantCfg instanceConfig }{ { "/x", "domain.com:my-proj:my-reg:my-instance", instanceConfig{"domain.com:my-proj:my-reg:my-instance", "unix", "/x/domain.com:my-proj:my-reg:my-instance"}, }, { "/x", "my-proj:my-reg:my-instance", instanceConfig{"my-proj:my-reg:my-instance", "unix", "/x/my-proj:my-reg:my-instance"}, }, { "/x", "my-proj:my-reg:my-instance=unix:socket_name", instanceConfig{"my-proj:my-reg:my-instance", "unix", "/x/socket_name"}, }, { "/x", "my-proj:my-reg:my-instance=unix:/my/custom/sql-socket", instanceConfig{"my-proj:my-reg:my-instance", "unix", "/my/custom/sql-socket"}, }, { "/x", "my-proj:my-reg:my-instance=tcp:1234", instanceConfig{"my-proj:my-reg:my-instance", "tcp", anyLoopbackAddress}, }, { "/x", "my-proj:my-reg:my-instance=tcp4:1234", instanceConfig{"my-proj:my-reg:my-instance", "tcp4", "127.0.0.1:1234"}, }, { "/x", "my-proj:my-reg:my-instance=tcp6:1234", instanceConfig{"my-proj:my-reg:my-instance", "tcp6", "[::1]:1234"}, }, { "/x", "my-proj:my-reg:my-instance=tcp:my-host:1111", instanceConfig{"my-proj:my-reg:my-instance", "tcp", "my-host:1111"}, }, { "/x", "my-proj:my-reg:my-instance=", wantErr, }, { "/x", "my-proj:my-reg:my-instance=cool network", wantErr, }, { "/x", "my-proj:my-reg:my-instance=cool network:1234", wantErr, }, { "/x", "my-proj:my-reg:my-instance=oh:so:many:colons", wantErr, }, } for _, tc := range tcs { t.Run(fmt.Sprintf("parseInstanceConfig(%q, %q)", tc.dir, tc.instance), func(t *testing.T) { if os.Getenv("EXPECT_IPV4_AND_IPV6") != "true" { // Skip ipv4 and ipv6 if they are not supported by the machine. // (assumption is that validNets isn't buggy) if tc.wantCfg.Network == "tcp4" || tc.wantCfg.Network == "tcp6" { if !validNets[tc.wantCfg.Network] { t.Skipf("%q net not supported, skipping", tc.wantCfg.Network) } } // Skip unix sockets on Windows if runtime.GOOS == "windows" && tc.wantCfg.Network == "unix" { t.Skipf("%q net not supported on Windows, skipping", tc.wantCfg.Network) } } got, err := parseInstanceConfig(tc.dir, tc.instance, mockClient) if tc.wantCfg == wantErr { if err != nil { return // pass. an error was expected and returned. } t.Fatalf("parseInstanceConfig(%s, %s) = %+v, wanted error", tc.dir, tc.instance, got) } if err != nil { t.Fatalf("parseInstanceConfig(%s, %s) had unexpected error: %v", tc.dir, tc.instance, err) } if tc.wantCfg.Address == anyLoopbackAddress { host, _, err := net.SplitHostPort(got.Address) if err != nil { t.Fatalf("net.SplitHostPort(%v): %v", got.Address, err) } ip := net.ParseIP(host) if !ip.IsLoopback() { t.Fatalf("want loopback, got addr: %v", got.Address) } // use a placeholder address, so the rest of the config can be compared got.Address = "" tc.wantCfg.Address = got.Address } if got != tc.wantCfg { t.Errorf("parseInstanceConfig(%s, %s) = %+v, want %+v", tc.dir, tc.instance, got, tc.wantCfg) } }) } } cloud-sql-proxy-1.33.14/examples/000077500000000000000000000000001452473605000165715ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/examples/disaster-recovery/000077500000000000000000000000001452473605000222435ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/examples/disaster-recovery/README.md000066400000000000000000000035401452473605000235240ustar00rootroot00000000000000# Coordinate disaster recovery with Secret Manager ## Background This document assumes you are already using the following strategy for detecting and triggering failovers: 1. Using an independent service to detect when the primary is down 2. Trigger a promotion of an existing read replica to become a primary 3. Update a Secret Manager secret with the name of the current primary ## Restart Auth proxy when secret changes This option uses a wrapper script around the Cloud SQL Auth proxy to detect when the secret has changed, and restart the proxy with the new value. This could be done in many languages, but here’s an example using bash: > [failover.sh](examples/disaster-recovery/failover.sh) ```sh #!/bin/bash SECRET_ID="my-secret-id" # TODO(developer): replace this value REFRESH_INTERVAL=5 PORT=5432 # TODO(developer): change this port as needed # Get the latest version of the secret and start the proxy INSTANCE=$(gcloud secrets versions access "latest" --secret="$SECRET_ID") cloud_sql_proxy -instances="$INSTANCE"=tcp:"$PORT" & PID=$! # Every 5s, get the latest version of the secret. If it's changed, restart the # proxy with the new value. while true; do sleep $REFRESH_INTERVAL NEW=$(gcloud secrets versions access "latest" --secret="$SECRET_ID") if [ "$INSTANCE" != "$NEW" ]; then INSTANCE=$NEW kill $PID wait $PID cloud_sql_proxy -instances="$INSTANCE"=tcp:"$PORT" & PID=$! fi done ``` ## Benefits of this approach Using this approach will help assist with failovers without needing to reconfigure your application. Instead, by changing the proxy the application will always connect to 127.0.0.1 and won’t need to restart to apply configuration changes. Additionally, it will prevent split brain syndrome by ensuring that your application can only connect to the current “primary”. cloud-sql-proxy-1.33.14/examples/disaster-recovery/failover.sh000066400000000000000000000026441452473605000244140ustar00rootroot00000000000000# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START cloud_sql_proxy_secret_manager_failover] #!/bin/bash SECRET_ID="my-secret-id" # TODO(developer): replace this value REFRESH_INTERVAL=5 PORT=5432 # TODO(developer): change this port as needed # Get the latest version of the secret and start the proxy INSTANCE=$(gcloud secrets versions access "latest" --secret="$SECRET_ID") cloud_sql_proxy -instances="$INSTANCE"=tcp:"$PORT" & PID=$! # Every 5s, get the latest version of the secret. If it's changed, restart the # proxy with the new value. while true; do sleep $REFRESH_INTERVAL NEW=$(gcloud secrets versions access "latest" --secret="$SECRET_ID") if [ "$INSTANCE" != "$NEW" ]; then INSTANCE=$NEW kill $PID wait $PID cloud_sql_proxy -instances="$INSTANCE"=tcp:"$PORT" & PID=$! fi done # [END cloud_sql_proxy_secret_manager_failover] cloud-sql-proxy-1.33.14/examples/k8s-health-check/000077500000000000000000000000001452473605000216145ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/examples/k8s-health-check/README.md000066400000000000000000000063441452473605000231020ustar00rootroot00000000000000# Cloud SQL proxy health checks Kubernetes supports three types of health checks. 1. Startup probes determine whether a container is done starting up. As soon as this probe succeeds, Kubernetes switches over to using liveness and readiness probing. 2. Liveness probes determine whether a container is healthy. When this probe is unsuccessful, the container is restarted. 3. Readiness probes determine whether a container can serve new traffic. When this probe fails, Kubernetes will wait to send requests to the container. ## Running Cloud SQL proxy with health checks in Kubernetes 1. Configure your Cloud SQL proxy container to include health check probes. > [proxy_with_http_health_check.yaml](proxy_with_http_health_check.yaml#L77-L111) ```yaml # Recommended configurations for health check probes. # Probe parameters can be adjusted to best fit the requirements of your application. # For details, see https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ livenessProbe: httpGet: path: /liveness port: 8090 # Number of seconds after the container has started before the first probe is scheduled. Defaults to 0. # Not necessary when the startup probe is in use. initialDelaySeconds: 0 # Frequency of the probe. Defaults to 10. periodSeconds: 10 # Number of seconds after which the probe times out. Defaults to 1. timeoutSeconds: 5 # Number of times the probe is allowed to fail before the transition from healthy to failure state. # Defaults to 3. failureThreshold: 1 readinessProbe: httpGet: path: /readiness port: 8090 initialDelaySeconds: 0 periodSeconds: 10 timeoutSeconds: 5 # Number of times the probe must report success to transition from failure to healthy state. # Defaults to 1 for readiness probe. successThreshold: 1 failureThreshold: 1 startupProbe: httpGet: path: /startup port: 8090 periodSeconds: 1 timeoutSeconds: 5 failureThreshold: 20 ``` 2. Add `-use_http_health_check` and `-health-check-port` (optional) to your proxy container configuration under `command: `. > [proxy_with_http_health_check.yaml](proxy_with_http_health_check.yaml#L39-L55) ```yaml command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances==tcp:" # Enables HTTP health checks. - "-use_http_health_check" # Specifies the health check server port. # Defaults to 8090. - "-health_check_port=" # This flag specifies where the service account key can be found - "-credential_file=/secrets/service_account.json" ``` cloud-sql-proxy-1.33.14/examples/k8s-health-check/proxy_with_http_health_check.yaml000066400000000000000000000126431452473605000304430ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # You must configure probes in your deployment to use health checks in Kubernetes. # This sample configuration for HTTP probes is adapted from proxy_with_workload_identity.yaml. apiVersion: apps/v1 kind: Deployment metadata: name: spec: selector: matchLabels: app: template: metadata: labels: app: spec: containers: - name: # ... other container configuration env: - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database - name: cloud-sql-proxy # It is recommended to use the latest version of the Cloud SQL proxy # Make sure to update on a regular schedule! image: gcr.io/cloudsql-docker/gce-proxy:1.28.0 # make sure the use the latest version command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances==tcp:" # Enables HTTP health checks. - "-use_http_health_check" # Specifies the health check server port. # Defaults to 8090. - "-health_check_port=" # This flag specifies where the service account key can be found - "-credential_file=/secrets/service_account.json" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: true volumeMounts: - name: mountPath: /secrets/ readOnly: true # Resource configuration depends on an application's requirements. You # should adjust the following values based on what your application # needs. For details, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: requests: # The proxy's memory use scales linearly with the number of active # connections. Fewer open connections will use less memory. Adjust # this value based on your application's requirements. memory: "2Gi" # The proxy's CPU use scales linearly with the amount of IO between # the database and the application. Adjust this value based on your # application's requirements. cpu: "1" # Recommended configurations for health check probes. # Probe parameters can be adjusted to best fit the requirements of your application. # For details, see https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ livenessProbe: httpGet: path: /liveness port: 8090 # Number of seconds after the container has started before the first probe is scheduled. Defaults to 0. # Not necessary when the startup probe is in use. initialDelaySeconds: 0 # Frequency of the probe. periodSeconds: 60 # Number of seconds after which the probe times out. timeoutSeconds: 30 # Number of times the probe is allowed to fail before the transition # from healthy to failure state. # # If periodSeconds = 60, 5 tries will result in five minutes of # checks. The proxy starts to refresh a certificate five minutes # before its expiration. If those five minutes lapse without a # successful refresh, the liveness probe will fail and the pod will be # restarted. failureThreshold: 5 readinessProbe: httpGet: path: /readiness port: 8090 initialDelaySeconds: 0 periodSeconds: 10 timeoutSeconds: 5 # Number of times the probe must report success to transition from failure to healthy state. # Defaults to 1 for readiness probe. successThreshold: 1 failureThreshold: 1 startupProbe: httpGet: path: /startup port: 8090 periodSeconds: 1 timeoutSeconds: 5 failureThreshold: 20 volumes: - name: secret: secretName: cloud-sql-proxy-1.33.14/examples/k8s-service/000077500000000000000000000000001452473605000207345ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/examples/k8s-service/README.md000066400000000000000000000167161452473605000222260ustar00rootroot00000000000000# Running the Cloud SQL Proxy as a Service This example demonstrates how to run the Cloud SQL Auth Proxy with PgBouncer on Kubernetes as a service. It assumes you have already successfully completed all the steps in [Using the Cloud SQL Auth Proxy on Kubernetes][sidecar]. In this example, you will deploy [PgBouncer][] with the Cloud SQL Auth Proxy as a sidecar, in addition to configuring encryption between the application and PgBouncer. ## A Word of Warning Running PgBouncer with the Cloud SQL Auth Proxy may pose a significant operational burden and should be undertaken with caution given the attendant complexity. In general, we recommend [running the proxy as a sidecar][sidecar] to your application because it is simple, there is less overhead, it is secure out of the box, and there is less latency involved. However, the service pattern is useful when you are at very large scale, when you clearly need a database connection pooler, and when you are running into SQL Admin API quota problems. ## Initial Setup Before we deploy PgBouncer with the Cloud SQL Auth Proxy, there are three initial steps to take. ### Generate Certificates for PgBouncer First, you will need to generate certificates to encrypt the connection between the application and PgBouncer. We recommend using [CFSSL][] to handle certificate generation. Note: this example uses self-signed certificates. In some cases, using a certificate signed by a public certificate authority may be preferred. Alternatively, Kubernetes includes [an API for issuing certificates][k8s-tls]. See the documentation on [certificates][certificate-docs] for more details. The certificate signing request is encoded as JSON in [`ca_csr.json`](ca_csr.json) for the certificate authority and in [`server_csr.json`](server_csr.json) for the "server," here PgBouncer. First, we initialize our certificate authority. ``` shell # This step produces ca-key.pem (the CA private key) # and ca.pem (the CA certificate). cfssl genkey -initca ca_csr.json | cfssljson -bare ca ``` Next, we generate a public and private key for the server. These will be what we will use to encrypt traffic from the application to PgBouncer. ``` shell # This step produces server-key.pem (the server private key) # and server.pem (the server certicate). cfssl gencert -ca cert -ca-key key server_csr.json | cfssljson -bare server ``` ### Save the certificates as secrets Second, with all the necessary certificates generated, we will save them as secrets: ``` shell # First the CA cert kubectl create secret tls --key="ca-key.pem" --cert="ca.pem" # Next the server cert kubectl create secret tls --key="server-key.pem" \ --cert="server.pem" ``` ### Containerize PgBouncer Third, we will containerize PgBouncer. Some users may prefer to containerize PgBouncer themselves. For this example, we will make use of an open source container, [edoburu/pgbouncer][edoburu]. One nice benefit of `edoburu/pgbouncer` is that it will generate all the PgBouncer configuration based on environment variables passed to the container. ## Deploy PgBouncer as a Service With PgBouncer containerized, we will now create a deployment with PgBouncer and the proxy as a sidecar. First, we mount our CA certificate and server certificate and private key, renaming the certificate secrets to `cert.pem` and server private key to `key.pem`: > [`pgbouncer_deployment.yaml`](pgbouncer_deployment.yaml#L15-L29) ``` yaml volumes: - name: cacert secret: secretName: items: - key: tls.crt path: cert.pem - name: servercert secret: secretName: items: - key: tls.crt path: cert.pem - key: tls.key path: key.pem ``` Next, we specify volume mounts in our PgBouncer container where the secrets will be stored: > [`pgbouncer_deployment.yaml`](pgbouncer_deployment.yaml#L31-L41) ``` yaml - name: pgbouncer image: ports: - containerPort: 5432 volumeMounts: - name: cacert mountPath: "/etc/ca" readOnly: true - name: servercert mountPath: "/etc/server" readOnly: true ``` Then we configure PgBouncer through environment variables. Note: we use 5431 for `DB_PORT` to leave 5432 available. > [`pgbouncer_deployment.yaml`](pgbouncer_deployment.yaml#L42-L69) ``` yaml env: - name: DB_HOST value: "127.0.0.1" - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database - name: DB_PORT value: "5431" - name: CLIENT_TLS_SSLMODE value: "require" - name: CLIENT_TLS_CA_FILE value: "/etc/ca/cert.pem" - name: CLIENT_TLS_KEY_FILE value: "/etc/server/key.pem" - name: CLIENT_TLS_CERT_FILE value: "/etc/server/cert.pem" ``` For the PgBouncer deployment, we add the proxy as a sidecar, starting it on port 5431: > [`pgbouncer_deployment.yaml`](pgbouncer_deployment.yaml#L70-L76) ``` yaml - name: cloud-sql-proxy image: gcr.io/cloudsql-docker/gce-proxy:1.28.0 # make sure the use the latest version command: - "/cloud_sql_proxy" - "-instances==tcp:5431" securityContext: runAsNonRoot: true ``` Next, we create a PgBouncer service, listening on port 5342: > [`pgbouncer_service.yaml`](pgbouncer_service.yaml#L1-L11) ``` yaml apiVersion: v1 kind: Service metadata: name: spec: selector: app: ports: - protocol: TCP port: 5432 targetPort: 5432 ``` With the PgBouncer service and deployment done, we are ready to point our application at it. ## Configure your application First, we configure a volume for the CA certificate, mapping the file name to `cert.pem`. > [`deployment.yaml`](deployment.yaml#L1-L11) ``` yaml volumes: - name: cacert secret: secretName: items: - key: tls.crt path: cert.pem ``` Next, we mount the volume within the application container: > [`deployment.yaml`](deployment.yaml#L28-L31) ``` yaml volumeMounts: - name: cacert mountPath: "/etc/ca" readOnly: true ``` Then, we configure environment variables for connecting to the database, this time including a `CA_CERT`: > [`deployment.yaml`](deployment.yaml#L32-L53) ``` yaml env: - name: DB_HOST value: ".default.svc.cluster.local" # using the "default" namespace - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database - name: DB_PORT value: "5432" - name: CA_CERT value: "/etc/ca/cert.pem" ``` Note: now the `DB_HOST` value uses an internal DNS record pointing at the PgBouncer service. Finally, when configuring a database connection string, the application must provide the additional properties: 1. `sslmode` must be set to at least `verify-ca` 1. `sslrootcert` must set to the environment variable `CA_CERT` [certificate-docs]: https://kubernetes.io/docs/tasks/administer-cluster/certificates/ [CFSSL]: https://github.com/cloudflare/cfssl [edoburu]: https://hub.docker.com/r/edoburu/pgbouncer [sidecar]: ../k8s-sidecar/README.md [k8s-tls]: https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/ [PgBouncer]: https://www.pgbouncer.org cloud-sql-proxy-1.33.14/examples/k8s-service/ca_csr.json000066400000000000000000000004511452473605000230610ustar00rootroot00000000000000{ "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Boulder", "O": "My Cool Self-Signing Certificate Authority", "OU": "WWW", "ST": "Colorado" } ] } cloud-sql-proxy-1.33.14/examples/k8s-service/deployment.yaml000066400000000000000000000036031452473605000240020ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: apps/v1 kind: Deployment metadata: name: spec: replicas: 5 selector: matchLabels: app: template: metadata: labels: app: spec: serviceAccountName: volumes: - name: cacert secret: secretName: items: - key: tls.crt path: cert.pem containers: - name: image: ports: - containerPort: 8080 volumeMounts: - name: cacert mountPath: "/etc/ca" readOnly: true env: - name: DB_HOST value: ".default.svc.cluster.local" # using the "default" namespace - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database - name: DB_PORT value: "5432" - name: CA_CERT value: "/etc/ca/cert.pem" cloud-sql-proxy-1.33.14/examples/k8s-service/pgbouncer_deployment.yaml000066400000000000000000000051161452473605000260470ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: apps/v1 kind: Deployment metadata: name: spec: selector: matchLabels: app: template: metadata: labels: app: spec: serviceAccountName: volumes: - name: cacert secret: secretName: items: - key: tls.crt path: cert.pem - name: servercert secret: secretName: items: - key: tls.crt path: cert.pem - key: tls.key path: key.pem containers: - name: pgbouncer image: ports: - containerPort: 5432 volumeMounts: - name: cacert mountPath: "/etc/ca" readOnly: true - name: servercert mountPath: "/etc/server" readOnly: true env: - name: DB_HOST value: "127.0.0.1" - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database - name: DB_PORT value: "5431" - name: CLIENT_TLS_SSLMODE value: "require" - name: CLIENT_TLS_CA_FILE value: "/etc/ca/cert.pem" - name: CLIENT_TLS_KEY_FILE value: "/etc/server/key.pem" - name: CLIENT_TLS_CERT_FILE value: "/etc/server/cert.pem" - name: cloud-sql-proxy image: gcr.io/cloudsql-docker/gce-proxy:1.28.0 # make sure to use the latest version command: - "/cloud_sql_proxy" - "-instances==tcp:5431" securityContext: runAsNonRoot: true cloud-sql-proxy-1.33.14/examples/k8s-service/pgbouncer_service.yaml000066400000000000000000000013631452473605000253270ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: v1 kind: Service metadata: name: spec: selector: app: ports: - protocol: TCP port: 5432 targetPort: 5432 cloud-sql-proxy-1.33.14/examples/k8s-service/server_csr.json000066400000000000000000000005441452473605000240070ustar00rootroot00000000000000{ "hosts": [ "pgbouncersvc.default.svc.cluster.local", "localhost" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Boulder", "O": "My Cool Kubernetes Cluster", "OU": "WWW", "ST": "Colorado" } ] } cloud-sql-proxy-1.33.14/examples/k8s-sidecar/000077500000000000000000000000001452473605000207065ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/examples/k8s-sidecar/README.md000066400000000000000000000252201452473605000221660ustar00rootroot00000000000000# Using the Cloud SQL proxy on Kubernetes The Cloud SQL proxy is the recommended way to connect to Cloud SQL, even when using private IP. This is because the proxy provides strong encryption and authentication using IAM, which help keep your database secure. ## Configure your application with Secrets In Kubernetes, [Secrets][ksa-secret] are a secure way to pass configuration details to your application. Each Secret object can contain multiple key/value pairs that can be pass to your application in multiple ways. When connecting to a database, you can create a Secret with details such as your database name, user, and password which can be injected into your application as env vars. 1. Create a secret with information needed to access your database: ```shell kubectl create secret generic \ --from-literal=username= \ --from-literal=password= \ --from-literal=database= ``` 2. Next, configure your application's container to mount the secrets as env vars: > [proxy_with_workload_identity.yaml](proxy_with_workload_identity.yaml#L21-L36) ```yaml env: - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database ``` 3. Finally, configure your application to use these values. In the example above, the values will be in the env vars `DB_USER`, `DB_PASS`, and `DB_NAME`. [ksa-secret]: https://kubernetes.io/docs/concepts/configuration/secret/ ## Setting up a service account The first step to running the Cloud SQL proxy in Kubernetes is creating a service account to represent your application. It is recommended that you create a service account unique to each application, instead of using the same service account everywhere. This model is more secure since it allows your to limit permissions on a per-application basis. The service account for your application needs to meet the following criteria: 1. Belong to a project with the [Cloud SQL Admin API][admin-api] enabled 1. [Has been granted][grant-sa] the [`Cloud SQL Client` IAM role (or equivalent)][csql-roles] for the project containing the instance you want to connect to 1. If connecting using private IP, you must use a [VPC-native GKE cluster][vpc-gke], in the same VPC as your Cloud SQL instance [admin-api]: https://console.cloud.google.com/flows/enableapi?apiid=sqladmin&redirect=https://console.cloud.google.com [grant-sa]: https://cloud.google.com/iam/docs/granting-roles-to-service-accounts [csql-roles]: https://cloud.google.com/iam/docs/understanding-roles#cloud-sql-roles [vpc-gke]: https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips ## Providing the service account to the proxy Next, you need to configure Kubernetes to provide the service account to the Cloud SQL Auth proxy. There are two recommended ways to do this. ### Workload Identity If you are using [Google Kubernetes Engine][gke], the preferred method is to use GKE's [Workload Identity][workload-id] feature. This method allows you to bind a [Kubernetes Service Account (KSA)][ksa] to a Google Service Account (GSA). The GSA will then be accessible to applications using the matching KSA. 1. [Enable Workload Identity for your cluster][enable-wi] 1. [Enable Workload Identity for your node pool][enable-wi-node-pool] 1. Create a KSA for your application `kubectl apply -f service-account.yaml`: > [service-account.yaml](service_account.yaml#L2-L5) ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: # TODO(developer): replace these values ``` 1. Enable the IAM binding between your `` and ``: ```sh gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:.svc.id.goog[/]" \ @.iam.gserviceaccount.com ``` 1. Add an annotation to `` to complete the binding: ```sh kubectl annotate serviceaccount \ \ iam.gke.io/gcp-service-account=@.iam.gserviceaccount.com ``` 1. Finally, make sure to specify the service account for the k8s pod spec: > [proxy_with_workload_identity.yaml](proxy_with_workload_identity.yaml#L2-L15) ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: spec: selector: matchLabels: app: template: metadata: labels: app: spec: serviceAccountName: ``` [gke]: https://cloud.google.com/kubernetes-engine [workload-id]: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity [ksa]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ [enable-wi]: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_existing_cluster [enable-wi-node-pool]: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#option_2_node_pool_modification ### Service account key file Alternatively, if your can't use Workload Identity, the recommended pattern is to mount a service account key file into the Cloud SQL proxy pod and use the `-credential_file` flag. 1. Create a credential file for your service account key: ```sh gcloud iam service-accounts keys create ~/key.json \ --iam-account @project-id.iam.gserviceaccount.com ``` 1. Turn your service account key into a k8s [Secret][k8s-secret]: ```shell kubectl create secret generic \ --from-file=service_account.json=~/key.json ``` 3. Mount the secret as a volume under the`spec:` for your k8s object: > [proxy_with_sa_key.yaml](proxy_with_sa_key.yaml#L74-L77) ```yaml volumes: - name: secret: secretName: ``` 4. Follow the instructions in the next section to access the volume from the proxy's pod. [k8s-secret]: https://kubernetes.io/docs/concepts/configuration/secret/ ## Run the Cloud SQL proxy as a sidecar We recommend running the proxy in a "sidecar" pattern (as an additional container sharing a pod with your application). We recommend this over running as a separate service for several reasons: * Prevents your SQL traffic from being exposed locally - the proxy provides encryption on outgoing connections, but you should limit exposure for incoming connections * Prevents a single point of failure - each application's access to your database is independent from the others, making it more resilient. * Limits access to the proxy, allowing you to use IAM permissions per application rather than exposing the database to the entire cluster * Allows you to scope resource requests more accurately - because the proxy consumes resources linearly to usage, this pattern allows you to more accurately scope and request resources to match your applications as it scales 1. Add the Cloud SQL proxy to the pod configuration under `containers`: > [proxy_with_workload-identity.yaml](proxy_with_workload_identity.yaml#L39-L69) ```yaml - name: cloud-sql-proxy # It is recommended to use the latest version of the Cloud SQL proxy # Make sure to update on a regular schedule! image: gcr.io/cloudsql-docker/gce-proxy:1.28.0 # make sure the use the latest version command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances==tcp:" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: true # Resource configuration depends on an application's requirements. You # should adjust the following values based on what your application # needs. For details, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: requests: # The proxy's memory use scales linearly with the number of active # connections. Fewer open connections will use less memory. Adjust # this value based on your application's requirements. memory: "2Gi" # The proxy's CPU use scales linearly with the amount of IO between # the database and the application. Adjust this value based on your # application's requirements. cpu: "1" ``` If you are using a service account key, specify your secret volume and add the `-credential_file` flag to the command: > [proxy_with_sa_key.yaml](proxy_with_sa_key.yaml#L49-L58) ```yaml # This flag specifies where the service account key can be found - "-credential_file=/secrets/service_account.json" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: true volumeMounts: - name: mountPath: /secrets/ readOnly: true ``` 1. Finally, configure your application to connect via `127.0.0.1` on whichever `` you specified in the command section. ## Connecting without the Cloud SQL proxy While not as secure, it is possible to connect from a VPC-native GKE cluster to a Cloud SQL instance on the same VPC using private IP without the proxy. 1. Create a secret with your instance's private IP address: ```shell kubectl create secret generic \ --from-literal=db_host= ``` 2. Next make sure you add the secret to your application's container: > [no_proxy_private_ip.yaml](no_proxy_private_ip.yaml#L34-L38) ```yaml - name: DB_HOST valueFrom: secretKeyRef: name: key: db_host ``` 3. Finally, configure your application to connect using the IP address from the `DB_HOST` env var. You will need to use the correct port for your db-engine (MySQL: `3306`, Postgres: `5432`, SQLServer: `1433`). cloud-sql-proxy-1.33.14/examples/k8s-sidecar/no_proxy_private_ip.yaml000066400000000000000000000030351452473605000256720ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: apps/v1 kind: Deployment metadata: name: spec: selector: matchLabels: app: template: metadata: labels: app: spec: containers: - name: # ... other container configuration env: - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database # [START cloud_sql_proxy_secret_host] - name: DB_HOST valueFrom: secretKeyRef: name: key: db_host # [END cloud_sql_proxy_secret_host] cloud-sql-proxy-1.33.14/examples/k8s-sidecar/proxy_with_sa_key.yaml000066400000000000000000000074201452473605000253440ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: apps/v1 kind: Deployment metadata: name: spec: selector: matchLabels: app: template: metadata: labels: app: spec: containers: - name: # ... other container configuration env: - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database - name: cloud-sql-proxy # It is recommended to use the latest version of the Cloud SQL proxy # Make sure to update on a regular schedule! image: gcr.io/cloudsql-docker/gce-proxy:1.28.0 # make sure the use the latest version command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # By default, the proxy will write all logs to stderr. In some # environments, anything printed to stderr is considered an error. To # disable this behavior and write all logs to stdout (except errors # which will still go to stderr), use: - "-log_debug_stdout" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances==tcp:" # [START cloud_sql_proxy_k8s_volume_mount] # This flag specifies where the service account key can be found - "-credential_file=/secrets/service_account.json" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: true volumeMounts: - name: mountPath: /secrets/ readOnly: true # [END cloud_sql_proxy_k8s_volume_mount] # Resource configuration depends on an application's requirements. You # should adjust the following values based on what your application # needs. For details, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: requests: # The proxy's memory use scales linearly with the number of active # connections. Fewer open connections will use less memory. Adjust # this value based on your application's requirements. memory: "2Gi" # The proxy's CPU use scales linearly with the amount of IO between # the database and the application. Adjust this value based on your # application's requirements. cpu: "1" # [START cloud_sql_proxy_k8s_volume_secret] volumes: - name: secret: secretName: # [END cloud_sql_proxy_k8s_volume_secret] cloud-sql-proxy-1.33.14/examples/k8s-sidecar/proxy_with_workload_identity.yaml000066400000000000000000000071461452473605000276310ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START cloud_sql_proxy_k8s_sa] apiVersion: apps/v1 kind: Deployment metadata: name: spec: selector: matchLabels: app: template: metadata: labels: app: spec: serviceAccountName: # [END cloud_sql_proxy_k8s_sa] # [START cloud_sql_proxy_k8s_secrets] containers: - name: # ... other container configuration env: - name: DB_USER valueFrom: secretKeyRef: name: key: username - name: DB_PASS valueFrom: secretKeyRef: name: key: password - name: DB_NAME valueFrom: secretKeyRef: name: key: database # [END cloud_sql_proxy_k8s_secrets] # [START cloud_sql_proxy_k8s_container] - name: cloud-sql-proxy # It is recommended to use the latest version of the Cloud SQL proxy # Make sure to update on a regular schedule! image: gcr.io/cloudsql-docker/gce-proxy:1.28.0 # make sure the use the latest version command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # By default, the proxy will write all logs to stderr. In some # environments, anything printed to stderr is consider an error. To # disable this behavior and write all logs to stdout (except errors # which will still go to stderr), use: - "-log_debug_stdout" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances==tcp:" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: true # You should use resource requests/limits as a best practice to prevent # pods from consuming too many resources and affecting the execution of # other pods. You should adjust the following values based on what your # application needs. For details, see # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: requests: # The proxy's memory use scales linearly with the number of active # connections. Fewer open connections will use less memory. Adjust # this value based on your application's requirements. memory: "2Gi" # The proxy's CPU use scales linearly with the amount of IO between # the database and the application. Adjust this value based on your # application's requirements. cpu: "1" # [END cloud_sql_proxy_k8s_container] cloud-sql-proxy-1.33.14/examples/k8s-sidecar/service_account.yaml000066400000000000000000000013651452473605000247530ustar00rootroot00000000000000# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START cloud_sql_proxy_k8s_sa_yml] apiVersion: v1 kind: ServiceAccount metadata: name: # TODO(developer): replace these values # [END cloud_sql_proxy_k8s_sa_yml]cloud-sql-proxy-1.33.14/go.mod000066400000000000000000000034311452473605000160620ustar00rootroot00000000000000module github.com/GoogleCloudPlatform/cloudsql-proxy go 1.17 require ( cloud.google.com/go/compute/metadata v0.2.3 github.com/coreos/go-systemd/v22 v22.5.0 github.com/go-sql-driver/mysql v1.7.1 github.com/hanwen/go-fuse/v2 v2.4.0 github.com/jackc/pgx/v4 v4.18.1 github.com/lib/pq v1.10.9 github.com/microsoft/go-mssqldb v1.6.0 go.uber.org/zap v1.26.0 golang.org/x/net v0.18.0 golang.org/x/oauth2 v0.14.0 golang.org/x/sys v0.14.0 golang.org/x/time v0.4.0 google.golang.org/api v0.150.0 ) require ( cloud.google.com/go/compute v1.23.1 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.4.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.2 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgtype v1.14.0 // indirect github.com/pkg/errors v0.9.1 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect ) cloud-sql-proxy-1.33.14/go.sum000066400000000000000000006453411452473605000161230ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0= cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= cloud.google.com/go/accesscontextmanager v1.8.2/go.mod h1:E6/SCRM30elQJ2PKtFMs2YhfJpZSNcJyejhuzoId4Zk= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= cloud.google.com/go/aiplatform v1.51.1/go.mod h1:kY3nIMAVQOK2XDqDPHaOuD9e+FdMA6OOpfBjsvaFSOo= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= cloud.google.com/go/analytics v0.21.4/go.mod h1:zZgNCxLCy8b2rKKVfC1YkC2vTrpfZmeRCySM3aUbskA= cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= cloud.google.com/go/apigateway v1.6.2/go.mod h1:CwMC90nnZElorCW63P2pAYm25AtQrHfuOkbRSHj0bT8= cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= cloud.google.com/go/apigeeconnect v1.6.2/go.mod h1:s6O0CgXT9RgAxlq3DLXvG8riw8PYYbU/v25jqP3Dy18= cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= cloud.google.com/go/apigeeregistry v0.7.2/go.mod h1:9CA2B2+TGsPKtfi3F7/1ncCCsL62NXBRfM6iPoGSM+8= cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= cloud.google.com/go/appengine v1.8.2/go.mod h1:WMeJV9oZ51pvclqFN2PqHoGnys7rK0rz6s3Mp6yMvDo= cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= cloud.google.com/go/area120 v0.8.2/go.mod h1:a5qfo+x77SRLXnCynFWPUZhnZGeSgvQ+Y0v1kSItkh4= cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= cloud.google.com/go/artifactregistry v1.14.2/go.mod h1:Xk+QbsKEb0ElmyeMfdHAey41B+qBq3q5R5f5xD4XT3U= cloud.google.com/go/artifactregistry v1.14.3/go.mod h1:A2/E9GXnsyXl7GUvQ/2CjHA+mVRoWAXC0brg2os+kNI= cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+okxFECHcg= cloud.google.com/go/asset v1.15.1/go.mod h1:yX/amTvFWRpp5rcFq6XbCxzKT8RJUam1UoboE179jU4= cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= cloud.google.com/go/assuredworkloads v1.11.2/go.mod h1:O1dfr+oZJMlE6mw0Bp0P1KZSlj5SghMBvTpZqIcUAW4= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg= cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= cloud.google.com/go/baremetalsolution v1.2.1/go.mod h1:3qKpKIw12RPXStwQXcbhfxVj1dqQGEvcmA+SX/mUR88= cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= cloud.google.com/go/batch v1.5.1/go.mod h1:RpBuIYLkQu8+CWDk3dFD/t/jOCGuUpkpX+Y0n1Xccs8= cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= cloud.google.com/go/beyondcorp v1.0.1/go.mod h1:zl/rWWAFVeV+kx+X2Javly7o1EIQThU4WlkynffL/lk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= cloud.google.com/go/bigquery v1.56.0/go.mod h1:KDcsploXTEY7XT3fDQzMUZlpQLHzE4itubHrnmhUrZA= cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= cloud.google.com/go/billing v1.17.2/go.mod h1:u/AdV/3wr3xoRBk5xvUzYMS1IawOAPwQMuHgHMdljDg= cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= cloud.google.com/go/binaryauthorization v1.7.1/go.mod h1:GTAyfRWYgcbsP3NJogpV3yeunbUIjx2T9xVeYovtURE= cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= cloud.google.com/go/certificatemanager v1.7.2/go.mod h1:15SYTDQMd00kdoW0+XY5d9e+JbOPjp24AvF48D8BbcQ= cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= cloud.google.com/go/channel v1.17.1/go.mod h1:xqfzcOZAcP4b/hUDH0GkGg1Sd5to6di1HOJn/pi5uBQ= cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= cloud.google.com/go/cloudbuild v1.14.1/go.mod h1:K7wGc/3zfvmYWOWwYTgF/d/UVJhS4pu+HAy7PL7mCsU= cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= cloud.google.com/go/clouddms v1.7.1/go.mod h1:o4SR8U95+P7gZ/TX+YbJxehOCsM+fe6/brlrFquiszk= cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= cloud.google.com/go/cloudtasks v1.12.2/go.mod h1:A7nYkjNlW2gUoROg1kvJrQGhJP/38UaWwsnuBDOBVUk= cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0= cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU= cloud.google.com/go/contactcenterinsights v1.11.1/go.mod h1:FeNP3Kg8iteKM80lMwSk3zZZKVxr+PGnAId6soKuXwE= cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= cloud.google.com/go/container v1.26.1/go.mod h1:5smONjPRUxeEpDG7bMKWfDL4sauswqEtnBK1/KKpR04= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= cloud.google.com/go/containeranalysis v0.11.1/go.mod h1:rYlUOM7nem1OJMKwE1SadufX0JP3wnXj844EtZAwWLY= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= cloud.google.com/go/datacatalog v1.18.1/go.mod h1:TzAWaz+ON1tkNr4MOcak8EBHX7wIRX/gZKM+yTVsv+A= cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= cloud.google.com/go/dataflow v0.9.2/go.mod h1:vBfdBZ/ejlTaYIGB3zB4T08UshH70vbtZeMD+urnUSo= cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= cloud.google.com/go/dataform v0.8.2/go.mod h1:X9RIqDs6NbGPLR80tnYoPNiO1w0wenKTb8PxxlhTMKM= cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= cloud.google.com/go/datafusion v1.7.2/go.mod h1:62K2NEC6DRlpNmI43WHMWf9Vg/YvN6QVi8EVwifElI0= cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= cloud.google.com/go/datalabeling v0.8.2/go.mod h1:cyDvGHuJWu9U/cLDA7d8sb9a0tWLEletStu2sTmg3BE= cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= cloud.google.com/go/dataplex v1.10.1/go.mod h1:1MzmBv8FvjYfc7vDdxhnLFNskikkB+3vl475/XdCDhs= cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= cloud.google.com/go/dataproc/v2 v2.2.1/go.mod h1:QdAJLaBjh+l4PVlVZcmrmhGccosY/omC1qwfQ61Zv/o= cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= cloud.google.com/go/dataqna v0.8.2/go.mod h1:KNEqgx8TTmUipnQsScOoDpq/VlXVptUqVMZnt30WAPs= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= cloud.google.com/go/datastream v1.10.1/go.mod h1:7ngSYwnw95YFyTd5tOGBxHlOZiL+OtpjheqU7t2/s/c= cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= cloud.google.com/go/deploy v1.13.1/go.mod h1:8jeadyLkH9qu9xgO3hVWw8jVr29N1mnW42gRJT8GY6g= cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= cloud.google.com/go/dialogflow v1.44.1/go.mod h1:n/h+/N2ouKOO+rbe/ZnI186xImpqvCVj2DdsWS/0EAk= cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= cloud.google.com/go/dlp v1.10.2/go.mod h1:ZbdKIhcnyhILgccwVDzkwqybthh7+MplGC3kZVZsIOQ= cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= cloud.google.com/go/documentai v1.23.2/go.mod h1:Q/wcRT+qnuXOpjAkvOV4A+IeQl04q2/ReT7SSbytLSo= cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= cloud.google.com/go/domains v0.9.2/go.mod h1:3YvXGYzZG1Temjbk7EyGCuGGiXHJwVNmwIf+E/cUp5I= cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= cloud.google.com/go/edgecontainer v1.1.2/go.mod h1:wQRjIzqxEs9e9wrtle4hQPSR1Y51kqN75dgF7UllZZ4= cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= cloud.google.com/go/essentialcontacts v1.6.3/go.mod h1:yiPCD7f2TkP82oJEFXFTou8Jl8L6LBRPeBEkTaO0Ggo= cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= cloud.google.com/go/eventarc v1.13.1/go.mod h1:EqBxmGHFrruIara4FUQ3RHlgfCn7yo1HYsu2Hpt/C3Y= cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= cloud.google.com/go/filestore v1.7.2/go.mod h1:TYOlyJs25f/omgj+vY7/tIG/E7BX369triSPzE4LdgE= cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= cloud.google.com/go/functions v1.15.2/go.mod h1:CHAjtcR6OU4XF2HuiVeriEdELNcnvRZSk1Q8RMqy4lE= cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= cloud.google.com/go/gkebackup v1.3.2/go.mod h1:OMZbXzEJloyXMC7gqdSB+EOEQ1AKcpGYvO3s1ec5ixk= cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= cloud.google.com/go/gkeconnect v0.8.2/go.mod h1:6nAVhwchBJYgQCXD2pHBFQNiJNyAd/wyxljpaa6ZPrY= cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= cloud.google.com/go/gkehub v0.14.2/go.mod h1:iyjYH23XzAxSdhrbmfoQdePnlMj2EWcvnR+tHdBQsCY= cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= cloud.google.com/go/gkemulticloud v1.0.1/go.mod h1:AcrGoin6VLKT/fwZEYuqvVominLriQBCKmbjtnbMjG8= cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= cloud.google.com/go/gsuiteaddons v1.6.2/go.mod h1:K65m9XSgs8hTF3X9nNTPi8IQueljSdYo9F+Mi+s4MyU= cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q= cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= cloud.google.com/go/ids v1.4.2/go.mod h1:3vw8DX6YddRu9BncxuzMyWn0g8+ooUjI2gslJ7FH3vk= cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= cloud.google.com/go/iot v1.7.2/go.mod h1:q+0P5zr1wRFpw7/MOgDXrG/HVA+l+cSwdObffkrpnSg= cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= cloud.google.com/go/language v1.11.1/go.mod h1:Xyid9MG9WOX3utvDbpX7j3tXDmmDooMyMDqgUVpH17U= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= cloud.google.com/go/lifesciences v0.9.2/go.mod h1:QHEOO4tDzcSAzeJg7s2qwnLM2ji8IRpQl4p6m5Z9yTA= cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= cloud.google.com/go/maps v1.4.1/go.mod h1:BxSa0BnW1g2U2gNdbq5zikLlHUuHW0GFWh7sgML2kIY= cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= cloud.google.com/go/mediatranslation v0.8.2/go.mod h1:c9pUaDRLkgHRx3irYE5ZC8tfXGrMYwNZdmDqKMSfFp8= cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= cloud.google.com/go/memcache v1.10.2/go.mod h1:f9ZzJHLBrmd4BkguIAa/l/Vle6uTHzHokdnzSWOdQ6A= cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= cloud.google.com/go/metastore v1.13.0/go.mod h1:URDhpG6XLeh5K+Glq0NOt74OfrPKTwS62gEPZzb5SOk= cloud.google.com/go/metastore v1.13.1/go.mod h1:IbF62JLxuZmhItCppcIfzBBfUFq0DIB9HPDoLgWrVOU= cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= cloud.google.com/go/monitoring v1.16.1/go.mod h1:6HsxddR+3y9j+o/cMJH6q/KJ/CBTvM/38L/1m7bTRJ4= cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= cloud.google.com/go/networkconnectivity v1.14.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= cloud.google.com/go/networkconnectivity v1.14.1/go.mod h1:LyGPXR742uQcDxZ/wv4EI0Vu5N6NKJ77ZYVnDe69Zug= cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= cloud.google.com/go/networkmanagement v1.9.1/go.mod h1:CCSYgrQQvW73EJawO2QamemYcOb57LvrDdDU51F0mcI= cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= cloud.google.com/go/networksecurity v0.9.2/go.mod h1:jG0SeAttWzPMUILEHDUvFYdQTl8L/E/KC8iZDj85lEI= cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= cloud.google.com/go/notebooks v1.10.1/go.mod h1:5PdJc2SgAybE76kFQCWrTfJolCOUQXF97e+gteUUA6A= cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= cloud.google.com/go/optimization v1.5.1/go.mod h1:NC0gnUD5MWVAF7XLdoYVPmYYVth93Q6BUzqAq3ZwtV8= cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= cloud.google.com/go/orchestration v1.8.2/go.mod h1:T1cP+6WyTmh6LSZzeUhvGf0uZVmJyTx7t8z7Vg87+A0= cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= cloud.google.com/go/orgpolicy v1.11.2/go.mod h1:biRDpNwfyytYnmCRWZWxrKF22Nkz9eNVj9zyaBdpm1o= cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= cloud.google.com/go/osconfig v1.12.2/go.mod h1:eh9GPaMZpI6mEJEuhEjUJmaxvQ3gav+fFEJon1Y8Iw0= cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3xlOxaboXE= cloud.google.com/go/oslogin v1.11.1/go.mod h1:OhD2icArCVNUxKqtK0mcSmKL7lgr0LVlQz+v9s1ujTg= cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= cloud.google.com/go/phishingprotection v0.8.2/go.mod h1:LhJ91uyVHEYKSKcMGhOa14zMMWfbEdxG032oT6ECbC8= cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= cloud.google.com/go/policytroubleshooter v1.9.1/go.mod h1:MYI8i0bCrL8cW+VHN1PoiBTyNZTstCg2WUw2eVC4c4U= cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= cloud.google.com/go/privatecatalog v0.9.2/go.mod h1:RMA4ATa8IXfzvjrhhK8J6H4wwcztab+oZph3c6WmtFc= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3XuJyNsjEqMlMzg3v3scCJ46c= cloud.google.com/go/recaptchaenterprise/v2 v2.8.1/go.mod h1:JZYZJOeZjgSSTGP4uz7NlQ4/d1w5hGmksVgM0lbEij0= cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= cloud.google.com/go/recommendationengine v0.8.2/go.mod h1:QIybYHPK58qir9CV2ix/re/M//Ty10OxjnnhWdaKS1Y= cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= cloud.google.com/go/recommender v1.11.1/go.mod h1:sGwFFAyI57v2Hc5LbIj+lTwXipGu9NW015rkaEM5B18= cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= cloud.google.com/go/redis v1.13.2/go.mod h1:0Hg7pCMXS9uz02q+LoEVl5dNHUkIQv+C/3L76fandSA= cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= cloud.google.com/go/resourcemanager v1.9.2/go.mod h1:OujkBg1UZg5lX2yIyMo5Vz9O5hf7XQOSV7WxqxxMtQE= cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= cloud.google.com/go/resourcesettings v1.6.2/go.mod h1:mJIEDd9MobzunWMeniaMp6tzg4I2GvD3TTmPkc8vBXk= cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= cloud.google.com/go/retail v1.14.2/go.mod h1:W7rrNRChAEChX336QF7bnMxbsjugcOCPU44i5kbLiL8= cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= cloud.google.com/go/run v1.3.0/go.mod h1:S/osX/4jIPZGg+ssuqh6GNgg7syixKe3YnprwehzHKU= cloud.google.com/go/run v1.3.1/go.mod h1:cymddtZOzdwLIAsmS6s+Asl4JoXIDm/K1cpZTxV4Q5s= cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= cloud.google.com/go/scheduler v1.10.2/go.mod h1:O3jX6HRH5eKCA3FutMw375XHZJudNIKVonSCHv7ropY= cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= cloud.google.com/go/secretmanager v1.11.2/go.mod h1:MQm4t3deoSub7+WNwiC4/tRYgDBHJgJPvswqQVB1Vss= cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= cloud.google.com/go/security v1.15.2/go.mod h1:2GVE/v1oixIRHDaClVbHuPcZwAqFM28mXuAKCfMgYIg= cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= cloud.google.com/go/securitycenter v1.23.1/go.mod h1:w2HV3Mv/yKhbXKwOCu2i8bCuLtNP1IMHuiYQn4HJq5s= cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= cloud.google.com/go/servicedirectory v1.11.1/go.mod h1:tJywXimEWzNzw9FvtNjsQxxJ3/41jseeILgwU/QLrGI= cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= cloud.google.com/go/shell v1.7.2/go.mod h1:KqRPKwBV0UyLickMn0+BY1qIyE98kKyI216sH/TuHmc= cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= cloud.google.com/go/spanner v1.50.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= cloud.google.com/go/speech v1.19.1/go.mod h1:WcuaWz/3hOlzPFOVo9DUsblMIHwxP589y6ZMtaG+iAA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= cloud.google.com/go/storagetransfer v1.10.1/go.mod h1:rS7Sy0BtPviWYTTJVWCSV4QrbBitgPeuK4/FKa4IdLs= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= cloud.google.com/go/talent v1.6.3/go.mod h1:xoDO97Qd4AK43rGjJvyBHMskiEf3KulgYzcH6YWOVoo= cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= cloud.google.com/go/texttospeech v1.7.2/go.mod h1:VYPT6aTOEl3herQjFHYErTlSZJ4vB00Q2ZTmuVgluD4= cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= cloud.google.com/go/tpu v1.6.2/go.mod h1:NXh3NDwt71TsPZdtGWgAG5ThDfGd32X1mJ2cMaRlVgU= cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= cloud.google.com/go/trace v1.10.2/go.mod h1:NPXemMi6MToRFcSxRl2uDnu/qAlAQ3oULUphcHGh1vA= cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= cloud.google.com/go/translate v1.9.1/go.mod h1:TWIgDZknq2+JD4iRcojgeDtqGEp154HN/uL6hMvylS8= cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= cloud.google.com/go/video v1.20.1/go.mod h1:3gJS+iDprnj8SY6pe0SwLeC5BUW80NjhwX7INWEuWGU= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= cloud.google.com/go/videointelligence v1.11.2/go.mod h1:ocfIGYtIVmIcWk1DsSGOoDiXca4vaZQII1C85qtoplc= cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= cloud.google.com/go/vision/v2 v2.7.3/go.mod h1:V0IcLCY7W+hpMKXK1JYE0LV5llEqVmj+UJChjvA1WsM= cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= cloud.google.com/go/vmmigration v1.7.2/go.mod h1:iA2hVj22sm2LLYXGPT1pB63mXHhrH1m/ruux9TwWLd8= cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= cloud.google.com/go/vmwareengine v1.0.1/go.mod h1:aT3Xsm5sNx0QShk1Jc1B8OddrxAScYLwzVoaiXfdzzk= cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= cloud.google.com/go/vpcaccess v1.7.2/go.mod h1:mmg/MnRHv+3e8FJUjeSibVFvQF1cCy2MsFaFqxeY1HU= cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= cloud.google.com/go/webrisk v1.9.2/go.mod h1:pY9kfDgAqxUpDBOrG4w8deLfhvJmejKB0qd/5uQIPBc= cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= cloud.google.com/go/websecurityscanner v1.6.2/go.mod h1:7YgjuU5tun7Eg2kpKgGnDuEOXWIrh8x8lWrJT4zfmas= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 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/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= 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-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= 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-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/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/go-pkcs11 v0.2.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/hanwen/go-fuse/v2 v2.4.0 h1:12OhD7CkXXQdvxG2osIdBQLdXh+nmLXY9unkUIe/xaU= github.com/hanwen/go-fuse/v2 v2.4.0/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 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/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.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.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/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= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= cloud-sql-proxy-1.33.14/logging/000077500000000000000000000000001452473605000164015ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/logging/logging.go000066400000000000000000000064371452473605000203700ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package logging contains helpers to support log messages. If you are using // the Cloud SQL Auth proxy as a Go library, you can override these variables to // control where log messages end up. package logging import ( "log" "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) // Verbosef is called to write verbose logs, such as when a new connection is // established correctly. var Verbosef = log.Printf // Infof is called to write informational logs, such as when startup has var Infof = log.Printf // Errorf is called to write an error log, such as when a new connection fails. var Errorf = log.Printf // LogDebugToStdout updates Verbosef and Info logging to use stdout instead of stderr. func LogDebugToStdout() { logger := log.New(os.Stdout, "", log.LstdFlags) Verbosef = logger.Printf Infof = logger.Printf } func noop(string, ...interface{}) {} // LogVerboseToNowhere updates Verbosef so verbose log messages are discarded func LogVerboseToNowhere() { Verbosef = noop } // DisableLogging sets all logging levels to no-op's. func DisableLogging() { Verbosef = noop Infof = noop Errorf = noop } // EnableStructuredLogs replaces all logging functions with structured logging // variants. func EnableStructuredLogs(logDebugStdout, verbose bool) (func(), error) { // Configuration of zap is based on its Advanced Configuration example. // See: https://pkg.go.dev/go.uber.org/zap#example-package-AdvancedConfiguration // Define level-handling logic. highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl >= zapcore.ErrorLevel }) lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl < zapcore.ErrorLevel }) // Lock wraps a WriteSyncer in a mutex to make it safe for concurrent use. In // particular, *os.File types must be locked before use. consoleErrors := zapcore.Lock(os.Stderr) consoleDebugging := consoleErrors if logDebugStdout { consoleDebugging = zapcore.Lock(os.Stdout) } config := zap.NewProductionEncoderConfig() config.LevelKey = "severity" config.MessageKey = "message" config.TimeKey = "timestamp" config.EncodeLevel = zapcore.CapitalLevelEncoder config.EncodeTime = zapcore.ISO8601TimeEncoder consoleEncoder := zapcore.NewJSONEncoder(config) core := zapcore.NewTee( zapcore.NewCore(consoleEncoder, consoleErrors, highPriority), zapcore.NewCore(consoleEncoder, consoleDebugging, lowPriority), ) // By default, caller and stacktrace are not included, so add them here logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) sugar := logger.Sugar() Verbosef = sugar.Infof if !verbose { Verbosef = noop } Infof = sugar.Infof Errorf = sugar.Errorf return func() { logger.Sync() }, nil } cloud-sql-proxy-1.33.14/proxy/000077500000000000000000000000001452473605000161345ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/README.md000066400000000000000000000032701452473605000174150ustar00rootroot00000000000000# Cloud SQL proxy dialer for Go ## Note This package is deprecated. Instead use the [Cloud SQL Go Connector][go-connector] which has support for MySQL, Postgres, and SQL Server, in addition to better configurability, support for metrics and tracing, and a number of additional features. See the [migration guide][migration-guide] for how to switch. ## Overview You can also use the Cloud SQL proxy directly from a Go program. These packages are primarily used as implementation for the Cloud SQL proxy command, and may be changed in backwards incompatible ways in the future. ## Usage If your program is written in [Go](https://golang.org) you can use the Cloud SQL Proxy as a library, avoiding the need to start the Proxy as a companion process. Alternatively, there are Cloud SQL Connectors for [Java][] and [Python][]. ### MySQL If you're using the MySQL [go-sql-driver][go-mysql] you can use helper functions found in the [`proxy/dialers/mysql`][mysql-godoc] See [example usage](dialers/mysql/hook_test.go). ### Postgres If you're using the Postgres [lib/pq](https://github.com/lib/pq), you can use the `cloudsqlpostgres` driver from [here](proxy/dialers/postgres). See [example usage](dialers/postgres/hook_test.go). [Java]: https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory [Python]: https://github.com/GoogleCloudPlatform/cloud-sql-python-connector [go-mysql]: https://github.com/go-sql-driver/mysql [mysql-godoc]: https://pkg.go.dev/github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql [go-connector]: https://pkg.go.dev/cloud.google.com/go/cloudsqlconn [migration-guide]: https://github.com/GoogleCloudPlatform/cloud-sql-go-connector/blob/main/migration-guide.md cloud-sql-proxy-1.33.14/proxy/certs/000077500000000000000000000000001452473605000172545ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/certs/certs.go000066400000000000000000000276441452473605000207400ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package certs implements a CertSource which speaks to the public Cloud SQL API endpoint. package certs import ( "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/pem" "errors" "fmt" "math" mrand "math/rand" "net/http" "strings" "sync" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/util" "golang.org/x/oauth2" "google.golang.org/api/googleapi" sqladmin "google.golang.org/api/sqladmin/v1beta4" ) var defaultUserAgent = util.UserAgentFromVersionString() // NewCertSource returns a CertSource which can be used to authenticate using // the provided client, which must not be nil. // // This function is deprecated; use NewCertSourceOpts instead. func NewCertSource(host string, c *http.Client, checkRegion bool) *RemoteCertSource { return NewCertSourceOpts(c, RemoteOpts{ APIBasePath: host, IgnoreRegion: !checkRegion, UserAgent: defaultUserAgent, }) } // RemoteOpts are a collection of options for NewCertSourceOpts. All fields are // optional. type RemoteOpts struct { // APIBasePath specifies the base path for the sqladmin API. If left blank, // the default from the autogenerated sqladmin library is used (which is // sufficient for nearly all users) APIBasePath string // IgnoreRegion specifies whether a missing or mismatched region in the // instance name should be ignored. In a future version this value will be // forced to 'false' by the RemoteCertSource. IgnoreRegion bool // A string for the RemoteCertSource to identify itself when contacting the // sqladmin API. UserAgent string // IP address type options IPAddrTypeOpts []string // Enable IAM proxy db authentication EnableIAMLogin bool // Token source for token information used in cert creation TokenSource oauth2.TokenSource // DelayKeyGenerate, if true, causes the RSA key to be generated lazily // on the first connection to a database. The default behavior is to generate // the key when the CertSource is created. DelayKeyGenerate bool } // NewCertSourceOpts returns a CertSource configured with the provided Opts. // The provided http.Client must not be nil. // // Use this function instead of NewCertSource; it has a more forward-compatible // signature. func NewCertSourceOpts(c *http.Client, opts RemoteOpts) *RemoteCertSource { serv, err := sqladmin.New(c) if err != nil { panic(err) // Only will happen if the provided client is nil. } if opts.APIBasePath != "" { serv.BasePath = opts.APIBasePath } ua := opts.UserAgent if ua == "" { ua = defaultUserAgent } serv.UserAgent = ua // Set default value to be "PUBLIC,PRIVATE" if not specified if len(opts.IPAddrTypeOpts) == 0 { opts.IPAddrTypeOpts = []string{"PUBLIC", "PRIVATE"} } // Add "PUBLIC" as an alias for "PRIMARY" for index, ipAddressType := range opts.IPAddrTypeOpts { if strings.ToUpper(ipAddressType) == "PUBLIC" { opts.IPAddrTypeOpts[index] = "PRIMARY" } } certSource := &RemoteCertSource{ serv: serv, checkRegion: !opts.IgnoreRegion, IPAddrTypes: opts.IPAddrTypeOpts, EnableIAMLogin: opts.EnableIAMLogin, TokenSource: opts.TokenSource, } if !opts.DelayKeyGenerate { // Generate the RSA key now, but don't block on it. go certSource.generateKey() } return certSource } // RemoteCertSource implements a CertSource, using Cloud SQL APIs to // return Local certificates for identifying oneself as a specific user // to the remote instance and Remote certificates for confirming the // remote database's identity. type RemoteCertSource struct { // keyOnce is used to create `key` lazily. keyOnce sync.Once // key is the private key used for certificates returned by Local. key *rsa.PrivateKey // serv is used to make authenticated API calls to Cloud SQL. serv *sqladmin.Service // If set, providing an incorrect region in their connection string will be // treated as an error. This is to provide the same functionality that will // occur when API calls require the region. checkRegion bool // a list of ip address types that users select IPAddrTypes []string // flag to enable IAM proxy db authentication EnableIAMLogin bool // token source for the token information used in cert creation TokenSource oauth2.TokenSource } // Constants for backoffAPIRetry. These cause the retry logic to scale the // backoff delay from 200ms to around 3.5s. const ( baseBackoff = float64(200 * time.Millisecond) backoffMult = 1.618 backoffRetries = 5 ) func backoffAPIRetry(desc, instance string, do func(staleRead time.Time) error) error { var ( err error t time.Time ) for i := 0; i < backoffRetries; i++ { err = do(t) gErr, ok := err.(*googleapi.Error) switch { case !ok: // 'ok' will also be false if err is nil. return err case gErr.Code == 403 && len(gErr.Errors) > 0 && gErr.Errors[0].Reason == "insufficientPermissions": // The case where the admin API has not yet been enabled. return fmt.Errorf("ensure that the Cloud SQL API is enabled for your project (https://console.cloud.google.com/flows/enableapi?apiid=sqladmin). Error during %s %s: %v", desc, instance, err) case gErr.Code == 404 || gErr.Code == 403: return fmt.Errorf("ensure that the account has access to %q (and make sure there's no typo in that name). Error during %s %s: %v", instance, desc, instance, err) case gErr.Code < 500: // Only Server-level HTTP errors are immediately retryable. return err } // sleep = baseBackoff * backoffMult^(retries + randomFactor) exp := float64(i+1) + mrand.Float64() sleep := time.Duration(baseBackoff * math.Pow(backoffMult, exp)) logging.Errorf("Error in %s %s: %v; retrying in %v", desc, instance, err, sleep) time.Sleep(sleep) // Create timestamp 30 seconds before now for stale read requests t = time.Now().UTC().Add(-30 * time.Second) } return err } func refreshToken(ts oauth2.TokenSource, tok *oauth2.Token) (*oauth2.Token, error) { expiredToken := &oauth2.Token{ AccessToken: tok.AccessToken, TokenType: tok.TokenType, RefreshToken: tok.RefreshToken, Expiry: time.Time{}.Add(1), // Expired } return oauth2.ReuseTokenSource(expiredToken, ts).Token() } // Local returns a certificate that may be used to establish a TLS // connection to the specified instance. func (s *RemoteCertSource) Local(instance string) (tls.Certificate, error) { pkix, err := x509.MarshalPKIXPublicKey(s.generateKey().Public()) if err != nil { return tls.Certificate{}, err } p, r, n := util.SplitName(instance) regionName := fmt.Sprintf("%s~%s", r, n) pubKey := string(pem.EncodeToMemory(&pem.Block{Bytes: pkix, Type: "RSA PUBLIC KEY"})) generateEphemeralCertRequest := &sqladmin.GenerateEphemeralCertRequest{ PublicKey: pubKey, } var tok *oauth2.Token // If IAM login is enabled, add the OAuth2 token into the ephemeral // certificate request. if s.EnableIAMLogin { var tokErr error tok, tokErr = s.TokenSource.Token() if tokErr != nil { return tls.Certificate{}, tokErr } // Always refresh the token to ensure its expiration is far enough in // the future. tok, tokErr = refreshToken(s.TokenSource, tok) if tokErr != nil { return tls.Certificate{}, tokErr } generateEphemeralCertRequest.AccessToken = tok.AccessToken } req := s.serv.Connect.GenerateEphemeralCert(p, regionName, generateEphemeralCertRequest) var data *sqladmin.GenerateEphemeralCertResponse err = backoffAPIRetry("generateEphemeral for", instance, func(staleRead time.Time) error { if !staleRead.IsZero() { generateEphemeralCertRequest.ReadTime = staleRead.Format(time.RFC3339) } data, err = req.Do() return err }) if err != nil { return tls.Certificate{}, err } c, err := parseCert(data.EphemeralCert.Cert) if err != nil { return tls.Certificate{}, fmt.Errorf("couldn't parse ephemeral certificate for instance %q: %v", instance, err) } if s.EnableIAMLogin { // Adjust the certificate's expiration to be the earlier of tok.Expiry or c.NotAfter if tok.Expiry.Before(c.NotAfter) { c.NotAfter = tok.Expiry } } return tls.Certificate{ Certificate: [][]byte{c.Raw}, PrivateKey: s.generateKey(), Leaf: c, }, nil } func parseCert(pemCert string) (*x509.Certificate, error) { bl, _ := pem.Decode([]byte(pemCert)) if bl == nil { return nil, errors.New("invalid PEM: " + pemCert) } return x509.ParseCertificate(bl.Bytes) } // Return the RSA private key, which is lazily initialized. func (s *RemoteCertSource) generateKey() *rsa.PrivateKey { s.keyOnce.Do(func() { start := time.Now() pkey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) // very unexpected. } logging.Verbosef("Generated RSA key in %v", time.Since(start)) s.key = pkey }) return s.key } // Find the first matching IP address by user input IP address types func (s *RemoteCertSource) findIPAddr(data *sqladmin.ConnectSettings, instance string) (ipAddrInUse string, err error) { for _, eachIPAddrTypeByUser := range s.IPAddrTypes { for _, eachIPAddrTypeOfInstance := range data.IpAddresses { if strings.ToUpper(eachIPAddrTypeOfInstance.Type) == strings.ToUpper(eachIPAddrTypeByUser) { ipAddrInUse = eachIPAddrTypeOfInstance.IpAddress return ipAddrInUse, nil } } } ipAddrTypesOfInstance := "" for _, eachIPAddrTypeOfInstance := range data.IpAddresses { ipAddrTypesOfInstance += fmt.Sprintf("(TYPE=%v, IP_ADDR=%v)", eachIPAddrTypeOfInstance.Type, eachIPAddrTypeOfInstance.IpAddress) } ipAddrTypeOfUser := fmt.Sprintf("%v", s.IPAddrTypes) return "", fmt.Errorf("User input IP address type %v does not match the instance %v, the instance's IP addresses are %v ", ipAddrTypeOfUser, instance, ipAddrTypesOfInstance) } // Remote returns the specified instance's CA certificate, address, and name. func (s *RemoteCertSource) Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) { p, region, n := util.SplitName(instance) regionName := fmt.Sprintf("%s~%s", region, n) req := s.serv.Connect.Get(p, regionName) var data *sqladmin.ConnectSettings err = backoffAPIRetry("get instance", instance, func(staleRead time.Time) error { if !staleRead.IsZero() { req.ReadTime(staleRead.Format(time.RFC3339)) } data, err = req.Do() return err }) if err != nil { return nil, "", "", "", err } // TODO(chowski): remove this when us-central is removed. if data.Region == "us-central" { data.Region = "us-central1" } if data.Region != region { if region == "" { err = fmt.Errorf("instance %v doesn't provide region", instance) } else { err = fmt.Errorf(`for connection string "%s": got region %q, want %q`, instance, region, data.Region) } if s.checkRegion { return nil, "", "", "", err } logging.Errorf("%v", err) logging.Errorf("WARNING: specifying the correct region in an instance string will become required in a future version!") } if len(data.IpAddresses) == 0 { return nil, "", "", "", fmt.Errorf("no IP address found for %v", instance) } if data.BackendType == "FIRST_GEN" { logging.Errorf("WARNING: proxy client does not support first generation Cloud SQL instances.") return nil, "", "", "", fmt.Errorf("%q is a first generation instance", instance) } // Find the first matching IP address by user input IP address types ipAddrInUse := "" ipAddrInUse, err = s.findIPAddr(data, instance) if err != nil { return nil, "", "", "", err } c, err := parseCert(data.ServerCaCert.Cert) return c, ipAddrInUse, p + ":" + n, data.DatabaseVersion, err } cloud-sql-proxy-1.33.14/proxy/certs/certs_test.go000066400000000000000000000132201452473605000217600ustar00rootroot00000000000000// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package certs import ( "context" "encoding/json" "fmt" "io/ioutil" "net/http" "net/http/httptest" "testing" "time" "google.golang.org/api/option" sqladmin "google.golang.org/api/sqladmin/v1beta4" ) const fakeCert = `-----BEGIN CERTIFICATE----- MIICgTCCAWmgAwIBAgIBADANBgkqhkiG9w0BAQsFADAAMCIYDzAwMDEwMTAxMDAw MDAwWhgPMDAwMTAxMDEwMDAwMDBaMAAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCvN0H6/ecloIfNyRu8KKtVSIK0JaW1lB1C1/ZI9iZmihqiUrxeyKTb 9hWuMPJ3u9NfSn1Vlwuj0bw7/T8e3Ol5BImcGxYxWMefkqFtqnjCafo2wnIea/eQ JFLt4wXYkeveHReUseGtaBzpCo4wYOiqgxyIrGiQ/rq4Xjr2hXuqTg4TTgxv+0Iv nrJwn61pitGvLPjsl9quzSQ6CdM3tWfb6cwozF5uJatbxRCZDsp1qUBXX9/zYqmx 8regdRG95btNgXLCfNS0iX0jopl00vGwYRGGKjfPZ5AkpuxX9M4Ys3X7pOspaQMC Zf4VjXdwOljqZxIOGhOBbrXQacSywTLjAgMBAAGjAjAAMA0GCSqGSIb3DQEBCwUA A4IBAQAXj/0iiU2AQGztlFstLVwQ9yz+7/pfqAr26DYu9hpI/QvrZsJWjwNUNlX+ 7gwhrwiJs7xsLZqnEr2qvj6at/MtxIEVgQd43sOsWW9de8R5WNQNzsCb+5npWcx7 vtcKXD9jFFLDDCIYjAf9+6m/QrMJtIf++zBmjguShccjZzY+GQih78oWqNTYqRQs //wOP15vFQ/gB4DcJ0UyO9icVgbJha66yzG7XABDEepha5uhpLhwFaONU8jMxW7A fOx52xqIUu3m4M3Ci0ZIp22TeGVuJ/Dy1CPbDOshcb0dXTE+mU5T91SHKRF4jz77 +9TQIXHGk7lJyVVhbed8xm/p727f -----END CERTIFICATE-----` func TestLocalCertSupportsStaleReads(t *testing.T) { var ( gotReadTimes []string ok bool ) handleEphemeralCert := func(w http.ResponseWriter, r *http.Request) { var actual sqladmin.GenerateEphemeralCertRequest data, err := ioutil.ReadAll(r.Body) if err != nil { t.Fatalf("failed to read request body: %v", err) } defer r.Body.Close() if err = json.Unmarshal(data, &actual); err != nil { t.Fatalf("failed to unmarshal request body: %v", err) } gotReadTimes = append(gotReadTimes, actual.ReadTime) if !ok { w.WriteHeader(http.StatusServiceUnavailable) fmt.Fprintln(w, `{"message":"the first request fails"}`) ok = true return } // the second request succeeds fmt.Fprintln(w, fmt.Sprintf(`{"ephemeralCert":{"cert": %q}}`, fakeCert)) } ts := httptest.NewServer(http.HandlerFunc(handleEphemeralCert)) defer ts.Close() cs := NewCertSourceOpts(ts.Client(), RemoteOpts{}) // replace SQL Admin API client with client backed by test server var err error cs.serv, err = sqladmin.NewService(context.Background(), option.WithEndpoint(ts.URL), option.WithHTTPClient(ts.Client())) if err != nil { t.Fatalf("failed to replace SQL Admin client: %v", err) } // Send request to generate a cert _, err = cs.Local("my-proj:reg:my-inst") if err != nil { t.Fatal(err) } // Verify read time is not present for first request // and is 30 seconds before "now" for second request if len(gotReadTimes) != 2 { t.Fatalf("expected two results, got = %v", len(gotReadTimes)) } if gotReadTimes[0] != "" { t.Fatalf("expected empty ReadTime for first request, got = %v", gotReadTimes[0]) } wantStaleness := 30 * time.Second if !staleTimestamp(gotReadTimes[1], wantStaleness) { t.Fatalf("expected timestamp at least %v old, got = %v (now = %v)", wantStaleness, gotReadTimes[1], time.Now().UTC().Format(time.RFC3339)) } } func staleTimestamp(ts string, staleness time.Duration) bool { t, err := time.Parse(time.RFC3339, ts) if err != nil { // ts was not in expected format, fail return false } return t.Before(time.Now().Add(-staleness)) } func TestRemoteCertSupportsStaleReads(t *testing.T) { var ( gotReadTimes []string ok bool ) handleConnectSettings := func(w http.ResponseWriter, r *http.Request) { rt := r.URL.Query()["readTime"] // if the URL parameter isn't nil, record its value; otherwise add an // empty string to indicate no query param was set if rt != nil { gotReadTimes = append(gotReadTimes, rt[0]) } else { gotReadTimes = append(gotReadTimes, "") } if !ok { w.WriteHeader(http.StatusServiceUnavailable) fmt.Fprintln(w, `{"message":"the first request fails"}`) ok = true return } fmt.Fprintln(w, fmt.Sprintf(`{ "region":"us-central1", "ipAddresses": [ {"type":"PRIMARY", "ipAddress":"127.0.0.1"} ], "serverCaCert": {"cert": %q} }`, fakeCert)) } ts := httptest.NewServer(http.HandlerFunc(handleConnectSettings)) defer ts.Close() cs := NewCertSourceOpts(ts.Client(), RemoteOpts{}) var err error // replace SQL Admin API client with client backed by test server cs.serv, err = sqladmin.NewService(context.Background(), option.WithEndpoint(ts.URL), option.WithHTTPClient(ts.Client())) if err != nil { t.Fatalf("failed to replace SQL Admin client: %v", err) } // Send request to retrieve instance metadata _, _, _, _, err = cs.Remote("my-proj:us-central1:my-inst") if err != nil { t.Fatal(err) } // Verify read time is not present for first request // and is 30 seconds before "now" for second request if len(gotReadTimes) != 2 { t.Fatalf("expected two results, got = %v", len(gotReadTimes)) } if gotReadTimes[0] != "" { t.Fatalf("expected empty ReadTime for first request, got = %v", gotReadTimes[0]) } wantStaleness := 30 * time.Second if !staleTimestamp(gotReadTimes[1], wantStaleness) { t.Fatalf("expected timestamp at least %v old, got = %v (now = %v)", wantStaleness, gotReadTimes[1], time.Now().UTC().Format(time.RFC3339)) } } cloud-sql-proxy-1.33.14/proxy/dialers/000077500000000000000000000000001452473605000175575ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/dialers/mysql/000077500000000000000000000000001452473605000207245ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/dialers/mysql/hook.go000066400000000000000000000076321452473605000222230ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package mysql adds a 'cloudsql' network to use when you want to access a // Cloud SQL Database via the mysql driver found at // github.com/go-sql-driver/mysql. It also exposes helper functions for // dialing. package mysql import ( "database/sql" "errors" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" "github.com/go-sql-driver/mysql" ) func init() { mysql.RegisterDialContext("cloudsql", proxy.DialContext) } // Dial logs into the specified Cloud SQL Instance using the given user and no // password. To set more options, consider calling DialCfg instead. // // The provided instance should be in the form project-name:region:instance-name. // // The returned *sql.DB may be valid even if there's also an error returned // (e.g. if there was a transient connection error). // // Deprecated: Dial has been replaced by the Cloud SQL Go connector which has // better support for configuring the dialer's behavior. // See cloud.google.com/go/cloudsqlconn/mysql/mysql.RegisterDriver instead. func Dial(instance, user string) (*sql.DB, error) { cfg := mysql.NewConfig() cfg.User = user cfg.Addr = instance return DialCfg(cfg) } // DialPassword is similar to Dial, but allows you to specify a password. // // Note that using a password with the proxy is not necessary as long as the // user's hostname in the mysql.user table is 'cloudsqlproxy~'. For more // information, see: // // https://cloud.google.com/sql/docs/sql-proxy#user // // Deprecated: DialPassword has been replaced by the Cloud SQL Go connector // which has better support for configuring the dialer's behavior. See // cloud.google.com/go/cloudsqlconn/mysql/mysql.RegisterDriver instead. func DialPassword(instance, user, password string) (*sql.DB, error) { cfg := mysql.NewConfig() cfg.User = user cfg.Passwd = password cfg.Addr = instance return DialCfg(cfg) } // Cfg returns the effective *mysql.Config to represent connectivity to the // provided instance via the given user and password. The config can be // modified and passed to DialCfg to connect. If you don't modify the returned // config before dialing, consider using Dial or DialPassword. // // Deprecated: Cfg has been replaced by the Cloud SQL Go connector which has // better support for configuring the dialer's behavior. // See cloud.google.com/go/cloudsqlconn/mysql/mysql.RegisterDriver instead. func Cfg(instance, user, password string) *mysql.Config { cfg := mysql.NewConfig() cfg.User = user cfg.Passwd = password cfg.Addr = instance cfg.Net = "cloudsql" return cfg } // DialCfg opens up a SQL connection to a Cloud SQL Instance specified by the // provided configuration. It is otherwise the same as Dial. // // The cfg.Addr should be the instance's connection string, in the format of: // // project-name:region:instance-name. // // Deprecated: DialCfg has been replaced by the Cloud SQL Go connector which has // better support for configuring the dialer's behavior. See // cloud.google.com/go/cloudsqlconn/mysql/mysql.RegisterDriver instead. func DialCfg(cfg *mysql.Config) (*sql.DB, error) { if cfg.TLSConfig != "" { return nil, errors.New("do not specify TLS when using the Proxy") } // Copy the config so that we can modify it without feeling bad. c := *cfg c.Net = "cloudsql" dsn := c.FormatDSN() db, err := sql.Open("mysql", dsn) if err == nil { err = db.Ping() } return db, err } cloud-sql-proxy-1.33.14/proxy/dialers/mysql/hook_test.go000066400000000000000000000026101452473605000232510ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package mysql_test import ( "fmt" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql" ) // ExampleCfg shows how to use Cloud SQL Auth proxy dialer if you must update some // settings normally passed in the DSN such as the DBName or timeouts. func ExampleCfg() { cfg := mysql.Cfg("project:region:instance-name", "user", "") cfg.DBName = "DB_1" cfg.ParseTime = true const timeout = 10 * time.Second cfg.Timeout = timeout cfg.ReadTimeout = timeout cfg.WriteTimeout = timeout db, err := mysql.DialCfg(cfg) if err != nil { panic("couldn't dial: " + err.Error()) } // Close db after this method exits since we don't need it for the // connection pooling. defer db.Close() var now time.Time fmt.Println(db.QueryRow("SELECT NOW()").Scan(&now)) fmt.Println(now) } cloud-sql-proxy-1.33.14/proxy/dialers/postgres/000077500000000000000000000000001452473605000214255ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/dialers/postgres/hook.go000066400000000000000000000053451452473605000227230ustar00rootroot00000000000000// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package postgres adds a 'cloudsqlpostgres' driver to use when you want // to access a Cloud SQL Database via the go database/sql library. // It is a wrapper over the driver found at github.com/lib/pq. // To use this driver, you can look at an example in // postgres_test package in the hook_test.go file package postgres import ( "database/sql" "database/sql/driver" "fmt" "net" "regexp" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" "github.com/lib/pq" ) func init() { sql.Register("cloudsqlpostgres", &Driver{}) } type Driver struct{} type dialer struct{} // instanceRegexp is used to parse the addr returned by lib/pq. // lib/pq returns the format '[project:region:instance]:port' var instanceRegexp = regexp.MustCompile(`^\[(.+)\]:[0-9]+$`) // Dial connects to the provider Cloud SQL instance. // // Deprecated: Dial has been replaced by the Cloud SQL Go connector which has // better support for configuring the dialer's behavior. See // cloud.google.com/go/cloudsqlconn/postgres/pgxv4.RegisterDriver instead. func (d dialer) Dial(ntw, addr string) (net.Conn, error) { matches := instanceRegexp.FindStringSubmatch(addr) if len(matches) != 2 { return nil, fmt.Errorf("failed to parse addr: %q. It should conform to the regular expression %q", addr, instanceRegexp) } instance := matches[1] return proxy.Dial(instance) } // DialTimeout connects to the provider Cloud SQL instance using the provided // timeout. // // Deprecated: DialTimeout has been replaced by the Cloud SQL Go connector which // has better support for configuring the dialer's behavior. See // cloud.google.com/go/cloudsqlconn/postgres/pgxv4.RegisterDriver instead. func (d dialer) DialTimeout(ntw, addr string, timeout time.Duration) (net.Conn, error) { return nil, fmt.Errorf("timeout is not currently supported for cloudsqlpostgres dialer") } // Deprecated: Open has been replaced by the Cloud SQL Go connector which has // better support for configuring the dialer's behavior. See // cloud.google.com/go/cloudsqlconn/postgres/pgxv4.RegisterDriver instead. func (d *Driver) Open(name string) (driver.Conn, error) { return pq.DialOpen(dialer{}, name) } cloud-sql-proxy-1.33.14/proxy/dialers/postgres/hook_test.go000066400000000000000000000025001452473605000237500ustar00rootroot00000000000000// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package postgres_test contains an example on how to use cloudsqlpostgres dialer package postgres_test import ( "database/sql" "fmt" "log" "time" _ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/postgres" ) // Example shows how to use cloudsqlpostgres dialer func Example() { // Note that sslmode=disable is required it does not mean that the connection // is unencrypted. All connections via the proxy are completely encrypted. db, err := sql.Open("cloudsqlpostgres", "host=project:region:instance user=postgres dbname=postgres password=password sslmode=disable") if err != nil { log.Fatal(err) } defer db.Close() var now time.Time fmt.Println(db.QueryRow("SELECT NOW()").Scan(&now)) fmt.Println(now) } cloud-sql-proxy-1.33.14/proxy/fuse/000077500000000000000000000000001452473605000170765ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/fuse/fuse.go000066400000000000000000000265611452473605000204010ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !windows && !openbsd && !freebsd // +build !windows,!openbsd,!freebsd // Package fuse provides a connection source wherein the user does not need to // specify which instance they are connecting to before they start the // executable. Instead, simply attempting to access a file in the provided // directory will transparently create a proxied connection to an instance // which has that name. // // Specifically, given that NewConnSrc was called with the mounting directory // as /cloudsql: // // 1. Execute `mysql -S /cloudsql/speckle:instance` // 2. The 'mysql' executable looks up the file "speckle:instance" inside "/cloudsql" // 3. This lookup is intercepted by the code in this package. A local unix socket // located in a temporary directory is opened for listening and the lookup for // "speckle:instance" returns to mysql saying that it is a symbolic link // pointing to this new local socket. // 4. mysql dials the local unix socket, creating a new connection to the // specified instance. package fuse import ( "bytes" "errors" "fmt" "io" "net" "os" "path/filepath" "strings" "sync" "syscall" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" "github.com/hanwen/go-fuse/v2/fuse/nodefs" "golang.org/x/net/context" ) // NewConnSrc returns a source of new connections based on Lookups in the // provided mount directory. If there isn't a directory located at tmpdir one // is created. The second return parameter can be used to shutdown and release // any resources. As a result of this shutdown, or during any other fatal // error, the returned chan will be closed. // // The connset parameter is optional. func NewConnSrc(mountdir, tmpdir string, client *proxy.Client, connset *proxy.ConnSet) (<-chan proxy.Conn, io.Closer, error) { if err := os.MkdirAll(tmpdir, 0777); err != nil { return nil, nil, err } if connset == nil { // Make a dummy one. connset = proxy.NewConnSet() } conns := make(chan proxy.Conn, 1) root := &fsRoot{ tmpDir: tmpdir, linkDir: mountdir, dst: conns, links: make(map[string]*symlink), connset: connset, client: client, } srv, err := fs.Mount(mountdir, root, &fs.Options{ MountOptions: fuse.MountOptions{AllowOther: true}, }) if err != nil { return nil, nil, fmt.Errorf("FUSE mount failed: %q: %v", mountdir, err) } closer := fuseCloser(func() error { err := srv.Unmount() // Best effort unmount if err != nil { logging.Errorf("Unmount failed: %v", err) } return root.Close() }) return conns, closer, nil } type fuseCloser func() error func (fc fuseCloser) Close() error { return fc() } // symlink implements a symbolic link, returning the underlying path when // Readlink is called. type symlink struct { fs.Inode path string } var _ fs.NodeReadlinker = &symlink{} func (s *symlink) Readlink(ctx context.Context) ([]byte, syscall.Errno) { return []byte(s.path), fs.OK } // fsRoot provides the in-memory file system that supports lazy connections to // Cloud SQL instances. type fsRoot struct { fs.Inode // tmpDir defines a temporary directory where all the sockets are placed // faciliating connections to Cloud SQL instances. tmpDir string // linkDir is the directory that holds symbolic links to the tmp dir for // each Cloud SQL instance connection. After shutdown, this directory is // cleaned out. linkDir string client *proxy.Client connset *proxy.ConnSet // sockLock protects fields in this struct related to sockets; specifically // 'links' and 'closers'. sockLock sync.Mutex links map[string]*symlink // closers includes a reference to all open Unix socket listeners. When // fs.Close is called, all of these listeners are also closed. closers []io.Closer sync.RWMutex dst chan<- proxy.Conn } var _ interface { fs.InodeEmbedder fs.NodeGetattrer fs.NodeLookuper fs.NodeReaddirer } = &fsRoot{} func (r *fsRoot) newConn(instance string, c net.Conn) { r.RLock() // dst will be nil if Close has been called already. if ch := r.dst; ch != nil { ch <- proxy.Conn{Instance: instance, Conn: c} } else { logging.Errorf("Ignored new conn request to %q: system has been closed", instance) } r.RUnlock() } // Close shuts down the fsRoot filesystem and closes all open Unix socket // listeners. func (r *fsRoot) Close() error { r.Lock() if r.dst != nil { // Since newConn only sends on dst while holding a reader lock, holding the // writer lock is sufficient to ensure there are no pending sends on the // channel when it is closed. close(r.dst) // Setting it to nil prevents further sends. r.dst = nil } r.Unlock() var errs bytes.Buffer r.sockLock.Lock() for _, c := range r.closers { if err := c.Close(); err != nil { fmt.Fprintln(&errs, err) } } r.sockLock.Unlock() if errs.Len() == 0 { return nil } logging.Errorf("Close %q: %v", r.linkDir, errs.String()) return errors.New(errs.String()) } // Getattr implements fs.NodeGetattrer and represents fsRoot as a directory. func (r *fsRoot) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { *out = fuse.AttrOut{Attr: fuse.Attr{ Mode: 0555 | fuse.S_IFDIR, }} return fs.OK } // Lookup implements fs.NodeLookuper and handles all requests, either for the // README, or for a new connection to a Cloud SQL instance. When receiving a // request for a Cloud SQL instance, Lookup will return a symlink to a Unix // socket that provides connectivity to a remote instance. func (r *fsRoot) Lookup(ctx context.Context, instance string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) { if instance == "README" { return r.NewInode(ctx, &readme{}, fs.StableAttr{}), fs.OK } r.sockLock.Lock() defer r.sockLock.Unlock() if _, _, _, _, err := proxy.ParseInstanceConnectionName(instance); err != nil { return nil, syscall.ENOENT } if ret, ok := r.links[instance]; ok { return ret.EmbeddedInode(), fs.OK } // path is the location of the Unix socket path := filepath.Join(r.tmpDir, instance) os.RemoveAll(path) // Best effort; the following will fail if this does. // linkpath is the location the symlink points to linkpath := path // Add a ".s.PGSQL.5432" suffix to path for Postgres instances if r.client != nil { version, err := r.client.InstanceVersionContext(ctx, instance) if err != nil { logging.Errorf("Failed to get Instance version for %s: %v", instance, err) return nil, syscall.ENOENT } if strings.HasPrefix(strings.ToLower(version), "postgres") { if err := os.MkdirAll(path, 0755); err != nil { logging.Errorf("Failed to create path %s: %v", path, err) return nil, syscall.EIO } path = filepath.Join(linkpath, ".s.PGSQL.5432") } } // TODO: check path length -- if it exceeds the max supported socket length, // return an error that helps the user understand what went wrong. // Otherwise, we get a "bind: invalid argument" error. sock, err := net.Listen("unix", path) if err != nil { logging.Errorf("couldn't listen at %q: %v", path, err) return nil, syscall.EEXIST } if err := os.Chmod(path, 0777|os.ModeSocket); err != nil { logging.Errorf("couldn't update permissions for socket file %q: %v; other users may be unable to connect", path, err) } go r.listenerLifecycle(sock, instance, path) ret := &symlink{path: linkpath} inode := r.NewInode(ctx, ret, fs.StableAttr{Mode: 0777 | fuse.S_IFLNK}) r.links[instance] = ret // TODO(chowski): memory leak when listeners exit on their own via removeListener. r.closers = append(r.closers, sock) return inode, fs.OK } // removeListener marks that a Listener for an instance has exited and is no // longer serving new connections. func (r *fsRoot) removeListener(instance, path string) { r.sockLock.Lock() defer r.sockLock.Unlock() v, ok := r.links[instance] if ok && v.path == path { delete(r.links, instance) } else { logging.Errorf("Removing a listener for %q at %q which was already replaced", instance, path) } } // listenerLifecycle calls l.Accept in a loop, and for each new connection // r.newConn is called. After the Listener returns an error it is removed. func (r *fsRoot) listenerLifecycle(l net.Listener, instance, path string) { for { start := time.Now() c, err := l.Accept() if err != nil { logging.Errorf("error in Accept for %q: %v", instance, err) if nerr, ok := err.(net.Error); ok && nerr.Temporary() { d := 10*time.Millisecond - time.Since(start) if d > 0 { time.Sleep(d) } continue } break } r.newConn(instance, c) } r.removeListener(instance, path) l.Close() if err := os.Remove(path); err != nil { logging.Errorf("couldn't remove %q: %v", path, err) } } // Readdir implements fs.NodeReaddirer and returns a list of files for each // instance to which the proxy is actively connected. In addition, the list // includes a README. func (r *fsRoot) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { activeConns := r.connset.IDs() entries := []fuse.DirEntry{ {Name: "README", Mode: 0555 | fuse.S_IFREG}, } for _, conn := range activeConns { entries = append(entries, fuse.DirEntry{ Name: conn, Mode: 0777 | syscall.S_IFSOCK, }) } ds := fs.NewListDirStream(entries) return ds, fs.OK } // readme represents a static read-only text file. type readme struct { fs.Inode } var _ interface { fs.InodeEmbedder fs.NodeGetattrer fs.NodeReader fs.NodeOpener } = &readme{} const readmeText = ` When programs attempt to open files in this directory, a remote connection to the Cloud SQL instance of the same name will be established. That is, running: mysql -u root -S "/path/to/this/directory/project:region:instance-2" -or- psql "host=/path/to/this/directory/project:region:instance-2 dbname=mydb user=myuser" will open a new connection to the specified instance, given you have the correct permissions. Listing the contents of this directory will show all instances with active connections. ` // Getattr implements fs.NodeGetattrer and indicates that this file is a regular // file. func (*readme) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { *out = fuse.AttrOut{Attr: fuse.Attr{ Mode: 0444 | syscall.S_IFREG, Size: uint64(len(readmeText)), }} return fs.OK } // Read implements fs.NodeReader and supports incremental reads. func (*readme) Read(ctx context.Context, f fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { end := int(off) + len(dest) if end > len(readmeText) { end = len(readmeText) } return fuse.ReadResultData([]byte(readmeText[off:end])), fs.OK } // Open implements fs.NodeOpener and supports opening the README as a read-only // file. func (*readme) Open(ctx context.Context, mode uint32) (fs.FileHandle, uint32, syscall.Errno) { df := nodefs.NewDataFile([]byte(readmeText)) rf := nodefs.NewReadOnlyFile(df) return rf, 0, fs.OK } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_darwin.go000066400000000000000000000030161452473605000217330ustar00rootroot00000000000000// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fuse import ( "os" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" ) const ( macfusePath = "/Library/Filesystems/macfuse.fs/Contents/Resources/mount_macfuse" osxfusePath = "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse" ) // Supported checks if macfuse or osxfuse are installed on the host by looking // for both in their known installation location. func Supported() bool { // This code follows the same strategy as hanwen/go-fuse. // See https://github.com/hanwen/go-fuse/blob/0f728ba15b38579efefc3dc47821882ca18ffea7/fuse/mount_darwin.go#L121-L124. // check for macfuse first (newer version of osxfuse) if _, err := os.Stat(macfusePath); err != nil { // if that fails, check for osxfuse next if _, err := os.Stat(osxfusePath); err != nil { logging.Errorf("Failed to find osxfuse or macfuse. Verify FUSE installation and try again (see https://osxfuse.github.io).") return false } } return true } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_freebsd.go000066400000000000000000000017721452473605000220700ustar00rootroot00000000000000// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package fuse is a package stub for freebsd, which isn't supported by our fuse // library. package fuse import ( "errors" "io" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" ) func Supported() bool { return false } func NewConnSrc(mountdir, tmpdir string, client *proxy.Client, connset *proxy.ConnSet) (<-chan proxy.Conn, io.Closer, error) { return nil, nil, errors.New("fuse not supported on freebsd") } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_linux.go000066400000000000000000000023061452473605000216070ustar00rootroot00000000000000// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fuse import ( "os/exec" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" ) // Supported returns true if the current system supports FUSE. func Supported() bool { // This code follows the same strategy found in hanwen/go-fuse. // See https://github.com/hanwen/go-fuse/blob/0f728ba15b38579efefc3dc47821882ca18ffea7/fuse/mount_linux.go#L184-L198. if _, err := exec.LookPath("fusermount"); err != nil { if _, err := exec.LookPath("/bin/fusermount"); err != nil { logging.Errorf("Failed to find fusermount binary in PATH or /bin. Verify FUSE installation and try again.") return false } } return true } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_linux_test.go000066400000000000000000000022141452473605000226440ustar00rootroot00000000000000// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // +build linux package fuse_test import ( "os" "testing" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/fuse" ) func TestFUSESupport(t *testing.T) { if testing.Short() { t.Skip("skipping fuse tests in short mode.") } removePath := func() func() { original := os.Getenv("PATH") os.Unsetenv("PATH") return func() { os.Setenv("PATH", original) } } if !fuse.Supported() { t.Fatal("expected FUSE to be supported") } cleanup := removePath() defer cleanup() if !fuse.Supported() { t.Fatal("expected FUSE to be supported") } } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_openbsd.go000066400000000000000000000020201452473605000220730ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package fuse is a package stub for openbsd, which isn't supported by our // fuse library. package fuse import ( "errors" "io" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" ) func Supported() bool { return false } func NewConnSrc(mountdir, tmpdir string, client *proxy.Client, connset *proxy.ConnSet) (<-chan proxy.Conn, io.Closer, error) { return nil, nil, errors.New("fuse not supported on openbsd") } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_test.go000066400000000000000000000126251452473605000214340ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !windows && !darwin // +build !windows,!darwin package fuse import ( "bytes" "io" "io/ioutil" "net" "os" "path/filepath" "sync" "syscall" "testing" "time" ) func randTmpDir(t interface { Fatalf(format string, args ...interface{}) }) string { name, err := ioutil.TempDir("", "*") if err != nil { t.Fatalf("failed to create tmp dir: %v", err) } return name } // tryFunc executes the provided function up to maxCount times, sleeping 100ms // between attempts. func tryFunc(f func() error, maxCount int) error { var errCount int for { err := f() if err == nil { return nil } errCount++ if errCount == maxCount { return err } time.Sleep(100 * time.Millisecond) } } func TestFuseClose(t *testing.T) { if testing.Short() { t.Skip("skipping fuse tests in short mode.") } dir := randTmpDir(t) tmpdir := randTmpDir(t) src, fuse, err := NewConnSrc(dir, tmpdir, nil, nil) if err != nil { t.Fatal(err) } if err := tryFunc(fuse.Close, 10); err != nil { t.Fatal(err) } if got, ok := <-src; ok { t.Fatalf("got new connection %#v, expected closed source", got) } } // TestBadDir verifies that the fuse module does not create directories, only simple files. func TestBadDir(t *testing.T) { if testing.Short() { t.Skip("skipping fuse tests in short mode.") } dir := randTmpDir(t) tmpdir := randTmpDir(t) _, fuse, err := NewConnSrc(dir, tmpdir, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := tryFunc(fuse.Close, 10); err != nil { t.Fatal(err) } }() _, err = os.Stat(filepath.Join(dir, "proj:region:inst-1", "proj:region:inst-2")) if err == nil { t.Fatal("able to find a directory inside the mount point, expected only regular files") } if err := err.(*os.PathError); err.Err != syscall.ENOTDIR { t.Fatalf("got %#v, want ENOTDIR (%v)", err.Err, syscall.ENOTDIR) } } func TestReadme(t *testing.T) { if testing.Short() { t.Skip("skipping fuse tests in short mode.") } dir := randTmpDir(t) tmpdir := randTmpDir(t) _, fuse, err := NewConnSrc(dir, tmpdir, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := tryFunc(fuse.Close, 10); err != nil { t.Fatal(err) } }() data, err := ioutil.ReadFile(filepath.Join(dir, "README")) if err != nil { t.Fatal(err) } // We just care that the file exists. Print out the contents for // informational purposes. t.Log(string(data)) } func TestSingleInstance(t *testing.T) { if testing.Short() { t.Skip("skipping fuse tests in short mode.") } dir := randTmpDir(t) tmpdir := randTmpDir(t) src, fuse, err := NewConnSrc(dir, tmpdir, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := tryFunc(fuse.Close, 10); err != nil { t.Fatal(err) } }() const want = "test:instance:string" path := filepath.Join(dir, want) fi, err := os.Stat(path) if err != nil { t.Fatal(err) } if fi.Mode()&os.ModeType != os.ModeSocket { t.Fatalf("%q had mode %v (%X), expected a socket file", path, fi.Mode(), uint32(fi.Mode())) } c, err := net.Dial("unix", path) if err != nil { t.Fatal(err) } defer c.Close() got, ok := <-src if !ok { t.Fatal("connection source was closed, expected a connection") } else if got.Instance != want { t.Fatalf("got %q, want %q", got.Instance, want) } else if got.Conn == nil { t.Fatal("got nil connection, wanted a connection") } const sent = "test string" go func() { if _, err := c.Write([]byte(sent)); err != nil { t.Error(err) } if err := c.Close(); err != nil { t.Error(err) } }() gotData := new(bytes.Buffer) if _, err := io.Copy(gotData, got.Conn); err != nil { t.Fatal(err) } else if gotData.String() != sent { t.Fatalf("got %q, want %v", gotData.String(), sent) } } func BenchmarkNewConnection(b *testing.B) { if testing.Short() { b.Skip("skipping fuse tests in short mode.") } dir := randTmpDir(b) tmpdir := randTmpDir(b) src, fuse, err := NewConnSrc(dir, tmpdir, nil, nil) if err != nil { b.Fatal(err) } const want = "X" incomingCount := 0 var incoming sync.Mutex // Is unlocked when the following goroutine exits. go func() { incoming.Lock() defer incoming.Unlock() for c := range src { c.Conn.Write([]byte(want)) c.Conn.Close() incomingCount++ } }() const instance = "test:instance:string" path := filepath.Join(dir, instance) b.ResetTimer() for i := 0; i < b.N; i++ { c, err := net.Dial("unix", path) if err != nil { b.Errorf("couldn't dial: %v", err) } data, err := ioutil.ReadAll(c) if err != nil { b.Errorf("got read error: %v", err) } else if got := string(data); got != want { b.Errorf("read %q, want %q", string(data), want) } } if err := fuse.Close(); err != nil { b.Fatal(err) } // Wait for the 'incoming' goroutine to finish. incoming.Lock() if incomingCount != b.N { b.Fatalf("got %d connections, want %d", incomingCount, b.N) } } cloud-sql-proxy-1.33.14/proxy/fuse/fuse_windows.go000066400000000000000000000017771452473605000221550ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package fuse is a package stub for windows, which does not support FUSE. package fuse import ( "errors" "io" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" ) func Supported() bool { return false } func NewConnSrc(mountdir, tmpdir string, client *proxy.Client, connset *proxy.ConnSet) (<-chan proxy.Conn, io.Closer, error) { return nil, nil, errors.New("fuse not supported on windows") } cloud-sql-proxy-1.33.14/proxy/limits/000077500000000000000000000000001452473605000174355ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/limits/limits.go000066400000000000000000000064501452473605000212720ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !windows && !freebsd // +build !windows,!freebsd // Package limits provides routines to check and enforce certain resource // limits on the Cloud SQL client proxy process. package limits import ( "fmt" "syscall" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" ) var ( // For overriding in unittests. syscallGetrlimit = syscall.Getrlimit syscallSetrlimit = syscall.Setrlimit ) // Each connection handled by the proxy requires two file descriptors, one // for the local end of the connection and one for the remote. So, the proxy // process should be able to open at least 8K file descriptors if it is to // handle 4K connections to one instance. const ExpectedFDs = 8500 // SetupFDLimits ensures that the process running the Cloud SQL proxy can have // at least wantFDs number of open file descriptors. It returns an error if it // cannot ensure the same. func SetupFDLimits(wantFDs uint64) error { rlim := &syscall.Rlimit{} if err := syscallGetrlimit(syscall.RLIMIT_NOFILE, rlim); err != nil { return fmt.Errorf("failed to read rlimit for max file descriptors: %v", err) } if rlim.Cur >= wantFDs { logging.Verbosef("current FDs rlimit set to %d, wanted limit is %d. Nothing to do here.", rlim.Cur, wantFDs) return nil } // Linux man page: // The soft limit is the value that the kernel enforces for the corre‐ // sponding resource. The hard limit acts as a ceiling for the soft limit: // an unprivileged process may set only its soft limit to a value in the // range from 0 up to the hard limit, and (irreversibly) lower its hard // limit. A privileged process (under Linux: one with the CAP_SYS_RESOURCE // capability in the initial user namespace) may make arbitrary changes to // either limit value. if rlim.Max < wantFDs { // When the hard limit is less than what is requested, let's just give it a // shot, and if we fail, we fallback and try just setting the softlimit. rlim2 := &syscall.Rlimit{} rlim2.Max = wantFDs rlim2.Cur = wantFDs if err := syscallSetrlimit(syscall.RLIMIT_NOFILE, rlim2); err == nil { logging.Verbosef("Rlimits for file descriptors set to {Current = %v, Max = %v}", rlim2.Cur, rlim2.Max) return nil } } rlim.Cur = wantFDs if err := syscallSetrlimit(syscall.RLIMIT_NOFILE, rlim); err != nil { return fmt.Errorf( `failed to set rlimit {Current = %v, Max = %v} for max file descriptors. The hard limit on file descriptors (4096) is lower than the requested rlimit. The proxy will only be able to handle ~2048 connections. To hide this message, please request a limit within the available range.`, rlim.Cur, rlim.Max, ) } logging.Verbosef("Rlimits for file descriptors set to {Current = %v, Max = %v}", rlim.Cur, rlim.Max) return nil } cloud-sql-proxy-1.33.14/proxy/limits/limits_freebsd.go000066400000000000000000000057711452473605000227710ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build freebsd // +build freebsd // Package limits provides routines to check and enforce certain resource // limits on the Cloud SQL client proxy process. package limits import ( "fmt" "syscall" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" ) var ( // For overriding in unittests. syscallGetrlimit = syscall.Getrlimit syscallSetrlimit = syscall.Setrlimit ) // Each connection handled by the proxy requires two file descriptors, one // for the local end of the connection and one for the remote. So, the proxy // process should be able to open at least 8K file descriptors if it is to // handle 4K connections to one instance. const ExpectedFDs = 8500 // SetupFDLimits ensures that the process running the Cloud SQL proxy can have // at least wantFDs number of open file descriptors. It returns an error if it // cannot ensure the same. func SetupFDLimits(wantFDs uint64) error { rlim := &syscall.Rlimit{} if err := syscallGetrlimit(syscall.RLIMIT_NOFILE, rlim); err != nil { return fmt.Errorf("failed to read rlimit for max file descriptors: %v", err) } if uint64(rlim.Cur) >= wantFDs { logging.Verbosef("current FDs rlimit set to %d, wanted limit is %d. Nothing to do here.", rlim.Cur, wantFDs) return nil } // Linux man page: // The soft limit is the value that the kernel enforces for the corre‐ // sponding resource. The hard limit acts as a ceiling for the soft limit: // an unprivileged process may set only its soft limit to a value in the // range from 0 up to the hard limit, and (irreversibly) lower its hard // limit. A privileged process (under Linux: one with the CAP_SYS_RESOURCE // capability in the initial user namespace) may make arbitrary changes to // either limit value. if uint64(rlim.Max) < wantFDs { // When the hard limit is less than what is requested, let's just give it a // shot, and if we fail, we fallback and try just setting the softlimit. rlim2 := &syscall.Rlimit{} rlim2.Max = int64(wantFDs) rlim2.Cur = int64(wantFDs) if err := syscallSetrlimit(syscall.RLIMIT_NOFILE, rlim2); err == nil { logging.Verbosef("Rlimits for file descriptors set to {%v}", rlim2) return nil } } rlim.Cur = int64(wantFDs) if err := syscallSetrlimit(syscall.RLIMIT_NOFILE, rlim); err != nil { return fmt.Errorf("failed to set rlimit {%v} for max file descriptors: %v", rlim, err) } logging.Verbosef("Rlimits for file descriptors set to {%v}", rlim) return nil } cloud-sql-proxy-1.33.14/proxy/limits/limits_test.go000066400000000000000000000063161452473605000223320ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !windows // +build !windows package limits import ( "errors" "math" "syscall" "testing" ) type rlimitFunc func(int, *syscall.Rlimit) error func TestSetupFDLimits(t *testing.T) { tests := []struct { desc string getFunc rlimitFunc setFunc rlimitFunc wantFDs uint64 wantErr bool }{ { desc: "Getrlimit fails", getFunc: func(_ int, _ *syscall.Rlimit) error { return errors.New("failed to read rlimit for max file descriptors") }, setFunc: func(_ int, _ *syscall.Rlimit) error { panic("shouldn't be called") }, wantFDs: 0, wantErr: true, }, { desc: "Getrlimit max is less than wantFDs", getFunc: func(_ int, rlim *syscall.Rlimit) error { rlim.Cur = 512 rlim.Max = 512 return nil }, setFunc: func(_ int, rlim *syscall.Rlimit) error { if rlim.Cur != 1024 || rlim.Max != 1024 { return errors.New("setrlimit called with unexpected value") } return nil }, wantFDs: 1024, wantErr: false, }, { desc: "Getrlimit returns rlim_infinity", getFunc: func(_ int, rlim *syscall.Rlimit) error { rlim.Cur = math.MaxUint64 rlim.Max = math.MaxUint64 return nil }, setFunc: func(_ int, _ *syscall.Rlimit) error { panic("shouldn't be called") }, wantFDs: 1024, wantErr: false, }, { desc: "Getrlimit cur is greater than wantFDs", getFunc: func(_ int, rlim *syscall.Rlimit) error { rlim.Cur = 512 rlim.Max = 512 return nil }, setFunc: func(_ int, _ *syscall.Rlimit) error { panic("shouldn't be called") }, wantFDs: 256, wantErr: false, }, { desc: "Setrlimit fails", getFunc: func(_ int, rlim *syscall.Rlimit) error { rlim.Cur = 128 rlim.Max = 512 return nil }, setFunc: func(_ int, _ *syscall.Rlimit) error { return errors.New("failed to set rlimit for max file descriptors") }, wantFDs: 256, wantErr: true, }, { desc: "Success", getFunc: func(_ int, rlim *syscall.Rlimit) error { rlim.Cur = 128 rlim.Max = 512 return nil }, setFunc: func(_ int, _ *syscall.Rlimit) error { return nil }, wantFDs: 256, wantErr: false, }, } for _, test := range tests { oldGetFunc := syscallGetrlimit syscallGetrlimit = test.getFunc defer func() { syscallGetrlimit = oldGetFunc }() oldSetFunc := syscallSetrlimit syscallSetrlimit = test.setFunc defer func() { syscallSetrlimit = oldSetFunc }() gotErr := SetupFDLimits(test.wantFDs) if (gotErr != nil) != test.wantErr { t.Errorf("%s: limits.SetupFDLimits(%d) returned error %v, wantErr %v", test.desc, test.wantFDs, gotErr, test.wantErr) } } } cloud-sql-proxy-1.33.14/proxy/limits/limits_windows.go000066400000000000000000000017621452473605000230450ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package limits is a package stub for windows, and we currently don't support // setting limits in windows. package limits import "errors" // We don't support limit on the number of file handles in windows. const ExpectedFDs = 0 func SetupFDLimits(wantFDs uint64) error { if wantFDs != 0 { return errors.New("setting limits on the number of file handles is not supported") } return nil } cloud-sql-proxy-1.33.14/proxy/proxy/000077500000000000000000000000001452473605000173155ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/proxy/client.go000066400000000000000000000535711452473605000211350ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package proxy import ( "context" "crypto/tls" "crypto/x509" "errors" "fmt" "net" "strings" "sync" "sync/atomic" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/util" "golang.org/x/net/proxy" "golang.org/x/time/rate" ) const ( // DefaultRefreshCfgThrottle is the time a refresh attempt must wait since // the last attempt. DefaultRefreshCfgThrottle = time.Minute // IAMLoginRefreshThrottle is the time a refresh attempt must wait since the // last attempt when using IAM login. IAMLoginRefreshThrottle = 30 * time.Second keepAlivePeriod = time.Minute // DefaultRefreshCfgBuffer is the minimum amount of time for which a // certificate must be valid to ensure the next refresh attempt has adequate // time to complete. DefaultRefreshCfgBuffer = 5 * time.Minute // IAMLoginRefreshCfgBuffer is the minimum amount of time for which a // certificate holding an Access Token must be valid. Because some token // sources (e.g., ouath2.ComputeTokenSource) are refreshed with only ~60 // seconds before expiration, this value must be smaller than the // DefaultRefreshCfgBuffer. IAMLoginRefreshCfgBuffer = 55 * time.Second ) var ( // errNotCached is returned when the instance was not found in the Client's // cache. It is an internal detail and is not actually ever returned to the // user. errNotCached = errors.New("instance was not found in cache") ) // Conn represents a connection from a client to a specific instance. type Conn struct { Instance string Conn net.Conn } // CertSource is how a Client obtains various certificates required for operation. type CertSource interface { // Local returns a certificate that can be used to authenticate with the // provided instance. Local(instance string) (tls.Certificate, error) // Remote returns the instance's CA certificate, address, and name. Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) } // Client is a type to handle connecting to a Server. All fields are required // unless otherwise specified. type Client struct { // ConnectionsCounter is used to enforce the optional maxConnections limit ConnectionsCounter uint64 // MaxConnections is the maximum number of connections to establish // before refusing new connections. 0 means no limit. MaxConnections uint64 // Port designates which remote port should be used when connecting to // instances. This value is defined by the server-side code, but for now it // should always be 3307. Port int // Required; specifies how certificates are obtained. Certs CertSource // Optionally tracks connections through this client. If nil, connections // are not tracked and will not be closed before method Run exits. Conns *ConnSet // ContextDialer should return a new connection to the provided address. // It is called on each new connection to an instance. // If left nil, Dialer will be tried first, and if that one is nil too then net.Dial will be used. ContextDialer func(ctx context.Context, net, addr string) (net.Conn, error) // Dialer should return a new connection to the provided address. It will be used only if ContextDialer is nil. Dialer func(net, addr string) (net.Conn, error) // The cfgCache holds the most recent connection configuration keyed by // instance. Relevant functions are refreshCfg and cachedCfg. It is // protected by cacheL. cfgCache map[string]cacheEntry cacheL sync.RWMutex // limiters holds a rate limiter keyed by instance. It is protected by // cacheL. limiters map[string]*rate.Limiter // refreshCfgL prevents multiple goroutines from contacting the Cloud SQL API at once. refreshCfgL sync.Mutex // RefreshCfgThrottle is the amount of time to wait between configuration // refreshes. If not set, it defaults to 1 minute. // // This is to prevent quota exhaustion in the case of client-side // malfunction. RefreshCfgThrottle time.Duration // RefreshCertBuffer is the amount of time before the configuration expires // to attempt to refresh it. If not set, it defaults to 5 minutes. When IAM // Login is enabled, this value should be set to IAMLoginRefreshCfgBuffer. RefreshCfgBuffer time.Duration } type cacheEntry struct { lastRefreshed time.Time // If err is not nil, the addr and cfg are not valid. err error addr string version string cfg *tls.Config // done represents the status of any pending refresh operation related to this instance. // If unset the op hasn't started, if open the op is still pending, and if closed the op has finished. done chan struct{} } // Run causes the client to start waiting for new connections to connSrc and // proxy them to the destination instance. It blocks until connSrc is closed. func (c *Client) Run(connSrc <-chan Conn) { c.RunContext(context.Background(), connSrc) } func (c *Client) run(ctx context.Context, connSrc <-chan Conn) { for { select { case conn, ok := <-connSrc: if !ok { return } go c.handleConn(ctx, conn) case <-ctx.Done(): return } } } // RunContext is like Run with an additional context.Context argument. func (c *Client) RunContext(ctx context.Context, connSrc <-chan Conn) { c.run(ctx, connSrc) if err := c.Conns.Close(); err != nil { logging.Errorf("closing client had error: %v", err) } } func (c *Client) handleConn(ctx context.Context, conn Conn) { active := atomic.AddUint64(&c.ConnectionsCounter, 1) // Deferred decrement of ConnectionsCounter upon connection closing defer atomic.AddUint64(&c.ConnectionsCounter, ^uint64(0)) if c.MaxConnections > 0 && active > c.MaxConnections { logging.Errorf("too many open connections (max %d)", c.MaxConnections) conn.Conn.Close() return } server, err := c.DialContext(ctx, conn.Instance) if err != nil { logging.Errorf("couldn't connect to %q: %v", conn.Instance, err) conn.Conn.Close() return } c.Conns.Add(conn.Instance, conn.Conn) copyThenClose(server, conn.Conn, conn.Instance, "local connection on "+conn.Conn.LocalAddr().String()) if err := c.Conns.Remove(conn.Instance, conn.Conn); err != nil { logging.Errorf("%s", err) } } // refreshCfg uses the CertSource inside the Client to find the instance's // address as well as construct a new tls.Config to connect to the instance. // This function should only be called from the scope of "cachedCfg", which // controls the logic around throttling. func (c *Client) refreshCfg(instance string) (addr string, cfg *tls.Config, version string, err error) { c.refreshCfgL.Lock() defer c.refreshCfgL.Unlock() logging.Verbosef("refreshing ephemeral certificate for instance %s", instance) mycert, err := c.Certs.Local(instance) if err != nil { return "", nil, "", err } scert, addr, name, version, err := c.Certs.Remote(instance) if err != nil { return "", nil, "", err } certs := x509.NewCertPool() certs.AddCert(scert) cfg = &tls.Config{ ServerName: name, Certificates: []tls.Certificate{mycert}, RootCAs: certs, // We need to set InsecureSkipVerify to true due to // https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/194 // https://tip.golang.org/doc/go1.11#crypto/x509 // // Since we have a secure channel to the Cloud SQL API which we use to retrieve the // certificates, we instead need to implement our own VerifyPeerCertificate function // that will verify that the certificate is OK. InsecureSkipVerify: true, VerifyPeerCertificate: genVerifyPeerCertificateFunc(name, certs), MinVersion: tls.VersionTLS13, } return fmt.Sprintf("%s:%d", addr, c.Port), cfg, version, nil } // refreshCertAfter refreshes the epehemeral certificate of the instance after timeToRefresh. func (c *Client) refreshCertAfter(instance string, timeToRefresh time.Duration) { <-time.After(timeToRefresh.Round(0)) logging.Verbosef("ephemeral certificate for instance %s will expire soon, refreshing now.", instance) if _, _, _, err := c.cachedCfg(context.Background(), instance); err != nil { logging.Errorf("failed to refresh the ephemeral certificate for %s before expiring: %v", instance, err) } } // genVerifyPeerCertificateFunc creates a VerifyPeerCertificate func that verifies that the peer // certificate is in the cert pool. We need to define our own because of our sketchy non-standard // CNs. func genVerifyPeerCertificateFunc(instanceName string, pool *x509.CertPool) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { if len(rawCerts) == 0 { return fmt.Errorf("no certificate to verify") } cert, err := x509.ParseCertificate(rawCerts[0]) if err != nil { return fmt.Errorf("x509.ParseCertificate(rawCerts[0]) returned error: %v", err) } opts := x509.VerifyOptions{Roots: pool} if _, err = cert.Verify(opts); err != nil { return err } if cert.Subject.CommonName != instanceName { return fmt.Errorf("certificate had CN %q, expected %q", cert.Subject.CommonName, instanceName) } return nil } } func isExpired(cfg *tls.Config) bool { if cfg == nil { return true } return time.Now().After(cfg.Certificates[0].Leaf.NotAfter) } // startRefresh kicks off a refreshCfg asynchronously, that updates the cacheEntry and closes the returned channel once the refresh is completed. This function // should only be called from the scope of "cachedCfg", which controls the logic around throttling refreshes. func (c *Client) startRefresh(instance string, refreshCfgBuffer time.Duration) chan struct{} { done := make(chan struct{}) go func() { defer close(done) addr, cfg, ver, err := c.refreshCfg(instance) c.cacheL.Lock() old := c.cfgCache[instance] // if we failed to refresh cfg do not throw out potentially valid one if err != nil && !isExpired(old.cfg) { logging.Errorf("failed to refresh the ephemeral certificate for %s, returning previous cert instead: %v", instance, err) addr, cfg, ver, err = old.addr, old.cfg, old.version, old.err } e := cacheEntry{ lastRefreshed: time.Now(), err: err, addr: addr, version: ver, cfg: cfg, done: done, } c.cfgCache[instance] = e c.cacheL.Unlock() if !isValid(e) { // Note: Future refreshes will not be scheduled unless another // connection attempt is made. logging.Errorf("failed to refresh the ephemeral certificate for %v: %v", instance, err) return } certExpiration := cfg.Certificates[0].Leaf.NotAfter now := time.Now() timeToRefresh := certExpiration.Sub(now) - refreshCfgBuffer if timeToRefresh <= 0 { // If a new certificate expires before our buffer has expired, we should wait a bit and schedule a new refresh to much closer to the expiration's date // This situation probably only occurs when the oauth2 token isn't refreshed before the cert is, so by scheduling closer to the expiration we can hope the oauth2 token is newer. timeToRefresh = certExpiration.Sub(now) - (5 * time.Second) logging.Errorf("new ephemeral certificate expires sooner than expected (adjusting refresh time to compensate): current time: %v, certificate expires: %v", now, certExpiration) } logging.Infof("Scheduling refresh of ephemeral certificate in %s", timeToRefresh.Round(time.Second)) go c.refreshCertAfter(instance, timeToRefresh) }() return done } // isValid returns true if the cacheEntry is still useable func isValid(c cacheEntry) bool { // the entry is only valid there wasn't an error retrieving it and it has a cfg return c.err == nil && c.cfg != nil } // InvalidError is an error from an instance connection that is invalid because // its recent refresh attempt has failed, its TLS config is invalid, etc. type InvalidError struct { // instance is the instance connection name instance string // err is what makes the instance invalid err error // hasTLS reports whether the instance has a valid TLS config hasTLS bool } func (e *InvalidError) Error() string { if e.hasTLS { return e.instance + ": " + e.err.Error() } return e.instance + ": missing TLS config, " + e.err.Error() } // InvalidInstances reports whether the existing connections have valid // configuration. func (c *Client) InvalidInstances() []*InvalidError { c.cacheL.RLock() defer c.cacheL.RUnlock() var invalid []*InvalidError for instance, entry := range c.cfgCache { var refreshInProgress bool select { case <-entry.done: // refresh has already completed default: refreshInProgress = true } if !isValid(entry) && !refreshInProgress { invalid = append(invalid, &InvalidError{ instance: instance, err: entry.err, hasTLS: entry.cfg != nil, }) } } return invalid } func needsRefresh(e cacheEntry, refreshCfgBuffer time.Duration) bool { if e.done == nil { // no refresh started return true } if !isValid(e) || e.cfg.Certificates[0].Leaf.NotAfter.Sub(time.Now().Round(0)) <= refreshCfgBuffer { // if the entry is invalid or close enough to expiring check // use the entry's done channel to determine if a refresh has started yet select { case <-e.done: // last refresh completed, so it's time for a new one return true default: // new refresh already started, so we can wait on that return false } } return false } func (c *Client) cachedCfg(ctx context.Context, instance string) (string, *tls.Config, string, error) { c.cacheL.RLock() throttle := c.RefreshCfgThrottle if throttle == 0 { throttle = DefaultRefreshCfgThrottle } refreshCfgBuffer := c.RefreshCfgBuffer if refreshCfgBuffer == 0 { refreshCfgBuffer = DefaultRefreshCfgBuffer } e := c.cfgCache[instance] c.cacheL.RUnlock() if needsRefresh(e, refreshCfgBuffer) { // Reenter the critical section with intent to make changes c.cacheL.Lock() if c.cfgCache == nil { c.cfgCache = make(map[string]cacheEntry) } if c.limiters == nil { c.limiters = make(map[string]*rate.Limiter) } // the state may have changed between critical sections, so double check e = c.cfgCache[instance] limiter := c.limiters[instance] if limiter == nil { limiter = rate.NewLimiter(rate.Every(throttle), 2) c.limiters[instance] = limiter } if needsRefresh(e, refreshCfgBuffer) { if limiter.Allow() { // start a new refresh and update the cachedEntry to reflect that e.done = c.startRefresh(instance, refreshCfgBuffer) e.lastRefreshed = time.Now() c.cfgCache[instance] = e } else { // TODO: Investigate returning this as an error instead of just logging logging.Infof("refresh operation throttled for %s: reusing config from last refresh (%s ago)", instance, time.Since(e.lastRefreshed)) } } c.cacheL.Unlock() } if !isValid(e) { // if the previous result was invalid, wait for the next result to complete select { case <-ctx.Done(): return "", nil, "", ctx.Err() case <-e.done: } c.cacheL.RLock() // the state may have changed between critical sections, so double check e = c.cfgCache[instance] c.cacheL.RUnlock() } return e.addr, e.cfg, e.version, e.err } // DialContext uses the configuration stored in the client to connect to an instance. // If this func returns a nil error the connection is correctly authenticated // to connect to the instance. func (c *Client) DialContext(ctx context.Context, instance string) (net.Conn, error) { addr, cfg, _, err := c.cachedCfg(ctx, instance) if err != nil { return nil, err } // TODO: attempt an early refresh if an connect fails? return c.tryConnect(ctx, addr, instance, cfg) } // Dial does the same as DialContext but using context.Background() as the context. func (c *Client) Dial(instance string) (net.Conn, error) { return c.DialContext(context.Background(), instance) } // ErrUnexpectedFailure indicates the internal refresh operation failed unexpectedly. var ErrUnexpectedFailure = errors.New("ErrUnexpectedFailure") func (c *Client) tryConnect(ctx context.Context, addr, instance string, cfg *tls.Config) (net.Conn, error) { // When multiple dial attempts start in quick succession, the internal // refresh logic is sometimes subject to a race condition. If the first // attempt fails on a handshake error, it will invalidate the cached config. // In some cases, a second dial attempt will initiate a connection with an // invalid config. This check fails fast in such cases. if addr == "" { return nil, ErrUnexpectedFailure } dial := c.selectDialer() conn, err := dial(ctx, "tcp", addr) if err != nil { return nil, err } type setKeepAliver interface { SetKeepAlive(keepalive bool) error SetKeepAlivePeriod(d time.Duration) error } if s, ok := conn.(setKeepAliver); ok { if err := s.SetKeepAlive(true); err != nil { logging.Verbosef("Couldn't set KeepAlive to true: %v", err) } else if err := s.SetKeepAlivePeriod(keepAlivePeriod); err != nil { logging.Verbosef("Couldn't set KeepAlivePeriod to %v", keepAlivePeriod) } } else { logging.Verbosef("KeepAlive not supported: long-running tcp connections may be killed by the OS.") } return c.connectTLS(ctx, conn, instance, cfg) } func (c *Client) selectDialer() func(context.Context, string, string) (net.Conn, error) { if c.ContextDialer != nil { return c.ContextDialer } if c.Dialer != nil { return func(_ context.Context, net, addr string) (net.Conn, error) { return c.Dialer(net, addr) } } dialer := proxy.FromEnvironment() if ctxDialer, ok := dialer.(proxy.ContextDialer); ok { // although proxy.FromEnvironment() returns a Dialer interface which only has a Dial method, // it happens in fact that method often returns ContextDialers. return ctxDialer.DialContext } return func(_ context.Context, net, addr string) (net.Conn, error) { return dialer.Dial(net, addr) } } func (c *Client) invalidateCfg(cfg *tls.Config, instance string, err error) { c.cacheL.RLock() e := c.cfgCache[instance] c.cacheL.RUnlock() if e.cfg != cfg { return } c.cacheL.Lock() defer c.cacheL.Unlock() e = c.cfgCache[instance] // the state may have changed between critical sections, so double check if e.cfg != cfg { return } err = fmt.Errorf("config invalidated after TLS handshake failed, error = %w", err) c.cfgCache[instance] = cacheEntry{ err: err, done: e.done, lastRefreshed: e.lastRefreshed, } } // NewConnSrc returns a chan which can be used to receive connections // on the passed Listener. All requests sent to the returned chan will have the // instance name provided here. The chan will be closed if the Listener returns // an error. func NewConnSrc(instance string, l net.Listener) <-chan Conn { ch := make(chan Conn) go func() { for { start := time.Now() c, err := l.Accept() if err != nil { logging.Errorf("listener (%#v) had error: %v", l, err) if nerr, ok := err.(net.Error); ok && nerr.Temporary() { d := 10*time.Millisecond - time.Since(start) if d > 0 { time.Sleep(d) } continue } l.Close() close(ch) return } ch <- Conn{instance, c} } }() return ch } // InstanceVersion uses client cache to return instance version string. // // Deprecated: Use Client.InstanceVersionContext instead. func (c *Client) InstanceVersion(instance string) (string, error) { return c.InstanceVersionContext(context.Background(), instance) } // InstanceVersionContext uses client cache to return instance version string. func (c *Client) InstanceVersionContext(ctx context.Context, instance string) (string, error) { _, _, version, err := c.cachedCfg(ctx, instance) if err != nil { return "", err } return version, nil } // ParseInstanceConnectionName verifies that instances are in the expected format and include // the necessary components. func ParseInstanceConnectionName(instance string) (string, string, string, []string, error) { args := strings.Split(instance, "=") if len(args) > 2 { return "", "", "", nil, fmt.Errorf("invalid instance argument: must be either form - `` or `=`; invalid arg was %q", instance) } // Parse the instance connection name - everything before the "=". proj, region, name := util.SplitName(args[0]) if proj == "" || region == "" || name == "" { return "", "", "", nil, fmt.Errorf("invalid instance connection string: must be in the form `project:region:instance-name`; invalid name was %q", args[0]) } return proj, region, name, args, nil } // GetInstances iterates through the client cache, returning a list of previously dialed // instances. func (c *Client) GetInstances() []string { var insts []string c.cacheL.Lock() cfgCache := c.cfgCache c.cacheL.Unlock() for i := range cfgCache { insts = append(insts, i) } return insts } // AvailableConn returns false if MaxConnections has been reached, true otherwise. // When MaxConnections is 0, there is no limit. func (c *Client) AvailableConn() bool { return c.MaxConnections == 0 || atomic.LoadUint64(&c.ConnectionsCounter) < c.MaxConnections } // Shutdown waits up to a given amount of time for all active connections to // close. Returns an error if there are still active connections after waiting // for the whole length of the timeout. func (c *Client) Shutdown(termTimeout time.Duration) error { term, ticker := time.After(termTimeout), time.NewTicker(100*time.Millisecond) defer ticker.Stop() for { select { case <-ticker.C: if atomic.LoadUint64(&c.ConnectionsCounter) > 0 { continue } case <-term: } break } active := atomic.LoadUint64(&c.ConnectionsCounter) if active == 0 { return nil } return fmt.Errorf("%d active connections still exist after waiting for %v", active, termTimeout) } cloud-sql-proxy-1.33.14/proxy/proxy/client_test.go000066400000000000000000000407031452473605000221650ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package proxy import ( "context" "crypto/tls" "crypto/x509" "errors" "fmt" "io/ioutil" "net" "net/http/httptest" "strings" "sync" "sync/atomic" "testing" "time" "unsafe" ) const instance = "project:region:instance" var ( sentinelError = errors.New("sentinel error") forever = time.Date(9999, 0, 0, 0, 0, 0, 0, time.UTC) ) type fakeCerts struct { sync.Mutex called int } type blockingCertSource struct { values map[string]*fakeCerts validUntil time.Time } func (cs *blockingCertSource) Local(instance string) (tls.Certificate, error) { v, ok := cs.values[instance] if !ok { return tls.Certificate{}, fmt.Errorf("test setup failure: unknown instance %q", instance) } v.Lock() v.called++ v.Unlock() // Returns a cert which is valid forever. return tls.Certificate{ Leaf: &x509.Certificate{ NotAfter: cs.validUntil, }, }, nil } func (cs *blockingCertSource) Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) { return &x509.Certificate{}, "fake address", "fake name", "fake version", nil } func newCertSource(certs *fakeCerts, expiration time.Time) CertSource { return &blockingCertSource{ values: map[string]*fakeCerts{ instance: certs, }, validUntil: expiration, } } func newClient(cs CertSource) *Client { return &Client{ Certs: cs, Dialer: func(string, string) (net.Conn, error) { return nil, sentinelError }, } } func TestContextDialer(t *testing.T) { cs := newCertSource(&fakeCerts{}, forever) c := newClient(cs) c.ContextDialer = func(context.Context, string, string) (net.Conn, error) { return nil, sentinelError } c.Dialer = func(string, string) (net.Conn, error) { return nil, fmt.Errorf("this dialer should not be used when ContextDialer is set") } if _, err := c.DialContext(context.Background(), instance); err != sentinelError { t.Errorf("unexpected error: %v", err) } } func TestClientCache(t *testing.T) { b := &fakeCerts{} c := newClient(newCertSource(b, forever)) for i := 0; i < 5; i++ { if _, err := c.Dial(instance); err != sentinelError { t.Errorf("unexpected error: %v", err) } } b.Lock() if b.called != 1 { t.Errorf("called %d times, want called 1 time", b.called) } b.Unlock() } func TestInvalidateConfigCache(t *testing.T) { srv := httptest.NewTLSServer(nil) defer srv.Close() b := &fakeCerts{} c := &Client{ Certs: newCertSource(b, forever), Dialer: func(string, string) (net.Conn, error) { return net.Dial( srv.Listener.Addr().Network(), srv.Listener.Addr().String(), ) }, } c.cachedCfg(context.Background(), instance) if needsRefresh(c.cfgCache[instance], DefaultRefreshCfgBuffer) { t.Error("cached config expected to be valid") } _, err := c.Dial(instance) if err == nil { t.Errorf("c.Dial(%q) expected to fail with handshake error", instance) } if !needsRefresh(c.cfgCache[instance], DefaultRefreshCfgBuffer) { t.Error("cached config expected to be invalidated after handshake error") } } func TestValidClient(t *testing.T) { someErr := errors.New("error") openCh := make(chan struct{}) closedCh := make(chan struct{}) close(closedCh) equalErrors := func(a, b []*InvalidError) bool { if len(a) != len(b) { return false } for i := range a { if a[i].instance != b[i].instance { return false } if a[i].err != b[i].err { return false } if a[i].hasTLS != b[i].hasTLS { return false } } return true } testCases := []struct { desc string cache map[string]cacheEntry want []*InvalidError }{ { desc: "when the cache has only valid entries", cache: map[string]cacheEntry{"proj:region:inst": cacheEntry{cfg: &tls.Config{}, done: closedCh}}, want: nil, }, { desc: "when the cache has invalid TLS entries", cache: map[string]cacheEntry{"proj:region:inst": cacheEntry{done: closedCh}}, want: []*InvalidError{&InvalidError{instance: "proj:region:inst", hasTLS: false}}, }, { desc: "when the cache has errored entries", cache: map[string]cacheEntry{"proj:region:inst": cacheEntry{err: someErr, done: closedCh}}, want: []*InvalidError{&InvalidError{instance: "proj:region:inst", hasTLS: false, err: someErr}}, }, { desc: "when the cache has an entry with an in-progress refresh", cache: map[string]cacheEntry{"proj:region:inst": cacheEntry{err: someErr, done: openCh}}, want: nil, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { client := &Client{cfgCache: tc.cache} if got := client.InvalidInstances(); !equalErrors(got, tc.want) { t.Errorf("want = %v, got = %v", tc.want, got) } }) } } func TestConcurrentRefresh(t *testing.T) { b := &fakeCerts{} c := newClient(newCertSource(b, forever)) ch := make(chan error) b.Lock() const numDials = 20 for i := 0; i < numDials; i++ { go func() { _, err := c.Dial(instance) ch <- err }() } b.Unlock() for i := 0; i < numDials; i++ { if err := <-ch; err != sentinelError { t.Errorf("unexpected error: %v", err) } } b.Lock() if b.called != 1 { t.Errorf("called %d times, want called 1 time", b.called) } b.Unlock() } func TestMaximumConnectionsCount(t *testing.T) { certSource := &blockingCertSource{ values: map[string]*fakeCerts{}, validUntil: forever, } c := newClient(certSource) const maxConnections = 10 c.MaxConnections = maxConnections var dials uint64 firstDialExited := make(chan struct{}) c.Dialer = func(string, string) (net.Conn, error) { atomic.AddUint64(&dials, 1) // Wait until the first dial fails to ensure the max connections count // is reached by a concurrent dialer <-firstDialExited return nil, sentinelError } // Build certSource.values before creating goroutines to avoid concurrent map read and map write const numConnections = maxConnections + 1 instanceNames := make([]string, numConnections) for i := 0; i < numConnections; i++ { // Vary instance name to bypass config cache and avoid second call to Client.tryConnect() in Client.Dial() instanceName := fmt.Sprintf("%s-%d", instance, i) certSource.values[instanceName] = &fakeCerts{} instanceNames[i] = instanceName } var wg sync.WaitGroup var firstDialOnce sync.Once for _, instanceName := range instanceNames { wg.Add(1) go func(instanceName string) { defer wg.Done() conn := Conn{ Instance: instanceName, Conn: &dummyConn{}, } c.handleConn(context.Background(), conn) firstDialOnce.Do(func() { close(firstDialExited) }) }(instanceName) } wg.Wait() switch { case dials > maxConnections: t.Errorf("client should have refused to dial new connection on %dth attempt when the maximum of %d connections was reached (%d dials)", numConnections, maxConnections, dials) case dials == maxConnections: t.Logf("client has correctly refused to dial new connection on %dth attempt when the maximum of %d connections was reached (%d dials)\n", numConnections, maxConnections, dials) case dials < maxConnections: t.Errorf("client should have dialed exactly the maximum of %d connections (%d connections, %d dials)", maxConnections, numConnections, dials) } } func TestShutdownTerminatesEarly(t *testing.T) { cs := newCertSource(&fakeCerts{}, forever) c := newClient(cs) // Ensure the dialer returns no error. c.Dialer = func(string, string) (net.Conn, error) { return nil, nil } shutdown := make(chan bool, 1) go func() { c.Shutdown(1) shutdown <- true }() shutdownFinished := false // In case the code is actually broken and the client doesn't shut down quickly, don't cause the test to hang until it times out. select { case <-time.After(100 * time.Millisecond): case shutdownFinished = <-shutdown: } if !shutdownFinished { t.Errorf("shutdown should have completed quickly because there are no active connections") } } func TestRefreshTimer(t *testing.T) { timeToExpire := 2 * time.Second certCreated := time.Now() cs := newCertSource(&fakeCerts{}, certCreated.Add(timeToExpire)) c := newClient(cs) c.RefreshCfgThrottle = 20 * time.Millisecond c.RefreshCfgBuffer = time.Second // Call Dial to cache the cert. if _, err := c.Dial(instance); err != sentinelError { t.Fatalf("Dial(%s) failed: %v", instance, err) } c.cacheL.Lock() cfg, ok := c.cfgCache[instance] c.cacheL.Unlock() if !ok { t.Fatalf("expected instance to be cached") } time.Sleep(timeToExpire - time.Since(certCreated)) // Check if cert was refreshed in the background, without calling Dial again. c.cacheL.Lock() newCfg, ok := c.cfgCache[instance] c.cacheL.Unlock() if !ok { t.Fatalf("expected instance to be cached") } if !newCfg.lastRefreshed.After(cfg.lastRefreshed) { t.Error("expected cert to be refreshed.") } } func TestSyncAtomicAlignment(t *testing.T) { // The sync/atomic pkg has a bug that requires the developer to guarantee // 64-bit alignment when using 64-bit functions on 32-bit systems. c := &Client{} if a := unsafe.Offsetof(c.ConnectionsCounter); a%64 != 0 { t.Errorf("Client.ConnectionsCounter is not aligned: want %v, got %v", 0, a) } } type invalidRemoteCertSource struct{} func (cs *invalidRemoteCertSource) Local(instance string) (tls.Certificate, error) { return tls.Certificate{}, nil } func (cs *invalidRemoteCertSource) Remote(instance string) (*x509.Certificate, string, string, string, error) { return nil, "", "", "", sentinelError } func TestRemoteCertError(t *testing.T) { c := newClient(&invalidRemoteCertSource{}) _, err := c.DialContext(context.Background(), instance) if err != sentinelError { t.Errorf("expected sentinel error, got %v", err) } } func TestParseInstanceConnectionName(t *testing.T) { // SplitName has its own tests and is not specifically tested here. table := []struct { in string wantErrorStr string }{ {"proj:region:my-db", ""}, {"proj:region:my-db=options", ""}, {"proj=region=my-db", "invalid instance argument: must be either form - `` or `=`; invalid arg was \"proj=region=my-db\""}, {"projregionmy-db", "invalid instance connection string: must be in the form `project:region:instance-name`; invalid name was \"projregionmy-db\""}, } for _, test := range table { _, _, _, _, gotError := ParseInstanceConnectionName(test.in) var gotErrorStr string if gotError != nil { gotErrorStr = gotError.Error() } if gotErrorStr != test.wantErrorStr { t.Errorf("ParseInstanceConnectionName(%q): got \"%v\" for error, want \"%v\"", test.in, gotErrorStr, test.wantErrorStr) } } } type localhostCertSource struct { } func (c localhostCertSource) Local(instance string) (tls.Certificate, error) { return tls.Certificate{ Leaf: &x509.Certificate{ NotAfter: forever, }, }, nil } func (c localhostCertSource) Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) { return &x509.Certificate{}, "localhost", "fake name", "fake version", nil } var _ CertSource = &localhostCertSource{} func TestClientHandshakeCanceled(t *testing.T) { errorIsDeadlineOrTimeout := func(err error) bool { if errors.Is(err, context.Canceled) { return true } if errors.Is(err, context.DeadlineExceeded) { return true } if strings.Contains(err.Error(), "i/o timeout") { // We should use os.ErrDeadlineExceeded exceeded here, // but it is not present in Go versions below 1.15. return true } return false } withTestHarness := func(t *testing.T, f func(port int)) { // serverShutdown is closed to free the server // goroutine that is holding up the client request. serverShutdown := make(chan struct{}) l, err := tls.Listen( "tcp", ":", &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { // Make the client wait forever to handshake. <-serverShutdown return nil, errors.New("some error") }, }) if err != nil { t.Fatalf("tls.Listen: %v", err) } port := l.Addr().(*net.TCPAddr).Port var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for { conn, err := l.Accept() if err != nil { // Below Go 1.16, we have to string match here. // https://golang.org/doc/go1.16#net if !strings.Contains(err.Error(), "use of closed network connection") { t.Errorf("l.Accept: %v", err) } return } _, _ = ioutil.ReadAll(conn) // Trigger the handshake. _ = conn.Close() } }() f(port) close(serverShutdown) // Free the server thread. _ = l.Close() wg.Wait() } validateError := func(t *testing.T, err error) { if err == nil { t.Fatal("nil error unexpected") } if !errorIsDeadlineOrTimeout(err) { t.Fatalf("unexpected error: %v", err) } } newClient := func(port int) *Client { return &Client{ Port: port, Certs: &localhostCertSource{}, } } // Makes it to Handshake. t.Run("with timeout", func(t *testing.T) { withTestHarness(t, func(port int) { c := newClient(port) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() _, err := c.DialContext(ctx, instance) validateError(t, err) }) }) t.Run("when liveness check is called on invalidated config", func(t *testing.T) { withTestHarness(t, func(port int) { c := newClient(port) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() _, err := c.DialContext(ctx, instance) if err == nil { t.Fatal("expected DialContext to fail, got no error") } invalid := c.InvalidInstances() if gotLen := len(invalid); gotLen != 1 { t.Fatalf("invalid instance want = 1, got = %v", gotLen) } got := invalid[0] if got.err == nil { t.Fatal("want invalid instance error, got nil") } }) }) // Makes it to Handshake. // Same as the above but the context doesn't have a deadline, // it is canceled manually after a while. t.Run("canceled after a while, no deadline", func(t *testing.T) { withTestHarness(t, func(port int) { c := newClient(port) ctx, cancel := context.WithCancel(context.Background()) defer cancel() time.AfterFunc(3*time.Second, cancel) _, err := c.DialContext(ctx, instance) validateError(t, err) }) }) // Doesn't make it to Handshake. t.Run("with short timeout", func(t *testing.T) { withTestHarness(t, func(port int) { c := newClient(port) ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond) defer cancel() _, err := c.DialContext(ctx, instance) validateError(t, err) }) }) // Doesn't make it to Handshake. t.Run("canceled without timeout", func(t *testing.T) { withTestHarness(t, func(port int) { c := newClient(port) ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := c.DialContext(ctx, instance) validateError(t, err) }) }) } func TestConnectingWithInvalidConfig(t *testing.T) { c := &Client{} _, err := c.tryConnect(context.Background(), "", "myinstance", &tls.Config{}) if err != ErrUnexpectedFailure { t.Fatalf("wanted ErrUnexpectedFailure, got = %v", err) } } var ( errLocal = errors.New("local failed") errRemote = errors.New("remote failed") ) type failingCertSource struct{} func (cs failingCertSource) Local(instance string) (tls.Certificate, error) { return tls.Certificate{}, errLocal } func (cs failingCertSource) Remote(instance string) (cert *x509.Certificate, addr, name, version string, err error) { return nil, "", "", "", errRemote } func TestInstanceVersionContext(t *testing.T) { testCases := []struct { certSource CertSource wantErr error wantVersion string }{ { certSource: newCertSource(&fakeCerts{}, forever), wantErr: nil, wantVersion: "fake version", }, { certSource: failingCertSource{}, wantErr: errLocal, wantVersion: "", }, } for _, tc := range testCases { c := newClient(tc.certSource) v, err := c.InstanceVersionContext(context.Background(), instance) if v != tc.wantVersion { t.Fatalf("want version = %v, got version = %v", tc.wantVersion, v) } if err != tc.wantErr { t.Fatalf("want = %v, got = %v", tc.wantErr, err) } } } cloud-sql-proxy-1.33.14/proxy/proxy/common.go000066400000000000000000000115751452473605000211450ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package proxy implements client and server code for proxying an unsecure connection over SSL. package proxy import ( "bytes" "errors" "fmt" "io" "net" "sync" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" ) // SQLScope is the Google Cloud Platform scope required for executing API // calls to Cloud SQL. const SQLScope = "https://www.googleapis.com/auth/sqlservice.admin" // myCopy is similar to io.Copy, but reports whether the returned error was due // to a bad read or write. The returned error will never be nil func myCopy(dst io.Writer, src io.Reader) (readErr bool, err error) { buf := make([]byte, 4096) for { n, err := src.Read(buf) if n > 0 { if _, werr := dst.Write(buf[:n]); werr != nil { if err == nil { return false, werr } // Read and write error; just report read error (it happened first). return true, err } } if err != nil { return true, err } } } func copyError(readDesc, writeDesc string, readErr bool, err error) { var desc string if readErr { desc = "Reading data from " + readDesc } else { desc = "Writing data to " + writeDesc } logging.Errorf("%v had error: %v", desc, err) } func copyThenClose(remote, local io.ReadWriteCloser, remoteDesc, localDesc string) { firstErr := make(chan error, 1) go func() { readErr, err := myCopy(remote, local) select { case firstErr <- err: if readErr && err == io.EOF { logging.Verbosef("Client closed %v", localDesc) } else { copyError(localDesc, remoteDesc, readErr, err) } remote.Close() local.Close() default: } }() readErr, err := myCopy(local, remote) select { case firstErr <- err: if readErr && err == io.EOF { logging.Verbosef("Instance %v closed connection", remoteDesc) } else { copyError(remoteDesc, localDesc, readErr, err) } remote.Close() local.Close() default: // In this case, the other goroutine exited first and already printed its // error (and closed the things). } } // NewConnSet initializes a new ConnSet and returns it. func NewConnSet() *ConnSet { return &ConnSet{m: make(map[string][]net.Conn)} } // A ConnSet tracks net.Conns associated with a provided ID. // A nil ConnSet will be a no-op for all methods called on it. type ConnSet struct { sync.RWMutex m map[string][]net.Conn } // String returns a debug string for the ConnSet. func (c *ConnSet) String() string { if c == nil { return "" } var b bytes.Buffer c.RLock() for id, conns := range c.m { fmt.Fprintf(&b, "ID %s:", id) for i, c := range conns { fmt.Fprintf(&b, "\n\t%d: %v", i, c) } } c.RUnlock() return b.String() } // Add saves the provided conn and associates it with the given string // identifier. func (c *ConnSet) Add(id string, conn net.Conn) { if c == nil { return } c.Lock() c.m[id] = append(c.m[id], conn) c.Unlock() } // IDs returns a slice of all identifiers which still have active connections. func (c *ConnSet) IDs() []string { if c == nil { return nil } ret := make([]string, 0, len(c.m)) c.RLock() for k := range c.m { ret = append(ret, k) } c.RUnlock() return ret } // Conns returns all active connections associated with the provided ids. func (c *ConnSet) Conns(ids ...string) []net.Conn { if c == nil { return nil } var ret []net.Conn c.RLock() for _, id := range ids { ret = append(ret, c.m[id]...) } c.RUnlock() return ret } // Remove undoes an Add operation to have the set forget about a conn. Do not // Remove an id/conn pair more than it has been Added. func (c *ConnSet) Remove(id string, conn net.Conn) error { if c == nil { return nil } c.Lock() defer c.Unlock() pos := -1 conns := c.m[id] for i, cc := range conns { if cc == conn { pos = i break } } if pos == -1 { return fmt.Errorf("couldn't find connection %v for id %s", conn, id) } if len(conns) == 1 { delete(c.m, id) } else { c.m[id] = append(conns[:pos], conns[pos+1:]...) } return nil } // Close closes every net.Conn contained in the set. func (c *ConnSet) Close() error { if c == nil { return nil } var errs bytes.Buffer c.Lock() for id, conns := range c.m { for _, c := range conns { if err := c.Close(); err != nil { fmt.Fprintf(&errs, "%s close error: %v\n", id, err) } } } c.Unlock() if errs.Len() == 0 { return nil } return errors.New(errs.String()) } cloud-sql-proxy-1.33.14/proxy/proxy/common_test.go000066400000000000000000000046031452473605000221760ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This file contains tests for common.go package proxy import ( "net" "reflect" "testing" ) var c1, c2, c3 = &dummyConn{}, &dummyConn{}, &dummyConn{} type dummyConn struct{ net.Conn } func (c dummyConn) Close() error { return nil } func TestConnSetAdd(t *testing.T) { s := NewConnSet() s.Add("a", c1) aSlice := []string{"a"} if !reflect.DeepEqual(s.IDs(), aSlice) { t.Fatalf("got %v, want %v", s.IDs(), aSlice) } s.Add("a", c2) if !reflect.DeepEqual(s.IDs(), aSlice) { t.Fatalf("got %v, want %v", s.IDs(), aSlice) } s.Add("b", c3) ids := s.IDs() if len(ids) != 2 { t.Fatalf("got %d ids, wanted 2", len(ids)) } ok := ids[0] == "a" && ids[1] == "b" || ids[1] == "a" && ids[0] == "b" if !ok { t.Fatalf(`got %v, want only "a" and "b"`, ids) } } func TestConnSetRemove(t *testing.T) { s := NewConnSet() s.Add("a", c1) s.Add("a", c2) s.Add("b", c3) s.Remove("b", c3) if got := s.Conns("b"); got != nil { t.Fatalf("got %v, want nil", got) } aSlice := []string{"a"} if !reflect.DeepEqual(s.IDs(), aSlice) { t.Fatalf("got %v, want %v", s.IDs(), aSlice) } s.Remove("a", c1) if !reflect.DeepEqual(s.IDs(), aSlice) { t.Fatalf("got %v, want %v", s.IDs(), aSlice) } s.Remove("a", c2) if len(s.IDs()) != 0 { t.Fatalf("got %v, want empty set", s.IDs()) } } func TestConns(t *testing.T) { s := NewConnSet() s.Add("a", c1) s.Add("a", c2) s.Add("b", c3) got := s.Conns("b") if !reflect.DeepEqual(got, []net.Conn{c3}) { t.Fatalf("got %v, wanted only %v", got, c3) } looking := map[net.Conn]bool{ c1: true, c2: true, c3: true, } for _, v := range s.Conns("a", "b") { if _, ok := looking[v]; !ok { t.Errorf("got unexpected conn %v", v) } delete(looking, v) } if len(looking) != 0 { t.Fatalf("didn't find %v in list of Conns", looking) } } cloud-sql-proxy-1.33.14/proxy/proxy/connect_tls_117.go000066400000000000000000000023761452473605000225570ustar00rootroot00000000000000// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build go1.17 // +build go1.17 package proxy import ( "context" "crypto/tls" "net" ) // connectTLS returns a new TLS client side connection // using conn as the underlying transport. // // The returned connection has already completed its TLS handshake. func (c *Client) connectTLS( ctx context.Context, conn net.Conn, instance string, cfg *tls.Config, ) (net.Conn, error) { ret := tls.Client(conn, cfg) // HandshakeContext was introduced in Go 1.17, hence // this file is conditionally compiled on only Go versions >= 1.17. if err := ret.HandshakeContext(ctx); err != nil { _ = ret.Close() c.invalidateCfg(cfg, instance, err) return nil, err } return ret, nil } cloud-sql-proxy-1.33.14/proxy/proxy/connect_tls_other.go000066400000000000000000000061401452473605000233610ustar00rootroot00000000000000// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !go1.17 // +build !go1.17 package proxy import ( "context" "crypto/tls" "net" "sync" "time" ) type cancelationWatcher struct { done chan struct{} // closed when the caller requests shutdown by calling stop(). wg sync.WaitGroup } // newCancelationWatcher starts a goroutine that will monitor // ctx for cancelation. If ctx is canceled, the I/O // deadline on conn is set to some point in the past, canceling // ongoing I/O and refusing new I/O. // // The caller must call stop() on the returned struct to // release resources associated with this. func newCancelationWatcher(ctx context.Context, conn net.Conn) *cancelationWatcher { cw := &cancelationWatcher{ done: make(chan struct{}), } // Monitor for context cancelation. cw.wg.Add(1) go func() { defer cw.wg.Done() select { case <-ctx.Done(): // Set the deadline to some point in the past, but not // the zero value. This will cancel ongoing requests // and refuse future ones. _ = conn.SetDeadline(time.Time{}.Add(1)) case <-cw.done: return } }() return cw } // stop shuts down this cancelationWatcher and releases // the resources associated with it. // // Once stop has returned, the provided context is no longer // watched for cancelation and the deadline on the // provided net.Conn is no longer manipulated. func (cw *cancelationWatcher) stop() { close(cw.done) cw.wg.Wait() } // connectTLS returns a new TLS client side connection // using conn as the underlying transport. // // The returned connection has already completed its TLS handshake. func (c *Client) connectTLS( ctx context.Context, conn net.Conn, instance string, cfg *tls.Config, ) (net.Conn, error) { // For the purposes of this Handshake, manipulate the I/O // deadlines on this connection inline. We have to do this // manual dance because we don't have HandshakeContext in this // version of Go. defer func() { // The connection didn't originally have a read deadline (we // just created it). So no matter what happens here, restore // the lack-of-deadline. // // In other words, only apply the deadline while dialing, // not during subsequent usage. _ = conn.SetDeadline(time.Time{}) }() // If we have a context deadline, apply it. if dl, ok := ctx.Deadline(); ok { _ = conn.SetDeadline(dl) } cw := newCancelationWatcher(ctx, conn) defer cw.stop() // Always free the context watcher. ret := tls.Client(conn, cfg) if err := ret.Handshake(); err != nil { _ = ret.Close() c.invalidateCfg(cfg, instance, err) return nil, err } return ret, nil } cloud-sql-proxy-1.33.14/proxy/proxy/dial.go000066400000000000000000000065661452473605000205720ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package proxy import ( "fmt" "net" "net/http" "sync" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/certs" "golang.org/x/net/context" "golang.org/x/oauth2/google" ) // The port that CloudSQL expects the client to connect to. const DefaultPort = 3307 var dialClient struct { // This client is initialized in Init/InitWithClient/InitDefault // and read in Dial. c *Client sync.Mutex } // Dial returns a net.Conn connected to the Cloud SQL Instance specified. The // format of 'instance' is "project-name:region:instance-name". // // If one of the Init functions hasn't been called yet, InitDefault is called. // // This is a network-level function; consider looking in the dialers // subdirectory for more convenience functions related to actually logging into // your database. func DialContext(ctx context.Context, instance string) (net.Conn, error) { dialClient.Lock() c := dialClient.c dialClient.Unlock() if c == nil { if err := InitDefault(ctx); err != nil { return nil, fmt.Errorf("default proxy initialization failed; consider calling proxy.Init explicitly: %v", err) } // InitDefault initialized the client. dialClient.Lock() c = dialClient.c dialClient.Unlock() } return c.DialContext(ctx, instance) } // Dial does the same as DialContext but using context.Background() as the context. func Dial(instance string) (net.Conn, error) { return DialContext(context.Background(), instance) } // Dialer is a convenience type to model the standard 'Dial' function. type Dialer func(net, addr string) (net.Conn, error) // Init must be called before Dial is called. This is a more flexible version // of InitDefault, but allows you to set more fields. // // The http.Client is used to authenticate API requests. // The connset parameter is optional. // If the dialer is nil, net.Conn is used. // Use InitWithClient to with a filled client if you want to provide a Context-Aware dialer func Init(auth *http.Client, connset *ConnSet, dialer Dialer) { dialClient.Lock() dialClient.c = &Client{ Port: DefaultPort, Certs: certs.NewCertSource("", auth, true), Conns: connset, Dialer: dialer, } dialClient.Unlock() } // InitClient is similar to Init, but allows you to specify the Client // directly. // Deprecated: Use InitWithClient instead. func InitClient(c Client) { dialClient.Lock() dialClient.c = &c dialClient.Unlock() } // InitWithClient specifies the Client directly. func InitWithClient(c *Client) { dialClient.Lock() dialClient.c = c dialClient.Unlock() } // InitDefault attempts to initialize the Dial function using application // default credentials. func InitDefault(ctx context.Context) error { cl, err := google.DefaultClient(ctx, "https://www.googleapis.com/auth/sqlservice.admin") if err != nil { return err } Init(cl, nil, nil) return nil } cloud-sql-proxy-1.33.14/proxy/util/000077500000000000000000000000001452473605000171115ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/proxy/util/cloudsqlutil.go000066400000000000000000000042421452473605000221660ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package util contains utility functions for use throughout the Cloud SQL Auth proxy. package util import ( _ "embed" "strings" ) // SplitName splits a fully qualified instance into its project, region, and // instance name components. While we make the transition to regionalized // metadata, the region is optional. // // Examples: // // "proj:region:my-db" -> ("proj", "region", "my-db") // "google.com:project:region:instance" -> ("google.com:project", "region", "instance") // "google.com:missing:part" -> ("google.com:missing", "", "part") func SplitName(instance string) (project, region, name string) { spl := strings.Split(instance, ":") if len(spl) < 2 { return "", "", instance } if dot := strings.Index(spl[0], "."); dot != -1 { spl[1] = spl[0] + ":" + spl[1] spl = spl[1:] } switch { case len(spl) < 2: return "", "", instance case len(spl) == 2: return spl[0], "", spl[1] default: return spl[0], spl[1], spl[2] } } // versionString indicates the version of the proxy currently in use. // //go:embed version.txt var versionString string // metadataString indicates additional build or distribution metadata. var metadataString = "" // SemanticVersion returns the version of the proxy in a semver format. func SemanticVersion() string { v := strings.TrimSpace(versionString) if metadataString != "" { v += "+" + metadataString } return v } // UserAgentFromVersionString returns an appropriate user agent string // for identifying this proxy process. func UserAgentFromVersionString() string { return "cloud_sql_proxy/" + SemanticVersion() } cloud-sql-proxy-1.33.14/proxy/util/cloudsqlutil_test.go000066400000000000000000000036071452473605000232310ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package util import ( _ "embed" "strings" "testing" ) //go:embed version.txt var actualVersion string func TestSemanticVersion(t *testing.T) { want := strings.TrimSpace(actualVersion) if got := SemanticVersion(); got != want { t.Fatalf("want = %q, got = %q", want, got) } } func TestUserAgentFromVersionString(t *testing.T) { want := "cloud_sql_proxy/" + strings.TrimSpace(actualVersion) if got := UserAgentFromVersionString(); got != want { t.Fatalf("want = %q, got = %q", want, got) } } func TestSplitName(t *testing.T) { table := []struct{ in, wantProj, wantRegion, wantInstance string }{ {"proj:region:my-db", "proj", "region", "my-db"}, {"google.com:project:region:instance", "google.com:project", "region", "instance"}, {"google.com:missing:part", "google.com:missing", "", "part"}, } for _, test := range table { gotProj, gotRegion, gotInstance := SplitName(test.in) if gotProj != test.wantProj { t.Errorf("splitName(%q): got %v for project, want %v", test.in, gotProj, test.wantProj) } if gotRegion != test.wantRegion { t.Errorf("splitName(%q): got %v for region, want %v", test.in, gotRegion, test.wantRegion) } if gotInstance != test.wantInstance { t.Errorf("splitName(%q): got %v for instance, want %v", test.in, gotInstance, test.wantInstance) } } } cloud-sql-proxy-1.33.14/proxy/util/gcloudutil.go000066400000000000000000000062251452473605000216200ustar00rootroot00000000000000// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package util import ( "bytes" "context" "encoding/json" "fmt" "runtime" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" "golang.org/x/oauth2" exec "golang.org/x/sys/execabs" ) // GcloudConfigData represents the data returned by `gcloud config config-helper`. type GcloudConfigData struct { Configuration struct { Properties struct { Core struct { Project string Account string } } } Credential struct { AccessToken string `json:"access_token"` TokenExpiry time.Time `json:"token_expiry"` } } func (cfg *GcloudConfigData) oauthToken() *oauth2.Token { return &oauth2.Token{ AccessToken: cfg.Credential.AccessToken, Expiry: cfg.Credential.TokenExpiry, } } type GcloudStatusCode int const ( GcloudOk GcloudStatusCode = iota GcloudNotFound // generic execution failure error not specified above. GcloudExecErr ) type GcloudError struct { GcloudError error Status GcloudStatusCode } func (e *GcloudError) Error() string { return e.GcloudError.Error() } // GcloudConfig returns a GcloudConfigData object or an error of type *GcloudError. func GcloudConfig() (*GcloudConfigData, error) { gcloudCmd := "gcloud" if runtime.GOOS == "windows" { gcloudCmd = gcloudCmd + ".cmd" } if _, err := exec.LookPath(gcloudCmd); err != nil { return nil, &GcloudError{err, GcloudNotFound} } buf, errbuf := new(bytes.Buffer), new(bytes.Buffer) cmd := exec.Command(gcloudCmd, "--format", "json", "config", "config-helper", "--min-expiry", "1h") cmd.Stdout = buf cmd.Stderr = errbuf if err := cmd.Run(); err != nil { err = fmt.Errorf("error reading config: %v; stderr was:\n%v", err, errbuf) logging.Errorf("GcloudConfig: %v", err) return nil, &GcloudError{err, GcloudExecErr} } data := &GcloudConfigData{} if err := json.Unmarshal(buf.Bytes(), data); err != nil { logging.Errorf("Failed to unmarshal bytes from gcloud: %v", err) logging.Errorf(" gcloud returned:\n%s", buf) return nil, &GcloudError{err, GcloudExecErr} } return data, nil } // gcloudTokenSource implements oauth2.TokenSource via the `gcloud config config-helper` command. type gcloudTokenSource struct { } // Token helps gcloudTokenSource implement oauth2.TokenSource. func (src *gcloudTokenSource) Token() (*oauth2.Token, error) { cfg, err := GcloudConfig() if err != nil { return nil, err } return cfg.oauthToken(), nil } func GcloudTokenSource(ctx context.Context) (oauth2.TokenSource, error) { src := &gcloudTokenSource{} tok, err := src.Token() if err != nil { return nil, err } return oauth2.ReuseTokenSource(tok, src), nil } cloud-sql-proxy-1.33.14/proxy/util/version.txt000066400000000000000000000000101452473605000213260ustar00rootroot000000000000001.33.14 cloud-sql-proxy-1.33.14/tests/000077500000000000000000000000001452473605000161155ustar00rootroot00000000000000cloud-sql-proxy-1.33.14/tests/alldb_test.go000066400000000000000000000047521452473605000205710ustar00rootroot00000000000000// Copyright 2021 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // alldb_test.go contains end to end tests that require all environment variables to be defined. package tests import ( "context" "fmt" "net/http" "testing" ) // requireAllVars skips the given test if at least one environment variable is undefined. func requireAllVars(t *testing.T) { var allVars []string allVars = append(allVars, *mysqlConnName, *mysqlUser, *mysqlPass, *mysqlDb) allVars = append(allVars, *postgresConnName, *postgresUser, *postgresPass, *postgresDb) allVars = append(allVars, *sqlserverConnName, *sqlserverUser, *sqlserverPass, *sqlserverDb) for _, envVar := range allVars { if envVar == "" { t.Skip("skipping test, all environment variable must be defined") } } } // Test to verify that when a proxy client serves multiple instances that can all be successfully dialed, // the health check readiness endpoint serves http.StatusOK. func TestMultiInstanceDial(t *testing.T) { // Skipping flaky Github Action test // https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1228 t.Skip("Unblocking WIF Builds!") if testing.Short() { t.Skip("skipping Health Check integration tests") } requireAllVars(t) ctx := context.Background() var args []string args = append(args, fmt.Sprintf("-instances=%s=tcp:%d,%s=tcp:%d,%s=tcp:%d", *mysqlConnName, mysqlPort, *postgresConnName, postgresPort, *sqlserverConnName, sqlserverPort)) args = append(args, "-use_http_health_check") // Start the proxy. p, err := StartProxy(ctx, args...) if err != nil { t.Fatalf("unable to start proxy: %v", err) } defer p.Close() output, err := p.WaitForServe(ctx) if err != nil { t.Fatalf("unable to verify proxy was serving: %s \n %s", err, output) } resp, err := http.Get("http://localhost:" + testPort + readinessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusOK { t.Errorf("want %v, got %v", http.StatusOK, resp.StatusCode) } } cloud-sql-proxy-1.33.14/tests/common_test.go000066400000000000000000000112561452473605000210000ustar00rootroot00000000000000// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package tests contains end to end tests meant to verify the Cloud SQL Auth proxy // works as expected when executed as a binary. // // Required flags: // // -mysql_conn_name, -db_user, -db_pass package tests import ( "bufio" "bytes" "context" "flag" "fmt" "io" "io/ioutil" "log" "os" "os/exec" "path" "runtime" "strings" "testing" ) var ( binPath = "" ) func TestMain(m *testing.M) { flag.Parse() // compile the proxy as a binary var err error binPath, err = compileProxy() if err != nil { log.Fatalf("failed to compile proxy: %s", err) } // Run tests and cleanup rtn := m.Run() os.RemoveAll(binPath) os.Exit(rtn) } // compileProxy compiles the binary into a temporary directory, and returns the path to the file or any error that occured. func compileProxy() (string, error) { // get path of the cmd pkg _, f, _, ok := runtime.Caller(0) if !ok { return "", fmt.Errorf("failed to find cmd pkg") } projRoot := path.Dir(path.Dir(f)) // cd ../.. pkgPath := path.Join(projRoot, "cmd", "cloud_sql_proxy") // compile the proxy into a tmp directory tmp, err := ioutil.TempDir("", "") if err != nil { return "", fmt.Errorf("failed to create temp dir: %s", err) } b := path.Join(tmp, "cloud_sql_proxy") if runtime.GOOS == "windows" { b += ".exe" } cmd := exec.Command("go", "build", "-o", b, pkgPath) out, err := cmd.CombinedOutput() if err != nil { return "", fmt.Errorf("failed to run 'go build': %w \n %s", err, out) } return b, nil } // proxyExec represents an execution of the Cloud SQL proxy. type ProxyExec struct { Out io.ReadCloser cmd *exec.Cmd cancel context.CancelFunc closers []io.Closer done chan bool // closed once the cmd is completed err error } // StartProxy returns a proxyExec representing a running instance of the proxy. func StartProxy(ctx context.Context, args ...string) (*ProxyExec, error) { var err error ctx, cancel := context.WithCancel(ctx) p := ProxyExec{ cmd: exec.CommandContext(ctx, binPath, args...), cancel: cancel, done: make(chan bool), } pr, pw, err := os.Pipe() if err != nil { return nil, fmt.Errorf("unable to open stdout pipe: %w", err) } defer pw.Close() p.Out, p.cmd.Stdout, p.cmd.Stderr = pr, pw, pw p.closers = append(p.closers, pr) if err := p.cmd.Start(); err != nil { defer p.Close() return nil, fmt.Errorf("unable to start cmd: %w", err) } // when process is complete, mark as finished go func() { defer close(p.done) p.err = p.cmd.Wait() }() return &p, nil } // Stop sends the pskill signal to the proxy and returns. func (p *ProxyExec) Kill() { p.cancel() } // Waits until the execution is completed and returns any error. func (p *ProxyExec) Wait() error { select { case <-p.done: return p.err } } // Stop sends the pskill signal to the proxy and returns. func (p *ProxyExec) Done() bool { select { case <-p.done: return true default: } return false } // Close releases any resources assotiated with the instance. func (p *ProxyExec) Close() { p.cancel() for _, c := range p.closers { c.Close() } } // WaitForServe waits until the proxy ready to serve traffic. Returns any output from the proxy // while starting or any errors experienced before the proxy was ready to server. func (p *ProxyExec) WaitForServe(ctx context.Context) (output string, err error) { // Watch for the "Ready for new connections" to indicate the proxy is listening buf, in, errCh := new(bytes.Buffer), bufio.NewReader(p.Out), make(chan error, 1) go func() { defer close(errCh) for { // if ctx is finished, stop processing select { case <-ctx.Done(): return default: } s, err := in.ReadString('\n') if err != nil { errCh <- err return } buf.WriteString(s) if strings.Contains(s, "Ready for new connections") { errCh <- nil return } } }() // Wait for either the background thread of the context to complete select { case <-ctx.Done(): return buf.String(), fmt.Errorf("context done: %w", ctx.Err()) case err := <-errCh: if err != nil { return buf.String(), fmt.Errorf("proxy start failed: %w", err) } } return buf.String(), nil } cloud-sql-proxy-1.33.14/tests/connection_test.go000066400000000000000000000061551452473605000216510ustar00rootroot00000000000000// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // connection_test.go provides some helpers for basic connectivity tests to Cloud SQL instances. package tests import ( "context" "database/sql" "fmt" "sync" "testing" ) // proxyConnTest is a test helper to verify the proxy works with a basic connectivity test. func proxyConnTest(t *testing.T, connName, driver, dsn string, port int, dir string) { ctx := context.Background() var args []string if dir != "" { // unix port args = append(args, fmt.Sprintf("-dir=%s", dir), fmt.Sprintf("-instances=%s", connName)) } else { // tcp socket args = append(args, fmt.Sprintf("-instances=%s=tcp:%d", connName, port)) } // Start the proxy p, err := StartProxy(ctx, args...) if err != nil { t.Fatalf("unable to start proxy: %v", err) } defer p.Close() output, err := p.WaitForServe(ctx) if err != nil { t.Fatalf("unable to verify proxy was serving: %s \n %s", err, output) } // Connect to the instance db, err := sql.Open(driver, dsn) if err != nil { t.Fatalf("unable to connect to db: %s", err) } defer db.Close() _, err = db.Exec("SELECT 1;") if err != nil { t.Fatalf("unable to exec on db: %s", err) } } func proxyConnLimitTest(t *testing.T, connName, driver, dsn string, port int) { ctx := context.Background() maxConn, totConn := 5, 10 // Start the proxy p, err := StartProxy(ctx, fmt.Sprintf("-instances=%s=tcp:%d", connName, port), fmt.Sprintf("-max_connections=%d", maxConn)) if err != nil { t.Fatalf("unable to start proxy: %v", err) } defer p.Close() output, err := p.WaitForServe(ctx) if err != nil { t.Fatalf("unable to verify proxy was serving: %s \n %s", err, output) } // Create connection pool var stmt string switch driver { case "mysql": stmt = "SELECT sleep(2);" case "postgres": stmt = "SELECT pg_sleep(2);" case "sqlserver": stmt = "WAITFOR DELAY '00:00:02'" default: t.Fatalf("unsupported driver: no sleep query found") } db, err := sql.Open(driver, dsn) if err != nil { t.Fatalf("unable to connect to db: %s", err) } db.SetMaxIdleConns(0) defer db.Close() // Connect with up to totConn and count errors var wg sync.WaitGroup c := make(chan error, totConn) for i := 0; i < totConn; i++ { wg.Add(1) go func() { defer wg.Done() _, err := db.ExecContext(ctx, stmt) if err != nil { c <- err } }() } wg.Wait() close(c) var errs []error for e := range c { errs = append(errs, e) } want, got := totConn-maxConn, len(errs) if want != got { t.Errorf("wrong errCt - want: %d, got %d", want, got) for _, e := range errs { t.Errorf("%s\n", e) } t.Fail() } } cloud-sql-proxy-1.33.14/tests/dialer_test.go000066400000000000000000000073751452473605000207570ustar00rootroot00000000000000// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tests import ( "context" "database/sql" "fmt" "net" "net/http" "testing" "time" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/certs" "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy" "github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4/stdlib" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/option" "google.golang.org/api/sqladmin/v1" ) func TestClientHandlesSSLReset(t *testing.T) { if testing.Short() { t.Skip("skipping dialer integration tests") } newClient := func(c *http.Client) *proxy.Client { return &proxy.Client{ Port: 3307, Certs: certs.NewCertSourceOpts(c, certs.RemoteOpts{ UserAgent: "cloud_sql_proxy/test_build", IPAddrTypeOpts: []string{"PUBLIC", "PRIVATE"}, }), Conns: proxy.NewConnSet(), } } connectToDB := func(c *proxy.Client) (*sql.DB, error) { var ( dbUser = *postgresUser dbPwd = *postgresPass dbName = *postgresDb ) dsn := fmt.Sprintf("user=%s password=%s database=%s", dbUser, dbPwd, dbName) config, err := pgx.ParseConfig(dsn) if err != nil { return nil, err } config.DialFunc = func(ctx context.Context, network, instance string) (net.Conn, error) { return c.DialContext(ctx, *postgresConnName) } dbURI := stdlib.RegisterConnConfig(config) return sql.Open("pgx", dbURI) } resetSSL := func(c *http.Client) error { svc, err := sqladmin.NewService(context.Background(), option.WithHTTPClient(c)) if err != nil { return err } project, _, instance, _, _ := proxy.ParseInstanceConnectionName(*postgresConnName) t.Log("Resetting SSL config.") op, err := svc.Instances.ResetSslConfig(project, instance).Do() if err != nil { return err } for { t.Log("Waiting for operation to complete.") op, err = svc.Operations.Get(project, op.Name).Do() if err != nil { return err } if op.Status == "DONE" { t.Log("reset SSL config operation complete") break } time.Sleep(time.Second) } return nil } // SETUP: create HTTP client and proxy client, then connect to database src, err := google.DefaultTokenSource(context.Background(), proxy.SQLScope) if err != nil { t.Fatal(err) } client := oauth2.NewClient(context.Background(), src) proxyClient := newClient(client) db, err := connectToDB(proxyClient) if err != nil { t.Fatalf("failed to connect to DB: %v", err) } // Begin database transaction tx, err := db.Begin() if err != nil { t.Fatal(err) } defer tx.Rollback() resetSSL(client) // Re-dial twice, once to invalidate config, once to establish connection var attempts int for { t.Log("Re-dialing instance") _, err = proxyClient.DialContext(context.Background(), *postgresConnName) if err != nil { t.Logf("Dial error: %v", err) } if err == nil { break } attempts++ if attempts > 1 { t.Fatalf("could not dial: %v", err) } time.Sleep(time.Second) } for i := 0; i < 5; i++ { row, err := tx.Query("SELECT 1") if err != nil { t.Logf("Query after Reset SSL failed as expected after %v retries (error was %v)", i, err) break } row.Close() time.Sleep(time.Second) } if err = db.Ping(); err != nil { t.Fatalf("could not re-stablish a DB connection: %v", err) } } cloud-sql-proxy-1.33.14/tests/healthcheck_test.go000066400000000000000000000035361452473605000217550ustar00rootroot00000000000000// Copyright 2021 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // healthcheck_test.go provides some helpers for end to end health check server tests. package tests import ( "context" "fmt" "net/http" "testing" ) const ( readinessPath = "/readiness" testPort = "8090" ) // singleInstanceDial verifies that when a proxy client serves the given instance, the readiness // endpoint serves http.StatusOK. func singleInstanceDial(t *testing.T, connName string) { // Skipping flaky Github Action test // https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/1228 t.Skip("Unblocking WIF Builds!") ctx := context.Background() // Start a listener on a random port. This test doesn't require a specific // port otherwise. args := []string{ fmt.Sprintf("-instances=%s=tcp:0", connName), "-use_http_health_check", } // Start the proxy. p, err := StartProxy(ctx, args...) if err != nil { t.Fatalf("unable to start proxy: %v", err) } defer p.Close() output, err := p.WaitForServe(ctx) if err != nil { t.Fatalf("unable to verify proxy was serving: %s \n %s", err, output) } resp, err := http.Get("http://localhost:" + testPort + readinessPath) if err != nil { t.Fatalf("HTTP GET failed: %v", err) } if resp.StatusCode != http.StatusOK { t.Errorf("want %v, got %v", http.StatusOK, resp.StatusCode) } } cloud-sql-proxy-1.33.14/tests/mysql_test.go000066400000000000000000000066141452473605000206570ustar00rootroot00000000000000// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // mysql_test runs various tests against a MySQL flavored Cloud SQL instance. package tests import ( "flag" "io/ioutil" "log" "os" "path" "runtime" "testing" mysql "github.com/go-sql-driver/mysql" ) var ( mysqlConnName = flag.String("mysql_conn_name", os.Getenv("MYSQL_CONNECTION_NAME"), "Cloud SQL MYSQL instance connection name, in the form of 'project:region:instance'.") mysqlUser = flag.String("mysql_user", os.Getenv("MYSQL_USER"), "Name of database user.") mysqlPass = flag.String("mysql_pass", os.Getenv("MYSQL_PASS"), "Password for the database user; be careful when entering a password on the command line (it may go into your terminal's history).") mysqlDb = flag.String("mysql_db", os.Getenv("MYSQL_DB"), "Name of the database to connect to.") mysqlPort = 3306 ) func requireMysqlVars(t *testing.T) { switch "" { case *mysqlConnName: t.Fatal("'mysql_conn_name' not set") case *mysqlUser: t.Fatal("'mysql_user' not set") case *mysqlPass: t.Fatal("'mysql_pass' not set") case *mysqlDb: t.Fatal("'mysql_db' not set") } } func TestMysqlTcp(t *testing.T) { if testing.Short() { t.Skip("skipping MySQL integration tests") } requireMysqlVars(t) cfg := mysql.Config{ User: *mysqlUser, Passwd: *mysqlPass, DBName: *mysqlDb, AllowNativePasswords: true, } proxyConnTest(t, *mysqlConnName, "mysql", cfg.FormatDSN(), mysqlPort, "") } func TestMysqlSocket(t *testing.T) { if testing.Short() { t.Skip("skipping MySQL integration tests") } if runtime.GOOS == "windows" { t.Skip("Skipped Unix socket test on Windows") } requireMysqlVars(t) dir, err := ioutil.TempDir("", "csql-proxy-tests") if err != nil { log.Fatalf("unable to create tmp dir: %s", err) } defer os.RemoveAll(dir) cfg := mysql.Config{ User: *mysqlUser, Passwd: *mysqlPass, Net: "unix", Addr: path.Join(dir, *mysqlConnName), DBName: *mysqlDb, AllowNativePasswords: true, } proxyConnTest(t, *mysqlConnName, "mysql", cfg.FormatDSN(), 0, dir) } func TestMysqlConnLimit(t *testing.T) { if testing.Short() { t.Skip("skipping MySQL integration tests") } requireMysqlVars(t) cfg := mysql.Config{ User: *mysqlUser, Passwd: *mysqlPass, DBName: *mysqlDb, AllowNativePasswords: true, } proxyConnLimitTest(t, *mysqlConnName, "mysql", cfg.FormatDSN(), mysqlPort) } // Test to verify that when a proxy client serves one mysql instance that can be // dialed successfully, the health check readiness endpoint serves http.StatusOK. func TestMysqlDial(t *testing.T) { if testing.Short() { t.Skip("skipping MySQL integration tests") } switch "" { case *mysqlConnName: t.Fatal("'mysql_conn_name' not set") } singleInstanceDial(t, *mysqlConnName) } cloud-sql-proxy-1.33.14/tests/postgres_test.go000066400000000000000000000117721452473605000213610ustar00rootroot00000000000000// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // postgres_test runs various tests against a Postgres flavored Cloud SQL instance. package tests import ( "context" "database/sql" "flag" "fmt" "io/ioutil" "log" "os" "path" "runtime" "testing" "time" _ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/postgres" _ "github.com/lib/pq" ) var ( postgresConnName = flag.String("postgres_conn_name", os.Getenv("POSTGRES_CONNECTION_NAME"), "Cloud SQL Postgres instance connection name, in the form of 'project:region:instance'.") postgresUser = flag.String("postgres_user", os.Getenv("POSTGRES_USER"), "Name of database user.") postgresPass = flag.String("postgres_pass", os.Getenv("POSTGRES_PASS"), "Password for the database user; be careful when entering a password on the command line (it may go into your terminal's history).") postgresDb = flag.String("postgres_db", os.Getenv("POSTGRES_DB"), "Name of the database to connect to.") postgresIAMUser = flag.String("postgres_user_iam", os.Getenv("POSTGRES_USER_IAM"), "Name of database user configured with IAM DB Authentication.") postgresPort = 5432 ) func requirePostgresVars(t *testing.T) { switch "" { case *postgresConnName: t.Fatal("'postgres_conn_name' not set") case *postgresUser: t.Fatal("'postgres_user' not set") case *postgresPass: t.Fatal("'postgres_pass' not set") case *postgresDb: t.Fatal("'postgres_db' not set") } } func TestPostgresTcp(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") } requirePostgresVars(t) dsn := fmt.Sprintf("user=%s password=%s database=%s sslmode=disable", *postgresUser, *postgresPass, *postgresDb) proxyConnTest(t, *postgresConnName, "postgres", dsn, postgresPort, "") } func TestPostgresSocket(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") } if runtime.GOOS == "windows" { t.Skip("Skipped Unix socket test on Windows") } requirePostgresVars(t) dir, err := ioutil.TempDir("", "csql-proxy") if err != nil { log.Fatalf("unable to create tmp dir: %s", err) } defer os.RemoveAll(dir) dsn := fmt.Sprintf("user=%s password=%s database=%s host=%s", *postgresUser, *postgresPass, *postgresDb, path.Join(dir, *postgresConnName)) proxyConnTest(t, *postgresConnName, "postgres", dsn, 0, dir) } func TestPostgresConnLimit(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") } requirePostgresVars(t) dsn := fmt.Sprintf("user=%s password=%s database=%s sslmode=disable", *postgresUser, *postgresPass, *postgresDb) proxyConnLimitTest(t, *postgresConnName, "postgres", dsn, postgresPort) } func TestPostgresIAMDBAuthn(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") } requirePostgresVars(t) if *postgresIAMUser == "" { t.Fatal("'postgres_user_iam' not set") } ctx := context.Background() // Start the proxy p, err := StartProxy(ctx, fmt.Sprintf("-instances=%s=tcp:%d", *postgresConnName, 5432), "-enable_iam_login") if err != nil { t.Fatalf("unable to start proxy: %v", err) } defer p.Close() output, err := p.WaitForServe(ctx) if err != nil { t.Fatalf("unable to verify proxy was serving: %s \n %s", err, output) } dsn := fmt.Sprintf("user=%s database=%s sslmode=disable", *postgresIAMUser, *postgresDb) db, err := sql.Open("postgres", dsn) if err != nil { t.Fatalf("unable to connect to db: %s", err) } defer db.Close() _, err = db.Exec("SELECT 1;") if err != nil { t.Fatalf("unable to exec on db: %s", err) } } func TestPostgresHook(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", *postgresConnName, *postgresUser, *postgresPass, *postgresDb) db, err := sql.Open("cloudsqlpostgres", dsn) if err != nil { t.Fatalf("connect failed: %s", err) } defer db.Close() var now time.Time err = db.QueryRowContext(ctx, "SELECT NOW()").Scan(&now) if err != nil { t.Fatalf("query failed: %s", err) } } // Test to verify that when a proxy client serves one postgres instance that can be // dialed successfully, the health check readiness endpoint serves http.StatusOK. func TestPostgresDial(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") } switch "" { case *postgresConnName: t.Fatal("'postgres_conn_name' not set") } singleInstanceDial(t, *postgresConnName) } cloud-sql-proxy-1.33.14/tests/sqlserver_test.go000066400000000000000000000053621452473605000215370ustar00rootroot00000000000000// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // sqlserver_test runs various tests against a SqlServer flavored Cloud SQL instance. package tests import ( "flag" "fmt" "os" "testing" _ "github.com/microsoft/go-mssqldb" ) var ( sqlserverConnName = flag.String("sqlserver_conn_name", os.Getenv("SQLSERVER_CONNECTION_NAME"), "Cloud SQL SqlServer instance connection name, in the form of 'project:region:instance'.") sqlserverUser = flag.String("sqlserver_user", os.Getenv("SQLSERVER_USER"), "Name of database user.") sqlserverPass = flag.String("sqlserver_pass", os.Getenv("SQLSERVER_PASS"), "Password for the database user; be careful when entering a password on the command line (it may go into your terminal's history).") sqlserverDb = flag.String("sqlserver_db", os.Getenv("SQLSERVER_DB"), "Name of the database to connect to.") sqlserverPort = 1433 ) func requireSqlserverVars(t *testing.T) { switch "" { case *sqlserverConnName: t.Fatal("'sqlserver_conn_name' not set") case *sqlserverUser: t.Fatal("'sqlserver_user' not set") case *sqlserverPass: t.Fatal("'sqlserver_pass' not set") case *sqlserverDb: t.Fatal("'sqlserver_db' not set") } } func TestSqlServerTcp(t *testing.T) { if testing.Short() { t.Skip("skipping SQL Server integration tests") } requireSqlserverVars(t) dsn := fmt.Sprintf("sqlserver://%s:%s@127.0.0.1?database=%s", *sqlserverUser, *sqlserverPass, *sqlserverDb) proxyConnTest(t, *sqlserverConnName, "sqlserver", dsn, sqlserverPort, "") } func TestSqlserverConnLimit(t *testing.T) { if testing.Short() { t.Skip("skipping SQL Server integration tests") } requireSqlserverVars(t) dsn := fmt.Sprintf("sqlserver://%s:%s@127.0.0.1?database=%s", *sqlserverUser, *sqlserverPass, *sqlserverDb) proxyConnLimitTest(t, *sqlserverConnName, "sqlserver", dsn, sqlserverPort) } // Test to verify that when a proxy client serves one sqlserver instance that can be // dialed successfully, the health check readiness endpoint serves http.StatusOK. func TestSqlserverDial(t *testing.T) { if testing.Short() { t.Skip("skipping SQL Server integration tests") } switch "" { case *sqlserverConnName: t.Fatal("'sqlserver_conn_name' not set") } singleInstanceDial(t, *sqlserverConnName) }