Multiplex the Vault Provider (#2382)

* Multiplex provider to support both SDKv2 and Plugin Framework

* [Phase 1] Multiplex provider - minimal TF Plugin Framework provider implementation (#2067)

* [Phase 2] Complete the provider configuration setup (#2090)

* [Phase 3] Include Auth Login blocks in multiplexed Provider configuration (#2097)

* [Phase 4] Migrate resource `vault_password_policy` to new FW and add tests

Co-authored-by: Vinay Gopalan <vinay@hashicorp.com>
Co-authored-by: JM Faircloth <jmfaircloth@hashicorp.com>
This commit is contained in:
vinay-gopalan 2025-05-07 09:48:12 -07:00 committed by GitHub
parent 90f4969e93
commit ab599e6324
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
78 changed files with 3470 additions and 1349 deletions

View file

@ -33,7 +33,7 @@ jobs:
# this then the terraform-plugin-sdk will attempt to download it for each test!
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: '1.7.*'
terraform_version: '1.11.*'
terraform_wrapper: false
- name: Cache go build

153
go.mod
View file

@ -1,19 +1,21 @@
module github.com/hashicorp/terraform-provider-vault
go 1.21
go 1.23.3
toolchain go1.23.4
require (
cloud.google.com/go/compute/metadata v0.2.3
cloud.google.com/go/iam v1.1.5
cloud.google.com/go/compute/metadata v0.6.0
cloud.google.com/go/iam v1.2.2
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
github.com/aws/aws-sdk-go v1.50.13
github.com/cenkalti/backoff/v4 v4.2.1
github.com/aws/aws-sdk-go v1.55.6
github.com/cenkalti/backoff/v4 v4.3.0
github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8
github.com/denisenkom/go-mssqldb v0.12.3
github.com/go-sql-driver/mysql v1.7.1
github.com/go-test/deep v1.1.0
github.com/go-sql-driver/mysql v1.8.1
github.com/go-test/deep v1.1.1
github.com/google/uuid v1.6.0
github.com/gosimple/slug v1.13.1
github.com/hashicorp/consul/api v1.27.0
@ -23,97 +25,104 @@ require (
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0
github.com/hashicorp/go-secure-stdlib/awsutil v0.2.3
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.9
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/terraform-plugin-framework v1.14.1
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0
github.com/hashicorp/terraform-plugin-go v0.26.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-mux v0.18.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1
github.com/hashicorp/vault-plugin-auth-jwt v0.20.3
github.com/hashicorp/vault-plugin-auth-kerberos v0.11.0
github.com/hashicorp/vault-plugin-auth-oci v0.15.1
github.com/hashicorp/vault/api v1.14.0
github.com/hashicorp/vault/sdk v0.13.0
github.com/hashicorp/vault/api v1.16.0
github.com/hashicorp/vault/sdk v0.15.2
github.com/jackc/pgx/v4 v4.18.3
github.com/jcmturner/gokrb5/v8 v8.4.4
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.5.0
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.31.0
golang.org/x/net v0.33.0
golang.org/x/oauth2 v0.18.0
google.golang.org/api v0.163.0
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe
k8s.io/utils v0.0.0-20240102154912-e7106e64919e
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.33.0
golang.org/x/net v0.34.0
golang.org/x/oauth2 v0.25.0
google.golang.org/api v0.219.0
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
)
require (
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/auth v0.14.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/agext/levenshtein v1.2.2 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/containerd/containerd v1.7.12 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-oidc/v3 v3.10.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v25.0.6+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/docker v27.2.1+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/frankban/quicktest v1.14.6 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-ldap/ldap/v3 v3.4.6 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
github.com/go-ldap/ldap/v3 v3.4.8 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.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.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.3.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/hashicorp/cap v0.6.0 // indirect
github.com/hashicorp/cap/ldap v0.0.0-20240328153749-fcfe271d0227 // indirect
github.com/hashicorp/cap/ldap v0.0.0-20250106213447-9047b8b3240f // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.1 // indirect
github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect
github.com/hashicorp/go-plugin v1.6.0 // indirect
github.com/hashicorp/go-kms-wrapping/v2 v2.0.18 // indirect
github.com/hashicorp/go-msgpack v1.1.5 // indirect
github.com/hashicorp/go-plugin v1.6.2 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect
github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.1 // indirect
github.com/hashicorp/go-secure-stdlib/mlock v0.1.3 // indirect
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.3.0 // indirect
github.com/hashicorp/go-secure-stdlib/permitpool v1.0.0 // indirect
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.4.1 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 // indirect
github.com/hashicorp/go-sockaddr v1.0.6 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/hc-install v0.6.2 // indirect
github.com/hashicorp/hc-install v0.9.1 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/hashicorp/hcl/v2 v2.19.1 // indirect
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/hashicorp/terraform-exec v0.19.0 // indirect
github.com/hashicorp/terraform-json v0.18.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.20.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-exec v0.22.0 // indirect
github.com/hashicorp/terraform-json v0.24.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.4 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
@ -122,15 +131,15 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgtype v1.14.3 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -139,47 +148,49 @@ require (
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/pointerstructure v1.2.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/moby/sys/user v0.2.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/natefinch/atomic v1.0.1 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/oracle/oci-go-sdk/v59 v59.0.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sasha-s/go-deadlock v0.2.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/zclconf/go-cty v1.14.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
github.com/zclconf/go-cty v1.16.2 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel v1.32.0 // indirect
go.opentelemetry.io/otel/metric v1.32.0 // indirect
go.opentelemetry.io/otel/trace v1.32.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.29.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/grpc v1.61.1 // indirect
google.golang.org/protobuf v1.34.1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 // indirect
google.golang.org/grpc v1.70.0 // indirect
google.golang.org/protobuf v1.36.4 // indirect
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

374
go.sum
View file

@ -161,6 +161,10 @@ cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav
cloud.google.com/go/assuredworkloads v1.11.2/go.mod h1:O1dfr+oZJMlE6mw0Bp0P1KZSlj5SghMBvTpZqIcUAW4=
cloud.google.com/go/assuredworkloads v1.11.3/go.mod h1:vEjfTKYyRUaIeA0bsGJceFV2JKpVRgyG2op3jfa59Zs=
cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U=
cloud.google.com/go/auth v0.14.0 h1:A5C4dKV/Spdvxcl0ggWwWEzzP7AZMJSEIgrkngwhGYM=
cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A=
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
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=
@ -304,13 +308,13 @@ cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78=
cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
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/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
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=
@ -593,8 +597,9 @@ cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+K
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/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8=
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA=
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
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=
@ -1142,6 +1147,8 @@ cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/v
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
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/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
@ -1173,8 +1180,9 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
@ -1203,8 +1211,9 @@ github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
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/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@ -1216,8 +1225,9 @@ github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOp
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
@ -1233,8 +1243,6 @@ github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfy
github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@ -1243,8 +1251,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
@ -1262,8 +1270,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
github.com/alexflint/go-filemutex v1.2.0/go.mod h1:mYyQSWvw9Tx2/H2n9qXPb52tTYfE0pZAWcBq5mK025c=
@ -1294,8 +1302,8 @@ github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo
github.com/aws/aws-sdk-go v1.34.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.43.9/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.50.13 h1:yeXram2g7q8uKkQkAEeZyk9FmPzxI4UpGwAZGZtEGmM=
github.com/aws/aws-sdk-go v1.50.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@ -1314,14 +1322,14 @@ github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM=
github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@ -1332,8 +1340,8 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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=
@ -1359,7 +1367,6 @@ github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnx
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
@ -1377,7 +1384,6 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH
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/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/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=
@ -1431,8 +1437,6 @@ github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0
github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
github.com/containerd/containerd v1.6.9/go.mod h1:XVicUvkxOrftE2Q1YWUXgZwkkAxwQYNOFzYWvfVfEfQ=
github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc=
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@ -1441,9 +1445,8 @@ github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR
github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
@ -1547,8 +1550,8 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
@ -1592,13 +1595,14 @@ github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05
github.com/docker/docker v20.10.20+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg=
github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI=
github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
@ -1639,7 +1643,6 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+
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 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@ -1651,8 +1654,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@ -1669,9 +1672,8 @@ github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897/go.mod h1:lgRN6+
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
@ -1696,10 +1698,10 @@ github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2H
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk=
github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg=
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E=
github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw=
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=
@ -1708,8 +1710,8 @@ github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
@ -1719,8 +1721,8 @@ github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpx
github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
@ -1732,8 +1734,8 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
@ -1757,13 +1759,15 @@ github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhO
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
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-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -1774,8 +1778,9 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0/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/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc=
github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -1844,9 +1849,12 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
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/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw=
github.com/google/certificate-transparency-go v1.3.1 h1:akbcTfQg0iZlANZLn0L9xOeWtyCIdeoYhKrqi5iH3Go=
github.com/google/certificate-transparency-go v1.3.1/go.mod h1:gg+UQlx6caKEDQ9EElFOujyxEQEfOiQzAt6782Bvi8k=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
@ -1899,8 +1907,9 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
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/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
@ -1920,8 +1929,9 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5
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/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
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=
@ -1936,8 +1946,9 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38
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/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
@ -1971,12 +1982,12 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
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/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/hashicorp/cap v0.6.0 h1:uOSdbtXu8zsbRyjwpiTy6QiuX3+5paAbNkYlop7QexM=
github.com/hashicorp/cap v0.6.0/go.mod h1:DwzHkoG6pxSARiqwvAgxmCPUpTTCCw2wVuPrIFOzpe0=
github.com/hashicorp/cap/ldap v0.0.0-20240328153749-fcfe271d0227 h1:R5CMNyBNZqODw2DcGaSa2X96AgtLotXsH7aOa07zTTI=
github.com/hashicorp/cap/ldap v0.0.0-20240328153749-fcfe271d0227/go.mod h1:Ofp5fMLl1ImcwjNGu9FtEwNOdxA0LYoWpcWQE2vltuI=
github.com/hashicorp/cap/ldap v0.0.0-20250106213447-9047b8b3240f h1:iixO0KNqHfSMImUgaHnMHTzmu0FVLwk7VzIZf6++wak=
github.com/hashicorp/cap/ldap v0.0.0-20250106213447-9047b8b3240f/go.mod h1:vGqAhHKOR5gadKWjwhoWp3RKto/tmhVOtH8gcD0c8ss=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc=
github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8=
@ -2002,6 +2013,8 @@ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH
github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6 h1:kBoJV4Xl5FLtBfnBjDvBxeNSy2IRITSGs73HQsFUEjY=
github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6/go.mod h1:y+HSOcOGB48PkUxNyLAiCiY6rEENu+E+Ss4LG8QHwf4=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
@ -2010,11 +2023,11 @@ github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8D
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.1 h1:KIge4FHZEDb2/xjaWgmBheCTgRL6HV4sgTfDsH876L8=
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.1/go.mod h1:aHO1EoFD0kBYLBedqxXgalfFT8lrWfP7kpuSoaqGjH0=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.18 h1:DLfC677GfKEpSAFpEWvl1vXsGpEcSHmbhBaPLrdDQHc=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.18/go.mod h1:t/eaR/mi2mw3klfl1WEAuiLKrlZ/Q8cosmsT+RIPLu0=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs=
github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
@ -2023,8 +2036,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
github.com/hashicorp/go-plugin v1.5.1/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4=
github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4=
github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
@ -2033,11 +2046,13 @@ github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFO
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0 h1:I8bynUKMh9I7JdwtW9voJ0xmHvBpxQtLjrMFDYmhOxY=
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0/go.mod h1:oKHSQs4ivIfZ3fbXGQOop1XuDfdSb8RIsWTGaAanSfg=
github.com/hashicorp/go-secure-stdlib/awsutil v0.2.3 h1:AAQ6Vmo/ncfrZYtbpjhO+g0Qt+iNpYtl3UWT1NLmbYY=
github.com/hashicorp/go-secure-stdlib/awsutil v0.2.3/go.mod h1:oKHSQs4ivIfZ3fbXGQOop1XuDfdSb8RIsWTGaAanSfg=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.1 h1:VaLXp47MqD1Y2K6QVrA9RooQiPyCgAbnfeJg44wKuJk=
github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.1/go.mod h1:hH8rgXHh9fPSDPerG6WzABHsHF+9ZpLhRI1LPk4JZ8c=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.3 h1:kH3Rhiht36xhAfhuHyWJDgdXXEx9IIZhDGRk24CDhzg=
@ -2045,12 +2060,14 @@ github.com/hashicorp/go-secure-stdlib/mlock v0.1.3/go.mod h1:ov1Q0oEDjC3+A4BwsG2
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.9 h1:FW0YttEnUNDJ2WL9XcrrfteS1xW8u+sh4ggM8pN5isQ=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.9/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/permitpool v1.0.0 h1:U6y5MXGiDVOOtkWJ6o/tu1TxABnI0yKTQWJr7z6BpNk=
github.com/hashicorp/go-secure-stdlib/permitpool v1.0.0/go.mod h1:ecDb3o+8D4xtP0nTCufJaAVawHavy5M2eZ64Nq/8/LM=
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.2.2/go.mod h1:7xQt0+IfRmzYBLpFx+4MYfLpBdd1PT1VatGKRswf7xE=
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.3.0 h1:KMWpBsC65ZBXDpoxJ0n2/zVfZaZIW73k2d8cy5Dv/Kk=
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.3.0/go.mod h1:qKYwSZ2EOpppko5ud+Sh9TrUgiTAZSaQCr8XWIYXsbM=
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.4.1 h1:JY+zGg8gOmslwif1fiCqT5Hu1SikLZQcHkmQhCoA9gY=
github.com/hashicorp/go-secure-stdlib/plugincontainer v0.4.1/go.mod h1:jW3KCTvdPyAdVecOUwiiO2XaYgUJ/isigt++ISkszkY=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
@ -2069,21 +2086,22 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hc-install v0.6.2 h1:V1k+Vraqz4olgZ9UzKiAcbman9i9scg9GgSt/U3mw/M=
github.com/hashicorp/hc-install v0.6.2/go.mod h1:2JBpd+NCFKiHiu/yYCGaPyPHhZLxXTpz8oreHa/a3Ps=
github.com/hashicorp/hc-install v0.9.1 h1:gkqTfE3vVbafGQo6VZXcy2v5yoz2bE0+nhZXruCuODQ=
github.com/hashicorp/hc-install v0.9.1/go.mod h1:pWWvN/IrfeBK4XPeXXYkL6EjMufHkCK5DvwxeLKuBf0=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
@ -2094,18 +2112,24 @@ github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81SpgVtZNNtFSM=
github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg=
github.com/hashicorp/terraform-json v0.18.0 h1:pCjgJEqqDESv4y0Tzdqfxr/edOIGkjs8keY42xfNBwU=
github.com/hashicorp/terraform-json v0.18.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk=
github.com/hashicorp/terraform-plugin-go v0.20.0 h1:oqvoUlL+2EUbKNsJbIt3zqqZ7wi6lzn4ufkn/UA51xQ=
github.com/hashicorp/terraform-plugin-go v0.20.0/go.mod h1:Rr8LBdMlY53a3Z/HpP+ZU3/xCDqtKNCkeI9qOyT10QE=
github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8l+uRmZHj64=
github.com/hashicorp/terraform-exec v0.22.0/go.mod h1:bjVbsncaeh8jVdhttWYZuBGj21FcYw6Ia/XfHcNO7lQ=
github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q=
github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow=
github.com/hashicorp/terraform-plugin-framework v1.14.1 h1:jaT1yvU/kEKEsxnbrn4ZHlgcxyIfjvZ41BLdlLk52fY=
github.com/hashicorp/terraform-plugin-framework v1.14.1/go.mod h1:xNUKmvTs6ldbwTuId5euAtg37dTxuyj3LHS3uj7BHQ4=
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0 h1:0uYQcqqgW3BMyyve07WJgpKorXST3zkpzvrOnf3mpbg=
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0/go.mod h1:VwdfgE/5Zxm43flraNa0VjcvKQOGVrcO4X8peIri0T0=
github.com/hashicorp/terraform-plugin-go v0.26.0 h1:cuIzCv4qwigug3OS7iKhpGAbZTiypAfFQmw8aE65O2M=
github.com/hashicorp/terraform-plugin-go v0.26.0/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0 h1:Bl3e2ei2j/Z3Hc2HIS15Gal2KMKyLAZ2om1HCEvK6es=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0/go.mod h1:i2C41tszDjiWfziPQDL5R/f3Zp0gahXe5No/MIO9rCE=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
github.com/hashicorp/terraform-plugin-mux v0.18.0 h1:7491JFSpWyAe0v9YqBT+kel7mzHAbO5EpxxT0cUL/Ms=
github.com/hashicorp/terraform-plugin-mux v0.18.0/go.mod h1:Ho1g4Rr8qv0qTJlcRKfjjXTIO67LNbDtM6r+zHUNHJQ=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 h1:WNMsTLkZf/3ydlgsuXePa3jvZFwAJhruxTxP/c1Viuw=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1/go.mod h1:P6o64QS97plG44iFzSM6rAn6VJIC/Sy9a9IkEtl79K4=
github.com/hashicorp/terraform-registry-address v0.2.4 h1:JXu/zHB2Ymg/TGVCRu10XqNa4Sh2bWcqCNyKWjnCPJA=
github.com/hashicorp/terraform-registry-address v0.2.4/go.mod h1:tUNYTVyCtU4OIGXXMDp7WNcJ+0W1B4nmstVDgHMjfAU=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/vault-plugin-auth-jwt v0.20.3 h1:mLsdorH4m43rBqybHDZKl33rrmc80ens4hSB6E7i9o0=
@ -2117,12 +2141,12 @@ github.com/hashicorp/vault-plugin-auth-oci v0.15.1/go.mod h1:i3KYRLQFpAIJuvbXHBM
github.com/hashicorp/vault/api v1.4.1/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM=
github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs=
github.com/hashicorp/vault/api v1.11.0/go.mod h1:si+lJCYO7oGkIoNPAN8j3azBLTn9SjMGS+jFaHd1Cck=
github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU=
github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk=
github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4=
github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA=
github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0=
github.com/hashicorp/vault/sdk v0.10.2/go.mod h1:VxJIQgftEX7FCDM3i6TTLjrZszAeLhqPicNbCVNRg4I=
github.com/hashicorp/vault/sdk v0.13.0 h1:UmcLF+7r70gy1igU44Suflgio30P2GOL4MkHPhJuiP8=
github.com/hashicorp/vault/sdk v0.13.0/go.mod h1:LxhNTWRG99mXg9xijBCnCnIus+brLC5uFsQUQ4zgOnU=
github.com/hashicorp/vault/sdk v0.15.2 h1:Rp5Yp4lyBhlWgq24ZVb2n/YN47RKOAvmx/jlMfS9ku4=
github.com/hashicorp/vault/sdk v0.15.2/go.mod h1:2Wj2tHIgfz0gNWgEPWBbCXFIiPrq96E8FTjPNV9J1Bc=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
@ -2184,13 +2208,15 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C
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/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus=
github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
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/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
@ -2217,15 +2243,17 @@ github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+
github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/jimlambrt/gldap v0.1.13 h1:jxmVQn0lfmFbM9jglueoau5LLF/IGRti0SKf0vB753M=
github.com/jimlambrt/gldap v0.1.13/go.mod h1:nlC30c7xVphjImg6etk7vg7ZewHCCvl1dfAhO3ZJzPg=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
@ -2266,8 +2294,8 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
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=
@ -2299,8 +2327,9 @@ github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTRe
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 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
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/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
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=
@ -2390,6 +2419,8 @@ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
@ -2404,8 +2435,10 @@ github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/sys/user v0.2.0 h1:OnpapJsRp25vkhw8TFG6OLJODNh/3rEwRWtJ3kakwRM=
github.com/moby/sys/user v0.2.0/go.mod h1:RYstrcWOJpVh+6qzUqp2bU3eaRpdiQeKGlKitaH0PM8=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
@ -2492,8 +2525,9 @@ github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@ -2540,8 +2574,8 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
@ -2620,6 +2654,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
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=
@ -2644,8 +2680,8 @@ github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIH
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.2.0/go.mod h1:WkKB1DnNtvsMlDmQ50sgwowDJV/hGbJSOvJoEXs1AJQ=
github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
@ -2655,11 +2691,12 @@ github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvW
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
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/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
@ -2672,8 +2709,8 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@ -2731,8 +2768,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
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/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -2798,8 +2835,10 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
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=
@ -2832,7 +2871,6 @@ 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/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
@ -2840,13 +2878,13 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.0/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
@ -2854,8 +2892,8 @@ go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+n
go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM=
go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ=
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
@ -2867,8 +2905,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDD
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0/go.mod h1:Krqnjl22jUJ0HgMzw5eveuCvFDXY4nSYb4F8t5gdrag=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o=
@ -2876,14 +2914,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0/go.mod h
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 h1:umZgi92IyxfXd/l4kaDhnKgY8rnN/cZcF1LKc6I8OQ8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0/go.mod h1:4lVs6obhSVRb1EW5FhOuBTyiQhtRtAnnva9vD3yRfq8=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU=
go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A=
go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
@ -2891,10 +2929,12 @@ go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1t
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE=
go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
@ -2902,16 +2942,16 @@ go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48
go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4=
go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM=
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
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=
@ -2973,7 +3013,6 @@ golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
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=
@ -2985,8 +3024,10 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
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=
@ -3002,8 +3043,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
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/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
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=
@ -3050,8 +3091,8 @@ 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/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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=
@ -3144,8 +3185,10 @@ 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/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
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=
@ -3181,8 +3224,8 @@ golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQ
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/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -3203,8 +3246,8 @@ 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.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -3364,8 +3407,9 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -3387,8 +3431,9 @@ 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/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
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=
@ -3410,8 +3455,8 @@ 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/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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=
@ -3424,8 +3469,8 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb
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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
@ -3438,6 +3483,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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=
@ -3515,8 +3561,8 @@ 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/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
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=
@ -3602,8 +3648,8 @@ google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWL
google.golang.org/api v0.134.0/go.mod h1:sjRL3UnjTx5UqNQS9EWr9N8p7xbHpy1k0XGRLCf3Spk=
google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk=
google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI=
google.golang.org/api v0.163.0 h1:4BBDpPaSH+H28NhnX+WwjXxbRLQ7TWuEKp4BQyEjxvk=
google.golang.org/api v0.163.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0=
google.golang.org/api v0.219.0 h1:nnKIvxKs/06jWawp2liznTBnMRQBEPpGo7I+oEypTX0=
google.golang.org/api v0.219.0/go.mod h1:K6OmjGm+NtLrIkHxv1U3a0qIf/0JOvAHd5O/6AoyKYE=
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=
@ -3773,8 +3819,8 @@ google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo=
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
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=
@ -3792,8 +3838,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8=
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
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-20230720185612-659f7aaaa771/go.mod h1:3QoBVwTHkXbY1oRGzlhwhOykfcATQN43LJ6iT8Wy8kE=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c=
@ -3816,8 +3862,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 h1:91mG8dNTpkC0uChJUQ9zCiRqx3GEEFOWaRZ0mI6Oj2I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -3874,8 +3920,8 @@ google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSs
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
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=
@ -3896,8 +3942,8 @@ google.golang.org/protobuf v1.28.2-0.20230222093303-bc1253ad3743/go.mod h1:HV8QO
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/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -4019,8 +4065,8 @@ k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ=
k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
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=

View file

@ -528,7 +528,8 @@ const (
common environment variables
*/
EnvVarVaultNamespaceImport = "TERRAFORM_VAULT_NAMESPACE_IMPORT"
EnvVarSkipChildToken = "TERRAFORM_VAULT_SKIP_CHILD_TOKEN"
// EnvVarSkipChildToken to allow user from creating child tokens
EnvVarSkipChildToken = "TERRAFORM_VAULT_SKIP_CHILD_TOKEN"
// EnvVarUsername to get the username for the userpass auth method
EnvVarUsername = "TERRAFORM_VAULT_USERNAME"
// EnvVarPassword to get the password for the userpass auth method

View file

@ -0,0 +1,76 @@
package base
import (
"context"
"fmt"
"os"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
)
type withMeta struct {
meta *provider.ProviderMeta
}
func (w *withMeta) Meta() *provider.ProviderMeta {
return w.meta
}
// ResourceWithConfigure is a structure to be embedded within a Resource that
// implements the ResourceWithConfigure interface.
type ResourceWithConfigure struct {
withMeta
}
// Configure enables provider-level data or clients to be set in the
// provider-defined Resource type.
func (r *ResourceWithConfigure) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
if v, ok := request.ProviderData.(*provider.ProviderMeta); ok {
r.meta = v
}
}
// WithImportByID is intended to be embedded in resources which import state
// via the "id" attribute.
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources/import.
//
// This will ensure the Vault namespace is written to state if it is set in the
// environment.
// https://registry.terraform.io/providers/hashicorp/vault/latest/docs#namespace-support
type WithImportByID struct{}
func (w *WithImportByID) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root(consts.FieldID), request, response)
ns := os.Getenv(consts.EnvVarVaultNamespaceImport)
if ns != "" {
tflog.Info(
ctx,
fmt.Sprintf("Environment variable %s set, attempting TF state import", consts.EnvVarVaultNamespaceImport),
map[string]any{consts.FieldNamespace: ns},
)
response.Diagnostics.Append(
response.State.SetAttribute(ctx, path.Root(consts.FieldNamespace), ns)...,
)
}
}
// DataSourceWithConfigure is a structure to be embedded within a DataSource
// that implements the DataSourceWithConfigure interface.
type DataSourceWithConfigure struct {
withMeta
}
// Configure enables provider-level data or clients to be set in the
// provider-defined DataSource type.
func (d *DataSourceWithConfigure) Configure(_ context.Context, request datasource.ConfigureRequest, response *datasource.ConfigureResponse) {
if v, ok := request.ProviderData.(*provider.ProviderMeta); ok {
d.meta = v
}
}

View file

@ -0,0 +1,97 @@
package base
import (
"fmt"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/framework/validators"
)
// BaseModel describes common fields for all Terraform resource data models
//
// This struct should be embedded into all Terraform Plugin Framework Resources and Data Sources.
type BaseModel struct {
Namespace types.String `tfsdk:"namespace"`
}
// BaseModelLegacy describes common fields for all Terraform resource
// data models that have been migrated from SDKv2 to the TF Plugin Framework.
//
// This struct should be embedded into all SDKv2 Resources and Data Sources.
type BaseModelLegacy struct {
BaseModel
ID types.String `tfsdk:"id"`
}
// MustAddBaseSchema adds the schema fields that are required for all net new
// resources and data sources built with the TF Plugin Framework.
//
// This should be called from a resources or data source's Schema() method.
func MustAddBaseSchema(s *schema.Schema) {
mustAddSchema(s, baseSchema)
}
// MustAddLegacyBaseSchema adds the schema fields that are required for
// resources and data sources that have been migrated from SDKv2 to the
// Terraform Plugin Framework.
//
// This should be called from a resources or data source's Schema() method.
func MustAddLegacyBaseSchema(s *schema.Schema) {
mustAddSchema(s, baseSchema)
mustAddSchema(s, legacyBaseSchema)
}
func legacyBaseSchema() map[string]schema.Attribute {
return map[string]schema.Attribute{
// Add an 'id' field to the base schema because
// 1. The id field was implicitly added in the SDKv2, so we must
// explicitly add it for existing resources, otherwise its a
// breaking change for practitioners.
// 2. The id field is required for acceptance testing with the SDKv2
// package.
// See:
// https://developer.hashicorp.com/terraform/plugin/framework/acctests#no-id-found-in-attributes
// https://github.com/hashicorp/terraform-plugin-framework/issues/896
consts.FieldID: schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
}
}
type schemaFunc func() map[string]schema.Attribute
func baseSchema() map[string]schema.Attribute {
return map[string]schema.Attribute{
consts.FieldNamespace: schema.StringAttribute{
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
MarkdownDescription: "Target namespace. (requires Enterprise)",
Validators: []validator.String{
validators.PathValidator(),
},
},
}
}
func mustAddSchema(s *schema.Schema, schemaFuncs ...schemaFunc) {
for _, f := range schemaFuncs {
for k, v := range f() {
if _, ok := s.Attributes[k]; ok {
panic(fmt.Sprintf("cannot add schema field %q, already exists in the Schema map", k))
}
s.Attributes[k] = v
}
}
}

View file

@ -0,0 +1,39 @@
package client
import (
"context"
"fmt"
"os"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/vault/api"
)
func GetClient(ctx context.Context, meta interface{}, namespace string) (*api.Client, error) {
var p *provider.ProviderMeta
switch v := meta.(type) {
case *provider.ProviderMeta:
p = v
default:
return nil, fmt.Errorf("meta argument must be a %T, not %T", p, meta)
}
ns := namespace
if namespace == "" {
// in order to import namespaced resources the user must provide
// the namespace from an environment variable.
ns = os.Getenv(consts.EnvVarVaultNamespaceImport)
if ns != "" {
tflog.Debug(ctx, fmt.Sprintf("Value for %q set from environment", consts.FieldNamespace))
}
}
if ns != "" {
return p.GetNSClient(ns)
}
return p.GetClient()
}

View file

@ -0,0 +1,43 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package errutil
const (
unexpectedErr = "An unexpected error occurred while attempting to read the resource. " +
"Please retry the operation or report this issue to the provider developers.\n\n"
)
func ClientConfigureErr(err error) (string, string) {
return "Error Configuring Resource Client", err.Error()
}
func VaultCreateErr(err error) (string, string) {
return "Unable to Create Resource",
unexpectedErr +
"HTTP Error: " + err.Error()
}
func VaultReadErr(err error) (string, string) {
return "Unable to Read Resource from Vault",
unexpectedErr +
"HTTP Error: " + err.Error()
}
func VaultUpdateErr(err error) (string, string) {
return "Unable to Update Resource",
unexpectedErr +
"HTTP Error: " + err.Error()
}
func VaultDeleteErr(err error) (string, string) {
return "Unable to Delete Resource",
unexpectedErr +
"HTTP Error: " + err.Error()
}
func VaultReadResponseNil() (string, string) {
return "Unable to Read Resource from Vault",
unexpectedErr +
"Vault response was nil"
}

View file

@ -0,0 +1,27 @@
package model
import (
"encoding/json"
"fmt"
)
// ToAPIModel is helper to translate Vault response data to its respective
// Vault API data model
func ToAPIModel(data, model any) error {
jsonData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf(
"An unexpected error occurred while attempting to marshal the Vault response.\n\n" +
"Error: " + err.Error(),
)
}
err = json.Unmarshal(jsonData, &model)
if err != nil {
return fmt.Errorf(
"An unexpected error occurred while attempting to unmarshal the data.\n\n" +
"Error: " + err.Error(),
)
}
return nil
}

View file

@ -0,0 +1,3 @@
# Terraform Plugin Framework Validators
This package contains custom Terraform Plugin Framework [validators](https://developer.hashicorp.com/terraform/plugin/framework/validation).

View file

@ -0,0 +1,62 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"fmt"
"os"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/mitchellh/go-homedir"
)
var _ validator.String = fileExists{}
// fileExists validates that a given token is a valid initialization token
type fileExists struct{}
// Description describes the validation in plain text formatting.
func (v fileExists) Description(_ context.Context) string {
return "value must be a valid path to an existing file"
}
// MarkdownDescription describes the validation in Markdown formatting.
func (v fileExists) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}
// ValidateString performs the validation.
func (v fileExists) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
return
}
value := request.ConfigValue.ValueString()
if value == "" {
response.Diagnostics.AddError("invalid file", "value cannot be empty")
return
}
filename, err := homedir.Expand(value)
if err != nil {
response.Diagnostics.AddError("invalid file", err.Error())
return
}
st, err := os.Stat(filename)
if err != nil {
response.Diagnostics.AddError("invalid file", fmt.Sprintf("failed to stat path %q, err=%s", filename, err))
return
}
if st.IsDir() {
response.Diagnostics.AddError("invalid file", fmt.Sprintf("path %q is not a file", filename))
return
}
}
func FileExistsValidator() validator.String {
return fileExists{}
}

View file

@ -0,0 +1,68 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"testing"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
const testFilePath = "./testdata/fake_account.json"
func TestFrameworkProvider_FileExistsValidator(t *testing.T) {
cases := map[string]struct {
configValue func(t *testing.T) types.String
expectedErrorCount int
}{
"file-is-valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue(testFilePath) // Path to a test fixture
},
},
"non-existant-file-is-not-valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue("./this/path/doesnt/exist.json") // Doesn't exist
},
expectedErrorCount: 1,
},
"empty-string-is-not-valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue("")
},
expectedErrorCount: 1,
},
"unconfigured-is-valid": {
configValue: func(t *testing.T) types.String {
return types.StringNull()
},
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
// Arrange
req := validator.StringRequest{
ConfigValue: tc.configValue(t),
}
resp := validator.StringResponse{
Diagnostics: diag.Diagnostics{},
}
f := FileExistsValidator()
// Act
f.ValidateString(context.Background(), req, &resp)
// Assert
if resp.Diagnostics.ErrorsCount() != tc.expectedErrorCount {
t.Errorf("Expected %d errors, got %d", tc.expectedErrorCount, resp.Diagnostics.ErrorsCount())
}
})
}
}

View file

@ -0,0 +1,49 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"os"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
googleoauth "golang.org/x/oauth2/google"
)
// Credentials Validator
var _ validator.String = credentialsValidator{}
// credentialsValidator validates that a string Attribute's is valid JSON credentials.
type credentialsValidator struct{}
// Description describes the validation in plain text formatting.
func (v credentialsValidator) Description(_ context.Context) string {
return "value must be a path to valid JSON credentials or valid, raw, JSON credentials"
}
// MarkdownDescription describes the validation in Markdown formatting.
func (v credentialsValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}
// ValidateString performs the validation.
func (v credentialsValidator) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
return
}
value := request.ConfigValue.ValueString()
// if this is a path and we can stat it, assume it's ok
if _, err := os.Stat(value); err == nil {
return
}
if _, err := googleoauth.CredentialsFromJSON(context.Background(), []byte(value)); err != nil {
response.Diagnostics.AddError("JSON credentials are not valid", err.Error())
}
}
func GCPCredentialsValidator() validator.String {
return credentialsValidator{}
}

View file

@ -0,0 +1,79 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"io/ioutil"
"testing"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
const testFakeCredentialsPath = "./testdata/fake_account.json"
func TestFrameworkProvider_CredentialsValidator(t *testing.T) {
cases := map[string]struct {
configValue func(t *testing.T) types.String
expectedErrorCount int
}{
"configuring credentials as a path to a credentials JSON file is valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue(testFakeCredentialsPath) // Path to a test fixture
},
},
"configuring credentials as a path to a non-existant file is NOT valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue("./this/path/doesnt/exist.json") // Doesn't exist
},
expectedErrorCount: 1,
},
"configuring credentials as a credentials JSON string is valid": {
configValue: func(t *testing.T) types.String {
contents, err := ioutil.ReadFile(testFakeCredentialsPath)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
stringContents := string(contents)
return types.StringValue(stringContents)
},
},
"configuring credentials as an empty string is not valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue("")
},
expectedErrorCount: 1,
},
"leaving credentials unconfigured is valid": {
configValue: func(t *testing.T) types.String {
return types.StringNull()
},
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
// Arrange
req := validator.StringRequest{
ConfigValue: tc.configValue(t),
}
resp := validator.StringResponse{
Diagnostics: diag.Diagnostics{},
}
cv := GCPCredentialsValidator()
// Act
cv.ValidateString(context.Background(), req, &resp)
// Assert
if resp.Diagnostics.ErrorsCount() != tc.expectedErrorCount {
t.Errorf("Expected %d errors, got %d", tc.expectedErrorCount, resp.Diagnostics.ErrorsCount())
}
})
}
}

View file

@ -0,0 +1,62 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"encoding/base64"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/jcmturner/gokrb5/v8/spnego"
)
var _ validator.String = krbNegToken{}
// krbNegToken validates that a given token is a valid initialization token
type krbNegToken struct{}
// Description describes the validation in plain text formatting.
func (v krbNegToken) Description(_ context.Context) string {
return "value must be a valid initialization token"
}
// MarkdownDescription describes the validation in Markdown formatting.
func (v krbNegToken) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}
// ValidateString performs the validation.
func (v krbNegToken) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
return
}
value := request.ConfigValue.ValueString()
if value == "" {
response.Diagnostics.AddError("invalid token", "value cannot be empty")
return
}
b, err := base64.StdEncoding.DecodeString(value)
if err != nil {
response.Diagnostics.AddError("invalid token", "value cannot be empty")
return
}
isNeg, _, err := spnego.UnmarshalNegToken(b)
if err != nil {
response.Diagnostics.AddError("invalid token", fmt.Sprintf("failed to unmarshal token, err=%s", err))
return
}
if !isNeg {
response.Diagnostics.AddError("invalid token", "not an initialization token")
return
}
}
func KRBNegTokenValidator() validator.String {
return krbNegToken{}
}

View file

@ -0,0 +1,75 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"encoding/base64"
"testing"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
const (
// base64 encoded SPNEGO request token
testNegTokenInit = "oIICqjCCAqagJzAlBgkqhkiG9xIBAgIGBSsFAQUCBgkqhkiC9xIBAgIGBisGAQUCBaKCAnkEggJ1YIICcQYJKoZIhvcSAQICAQBuggJgMIICXKADAgEFoQMCAQ6iBwMFAAAAAACjggFwYYIBbDCCAWigAwIBBaENGwtURVNULkdPS1JCNaIjMCGgAwIBA6EaMBgbBEhUVFAbEGhvc3QudGVzdC5nb2tyYjWjggErMIIBJ6ADAgESoQMCAQKiggEZBIIBFdS9iQq8RW9E4uei6BEb1nZ6vwMmbfzal8Ypry7ORQpa4fFF5KTRvCyEjmamxrMdl0CyawPNvSVwv88SbpCt9fXrzp4oP/UIbaR7EpsU/Aqr1NHfnB88crgMxhTfwoeDRQsse3dJZR9DK0eqov8VjABmt1fz+wDde09j1oJ2x2Nz7N0/GcZuvEOoHld/PCY7h4NW9X6NbE7M1Ye4FTjnA5LPfnP8Eqb3xTeolKe7VWbIOsTWl1eqMgpR2NaQAXrr+VKt0Yia38Mwew5s2Mm1fPhYn75SgArLZGHCVHPUn6ob3OuLzj9h2yP5zWoJ1a3OtBHhxFRrMLMzMeVw/WvFCqQDVX519IjnWXUOoDiqtkVGZ9m2T0GkgdIwgc+gAwIBEqKBxwSBxNZ7oq5M9dkXyqsdhjYFJJMg6QSCVjZi7ZJAilQ7atXt64+TdekGCiBUkd8IL9Kl/sk9+3b0EBK7YMriDwetu3ehqlbwUh824eoQ3J+3YpArJU3XZk0LzG91HyAD5BmQrxtDMNEEd7+tY4ufC3BKyAzEdzH47I2AF2K62IhLjekK2x2+f8ew/6/Tj7Xri2VHzuMNiYcygc5jrXAEKhNHixp8K93g8iOs5i27hOLQbxBw9CZfZuBUREkzXi/MTQruW/gcWZk="
// base64 encoded response token
testNegTokenResp = "oRQwEqADCgEAoQsGCSqGSIb3EgECAg=="
)
func TestFrameworkProvider_KRBNegTokenValidator(t *testing.T) {
cases := map[string]struct {
configValue func(t *testing.T) types.String
expectedErrorCount int
}{
"basic": {
configValue: func(t *testing.T) types.String {
return types.StringValue(testNegTokenInit)
},
},
"error-b64-decoding": {
configValue: func(t *testing.T) types.String {
return types.StringValue("Negotiation foo")
},
expectedErrorCount: 1,
},
"error-unmarshal": {
configValue: func(t *testing.T) types.String {
return types.StringValue(base64.StdEncoding.EncodeToString([]byte(testNegTokenInit)))
},
expectedErrorCount: 1,
},
"error-not-init-token": {
configValue: func(t *testing.T) types.String {
return types.StringValue(testNegTokenResp)
},
expectedErrorCount: 1,
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
// Arrange
req := validator.StringRequest{
ConfigValue: tc.configValue(t),
}
resp := validator.StringResponse{
Diagnostics: diag.Diagnostics{},
}
k := KRBNegTokenValidator()
// Act
k.ValidateString(context.Background(), req, &resp)
// Assert
if resp.Diagnostics.ErrorsCount() != tc.expectedErrorCount {
t.Errorf("Expected %d errors, got %d", tc.expectedErrorCount, resp.Diagnostics.ErrorsCount())
}
})
}
}

View file

@ -0,0 +1,48 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
)
var _ validator.String = pathValidator{}
// pathValidator validates that a given path is a valid Vault path format
type pathValidator struct{}
// Description describes the validation in plain text formatting.
func (v pathValidator) Description(_ context.Context) string {
return "value must be a valid Vault path format"
}
// MarkdownDescription describes the validation in Markdown formatting.
func (v pathValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}
// ValidateString performs the validation.
func (v pathValidator) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
return
}
value := request.ConfigValue.ValueString()
if value == "" {
response.Diagnostics.AddError("invalid Vault path", "value cannot be empty")
return
}
if provider.RegexpPath.MatchString(value) {
response.Diagnostics.AddError("invalid Vault path", fmt.Sprintf("value %s contains leading/trailing \"/\"", value))
}
}
func PathValidator() validator.String {
return pathValidator{}
}

View file

@ -0,0 +1,72 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"testing"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
func TestFrameworkProvider_PathValidator(t *testing.T) {
cases := map[string]struct {
configValue func(t *testing.T) types.String
expectedErrorCount int
}{
"valid": {
configValue: func(t *testing.T) types.String {
return types.StringValue("foo")
},
},
"valid-nested": {
configValue: func(t *testing.T) types.String {
return types.StringValue("foo/bar")
},
},
"invalid-leading": {
configValue: func(t *testing.T) types.String {
return types.StringValue("/foo")
},
expectedErrorCount: 1,
},
"invalid-trailing": {
configValue: func(t *testing.T) types.String {
return types.StringValue("foo/")
},
expectedErrorCount: 1,
},
"invalid-both": {
configValue: func(t *testing.T) types.String {
return types.StringValue("/foo/")
},
expectedErrorCount: 1,
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
// Arrange
req := validator.StringRequest{
ConfigValue: tc.configValue(t),
}
resp := validator.StringResponse{
Diagnostics: diag.Diagnostics{},
}
cv := PathValidator()
// Act
cv.ValidateString(context.Background(), req, &resp)
// Assert
if resp.Diagnostics.ErrorsCount() != tc.expectedErrorCount {
t.Errorf("Expected %d errors, got %d: %s", tc.expectedErrorCount, resp.Diagnostics.ErrorsCount(), resp.Diagnostics.Errors())
}
})
}
}

View file

@ -0,0 +1,7 @@
{
"private_key_id": "foo",
"private_key": "bar",
"client_email": "foo@bar.com",
"client_id": "id@foo.com",
"type": "service_account"
}

View file

@ -0,0 +1,77 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"fmt"
"net/url"
"strings"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
)
var _ validator.String = uriValidator{}
// uriValidator validates that the raw url is a valid request URI, and
// optionally contains supported scheme(s).
type uriValidator struct {
schemes []string
}
// Description describes the validation in plain text formatting.
func (v uriValidator) Description(_ context.Context) string {
return "Invalid URI"
}
// MarkdownDescription describes the validation in Markdown formatting.
func (v uriValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}
// ValidateString performs the validation.
func (v uriValidator) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
return
}
value := request.ConfigValue.ValueString()
if value == "" {
response.Diagnostics.AddError(v.Description(ctx), "value cannot be empty")
return
}
u, err := url.ParseRequestURI(value)
if err != nil {
response.Diagnostics.AddError(v.Description(ctx), fmt.Sprintf("Failed to parse URL, err=%s", err))
return
}
if len(v.schemes) == 0 {
return
}
for _, scheme := range v.schemes {
if scheme == u.Scheme {
return
}
}
response.Diagnostics.AddError(
v.Description(ctx),
fmt.Sprintf(
"Unsupported scheme %q. Valid schemes are: %s",
u.Scheme,
strings.Join(v.schemes, ", "),
),
)
}
// URIValidator validates that the raw url is a valid request URI, and
// optionally contains supported scheme(s).
func URIValidator(schemes []string) validator.String {
return uriValidator{
schemes: schemes,
}
}

View file

@ -0,0 +1,65 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package validators
import (
"context"
"testing"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
func TestFrameworkProvider_URIValidator(t *testing.T) {
cases := map[string]struct {
configValue func(t *testing.T) types.String
schemes []string
expectedErrorCount int
}{
"basic": {
configValue: func(t *testing.T) types.String {
return types.StringValue("http://foo.baz:8080/qux")
},
schemes: []string{"http"},
},
"invalid-scheme": {
configValue: func(t *testing.T) types.String {
return types.StringValue("https://foo.baz:8080/qux")
},
schemes: []string{"http", "tcp"},
expectedErrorCount: 1,
},
"invalid-url": {
configValue: func(t *testing.T) types.String {
return types.StringValue("foo.bar")
},
schemes: []string{"http", "tcp"},
expectedErrorCount: 1,
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
// Arrange
req := validator.StringRequest{
ConfigValue: tc.configValue(t),
}
resp := validator.StringResponse{
Diagnostics: diag.Diagnostics{},
}
cv := URIValidator(tc.schemes)
// Act
cv.ValidateString(context.Background(), req, &resp)
// Assert
if resp.Diagnostics.ErrorsCount() != tc.expectedErrorCount {
t.Errorf("Expected %d errors, got %d: %s", tc.expectedErrorCount, resp.Diagnostics.ErrorsCount(), resp.Diagnostics.Errors())
}
})
}
}

View file

@ -6,6 +6,7 @@ package provider
import (
"errors"
"fmt"
"os"
"sync"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@ -18,7 +19,7 @@ import (
type (
loginSchemaFunc func(string) *schema.Schema
getSchemaResource func(string) *schema.Resource
validateFunc func(data *schema.ResourceData) error
validateFunc func(data *schema.ResourceData, params map[string]interface{}) error
authLoginFunc func(*schema.ResourceData) (AuthLogin, error)
)
@ -138,7 +139,7 @@ func (l *AuthLoginCommon) Init(d *schema.ResourceData, authField string, validat
}
for _, vf := range validators {
if err := vf(d); err != nil {
if err := vf(d, params); err != nil {
return err
}
}
@ -270,11 +271,46 @@ func (l *AuthLoginCommon) init(d *schema.ResourceData) (string, map[string]inter
return path, params, nil
}
func (l *AuthLoginCommon) checkRequiredFields(d *schema.ResourceData, required ...string) error {
type authDefault struct {
field string
// envVars will override defaultVal.
// If there are multiple entries in the slice, we use the first value we
// find that is set in the environment.
envVars []string
// defaultVal is the fallback if an env var is not set
defaultVal string
}
type authDefaults []authDefault
func (l *AuthLoginCommon) setDefaultFields(d *schema.ResourceData, defaults authDefaults, params map[string]interface{}) error {
for _, f := range defaults {
if _, ok := l.getOk(d, f.field); !ok {
// if field is unset in the config, check env
params[f.field] = f.defaultVal
for _, envVar := range f.envVars {
val := os.Getenv(envVar)
if val != "" {
params[f.field] = val
// found a value, no need to check other options
break
}
}
}
}
return nil
}
func (l *AuthLoginCommon) checkRequiredFields(d *schema.ResourceData, params map[string]interface{}, required ...string) error {
var missing []string
for _, f := range required {
if _, ok := l.getOk(d, f); !ok {
missing = append(missing, f)
if data, ok := l.getOk(d, f); !ok {
// if the field was unset in the config
if params[f] == data {
missing = append(missing, f)
}
}
}

View file

@ -15,6 +15,19 @@ import (
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
const (
envVarAWSAccessKeyID = "AWS_ACCESS_KEY_ID"
envVarAWSSecretAccessKey = "AWS_SECRET_ACCESS_KEY"
envVarAWSSessionToken = "AWS_SESSION_TOKEN"
envVarAWSProfile = "AWS_PROFILE"
envVarAWSSharedCredentialsFile = "AWS_SHARED_CREDENTIALS_FILE"
envVarAWSWebIdentityTokenFile = "AWS_WEB_IDENTITY_TOKEN_FILE"
envVarAWSRoleARN = "AWS_ROLE_ARN"
envVarAWSRoleSessionName = "AWS_ROLE_SESSION_NAME"
envVarAWSRegion = "AWS_REGION"
envVarAWSDefaultRegion = "AWS_DEFAULT_REGION"
)
func init() {
field := consts.FieldAuthLoginAWS
if err := globalAuthLoginRegistry.Register(field,
@ -49,39 +62,33 @@ func GetAWSLoginSchemaResource(authField string) *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: `The AWS access key ID.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_ACCESS_KEY_ID", nil),
},
consts.FieldAWSSecretAccessKey: {
Type: schema.TypeString,
Optional: true,
Description: `The AWS secret access key.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_SECRET_ACCESS_KEY", nil),
RequiredWith: []string{fmt.Sprintf("%s.0.%s", authField, consts.FieldAWSAccessKeyID)},
},
consts.FieldAWSSessionToken: {
Type: schema.TypeString,
Optional: true,
Description: `The AWS session token.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_SESSION_TOKEN", nil),
},
consts.FieldAWSProfile: {
Type: schema.TypeString,
Optional: true,
Description: `The name of the AWS profile.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_PROFILE", nil),
},
consts.FieldAWSSharedCredentialsFile: {
Type: schema.TypeString,
Optional: true,
Description: `Path to the AWS shared credentials file.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_SHARED_CREDENTIALS_FILE", nil),
},
consts.FieldAWSWebIdentityTokenFile: {
Type: schema.TypeString,
Optional: true,
Description: `Path to the file containing an OAuth 2.0 access token or OpenID ` +
`Connect ID token.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_WEB_IDENTITY_TOKEN_FILE", nil),
},
// STS assume role fields
consts.FieldAWSRoleARN: {
@ -89,26 +96,17 @@ func GetAWSLoginSchemaResource(authField string) *schema.Resource {
Optional: true,
Description: `The ARN of the AWS Role to assume.` +
`Used during STS AssumeRole`,
DefaultFunc: schema.EnvDefaultFunc("AWS_ROLE_ARN", nil),
},
consts.FieldAWSRoleSessionName: {
Type: schema.TypeString,
Optional: true,
Description: `Specifies the name to attach to the AWS role session. ` +
`Used during STS AssumeRole`,
DefaultFunc: schema.EnvDefaultFunc("AWS_ROLE_SESSION_NAME", nil),
},
consts.FieldAWSRegion: {
Type: schema.TypeString,
Optional: true,
Description: `The AWS region.`,
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{
"AWS_REGION",
"AWS_DEFAULT_REGION",
},
nil,
),
},
consts.FieldAWSSTSEndpoint: {
Type: schema.TypeString,
@ -140,9 +138,13 @@ type AuthLoginAWS struct {
}
func (l *AuthLoginAWS) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
defaults := l.getDefaults()
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldRole)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldRole)
},
); err != nil {
return nil, err
@ -193,6 +195,58 @@ func (l *AuthLoginAWS) Login(client *api.Client) (*api.Secret, error) {
return l.login(client, l.LoginPath(), params)
}
func (l *AuthLoginAWS) getDefaults() authDefaults {
defaults := authDefaults{
{
field: consts.FieldAWSAccessKeyID,
envVars: []string{envVarAWSAccessKeyID},
defaultVal: "",
},
{
field: consts.FieldAWSSecretAccessKey,
envVars: []string{envVarAWSSecretAccessKey},
defaultVal: "",
},
{
field: consts.FieldAWSSessionToken,
envVars: []string{envVarAWSSessionToken},
defaultVal: "",
},
{
field: consts.FieldAWSProfile,
envVars: []string{envVarAWSProfile},
defaultVal: "",
},
{
field: consts.FieldAWSSharedCredentialsFile,
envVars: []string{envVarAWSSharedCredentialsFile},
defaultVal: "",
},
{
field: consts.FieldAWSWebIdentityTokenFile,
envVars: []string{envVarAWSWebIdentityTokenFile},
defaultVal: "",
},
{
field: consts.FieldAWSRoleARN,
envVars: []string{envVarAWSRoleARN},
defaultVal: "",
},
{
field: consts.FieldAWSRoleSessionName,
envVars: []string{envVarAWSRoleSessionName},
defaultVal: "",
},
{
field: consts.FieldAWSRegion,
envVars: []string{envVarAWSRegion, envVarAWSDefaultRegion},
defaultVal: "",
},
}
return defaults
}
func (l *AuthLoginAWS) getLoginData(logger hclog.Logger) (map[string]interface{}, error) {
config, err := l.getCredentialsConfig(logger)
if err != nil {

View file

@ -46,7 +46,6 @@ func GetAzureLoginSchemaResource(authField string) *schema.Resource {
Optional: true,
Description: "A signed JSON Web Token. If not specified on will be " +
"created automatically",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarAzureAuthJWT, nil),
},
consts.FieldRole: {
Type: schema.TypeString,
@ -94,7 +93,6 @@ func GetAzureLoginSchemaResource(authField string) *schema.Resource {
consts.FieldScope: {
Type: schema.TypeString,
Optional: true,
Default: defaultAzureScope,
Description: "The scopes to include in the token request.",
ConflictsWith: []string{fmt.Sprintf("%s.0.%s", authField, consts.FieldJWT)},
},
@ -122,12 +120,30 @@ func (l *AuthLoginAzure) LoginPath() string {
}
func (l *AuthLoginAzure) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
defaults := authDefaults{
{
field: consts.FieldJWT,
envVars: []string{consts.EnvVarAzureAuthJWT},
defaultVal: "",
},
{
field: consts.FieldScope,
envVars: []string{""},
defaultVal: defaultAzureScope,
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
err := l.checkRequiredFields(d, l.requiredParams()...)
func(data *schema.ResourceData, params map[string]interface{}) error {
err := l.setDefaultFields(d, defaults, params)
if err != nil {
return err
}
err = l.checkRequiredFields(d, params, l.requiredParams()...)
if err != nil {
return err
}
return l.checkFieldsOneOf(d, consts.FieldVMName, consts.FieldVMSSName)
},
); err != nil {

View file

@ -257,6 +257,7 @@ func TestAuthLoginAzure_Login(t *testing.T) {
initialized: true,
},
},
token: "foo",
handler: &testLoginHandler{
handlerFunc: handlerFunc,
},

View file

@ -79,8 +79,8 @@ func (l *AuthLoginCert) LoginPath() string {
func (l *AuthLoginCert) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldCertFile, consts.FieldKeyFile)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldCertFile, consts.FieldKeyFile)
},
); err != nil {
return nil, err

View file

@ -190,6 +190,22 @@ func TestAuthLoginCert_LoginPath(t *testing.T) {
}
func TestAuthLoginCert_Login(t *testing.T) {
// Since Auth Cert login clones the Vault client,
// this test will fail if VAULT_TOKEN environment variable is set
env := "VAULT_TOKEN"
originalValue, exists := os.LookupEnv(env)
t.Setenv(env, "") // Unset the environment variable
t.Cleanup(func() {
if exists {
t.Setenv(env, originalValue) // Restore original value
} else {
os.Unsetenv(env) // Unset if it didn't exist initially
}
})
handlerFunc := func(t *testLoginHandler, w http.ResponseWriter, req *http.Request) {
role := "default"
if t.params != nil {
@ -261,8 +277,9 @@ func TestAuthLoginCert_Login(t *testing.T) {
},
},
},
tls: true,
wantErr: false,
tls: true,
wantErr: false,
cloneToken: true,
},
{
name: "named-role",
@ -296,8 +313,9 @@ func TestAuthLoginCert_Login(t *testing.T) {
},
},
},
tls: true,
wantErr: false,
tls: true,
wantErr: false,
cloneToken: true,
},
{
name: "error-vault-token-set",
@ -317,9 +335,10 @@ func TestAuthLoginCert_Login(t *testing.T) {
handler: &testLoginHandler{
handlerFunc: handlerFunc,
},
token: "foo",
wantErr: true,
expectErr: errors.New("vault login client has a token set"),
token: "foo",
cloneToken: true,
wantErr: true,
expectErr: errors.New("vault login client has a token set"),
},
{
name: "error-uninitialized",

View file

@ -58,7 +58,6 @@ func GetGCPLoginSchemaResource(authField string) *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "A signed JSON Web Token.",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarGCPAuthJWT, nil),
ConflictsWith: []string{fmt.Sprintf("%s.0.%s", authField, consts.FieldCredentials)},
},
consts.FieldCredentials: {
@ -66,7 +65,6 @@ func GetGCPLoginSchemaResource(authField string) *schema.Resource {
Optional: true,
ValidateFunc: validateCredentials,
Description: "Path to the Google Cloud credentials file.",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarGoogleApplicationCreds, nil),
ConflictsWith: []string{fmt.Sprintf("%s.0.%s", authField, consts.FieldJWT)},
},
consts.FieldServiceAccount: {
@ -89,7 +87,26 @@ type AuthLoginGCP struct {
}
func (l *AuthLoginGCP) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
if err := l.AuthLoginCommon.Init(d, authField); err != nil {
defaults := authDefaults{
{
field: consts.FieldJWT,
envVars: []string{consts.EnvVarGCPAuthJWT},
defaultVal: "",
},
{
field: consts.FieldCredentials,
envVars: []string{consts.EnvVarGoogleApplicationCreds},
defaultVal: "",
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldRole)
},
); err != nil {
return nil, err
}
return l, nil

View file

@ -204,6 +204,9 @@ func TestAuthLoginGCP_Login(t *testing.T) {
token: "foo",
wantErr: true,
expectErr: errors.New("vault login client has a token set"),
skipFunc: func(t *testing.T) {
testutil.SkipTestEnvUnset(t, consts.EnvVarGoogleApplicationCreds, envVarGCPServiceAccount)
},
},
{
name: "no-jwt",

View file

@ -42,10 +42,10 @@ func GetJWTLoginSchemaResource(authField string) *schema.Resource {
Description: "Name of the login role.",
},
consts.FieldJWT: {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
// can be set via an env var
Optional: true,
Description: "A signed JSON Web Token.",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarVaultAuthJWT, nil),
},
},
}, authField, consts.MountTypeJWT)
@ -71,9 +71,20 @@ func (l *AuthLoginJWT) LoginPath() string {
}
func (l *AuthLoginJWT) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
defaults := authDefaults{
{
field: consts.FieldJWT,
envVars: []string{consts.EnvVarVaultAuthJWT},
defaultVal: "",
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldRole, consts.FieldJWT)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldRole, consts.FieldJWT)
},
); err != nil {
return nil, err

View file

@ -39,6 +39,29 @@ func TestAuthLoginJWT_Init(t *testing.T) {
},
wantErr: false,
},
{
name: "basic-with-env",
authField: consts.FieldAuthLoginJWT,
raw: map[string]interface{}{
consts.FieldAuthLoginJWT: []interface{}{
map[string]interface{}{
consts.FieldNamespace: "ns1",
consts.FieldRole: "alice",
},
},
},
envVars: map[string]string{
consts.EnvVarVaultAuthJWT: "jwt1",
},
expectParams: map[string]interface{}{
consts.FieldNamespace: "ns1",
consts.FieldUseRootNamespace: false,
consts.FieldMount: consts.MountTypeJWT,
consts.FieldRole: "alice",
consts.FieldJWT: "jwt1",
},
wantErr: false,
},
{
name: "error-missing-resource",
authField: consts.FieldAuthLoginJWT,

View file

@ -45,7 +45,6 @@ func GetKerberosLoginSchemaResource(authField string) *schema.Resource {
consts.FieldToken: {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarKrbSPNEGOToken, nil),
Description: "Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) token",
ValidateFunc: validateKRBNegToken,
},
@ -71,7 +70,6 @@ func GetKerberosLoginSchemaResource(authField string) *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "A valid Kerberos configuration file e.g. /etc/krb5.conf.",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarKRB5Conf, nil),
ValidateFunc: validateFileExists,
ConflictsWith: conflicts,
},
@ -79,21 +77,18 @@ func GetKerberosLoginSchemaResource(authField string) *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "The Kerberos keytab file containing the entry of the login entity.",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarKRBKeytab, nil),
ValidateFunc: validateFileExists,
ConflictsWith: conflicts,
},
consts.FieldDisableFastNegotiation: {
Type: schema.TypeBool,
Optional: true,
Default: false,
ConflictsWith: conflicts,
Description: "Disable the Kerberos FAST negotiation.",
},
consts.FieldRemoveInstanceName: {
Type: schema.TypeBool,
Optional: true,
Default: false,
ConflictsWith: conflicts,
Description: "Strip the host from the username found in the keytab.",
},
@ -125,16 +120,31 @@ func (l *AuthLoginKerberos) LoginPath() string {
}
func (l *AuthLoginKerberos) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
defaults := authDefaults{
{
field: consts.FieldToken,
envVars: []string{consts.EnvVarKrbSPNEGOToken},
defaultVal: "",
},
{
field: consts.FieldKRB5ConfPath,
envVars: []string{consts.EnvVarKRB5Conf},
defaultVal: "",
},
{
field: consts.FieldKeytabPath,
envVars: []string{consts.EnvVarKRBKeytab},
defaultVal: "",
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
if _, ok := l.getOk(d, consts.FieldToken); !ok {
return l.checkRequiredFields(d,
consts.FieldUsername,
consts.FieldService,
consts.FieldRealm,
consts.FieldKeytabPath,
consts.FieldKRB5ConfPath,
)
return l.checkRequiredFields(d, params, consts.FieldUsername, consts.FieldService, consts.FieldRealm, consts.FieldKeytabPath, consts.FieldKRB5ConfPath)
}
return nil
},

View file

@ -85,8 +85,8 @@ func (l *AuthLoginOCI) LoginPath() string {
func (l *AuthLoginOCI) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldRole, consts.FieldAuthType)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldRole, consts.FieldAuthType)
},
); err != nil {
return nil, err

View file

@ -207,6 +207,9 @@ func TestAuthLoginOCI_Login(t *testing.T) {
token: "foo",
wantErr: true,
expectErr: errors.New("vault login client has a token set"),
skipFunc: func(t *testing.T) {
testutil.SkipTestEnvUnset(t, envVarTFAccOCIAuth)
},
},
{
name: "error-uninitialized",

View file

@ -86,8 +86,8 @@ func (l *AuthLoginOIDC) LoginPath() string {
func (l *AuthLoginOIDC) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldRole)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldRole)
},
); err != nil {
return nil, err

View file

@ -5,7 +5,6 @@ package provider
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"reflect"
@ -231,25 +230,6 @@ func TestAuthLoginOIDC_Login(t *testing.T) {
}
tests := []authLoginTest{
{
name: "error-vault-token-set",
authLogin: &AuthLoginOIDC{
AuthLoginCommon{
authField: "baz",
mount: "foo",
params: map[string]interface{}{
consts.FieldRole: "bob",
},
initialized: true,
},
},
handler: &testLoginHandler{
handlerFunc: handlerFunc,
},
token: "foo",
wantErr: true,
expectErr: errors.New("vault login client has a token set"),
},
{
name: "error-uninitialized",
authLogin: &AuthLoginOIDC{

View file

@ -39,14 +39,14 @@ func GetRadiusLoginSchemaResource(authField string) *schema.Resource {
consts.FieldUsername: {
Type: schema.TypeString,
Description: "The Radius username.",
Required: true,
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarRadiusUsername, nil),
// can be set via an env var
Optional: true,
},
consts.FieldPassword: {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
// can be set via an env var
Optional: true,
Description: "The Radius password for username.",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarRadiusPassword, nil),
},
},
}, authField, consts.MountTypeRadius)
@ -72,9 +72,24 @@ func (l *AuthLoginRadius) LoginPath() string {
}
func (l *AuthLoginRadius) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
defaults := authDefaults{
{
field: consts.FieldUsername,
envVars: []string{consts.EnvVarRadiusUsername},
defaultVal: "",
},
{
field: consts.FieldPassword,
envVars: []string{consts.EnvVarRadiusPassword},
defaultVal: "",
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldUsername, consts.FieldPassword)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldUsername, consts.FieldPassword)
},
); err != nil {
return nil, err

View file

@ -39,6 +39,29 @@ func TestAuthLoginRadius_Init(t *testing.T) {
},
wantErr: false,
},
{
name: "basic-with-env",
authField: consts.FieldAuthLoginRadius,
raw: map[string]interface{}{
consts.FieldAuthLoginRadius: []interface{}{
map[string]interface{}{
consts.FieldNamespace: "ns1",
},
},
},
envVars: map[string]string{
consts.EnvVarRadiusUsername: "alice",
consts.EnvVarRadiusPassword: "password1",
},
expectParams: map[string]interface{}{
consts.FieldNamespace: "ns1",
consts.FieldUseRootNamespace: false,
consts.FieldMount: consts.MountTypeRadius,
consts.FieldUsername: "alice",
consts.FieldPassword: "password1",
},
wantErr: false,
},
{
name: "error-missing-resource",
authField: consts.FieldAuthLoginRadius,

View file

@ -8,6 +8,7 @@ import (
"io"
"net"
"net/http"
"os"
"reflect"
"testing"
@ -37,6 +38,7 @@ type authLoginTest struct {
tls bool
preLoginFunc func(t *testing.T)
token string
cloneToken bool
}
type authLoginInitTest struct {
@ -117,6 +119,10 @@ func testAuthLogin(t *testing.T, tt authLoginTest) {
}
defer ln.Close()
if tt.cloneToken {
config.CloneToken = tt.cloneToken
}
c, err := api.NewClient(config)
if err != nil {
t.Fatal(err)
@ -316,3 +322,195 @@ func TestAuthLoginCommon_Namespace(t *testing.T) {
})
}
}
func TestAuthLoginCommon_setDefaultFields(t *testing.T) {
tests := []struct {
name string
params map[string]interface{}
expectParams map[string]interface{}
setEnv map[string]string
defaults authDefaults
}{
{
name: "default-unset-and-env-unset",
params: map[string]interface{}{
"foo": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO"},
defaultVal: "",
},
},
expectParams: map[string]interface{}{
"foo": "",
},
},
{
name: "default-set-and-env-unset",
params: map[string]interface{}{
"foo": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO"},
defaultVal: "bar",
},
},
expectParams: map[string]interface{}{
"foo": "bar",
},
},
{
name: "default-set-and-env-set",
params: map[string]interface{}{
"foo": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO"},
defaultVal: "bar",
},
},
// env vars should override authDefault.defaultVal
setEnv: map[string]string{
"TEST_TERRAFORM_VAULT_PROVIDER_FOO": "baz",
},
expectParams: map[string]interface{}{
"foo": "baz",
},
},
{
name: "default-unset-and-env-set",
params: map[string]interface{}{
"foo": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO"},
defaultVal: "",
},
},
// env vars should override authDefault.defaultVal
setEnv: map[string]string{
"TEST_TERRAFORM_VAULT_PROVIDER_FOO": "baz",
},
expectParams: map[string]interface{}{
"foo": "baz",
},
},
{
name: "multiple-params-default-set-and-env-set",
params: map[string]interface{}{
"foo": "",
"dog": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO"},
defaultVal: "bar",
},
{
field: "dog",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_DOG"},
defaultVal: "bark",
},
},
// env vars should override authDefault.defaultVal
setEnv: map[string]string{
"TEST_TERRAFORM_VAULT_PROVIDER_FOO": "baz",
"TEST_TERRAFORM_VAULT_PROVIDER_DOG": "woof",
},
expectParams: map[string]interface{}{
"foo": "baz",
"dog": "woof",
},
},
{
name: "multiple-params-mixed-set-and-unset",
params: map[string]interface{}{
"foo": "",
"dog": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO"},
defaultVal: "bar",
},
{
field: "dog",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_DOG"},
defaultVal: "bark",
},
},
// env vars should override authDefault.defaultVal
setEnv: map[string]string{
"TEST_TERRAFORM_VAULT_PROVIDER_FOO": "baz",
},
expectParams: map[string]interface{}{
"foo": "baz",
"dog": "bark",
},
},
{
name: "multiple-env",
params: map[string]interface{}{
"foo": "",
},
defaults: authDefaults{
{
field: "foo",
envVars: []string{"TEST_TERRAFORM_VAULT_PROVIDER_FOO", "TEST_TERRAFORM_VAULT_PROVIDER_QUX"},
defaultVal: "",
},
},
setEnv: map[string]string{
"TEST_TERRAFORM_VAULT_PROVIDER_QUX": "qux",
},
expectParams: map[string]interface{}{
"foo": "qux",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.setEnv != nil {
for k, v := range tt.setEnv {
t.Setenv(k, v)
t.Cleanup(func() {
err := os.Unsetenv(k)
if err != nil {
t.Fatalf("could not unset env, err: %v", err)
}
},
)
}
}
l := &AuthLoginCommon{
params: tt.params,
initialized: true,
}
rootProvider := NewProvider(nil, nil)
pr := &schema.Resource{
Schema: rootProvider.Schema,
}
d := pr.TestResourceData()
err := l.setDefaultFields(d, tt.defaults, tt.params)
if err != nil {
t.Errorf("setDefaultFields() err: %v", err)
}
if !reflect.DeepEqual(tt.expectParams, l.Params()) {
t.Errorf("setDefaultFields() expected params %#v, actual %#v", tt.expectParams, l.Params())
}
})
}
}

View file

@ -41,9 +41,9 @@ func GetTokenFileSchemaResource(authField string) *schema.Resource {
return mustAddLoginSchema(&schema.Resource{
Schema: map[string]*schema.Schema{
consts.FieldFilename: {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarTokenFilename, nil),
Type: schema.TypeString,
// can be set via an env var
Optional: true,
Description: "The name of a file containing a single " +
"line that is a valid Vault token",
},
@ -72,9 +72,19 @@ func (l *AuthLoginTokenFile) Init(d *schema.ResourceData,
) (AuthLogin, error) {
l.mount = consts.MountTypeNone
defaults := authDefaults{
{
field: consts.FieldFilename,
envVars: []string{consts.EnvVarTokenFilename},
defaultVal: "",
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldFilename)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldFilename)
},
); err != nil {
return nil, err

View file

@ -5,7 +5,6 @@ package provider
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
@ -49,9 +48,7 @@ func TestAuthLoginTokenFile_Init(t *testing.T) {
consts.EnvVarTokenFilename: "/tmp/vault-token",
},
expectParams: map[string]interface{}{
consts.FieldNamespace: "",
consts.FieldUseRootNamespace: false,
consts.FieldFilename: "/tmp/vault-token",
consts.FieldFilename: "/tmp/vault-token",
},
wantErr: false,
},
@ -147,38 +144,6 @@ func TestAuthLoginTokenFile_Login(t *testing.T) {
},
wantErr: false,
},
{
name: "error-vault-token-set",
authLogin: &AuthLoginTokenFile{
AuthLoginCommon{
authField: "baz",
mount: consts.MountTypeNone,
params: map[string]interface{}{
consts.FieldFilename: path.Join(tempDir, "basic"),
},
initialized: true,
},
},
handler: &testLoginHandler{
handlerFunc: handlerFunc,
},
preLoginFunc: func(t *testing.T) {
t.Helper()
filename := path.Join(tempDir, "basic")
t.Cleanup(func() {
if err := os.Remove(filename); err != nil {
t.Error(err)
}
})
if err := os.WriteFile(filename, []byte("qux\n"), 0o600); err != nil {
t.Fatal(err)
}
},
token: "foo",
wantErr: true,
expectErr: errors.New("vault login client has a token set"),
},
{
name: "error-invalid-file-mode",
authLogin: &AuthLoginTokenFile{

View file

@ -40,22 +40,20 @@ func GetUserpassLoginSchemaResource(authField string) *schema.Resource {
return mustAddLoginSchema(&schema.Resource{
Schema: map[string]*schema.Schema{
consts.FieldUsername: {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
// can be set via an env var
Optional: true,
Description: "Login with username",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarUsername, nil),
},
consts.FieldPassword: {
Type: schema.TypeString,
Optional: true,
Description: "Login with password",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarPassword, nil),
},
consts.FieldPasswordFile: {
Type: schema.TypeString,
Optional: true,
Description: "Login with password from a file",
DefaultFunc: schema.EnvDefaultFunc(consts.EnvVarPasswordFile, nil),
// unfortunately the SDK does support conflicting relative fields
// within a list type. As long as the top level schema does not change
// we should be good to hard code fully qualified path like so.
@ -77,9 +75,30 @@ type AuthLoginUserpass struct {
}
func (l *AuthLoginUserpass) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
defaults := authDefaults{
{
field: consts.FieldUsername,
envVars: []string{consts.EnvVarUsername},
defaultVal: "",
},
{
field: consts.FieldPassword,
envVars: []string{consts.EnvVarPassword},
defaultVal: "",
},
{
field: consts.FieldPasswordFile,
envVars: []string{consts.EnvVarPasswordFile},
defaultVal: "",
},
}
if err := l.AuthLoginCommon.Init(d, authField,
func(data *schema.ResourceData) error {
return l.checkRequiredFields(d, consts.FieldUsername)
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.setDefaultFields(d, defaults, params)
},
func(data *schema.ResourceData, params map[string]interface{}) error {
return l.checkRequiredFields(d, params, consts.FieldUsername)
},
); err != nil {
return nil, err

View file

@ -0,0 +1,61 @@
package fwprovider
import (
"fmt"
"github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/framework/validators"
)
func mustAddLoginSchema(s *schema.ListNestedBlock, defaultMount string) schema.Block {
m := map[string]schema.Attribute{
consts.FieldNamespace: schema.StringAttribute{
Optional: true,
Description: fmt.Sprintf(
"The authentication engine's namespace. Conflicts with %s",
consts.FieldUseRootNamespace,
),
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtParent().AtName(consts.FieldUseRootNamespace),
),
},
},
consts.FieldUseRootNamespace: schema.BoolAttribute{
Optional: true,
Description: fmt.Sprintf(
"Authenticate to the root Vault namespace. Conflicts with %s",
consts.FieldNamespace,
),
Validators: []validator.Bool{
boolvalidator.ConflictsWith(
path.MatchRelative().AtParent().AtName(consts.FieldUseRootNamespace),
),
},
},
}
if defaultMount != consts.MountTypeNone {
m[consts.FieldMount] = &schema.StringAttribute{
Optional: true,
Description: "The path where the authentication engine is mounted.",
Validators: []validator.String{
validators.PathValidator(),
},
}
}
for k, v := range m {
if _, ok := s.NestedObject.Attributes[k]; ok {
panic(fmt.Sprintf("cannot add schema field %q, already exists in the Schema map", k))
}
s.NestedObject.Attributes[k] = v
}
return s
}

View file

@ -0,0 +1,82 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/framework/validators"
)
func AuthLoginAWSSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the AWS method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldRole: schema.StringAttribute{
Required: true,
Description: `The Vault role to use when logging into Vault.`,
},
// static credential fields
consts.FieldAWSAccessKeyID: schema.StringAttribute{
Optional: true,
Description: `The AWS access key ID.`,
},
consts.FieldAWSSecretAccessKey: schema.StringAttribute{
Optional: true,
Description: `The AWS secret access key.`,
},
consts.FieldAWSSessionToken: schema.StringAttribute{
Optional: true,
Description: `The AWS session token.`,
},
consts.FieldAWSProfile: schema.StringAttribute{
Optional: true,
Description: `The name of the AWS profile.`,
},
consts.FieldAWSSharedCredentialsFile: schema.StringAttribute{
Optional: true,
Description: `Path to the AWS shared credentials file.`,
},
consts.FieldAWSWebIdentityTokenFile: schema.StringAttribute{
Optional: true,
Description: `Path to the file containing an OAuth 2.0 access token or OpenID ` +
`Connect ID token.`,
},
// STS assume role fields
consts.FieldAWSRoleARN: schema.StringAttribute{
Optional: true,
Description: `The ARN of the AWS Role to assume.` +
`Used during STS AssumeRole`,
},
consts.FieldAWSRoleSessionName: schema.StringAttribute{
Optional: true,
Description: `Specifies the name to attach to the AWS role session. ` +
`Used during STS AssumeRole`,
},
consts.FieldAWSRegion: schema.StringAttribute{
Optional: true,
Description: `The AWS region.`,
},
consts.FieldAWSSTSEndpoint: schema.StringAttribute{
Optional: true,
Description: `The STS endpoint URL.`,
Validators: []validator.String{
validators.URIValidator([]string{"http", "https"}),
},
},
consts.FieldAWSIAMEndpoint: schema.StringAttribute{
Optional: true,
Description: `The IAM endpoint URL.`,
Validators: []validator.String{
validators.URIValidator([]string{"http", "https"}),
},
},
consts.FieldHeaderValue: schema.StringAttribute{
Optional: true,
Description: `The Vault header value to include in the STS signing request.`,
},
},
},
}, consts.MountTypeAWS)
}

View file

@ -0,0 +1,82 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginAzureSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the azure method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldJWT: schema.StringAttribute{
Optional: true,
Description: "A signed JSON Web Token. If not specified on will be " +
"created automatically",
},
consts.FieldRole: schema.StringAttribute{
Required: true,
Description: "Name of the login role.",
},
consts.FieldSubscriptionID: schema.StringAttribute{
Required: true,
Description: "The subscription ID for the machine that generated the MSI token. " +
"This information can be obtained through instance metadata.",
},
consts.FieldResourceGroupName: schema.StringAttribute{
Required: true,
Description: "The resource group for the machine that generated the MSI token. " +
"This information can be obtained through instance metadata.",
},
consts.FieldVMName: schema.StringAttribute{
Optional: true,
Description: "The virtual machine name for the machine that generated the MSI token. " +
"This information can be obtained through instance metadata.",
},
consts.FieldVMSSName: schema.StringAttribute{
Optional: true,
Description: "The virtual machine scale set name for the machine that generated " +
"the MSI token. This information can be obtained through instance metadata.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldVMName),
),
},
},
consts.FieldTenantID: schema.StringAttribute{
Optional: true,
Description: "Provides the tenant ID to use in a multi-tenant " +
"authentication scenario.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldJWT),
),
},
},
consts.FieldClientID: schema.StringAttribute{
Optional: true,
Description: "The identity's client ID.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldJWT),
),
},
},
consts.FieldScope: schema.StringAttribute{
Optional: true,
Description: "The scopes to include in the token request.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldJWT),
),
},
},
},
},
}, consts.MountTypeAzure)
}

View file

@ -0,0 +1,29 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginCertSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the cert method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldName: schema.StringAttribute{
Optional: true,
Description: "Name of the certificate's role",
},
consts.FieldCertFile: schema.StringAttribute{
Required: true,
Description: "Path to a file containing the client certificate.",
},
consts.FieldKeyFile: schema.StringAttribute{
Required: true,
Description: "Path to a file containing the private key that the certificate was issued for.",
},
},
},
}, consts.MountTypeCert)
}

View file

@ -0,0 +1,54 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/framework/validators"
)
func AuthLoginGCPSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the gcp method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldRole: schema.StringAttribute{
Required: true,
Description: "Name of the login role.",
},
consts.FieldJWT: schema.StringAttribute{
Optional: true,
Description: "A signed JSON Web Token.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldCredentials),
),
},
},
consts.FieldCredentials: schema.StringAttribute{
Optional: true,
Description: "Path to the Google Cloud credentials file.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldJWT),
),
stringvalidator.LengthAtLeast(1),
validators.GCPCredentialsValidator(),
},
},
consts.FieldServiceAccount: schema.StringAttribute{
Optional: true,
Description: "IAM service account.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldJWT),
),
},
},
},
},
}, consts.MountTypeGCP)
}

View file

@ -0,0 +1,29 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginGenericSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault with an existing auth method using auth/<mount>/login",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldPath: schema.StringAttribute{
Required: true,
},
consts.FieldParameters: schema.MapAttribute{
Optional: true,
ElementType: types.StringType,
Sensitive: true,
},
consts.FieldMethod: schema.StringAttribute{
Optional: true,
},
},
},
}, consts.MountTypeNone)
}

View file

@ -0,0 +1,26 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginJWTSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the jwt method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldRole: schema.StringAttribute{
Required: true,
Description: "Name of the login role.",
},
consts.FieldJWT: schema.StringAttribute{
// can be set via an env var
Optional: true,
Description: "A signed JSON Web Token.",
},
},
},
}, consts.MountTypeJWT)
}

View file

@ -0,0 +1,94 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/framework/validators"
)
func AuthLoginKerberosSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the kerberos method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldToken: schema.StringAttribute{
Optional: true,
Description: "Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) token",
Validators: []validator.String{
validators.KRBNegTokenValidator(),
},
},
consts.FieldUsername: schema.StringAttribute{
Optional: true,
Description: "The username to login into Kerberos with.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
},
consts.FieldService: schema.StringAttribute{
Optional: true,
Description: "The service principle name.",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
},
consts.FieldRealm: schema.StringAttribute{
Optional: true,
Description: "The Kerberos server's authoritative authentication domain",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
},
consts.FieldKRB5ConfPath: schema.StringAttribute{
Optional: true,
Description: "A valid Kerberos configuration file e.g. /etc/krb5.conf.",
Validators: []validator.String{
validators.FileExistsValidator(),
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
},
consts.FieldKeytabPath: schema.StringAttribute{
Optional: true,
Description: "The Kerberos keytab file containing the entry of the login entity.",
Validators: []validator.String{
validators.FileExistsValidator(),
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
},
consts.FieldDisableFastNegotiation: schema.BoolAttribute{
Optional: true,
Validators: []validator.Bool{
boolvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
Description: "Disable the Kerberos FAST negotiation.",
},
consts.FieldRemoveInstanceName: schema.BoolAttribute{
Optional: true,
Validators: []validator.Bool{
boolvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldToken),
),
},
Description: "Strip the host from the username found in the keytab.",
},
},
},
}, consts.MountTypeKerberos)
}

View file

@ -0,0 +1,35 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
const (
ociAuthTypeInstance = "instance"
ociAuthTypeAPIKeys = "apikey"
)
func AuthLoginOCISchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the OCI method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldRole: schema.StringAttribute{
Required: true,
Description: "Name of the login role.",
},
consts.FieldAuthType: schema.StringAttribute{
Required: true,
Description: "Authentication type to use when getting OCI credentials.",
Validators: []validator.String{
stringvalidator.OneOf([]string{ociAuthTypeInstance, ociAuthTypeAPIKeys}...),
},
},
},
},
}, consts.MountTypeOCI)
}

View file

@ -0,0 +1,38 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/framework/validators"
)
func AuthLoginOIDCSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the oidc method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldRole: schema.StringAttribute{
Required: true,
Description: "Name of the login role.",
},
consts.FieldCallbackListenerAddress: schema.StringAttribute{
Optional: true,
Description: "The callback listener's address. Must be a valid URI without the path.",
Validators: []validator.String{
validators.URIValidator([]string{"tcp"}),
},
},
consts.FieldCallbackAddress: schema.StringAttribute{
Optional: true,
Description: "The callback address. Must be a valid URI without the path.",
Validators: []validator.String{
validators.URIValidator([]string{"http", "https"}),
},
},
},
},
}, consts.MountTypeOIDC)
}

View file

@ -0,0 +1,27 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginRadiusSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the radius method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldUsername: schema.StringAttribute{
Description: "The Radius username.",
// can be set via an env var
Optional: true,
},
consts.FieldPassword: schema.StringAttribute{
// can be set via an env var
Optional: true,
Description: "The Radius password for username.",
},
},
},
}, consts.MountTypeRadius)
}

View file

@ -0,0 +1,22 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginTokenFileSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using ",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldFilename: schema.StringAttribute{
// can be set via an env var
Optional: true,
Description: "The name of a file containing a single " +
"line that is a valid Vault token",
},
},
},
}, consts.MountTypeNone)
}

View file

@ -0,0 +1,38 @@
package fwprovider
import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
func AuthLoginUserpassSchema() schema.Block {
return mustAddLoginSchema(&schema.ListNestedBlock{
Description: "Login to vault using the userpass method",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldUsername: schema.StringAttribute{
// can be set via an env var
Optional: true,
Description: "Login with username",
},
consts.FieldPassword: schema.StringAttribute{
Optional: true,
Description: "Login with password",
},
consts.FieldPasswordFile: schema.StringAttribute{
Optional: true,
Description: "Login with password from a file",
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtName(consts.FieldPassword),
),
},
},
},
},
}, consts.MountTypeUserpass)
}

View file

@ -0,0 +1,229 @@
package fwprovider
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"regexp"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
sdkv2provider "github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/terraform-provider-vault/internal/vault/sys"
)
// Ensure the implementation satisfies the provider.Provider interface
var _ provider.Provider = &fwprovider{}
// New returns a new, initialized Terraform Plugin Framework-style provider instance.
//
// The provider instance is fully configured once the `Configure` method has been called.
func New(primary interface{ Meta() interface{} }) provider.Provider {
return &fwprovider{
Primary: primary,
}
}
// Provider implements the terraform-plugin-framework's provider.Provider
// interface
//
// See: https://developer.hashicorp.com/terraform/plugin/framework
type fwprovider struct {
Primary interface{ Meta() interface{} }
}
// Metadata returns the metadata for the provider, such as a type name and
// version data.
func (p *fwprovider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "vault"
// TODO: inject provider version during build time
// resp.Version = "0.0.0-dev"
}
// Schema returns the schema for this provider's configuration.
//
// Schema is called during validate, plan and apply.
func (p *fwprovider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
// This schema must match exactly to the SDKv2 provider's schema
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
// Not `Required` but must be set via config or env. Otherwise we
// return an error.
consts.FieldAddress: schema.StringAttribute{
Optional: true,
Description: "URL of the root of the target Vault server.",
},
"add_address_to_env": schema.StringAttribute{
Optional: true,
Description: "If true, adds the value of the `address` argument to the Terraform process environment.",
},
// Not `Required` but must be set via config, env, or token helper.
// Otherwise we return an error.
"token": schema.StringAttribute{
Optional: true,
Description: "Token to use to authenticate to Vault.",
},
"token_name": schema.StringAttribute{
Optional: true,
Description: "Token name to use for creating the Vault child token.",
},
"skip_child_token": schema.BoolAttribute{
Optional: true,
// Setting to true will cause max_lease_ttl_seconds and token_name to be ignored (not used).
// Note that this is strongly discouraged due to the potential of exposing sensitive secret data.
Description: "Set this to true to prevent the creation of ephemeral child token used by this provider.",
},
consts.FieldCACertFile: schema.StringAttribute{
Optional: true,
Description: "Path to a CA certificate file to validate the server's certificate.",
},
consts.FieldCACertDir: schema.StringAttribute{
Optional: true,
Description: "Path to directory containing CA certificate files to validate the server's certificate.",
},
consts.FieldSkipTLSVerify: schema.BoolAttribute{
Optional: true,
Description: "Set this to true only if the target Vault server is an insecure development instance.",
},
consts.FieldTLSServerName: schema.StringAttribute{
Optional: true,
Description: "Name to use as the SNI host when connecting via TLS.",
},
"max_lease_ttl_seconds": schema.Int64Attribute{
Optional: true,
Description: "Maximum TTL for secret leases requested by this provider.",
},
"max_retries": schema.Int64Attribute{
Optional: true,
Description: "Maximum number of retries when a 5xx error code is encountered.",
},
"max_retries_ccc": schema.Int64Attribute{
Optional: true,
Description: "Maximum number of retries for Client Controlled Consistency related operations",
},
consts.FieldNamespace: schema.StringAttribute{
Optional: true,
Description: "The namespace to use. Available only for Vault Enterprise.",
},
consts.FieldSkipGetVaultVersion: schema.BoolAttribute{
Optional: true,
Description: "Skip the dynamic fetching of the Vault server version.",
},
consts.FieldVaultVersionOverride: schema.StringAttribute{
Optional: true,
Description: "Override the Vault server version, " +
"which is normally determined dynamically from the target Vault server",
Validators: []validator.String{
// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
stringvalidator.RegexMatches(
regexp.MustCompile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`),
"must be a valid semantic version",
),
},
},
consts.FieldSetNamespaceFromToken: schema.BoolAttribute{
Optional: true,
Description: "In the case where the Vault token is for a specific namespace " +
"and the provider namespace is not configured, use the token namespace " +
"as the root namespace for all resources.",
},
},
Blocks: map[string]schema.Block{
"headers": schema.ListNestedBlock{
Description: "The headers to send with each Vault request.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Required: true,
Sensitive: true,
Description: "The header name",
},
"value": schema.StringAttribute{
Required: true,
Sensitive: true,
Description: "The header value",
},
},
},
},
consts.FieldClientAuth: schema.ListNestedBlock{
Description: "Client authentication credentials.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
consts.FieldCertFile: schema.StringAttribute{
Required: true,
Description: "Path to a file containing the client certificate.",
},
consts.FieldKeyFile: schema.StringAttribute{
Required: true,
Description: "Path to a file containing the private key that the certificate was issued for.",
},
},
},
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},
},
consts.FieldAuthLoginAWS: AuthLoginAWSSchema(),
consts.FieldAuthLoginAzure: AuthLoginAzureSchema(),
consts.FieldAuthLoginCert: AuthLoginCertSchema(),
consts.FieldAuthLoginGCP: AuthLoginGCPSchema(),
consts.FieldAuthLoginGeneric: AuthLoginGenericSchema(),
consts.FieldAuthLoginJWT: AuthLoginJWTSchema(),
consts.FieldAuthLoginKerberos: AuthLoginKerberosSchema(),
consts.FieldAuthLoginOCI: AuthLoginOCISchema(),
consts.FieldAuthLoginOIDC: AuthLoginOIDCSchema(),
consts.FieldAuthLoginRadius: AuthLoginRadiusSchema(),
consts.FieldAuthLoginTokenFile: AuthLoginTokenFileSchema(),
consts.FieldAuthLoginUserpass: AuthLoginUserpassSchema(),
},
}
}
// Configure handles the configuration of any provider-level data or clients.
// These configuration values may be from the practitioner Terraform
// configuration, environment variables, or other means such as reading
// vendor-specific configuration files.
//
// Configure is called during plan and apply.
func (p *fwprovider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
// Provider's parsed configuration (its instance state) is available
// through the primary provider's Meta() method.
v, ok := p.Primary.Meta().(*sdkv2provider.ProviderMeta)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *provider.ProviderMeta, got: %T. Please report this issue to the provider developers.", p.Primary.Meta()),
)
return
}
resp.DataSourceData = v
resp.ResourceData = v
}
// Resources returns a slice of functions to instantiate each Resource
// implementation.
//
// The resource type name is determined by the Resource implementing
// the Metadata method. All resources must have unique names.
func (p *fwprovider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
sys.NewPasswordPolicyResource,
}
}
// DataSources returns a slice of functions to instantiate each DataSource
// implementation.
//
// The data source type name is determined by the DataSource implementing
// the Metadata method. All data sources must have unique names.
func (p *fwprovider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{}
}

View file

@ -9,6 +9,7 @@ import (
"log"
"net/http"
"os"
"strconv"
"strings"
"sync"
"time"
@ -189,27 +190,26 @@ func (p *ProviderMeta) setClient() error {
d := p.resourceData
clientConfig := api.DefaultConfig()
addr := d.Get(consts.FieldAddress).(string)
if addr != "" {
clientConfig.Address = addr
addr := GetResourceDataStr(d, consts.FieldAddress, api.EnvVaultAddress, "")
if addr == "" {
return fmt.Errorf("failed to configure Vault address")
}
clientConfig.Address = addr
clientConfig.CloneTLSConfig = true
tlsConfig := &api.TLSConfig{
CACert: d.Get(consts.FieldCACertFile).(string),
CAPath: d.Get(consts.FieldCACertDir).(string),
Insecure: d.Get(consts.FieldSkipTLSVerify).(bool),
TLSServerName: d.Get(consts.FieldTLSServerName).(string),
CACert: GetResourceDataStr(d, consts.FieldCACertFile, api.EnvVaultCACert, ""),
CAPath: GetResourceDataStr(d, consts.FieldCACertDir, api.EnvVaultCAPath, ""),
Insecure: GetResourceDataBool(d, consts.FieldSkipTLSVerify, "VAULT_SKIP_VERIFY", false),
TLSServerName: GetResourceDataStr(d, consts.FieldTLSServerName, api.EnvVaultTLSServerName, ""),
}
if _, ok := d.GetOk(consts.FieldClientAuth); ok {
prefix := fmt.Sprintf("%s.0.", consts.FieldClientAuth)
if v, ok := d.GetOk(prefix + consts.FieldCertFile); ok {
tlsConfig.ClientCert = v.(string)
}
if v, ok := d.GetOk(prefix + consts.FieldKeyFile); ok {
tlsConfig.ClientKey = v.(string)
}
tlsConfig.ClientCert = GetResourceDataStr(d, prefix+consts.FieldCertFile, api.EnvVaultClientCert, "")
tlsConfig.ClientKey = GetResourceDataStr(d, prefix+consts.FieldKeyFile, api.EnvVaultClientKey, "")
}
err := clientConfig.ConfigureTLS(tlsConfig)
@ -256,12 +256,12 @@ func (p *ProviderMeta) setClient() error {
}
client.SetHeaders(parsedHeaders)
client.SetMaxRetries(d.Get("max_retries").(int))
client.SetMaxRetries(GetResourceDataInt(d, "max_retries", "VAULT_MAX_RETRIES", DefaultMaxHTTPRetries))
MaxHTTPRetriesCCC = d.Get("max_retries_ccc").(int)
MaxHTTPRetriesCCC = GetResourceDataInt(d, "max_retries_ccc", "VAULT_MAX_RETRIES_CCC", DefaultMaxHTTPRetriesCCC)
// Set the namespace to the requested namespace, if provided
namespace := d.Get(consts.FieldNamespace).(string)
namespace := GetResourceDataStr(d, consts.FieldNamespace, "VAULT_NAMESPACE", "")
authLogin, err := GetAuthLogin(d)
if err != nil {
@ -330,7 +330,8 @@ func (p *ProviderMeta) setClient() error {
tokenNamespace = strings.Trim(v.(string), "/")
}
if !d.Get(consts.FieldSkipChildToken).(bool) {
skipChildToken := GetResourceDataBool(d, consts.FieldSkipChildToken, consts.EnvVarSkipChildToken, false)
if !skipChildToken {
// a child token is always created in the namespace of the parent token.
token, err = createChildToken(d, client, tokenNamespace)
if err != nil {
@ -353,7 +354,8 @@ func (p *ProviderMeta) setClient() error {
namespace = tokenNamespace
// set the namespace on the provider to ensure that all child
// namespace paths are properly honoured.
if v, ok := d.Get(consts.FieldSetNamespaceFromToken).(bool); ok && v {
setTokenFromNamespace := GetResourceDataBool(d, consts.FieldSetNamespaceFromToken, "VAULT_SET_NAMESPACE_FROM_TOKEN", true)
if setTokenFromNamespace {
if err := d.Set(consts.FieldNamespace, namespace); err != nil {
return err
}
@ -375,6 +377,7 @@ func (p *ProviderMeta) setVaultVersion() error {
}
d := p.resourceData
skipGetVaultVersion := GetResourceDataBool(d, consts.FieldSkipGetVaultVersion, "", false)
var vaultVersion *version.Version
if v, ok := d.GetOk(consts.FieldVaultVersionOverride); ok {
ver, err := version.NewVersion(v.(string))
@ -383,7 +386,7 @@ func (p *ProviderMeta) setVaultVersion() error {
consts.FieldVaultVersionOverride, err)
}
vaultVersion = ver
} else if !d.Get(consts.FieldSkipGetVaultVersion).(bool) {
} else if !skipGetVaultVersion {
// Set the Vault version to *ProviderMeta object
client, err := p.getClient()
if err != nil {
@ -559,10 +562,7 @@ func getVaultVersion(client *api.Client) (*version.Version, error) {
}
func createChildToken(d *schema.ResourceData, c *api.Client, namespace string) (string, error) {
tokenName := d.Get("token_name").(string)
if tokenName == "" {
tokenName = "terraform"
}
tokenName := GetResourceDataStr(d, "token_name", "VAULT_TOKEN_NAME", "terraform")
// the clone is only used to auth to Vault
clone, err := c.Clone()
@ -586,10 +586,11 @@ func createChildToken(d *schema.ResourceData, c *api.Client, namespace string) (
// Caution is still required with state files since not all secrets
// can explicitly be revoked, and this limited scope won't apply to
// any secrets that are *written* by Terraform to Vault.
ttl := GetResourceDataInt(d, consts.FieldMaxLeaseTTL, "TERRAFORM_VAULT_MAX_TTL", 1200)
childTokenLease, err := clone.Auth().Token().Create(&api.TokenCreateRequest{
DisplayName: tokenName,
TTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
ExplicitMaxTTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
TTL: fmt.Sprintf("%ds", ttl),
ExplicitMaxTTL: fmt.Sprintf("%ds", ttl),
Renewable: pointer.Bool(false),
})
if err != nil {
@ -604,9 +605,83 @@ func createChildToken(d *schema.ResourceData, c *api.Client, namespace string) (
return childToken, nil
}
// GetResourceDataStr returns the value for a given ResourceData field
// If the value is the zero value, then it checks the environment variable. If
// the environment variable is empty, the default dv is returned
func GetResourceDataStr(d *schema.ResourceData, field, env, dv string) string {
if s := d.Get(field).(string); s != "" {
return s
}
if env != "" {
if s := os.Getenv(env); s != "" {
return s
}
}
// return default
return dv
}
// GetResourceDataInt returns the value for a given ResourceData field
// If the value is the zero value, then it checks the environment variable. If
// the environment variable is empty, the default dv is returned
func GetResourceDataInt(d *schema.ResourceData, field, env string, dv int) int {
if v := d.Get(field).(int); v != 0 {
return v
}
if env != "" {
if s := os.Getenv(env); s != "" {
ret, err := strconv.Atoi(s)
if err == nil {
return ret
}
// swallow the error and return the default because that is the
// behavior we had when using SDKv2's schema.EnvDefaultFunc
}
}
// return default
return dv
}
// GetResourceDataBool returns the value for a given ResourceData field
// If the value is the zero value, then it checks the environment variable. If
// the environment variable is empty, the default dv is returned
func GetResourceDataBool(d *schema.ResourceData, field, env string, dv bool) bool {
// since Get does not tell us if the value is false or unset,
// we only return this value if it is non-nil, else we return the default
rawConfig := d.GetRawConfig()
rawVal := rawConfig.GetAttr(field)
// We don't care about the underlying value, just detecting if the config value is null (unset) or not.
if rawVal.IsNull() {
// The value is null (unset) in config, do our defaulting logic
if env != "" {
if s := os.Getenv(env); s != "" {
ret, err := strconv.ParseBool(s)
if err == nil {
return ret
}
// swallow the error and return the default because that is the
// behavior we had when using SDKv2's schema.EnvDefaultFunc
}
}
// return default if value not in environment
return dv
}
// If the value is set in config, return using d.Get
return d.Get(field).(bool)
}
func GetToken(d *schema.ResourceData) (string, error) {
if token := d.Get("token").(string); token != "" {
return token, nil
} else if token = os.Getenv(api.EnvVaultToken); token != "" {
return token, nil
}
if addAddr := d.Get("add_address_to_env").(string); addAddr == "true" {

View file

@ -6,19 +6,15 @@ package provider
import (
"errors"
"fmt"
"os"
"reflect"
"sync"
"testing"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/vault/api"
vault_consts "github.com/hashicorp/vault/sdk/helper/consts"
"os"
"reflect"
"sync"
"testing"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/testutil"
@ -530,497 +526,3 @@ func TestIsEnterpriseSupported(t *testing.T) {
})
}
}
func TestNewProviderMeta(t *testing.T) {
testutil.SkipTestAcc(t)
testutil.SkipTestAccEnt(t)
testutil.TestAccPreCheck(t)
nsPrefix := acctest.RandomWithPrefix("ns")
defaultUser := "alice"
defaultPassword := "f00bazB1ff"
rootProvider := NewProvider(nil, nil)
pr := &schema.Resource{
Schema: rootProvider.Schema,
}
tests := []struct {
name string
d *schema.ResourceData
data map[string]interface{}
wantNamespace string
tokenNamespace string
authLoginNamespace string
wantErr bool
checkSetSetTokenNamespace bool
wantNamespaceFromToken string
}{
{
name: "invalid-nil-ResourceData",
d: nil,
wantErr: true,
},
{
// expect provider namespace set.
name: "with-provider-ns-only",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldNamespace: nsPrefix + "prov",
consts.FieldSkipGetVaultVersion: true,
},
wantNamespace: nsPrefix + "prov",
wantErr: false,
},
{
// expect token namespace set
name: "with-token-ns-only",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
},
tokenNamespace: nsPrefix + "token-ns-only",
wantNamespace: nsPrefix + "token-ns-only",
wantErr: false,
},
{
// expect provider namespace set.
name: "with-provider-ns-and-token-ns",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldNamespace: nsPrefix + "prov-and-token",
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
},
tokenNamespace: nsPrefix + "token-ns",
wantNamespace: nsPrefix + "prov-and-token",
wantErr: false,
},
{
// expect auth_login namespace set.
name: "with-auth-login-and-ns",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
consts.FieldAuthLoginUserpass: []map[string]interface{}{
{
consts.FieldNamespace: nsPrefix + "auth-ns",
consts.FieldMount: consts.MountTypeUserpass,
consts.FieldUsername: defaultUser,
consts.FieldPassword: defaultPassword,
},
},
},
authLoginNamespace: nsPrefix + "auth-ns",
wantNamespace: nsPrefix + "auth-ns",
wantErr: false,
},
{
// expect provider namespace set.
name: "with-provider-ns-and-auth-login-with-ns",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldNamespace: nsPrefix + "prov-ns-prov-ns",
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
consts.FieldAuthLoginUserpass: []map[string]interface{}{
{
consts.FieldNamespace: nsPrefix + "auth-ns-auth-ns",
consts.FieldMount: consts.MountTypeUserpass,
consts.FieldUsername: defaultUser,
consts.FieldPassword: defaultPassword,
},
},
},
authLoginNamespace: nsPrefix + "auth-ns-auth-ns",
wantNamespace: nsPrefix + "prov-ns-prov-ns",
wantErr: false,
},
{
// expect token based namespace to be ignored.
name: "set-namespace-from-token-false",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldSkipGetVaultVersion: true,
consts.FieldSetNamespaceFromToken: false,
consts.FieldSkipChildToken: true,
},
tokenNamespace: nsPrefix + "set-ns-from-token-auth-false-ignored",
wantNamespace: nsPrefix + "set-ns-from-token-auth-false-ignored",
checkSetSetTokenNamespace: true,
wantNamespaceFromToken: "",
wantErr: false,
},
{
// expect token based namespace to be ignored.
name: "set-namespace-from-token-true",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldSkipGetVaultVersion: true,
consts.FieldSetNamespaceFromToken: true,
consts.FieldSkipChildToken: true,
consts.FieldAuthLoginUserpass: []map[string]interface{}{
{
consts.FieldNamespace: nsPrefix + "set-ns-from-token-auth-true",
consts.FieldMount: consts.MountTypeUserpass,
consts.FieldUsername: defaultUser,
consts.FieldPassword: defaultPassword,
},
},
},
authLoginNamespace: nsPrefix + "set-ns-from-token-auth-true",
wantNamespace: nsPrefix + "set-ns-from-token-auth-true",
checkSetSetTokenNamespace: true,
wantNamespaceFromToken: nsPrefix + "set-ns-from-token-auth-true",
wantErr: false,
},
}
createNamespace := func(t *testing.T, client *api.Client, ns string) {
t.Helper()
t.Cleanup(func() {
err := backoff.Retry(func() error {
_, err := client.Logical().Delete(consts.SysNamespaceRoot + ns)
return err
}, backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Microsecond*500), 10))
if err != nil {
t.Fatalf("failed to delete namespace %q, err=%s", ns, err)
}
})
if _, err := client.Logical().Write(
consts.SysNamespaceRoot+ns, nil); err != nil {
t.Fatalf("failed to create namespace, err=%s", err)
}
}
config := api.DefaultConfig()
config.CloneToken = true
client, err := api.NewClient(config)
if err != nil {
t.Fatalf("failed to create Vault client, err=%s", err)
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.authLoginNamespace != "" {
createNamespace(t, client, tt.authLoginNamespace)
options := &api.EnableAuthOptions{
Type: consts.MountTypeUserpass,
Description: "test auth_userpass",
Local: true,
}
clone, err := client.Clone()
if err != nil {
t.Fatalf("failed to clone Vault client, err=%s", err)
}
clone.SetNamespace(tt.authLoginNamespace)
if err := clone.Sys().EnableAuthWithOptions(consts.MountTypeUserpass, options); err != nil {
t.Fatalf("failed to enable auth, err=%s", err)
}
if _, err := clone.Logical().Write("auth/userpass/users/alice",
map[string]interface{}{
consts.FieldPassword: defaultPassword,
consts.FieldTokenPolicies: []string{"admin", "default"},
}); err != nil {
t.Fatalf("failed to create user, err=%s", err)
}
}
if tt.tokenNamespace != "" {
if tt.data == nil {
t.Fatal("test data cannot be nil when tokenNamespace set")
}
createNamespace(t, client, tt.tokenNamespace)
clone, err := client.Clone()
if err != nil {
t.Fatalf("failed to clone Vault client, err=%s", err)
}
// in order not to trigger the min TTL warning we can add some time to the min.
tokenTTL := TokenTTLMinRecommended + time.Second*10
clone.SetNamespace(tt.tokenNamespace)
resp, err := clone.Auth().Token().Create(&api.TokenCreateRequest{
TTL: tokenTTL.String(),
})
if err != nil {
t.Fatalf("failed to create Vault token, err=%s", err)
}
tt.data[consts.FieldToken] = resp.Auth.ClientToken
}
for k, v := range tt.data {
if err := tt.d.Set(k, v); err != nil {
t.Fatalf("failed to set resource data, key=%s, value=%#v", k, v)
}
}
got, err := NewProviderMeta(tt.d)
if (err != nil) != tt.wantErr {
t.Errorf("NewProviderMeta() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
if got != nil {
t.Errorf("NewProviderMeta() got = %v, want nil", got)
}
return
}
p, ok := got.(*ProviderMeta)
if !ok {
t.Fatalf("invalid type got %T, expected %T", got, &ProviderMeta{})
}
client, err := p.GetClient()
if err != nil {
t.Fatalf("got unexpected error %s", err)
}
if !reflect.DeepEqual(client.Namespace(), tt.wantNamespace) {
t.Errorf("NewProviderMeta() got ns = %v, want ns %v", p.client.Namespace(), tt.wantNamespace)
}
if tt.checkSetSetTokenNamespace && tt.wantNamespaceFromToken != tt.d.Get(consts.FieldNamespace).(string) {
t.Errorf("NewProviderMeta() got ns = %q, want ns %q", tt.d.Get(consts.FieldNamespace).(string), tt.wantNamespaceFromToken)
}
if client.Token() == "" {
t.Errorf("NewProviderMeta() got empty Client token")
}
})
}
}
func TestNewProviderMeta_Cert(t *testing.T) {
testutil.SkipTestAcc(t)
testutil.SkipTestAccEnt(t)
testutil.TestAccPreCheck(t)
nsPrefix := acctest.RandomWithPrefix("ns")
defaultUser := "alice"
defaultPassword := "f00bazB1ff"
rootProvider := NewProvider(nil, nil)
pr := &schema.Resource{
Schema: rootProvider.Schema,
}
tests := []struct {
name string
d *schema.ResourceData
data map[string]interface{}
wantNamespace string
tokenNamespace string
authLoginNamespace string
wantErr bool
}{
{
name: "invalid-nil-ResourceData",
d: nil,
wantErr: true,
},
{
// expect provider namespace set.
name: "with-provider-ns-only",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldNamespace: nsPrefix + "prov",
consts.FieldSkipGetVaultVersion: true,
},
wantNamespace: nsPrefix + "prov",
wantErr: false,
},
{
// expect token namespace set
name: "with-token-ns-only",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
},
tokenNamespace: nsPrefix + "token-ns-only",
wantNamespace: nsPrefix + "token-ns-only",
wantErr: false,
},
{
// expect provider namespace set.
name: "with-provider-ns-and-token-ns",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldNamespace: nsPrefix + "prov-and-token",
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
},
tokenNamespace: nsPrefix + "token-ns",
wantNamespace: nsPrefix + "prov-and-token",
wantErr: false,
},
{
// expect auth_login namespace set.
name: "with-auth-login-and-ns",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
consts.FieldAuthLoginUserpass: []map[string]interface{}{
{
consts.FieldNamespace: nsPrefix + "auth-ns",
consts.FieldMount: consts.MountTypeUserpass,
consts.FieldUsername: defaultUser,
consts.FieldPassword: defaultPassword,
},
},
},
authLoginNamespace: nsPrefix + "auth-ns",
wantNamespace: nsPrefix + "auth-ns",
wantErr: false,
},
{
// expect provider namespace set.
name: "with-provider-ns-and-auth-login-with-ns",
d: pr.TestResourceData(),
data: map[string]interface{}{
consts.FieldNamespace: nsPrefix + "prov-ns-auth-ns",
consts.FieldSkipGetVaultVersion: true,
consts.FieldSkipChildToken: true,
consts.FieldAuthLoginUserpass: []map[string]interface{}{
{
consts.FieldNamespace: nsPrefix + "auth-ns-prov-ns",
consts.FieldMount: consts.MountTypeUserpass,
consts.FieldUsername: defaultUser,
consts.FieldPassword: defaultPassword,
},
},
},
authLoginNamespace: nsPrefix + "auth-ns-prov-ns",
wantNamespace: nsPrefix + "prov-ns-auth-ns",
wantErr: false,
},
}
createNamespace := func(t *testing.T, client *api.Client, ns string) {
t.Helper()
t.Cleanup(func() {
err := backoff.Retry(func() error {
_, err := client.Logical().Delete(consts.SysNamespaceRoot + ns)
return err
}, backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Microsecond*500), 10))
if err != nil {
t.Fatalf("failed to delete namespace %q, err=%s", ns, err)
}
})
if _, err := client.Logical().Write(
consts.SysNamespaceRoot+ns, nil); err != nil {
t.Fatalf("failed to create namespace, err=%s", err)
}
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := api.DefaultConfig()
config.CloneToken = true
client, err := api.NewClient(config)
if err != nil {
t.Fatalf("failed to create Vault client, err=%s", err)
}
if tt.authLoginNamespace != "" {
createNamespace(t, client, tt.authLoginNamespace)
options := &api.EnableAuthOptions{
Type: consts.MountTypeUserpass,
Description: "test auth_userpass",
Local: true,
}
clone, err := client.Clone()
if err != nil {
t.Fatalf("failed to clone Vault client, err=%s", err)
}
clone.SetNamespace(tt.authLoginNamespace)
if err := clone.Sys().EnableAuthWithOptions(consts.MountTypeUserpass, options); err != nil {
t.Fatalf("failed to enable auth, err=%s", err)
}
if _, err := clone.Logical().Write("auth/userpass/users/alice",
map[string]interface{}{
consts.FieldPassword: defaultPassword,
consts.FieldTokenPolicies: []string{"admin", "default"},
}); err != nil {
t.Fatalf("failed to create user, err=%s", err)
}
}
if tt.tokenNamespace != "" {
if tt.data == nil {
t.Fatal("test data cannot be nil when tokenNamespace set")
}
createNamespace(t, client, tt.tokenNamespace)
clone, err := client.Clone()
if err != nil {
t.Fatalf("failed to clone Vault client, err=%s", err)
}
// in order not to trigger the min TTL warning we can add some time to the min.
tokenTTL := TokenTTLMinRecommended + time.Second*10
clone.SetNamespace(tt.tokenNamespace)
resp, err := clone.Auth().Token().Create(&api.TokenCreateRequest{
TTL: tokenTTL.String(),
})
if err != nil {
t.Fatalf("failed to create Vault token, err=%s", err)
}
tt.data[consts.FieldToken] = resp.Auth.ClientToken
}
for k, v := range tt.data {
if err := tt.d.Set(k, v); err != nil {
t.Fatalf("failed to set resource data, key=%s, value=%#v", k, v)
}
}
got, err := NewProviderMeta(tt.d)
if (err != nil) != tt.wantErr {
t.Errorf("NewProviderMeta() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
if got != nil {
t.Errorf("NewProviderMeta() got = %v, want nil", got)
}
return
}
p, ok := got.(*ProviderMeta)
if !ok {
t.Fatalf("invalid type got %T, expected %T", got, &ProviderMeta{})
}
pClient, err := p.GetClient()
if err != nil {
t.Fatalf("got unexpected error %s", err)
}
if !reflect.DeepEqual(pClient.Namespace(), tt.wantNamespace) {
t.Errorf("NewProviderMeta() got ns = %v, want ns %v", p.client.Namespace(), tt.wantNamespace)
}
if client.Token() == "" {
t.Errorf("NewProviderMeta() got empty Client token")
}
})
}
}

View file

@ -13,7 +13,6 @@ import (
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
)
@ -65,36 +64,36 @@ func NewProvider(
}
r := &schema.Provider{
// This schema must match exactly the fwprovider (Terraform Plugin Framework) schema.
// Notably the attributes can have no Default values.
Schema: map[string]*schema.Schema{
// Not `Required` but must be set via config or env. Otherwise we
// return an error.
consts.FieldAddress: {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultAddress, nil),
Optional: true,
Description: "URL of the root of the target Vault server.",
},
"add_address_to_env": {
Type: schema.TypeString,
Optional: true,
Default: false,
Description: "If true, adds the value of the `address` argument to the Terraform process environment.",
},
// Not `Required` but must be set via config, env, or token helper.
// Otherwise we return an error.
"token": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultToken, ""),
Optional: true,
Description: "Token to use to authenticate to Vault.",
},
"token_name": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_TOKEN_NAME", ""),
Description: "Token name to use for creating the Vault child token.",
},
"skip_child_token": {
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("TERRAFORM_VAULT_SKIP_CHILD_TOKEN", false),
Type: schema.TypeBool,
Optional: true,
// Setting to true will cause max_lease_ttl_seconds and token_name to be ignored (not used).
// Note that this is strongly discouraged due to the potential of exposing sensitive secret data.
Description: "Set this to true to prevent the creation of ephemeral child token used by this provider.",
@ -102,102 +101,59 @@ func NewProvider(
consts.FieldCACertFile: {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultCACert, ""),
Description: "Path to a CA certificate file to validate the server's certificate.",
},
consts.FieldCACertDir: {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultCAPath, ""),
Description: "Path to directory containing CA certificate files to validate the server's certificate.",
},
consts.FieldClientAuth: {
Type: schema.TypeList,
Optional: true,
Description: "Client authentication credentials.",
MaxItems: 1,
Deprecated: fmt.Sprintf("Use %s instead", consts.FieldAuthLoginCert),
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
consts.FieldCertFile: {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultClientCert, ""),
Description: "Path to a file containing the client certificate.",
},
consts.FieldKeyFile: {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultClientKey, ""),
Description: "Path to a file containing the private key that the certificate was issued for.",
},
},
},
},
consts.FieldSkipTLSVerify: {
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_SKIP_VERIFY", false),
Description: "Set this to true only if the target Vault server is an insecure development instance.",
},
consts.FieldTLSServerName: {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(api.EnvVaultTLSServerName, ""),
Description: "Name to use as the SNI host when connecting via TLS.",
},
"max_lease_ttl_seconds": {
Type: schema.TypeInt,
Optional: true,
// Default is 20min, which is intended to be enough time for
// a reasonable Terraform run can complete but not
// significantly longer, so that any leases are revoked shortly
// after Terraform has finished running.
DefaultFunc: schema.EnvDefaultFunc("TERRAFORM_VAULT_MAX_TTL", 1200),
Type: schema.TypeInt,
Optional: true,
Description: "Maximum TTL for secret leases requested by this provider.",
},
"max_retries": {
Type: schema.TypeInt,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_MAX_RETRIES", DefaultMaxHTTPRetries),
Description: "Maximum number of retries when a 5xx error code is encountered.",
},
"max_retries_ccc": {
Type: schema.TypeInt,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_MAX_RETRIES_CCC", DefaultMaxHTTPRetriesCCC),
Description: "Maximum number of retries for Client Controlled Consistency related operations",
},
consts.FieldNamespace: {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_NAMESPACE", ""),
Description: "The namespace to use. Available only for Vault Enterprise.",
},
consts.FieldSetNamespaceFromToken: {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "In the case where the Vault token is for a specific namespace " +
"and the provider namespace is not configured, use the token namespace " +
"as the root namespace for all resources.",
},
"headers": {
Type: schema.TypeList,
Optional: true,
Sensitive: true,
Description: "The headers to send with each Vault request.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
Description: "The header name",
},
"value": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
Description: "The header value",
},
},
@ -206,7 +162,6 @@ func NewProvider(
consts.FieldSkipGetVaultVersion: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Skip the dynamic fetching of the Vault server version.",
},
consts.FieldVaultVersionOverride: {
@ -216,6 +171,33 @@ func NewProvider(
"which is normally determined dynamically from the target Vault server",
ValidateDiagFunc: ValidateDiagSemVer,
},
consts.FieldSetNamespaceFromToken: {
Type: schema.TypeBool,
Optional: true,
Description: "In the case where the Vault token is for a specific namespace " +
"and the provider namespace is not configured, use the token namespace " +
"as the root namespace for all resources.",
},
consts.FieldClientAuth: {
Type: schema.TypeList,
Optional: true,
Description: "Client authentication credentials.",
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
consts.FieldCertFile: {
Type: schema.TypeString,
Required: true,
Description: "Path to a file containing the client certificate.",
},
consts.FieldKeyFile: {
Type: schema.TypeString,
Required: true,
Description: "Path to a file containing the private key that the certificate was issued for.",
},
},
},
},
},
ConfigureFunc: NewProviderMeta,
DataSourcesMap: dataSourcesMap,
@ -224,6 +206,11 @@ func NewProvider(
MustAddAuthLoginSchema(r.Schema)
// Set the provider Meta (instance data) here.
// It will be overwritten by the result of the call to ConfigureFunc,
// but can be used pre-configuration by other (non-primary) provider servers.
r.SetMeta(&ProviderMeta{})
return r
}

View file

@ -22,7 +22,7 @@ import (
var (
regexpPathLeading = regexp.MustCompile(fmt.Sprintf(`^%s`, consts.PathDelim))
regexpPathTrailing = regexp.MustCompile(fmt.Sprintf(`%s$`, consts.PathDelim))
regexpPath = regexp.MustCompile(fmt.Sprintf(`%s|%s`, regexpPathLeading, regexpPathTrailing))
RegexpPath = regexp.MustCompile(fmt.Sprintf(`%s|%s`, regexpPathLeading, regexpPathTrailing))
regexpUUID = regexp.MustCompile("^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$")
)
@ -63,7 +63,7 @@ func ValidateNoTrailingSlash(i interface{}, k string) ([]string, []error) {
func ValidateNoLeadingTrailingSlashes(i interface{}, k string) ([]string, []error) {
var errs []error
if err := validatePath(regexpPath, i, k); err != nil {
if err := validatePath(RegexpPath, i, k); err != nil {
errs = append(errs, err)
}
@ -71,7 +71,7 @@ func ValidateNoLeadingTrailingSlashes(i interface{}, k string) ([]string, []erro
}
func ValidateDiagPath(i interface{}, path cty.Path) diag.Diagnostics {
return validateDiagPath(regexpPath, i, path)
return validateDiagPath(RegexpPath, i, path)
}
func validateDiagPath(r *regexp.Regexp, i interface{}, path cty.Path) diag.Diagnostics {

View file

@ -0,0 +1,40 @@
package providertest
import (
"context"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-provider-vault/vault"
)
// ProtoV5ProviderFactories is a static map containing only the main provider instance
var (
ProtoV5ProviderFactories map[string]func() (tfprotov5.ProviderServer, error) = protoV5ProviderFactoriesInit(context.Background(), "vault")
)
// testAccProtoV5ProviderFactories will return a map of provider servers
// suitable for use as a resource.TestStep.ProtoV5ProviderFactories.
//
// When multiplexing providers, the schema and configuration handling must
// exactly match between all underlying providers of the mux server. Mismatched
// schemas will result in a runtime error.
// see: https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux
//
// Any tests that use this function will serve as a smoketest to verify the
// provider schemas match 1-1 so that we may catch runtime errors.
func protoV5ProviderFactoriesInit(ctx context.Context, providerNames ...string) map[string]func() (tfprotov5.ProviderServer, error) {
factories := make(map[string]func() (tfprotov5.ProviderServer, error), len(providerNames))
for _, name := range providerNames {
factories[name] = func() (tfprotov5.ProviderServer, error) {
providerServerFactory, _, err := vault.ProtoV5ProviderServerFactory(ctx)
if err != nil {
return nil, err
}
return providerServerFactory(), nil
}
}
return factories
}

View file

@ -0,0 +1,3 @@
# Vault Auth Methods
This package contains Vault [auth method API](https://developer.hashicorp.com/vault/api-docs/auth) resources and datasources.

View file

@ -0,0 +1,3 @@
# Vault Secrets Engine
This package contains Vault [secrets engine API](https://developer.hashicorp.com/vault/api-docs/secret) resources and datasources.

View file

@ -0,0 +1,3 @@
# Vault System Backend
This package contains Vault [system backend API](https://developer.hashicorp.com/vault/api-docs/system) resources and datasources.

View file

@ -0,0 +1,255 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package sys
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-vault/internal/framework/base"
"github.com/hashicorp/terraform-provider-vault/internal/framework/client"
"github.com/hashicorp/terraform-provider-vault/internal/framework/errutil"
"github.com/hashicorp/terraform-provider-vault/internal/framework/model"
)
// Ensure the implementation satisfies the resource.ResourceWithConfigure interface
var _ resource.ResourceWithConfigure = &PasswordPolicyResource{}
// NewPasswordPolicyResource returns the implementation for this resource to be
// imported by the Terraform Plugin Framework provider
func NewPasswordPolicyResource() resource.Resource {
return &PasswordPolicyResource{}
}
// PasswordPolicyResource implements the methods that define this resource
type PasswordPolicyResource struct {
base.ResourceWithConfigure
base.WithImportByID
}
// PasswordPolicyModel describes the Terraform resource data model to match the
// resource schema.
type PasswordPolicyModel struct {
// common fields to all migrated resources
base.BaseModelLegacy
// fields specific to this resource
Name types.String `tfsdk:"name"`
Policy types.String `tfsdk:"policy"`
}
// PasswordPolicyAPIModel describes the Vault API data model.
type PasswordPolicyAPIModel struct {
Policy string `json:"policy" mapstructure:"policy"`
}
// Metadata defines the resource name as it would appear in Terraform configurations
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources#metadata-method
func (r *PasswordPolicyResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_password_policy"
}
// Schema defines this resource's schema which is the data that is available in
// the resource's configuration, plan, and state
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources#schema-method
func (r *PasswordPolicyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
MarkdownDescription: "Name of the password policy.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"policy": schema.StringAttribute{
Required: true,
MarkdownDescription: "The password policy document",
},
},
MarkdownDescription: "Provides a resource to manage Password Policies.",
}
base.MustAddLegacyBaseSchema(&resp.Schema)
}
// Create is called during the terraform apply command.
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources/create
func (r *PasswordPolicyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data PasswordPolicyModel
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
client, err := client.GetClient(ctx, r.Meta(), data.Namespace.ValueString())
if err != nil {
resp.Diagnostics.AddError(errutil.ClientConfigureErr(err))
return
}
vaultRequest := map[string]interface{}{
"policy": data.Policy.ValueString(),
}
path := r.path(data.Name.ValueString())
// vault returns a nil response on success
_, err = client.Logical().WriteWithContext(ctx, path, vaultRequest)
if err != nil {
resp.Diagnostics.AddError(
errutil.VaultCreateErr(err),
)
return
}
// write the ID to state which is required for backwards compatibility
data.ID = types.StringValue(data.Name.ValueString())
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
// Read is called during the terraform apply, terraform plan, and terraform
// refresh commands.
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources/read
func (r *PasswordPolicyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data PasswordPolicyModel
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
client, err := client.GetClient(ctx, r.Meta(), data.Namespace.ValueString())
if err != nil {
resp.Diagnostics.AddError(errutil.ClientConfigureErr(err))
return
}
// read the name from the id field to support the import command
name := data.ID.ValueString()
path := r.path(name)
policyResp, err := client.Logical().ReadWithContext(ctx, path)
if err != nil {
resp.Diagnostics.AddError(
errutil.VaultReadErr(err),
)
return
}
if policyResp == nil {
resp.Diagnostics.AddError(
errutil.VaultReadResponseNil(),
)
return
}
var readResp PasswordPolicyAPIModel
err = model.ToAPIModel(policyResp.Data, &readResp)
if err != nil {
resp.Diagnostics.AddError("Unable to translate Vault response data", err.Error())
return
}
data.Policy = types.StringValue(readResp.Policy)
// write the name to state to support the import command
data.Name = types.StringValue(name)
// write the ID to state which is required for backwards compatibility
data.ID = types.StringValue(name)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
// Update is called during the terraform apply command
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources/update
func (r *PasswordPolicyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data PasswordPolicyModel
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
client, err := client.GetClient(ctx, r.Meta(), data.Namespace.ValueString())
if err != nil {
resp.Diagnostics.AddError(errutil.ClientConfigureErr(err))
return
}
vaultRequest := map[string]interface{}{
"policy": data.Policy.ValueString(),
}
path := r.path(data.Name.ValueString())
// vault returns a nil response on success
_, err = client.Logical().WriteWithContext(ctx, path, vaultRequest)
if err != nil {
resp.Diagnostics.AddError(
errutil.VaultUpdateErr(err),
)
return
}
// write the ID to state which is required for backwards compatibility
data.ID = types.StringValue(data.Name.ValueString())
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
// Delete is called during the terraform apply command
//
// https://developer.hashicorp.com/terraform/plugin/framework/resources/delete
func (r *PasswordPolicyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data PasswordPolicyModel
// Read Terraform state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
client, err := client.GetClient(ctx, r.Meta(), data.Namespace.ValueString())
if err != nil {
resp.Diagnostics.AddError(errutil.ClientConfigureErr(err))
return
}
path := r.path(data.Name.ValueString())
_, err = client.Logical().DeleteWithContext(ctx, path)
if err != nil {
resp.Diagnostics.AddError(
errutil.VaultDeleteErr(err),
)
return
}
// If the logic reaches here, it implicitly succeeded and will remove
// the resource from state if there are no other errors.
}
func (r *PasswordPolicyResource) path(name string) string {
return fmt.Sprintf("/sys/policies/password/%s", name)
}

View file

@ -0,0 +1,152 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package sys_test
import (
"fmt"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-vault/internal/providertest"
"github.com/hashicorp/terraform-provider-vault/testutil"
)
func TestAccPasswordPolicy(t *testing.T) {
policyName := acctest.RandomWithPrefix("test-policy")
resourceName := "vault_password_policy.test"
testPolicy := "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"
testPolicyUpdated := "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\nrule \"charset\" {\n charset = \"1234567890\"\nmin-chars = 1\n}\n"
updatedConfig := testAccPasswordPolicyConfig(policyName, testPolicyUpdated)
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProtoV5ProviderFactories: providertest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccPasswordPolicyConfig(policyName, testPolicy),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", policyName),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
),
},
{
Config: updatedConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", policyName),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
),
},
testutil.GetImportTestStep(resourceName, false, nil),
},
})
}
func TestAccPasswordPolicyNS(t *testing.T) {
ns := acctest.RandomWithPrefix("ns")
policyName := acctest.RandomWithPrefix("test-policy")
resourceName := "vault_password_policy.test"
testPolicy := "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"
testPolicyUpdated := "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\nrule \"charset\" {\n charset = \"1234567890\"\nmin-chars = 1\n}\n"
updatedConfig := testAccPasswordPolicyConfigNS(ns, policyName, testPolicyUpdated)
resource.Test(t, resource.TestCase{
PreCheck: func() {
testutil.TestAccPreCheck(t)
testutil.TestEntPreCheck(t)
},
ProtoV5ProviderFactories: providertest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccPasswordPolicyConfigNS(ns, policyName, testPolicy),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "namespace", ns),
resource.TestCheckResourceAttr(resourceName, "name", policyName),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
),
},
{
Config: updatedConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "namespace", ns),
resource.TestCheckResourceAttr(resourceName, "name", policyName),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
),
},
testutil.GetImportTestStepNS(t, ns, resourceName, updatedConfig),
testutil.GetImportTestStepNSCleanup(t, updatedConfig),
},
})
}
func TestAccPasswordPolicy_Muxing(t *testing.T) {
policyName := acctest.RandomWithPrefix("test-policy")
policyNameUpdated := acctest.RandomWithPrefix("test-policy-updated")
resourceName := "vault_password_policy.test"
testPolicy := "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"
testPolicyUpdated := "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\nrule \"charset\" {\n charset = \"1234567890\"\nmin-chars = 1\n}\n"
updatedConfig := testAccPasswordPolicyConfig(policyNameUpdated, testPolicyUpdated)
resource.Test(t, resource.TestCase{
PreCheck: func() {
testutil.TestAccPreCheck(t)
testutil.TestEntPreCheck(t)
},
Steps: []resource.TestStep{
{
ExternalProviders: map[string]resource.ExternalProvider{
"vault": {
// 4.8.0 is not multiplexed
VersionConstraint: "4.8.0",
Source: "hashicorp/vault",
},
},
Config: testAccPasswordPolicyConfig(policyName, testPolicy),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", policyName),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
),
},
// upgrade to new Muxed TFVP, ensure plan is seamless
{
ProtoV5ProviderFactories: providertest.ProtoV5ProviderFactories,
Config: testAccPasswordPolicyConfig(policyName, testPolicy),
PlanOnly: true,
},
// update name to ensure resource can get recreated on name updates
{
ProtoV5ProviderFactories: providertest.ProtoV5ProviderFactories,
Config: updatedConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", policyNameUpdated),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
),
},
},
})
}
func testAccPasswordPolicyConfig(policyName, policy string) string {
return fmt.Sprintf(`
resource "vault_password_policy" "test" {
name = "%s"
policy = <<EOT
%s
EOT
}`, policyName, policy)
}
func testAccPasswordPolicyConfigNS(ns, policyName, policy string) string {
return fmt.Sprintf(`
resource "vault_namespace" "ns1" {
path = "%s"
}
resource "vault_password_policy" "test" {
namespace = vault_namespace.ns1.path
name = "%s"
policy = <<EOT
%s
EOT
}`, ns, policyName, policy)
}

29
main.go
View file

@ -4,33 +4,40 @@
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
"github.com/hashicorp/terraform-provider-vault/schema"
"github.com/hashicorp/terraform-plugin-go/tfprotov5/tf5server"
"github.com/hashicorp/terraform-provider-vault/vault"
)
func main() {
p := schema.NewProvider(vault.Provider())
serveOpts := &plugin.ServeOpts{
ProviderFunc: p.SchemaProvider,
serverFactory, _, err := vault.ProtoV5ProviderServerFactory(context.Background())
if err != nil {
log.Fatal(err)
}
var serveOpts []tf5server.ServeOpt
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
if debug {
serveOpts.Debug = debug
serveOpts.ProviderAddr = "hashicorp/vault"
serveOpts = append(serveOpts, tf5server.WithManagedDebug())
}
// fix duplicate timestamp and incorrect level messages
// fix duplicate timestamp and incorrect level messages for legacy sdk v2
// https://developer.hashicorp.com/terraform/plugin/log/writing#legacy-log-troubleshooting
log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))
plugin.Serve(serveOpts)
err = tf5server.Serve(
"registry.terraform.io/hashicorp/vault",
serverFactory,
serveOpts...,
)
if err != nil {
log.Fatal(err)
}
}

View file

@ -4,6 +4,7 @@
package schema
import (
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
@ -28,3 +29,11 @@ func (p *Provider) RegisterResource(name string, resource *schema.Resource) {
func (p *Provider) SchemaProvider() *schema.Provider {
return p.provider
}
func (p *Provider) GRPCProvider() tfprotov5.ProviderServer {
return p.provider.GRPCProvider()
}
func (p *Provider) Meta() interface{} {
return p.provider.Meta()
}

View file

@ -805,6 +805,44 @@ func CheckJSONData(resourceName, attr, expected string) resource.TestCheckFunc {
}
}
// GetImportTestStepNS returns an import TestStep for namespace and resource name.
//
// NOTE: Should be called with GetImportTestStepNSCleanup
//
// Optionally include field names that should be ignored during the import
// verification, typically ignore fields should only be provided for values
// that are not returned from the provisioning API.
func GetImportTestStepNS(t *testing.T, namespace, resourceName, config string, ignoreFields ...string) resource.TestStep {
return resource.TestStep{
// Two steps are needed when testing import because the
// tf-plugin-sdk does not allow specifying environment variables.
// It is possible that this will cause issues if we ever want to
// support parallel tests.
PreConfig: func() {
t.Setenv(consts.EnvVarVaultNamespaceImport, namespace)
},
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: ignoreFields,
ResourceName: resourceName,
}
}
// GetImportTestStepNSCleanup return a cleanup TestStep for namespace and
// resource name to unset env vars.
//
// NOTE: Should be called after GetImportTestStepNS
func GetImportTestStepNSCleanup(t *testing.T, config string) resource.TestStep {
return resource.TestStep{
// needed for the import step above
Config: config,
PreConfig: func() {
os.Unsetenv(consts.EnvVarVaultNamespaceImport)
},
PlanOnly: true,
}
}
// GetImportTestStep for resource name. If a custom ImportStateCheck function is not desired, pass
// a nil value. Optionally include field names that should be ignored during the import
// verification, typically ignore fields should only be provided for values that are not returned

View file

@ -15,6 +15,8 @@ import (
)
func TestAccDataSourceNamespaces(t *testing.T) {
// TODO test is flaky and passes ~80% of the time in CI
t.Skip("skipping, because it's flaky in CI")
testutil.SkipTestAccEnt(t)
ns := acctest.RandomWithPrefix("tf-ns")

View file

@ -1,122 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package vault
import (
"context"
"errors"
"fmt"
"log"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
)
func readPasswordPolicy(client *api.Client, name string) (map[string]interface{}, error) {
r := client.NewRequest("GET", fmt.Sprintf("/v1/sys/policies/password/%s", name))
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := client.RawRequestWithContext(ctx, r)
if resp != nil {
defer resp.Body.Close()
if resp.StatusCode == 404 {
return nil, nil
}
}
if err != nil {
return nil, err
}
secret, err := api.ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, errors.New("data from server response is empty")
}
return secret.Data, nil
}
func passwordPolicyDelete(d *schema.ResourceData, meta interface{}) error {
client, e := provider.GetClient(d, meta)
if e != nil {
return e
}
name := d.Id()
log.Printf("[DEBUG] Deleting %s password policy from Vault", name)
r := client.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policies/password/%s", name))
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := client.RawRequestWithContext(ctx, r)
if err == nil {
defer resp.Body.Close()
}
return err
}
func passwordPolicyRead(attributes []string, d *schema.ResourceData, meta interface{}) error {
client, e := provider.GetClient(d, meta)
if e != nil {
return e
}
name := d.Id()
policy, err := readPasswordPolicy(client, name)
if err != nil {
return fmt.Errorf("error reading from Vault: %s", err)
}
for _, value := range attributes {
d.Set(value, policy[value])
}
d.Set("name", name)
return nil
}
func passwordPolicyWrite(attributes []string, d *schema.ResourceData, meta interface{}) error {
client, e := provider.GetClient(d, meta)
if e != nil {
return e
}
name := d.Get("name").(string)
log.Printf("[DEBUG] Writing %s password policy to Vault", name)
body := map[string]interface{}{}
for _, value := range attributes {
body[value] = d.Get(value)
}
r := client.NewRequest("PUT", fmt.Sprintf("/v1/sys/policies/password/%s", name))
if err := r.SetJSONBody(body); err != nil {
return err
}
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := client.RawRequestWithContext(ctx, r)
if err != nil {
return err
}
defer resp.Body.Close()
if err != nil {
return fmt.Errorf("error writing to Vault: %s", err)
}
d.SetId(name)
return passwordPolicyRead(attributes, d, meta)
}

View file

@ -587,10 +587,6 @@ var (
Resource: UpdateSchemaResource(rabbitMQSecretBackendRoleResource()),
PathInventory: []string{"/rabbitmq/roles/{name}"},
},
"vault_password_policy": {
Resource: UpdateSchemaResource(passwordPolicyResource()),
PathInventory: []string{"/sys/policy/password/{name}"},
},
"vault_pki_secret_backend_cert": {
Resource: UpdateSchemaResource(pkiSecretBackendCertResource()),
PathInventory: []string{"/pki/issue/{role}"},

29
vault/provider_factory.go Normal file
View file

@ -0,0 +1,29 @@
package vault
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-mux/tf5muxserver"
"github.com/hashicorp/terraform-provider-vault/internal/provider/fwprovider"
"github.com/hashicorp/terraform-provider-vault/schema"
)
// ProtoV5ProviderServerFactory returns a muxed terraform-plugin-go protocol v5 provider factory function.
// This factory function is suitable for use with the terraform-plugin-go Serve function.
// The primary (Plugin SDK) provider server is also returned (useful for testing).
func ProtoV5ProviderServerFactory(ctx context.Context) (func() tfprotov5.ProviderServer, *schema.Provider, error) {
primary := schema.NewProvider(Provider())
servers := []func() tfprotov5.ProviderServer{
primary.GRPCProvider,
providerserver.NewProtocol5(fwprovider.New(primary)),
}
muxServer, err := tf5muxserver.NewMuxServer(ctx, servers...)
if err != nil {
return nil, nil, err
}
return muxServer.ProviderServer, primary, nil
}

View file

@ -4,6 +4,7 @@
package vault
import (
"context"
"fmt"
"io/ioutil"
"os"
@ -11,6 +12,7 @@ import (
"sync"
"testing"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@ -107,16 +109,72 @@ const tokenHelperScript = `#!/usr/bin/env bash
echo "helper-token"
`
func TestAccAuthLoginProviderConfigure(t *testing.T) {
rootProvider := Provider()
rootProviderResource := &schema.Resource{
Schema: rootProvider.Schema,
// testAccProtoV5ProviderFactories will return a map of provider servers
// suitable for use as a resource.TestStep.ProtoV5ProviderFactories.
//
// When multiplexing providers, the schema and configuration handling must
// exactly match between all underlying providers of the mux server. Mismatched
// schemas will result in a runtime error.
// see: https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux
//
// Any tests that use this function will serve as a smoketest to verify the
// provider schemas match 1-1 so that we may catch runtime errors.
func testAccProtoV5ProviderFactories(ctx context.Context, t *testing.T, v **schema.Provider) map[string]func() (tfprotov5.ProviderServer, error) {
providerServerFactory, p, err := ProtoV5ProviderServerFactory(ctx)
if err != nil {
t.Fatal(err)
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
Providers: map[string]*schema.Provider{
"vault": rootProvider,
providerServer := providerServerFactory()
*v = p.SchemaProvider()
return map[string]func() (tfprotov5.ProviderServer, error){
providerName: func() (tfprotov5.ProviderServer, error) {
return providerServer, nil
},
}
}
// TestAccMuxServer uses ExternalProviders (vault) to generate a state file
// with a previous version of the provider and then verify that there are no
// planned changes after migrating to the Framework.
//
// As of TFVP v4.8.0, the resources used in this test are not implemented with
// the new Terraform Plugin Framework. However, this will act as a smoketest to
// verify the provider schemas match 1-1.
//
// Additionally, when migrating a resource this test can be used as a pattern
// to follow to verify that switching from SDKv2 to the Framework has not
// affected your provider's behavior.
func TestAccMuxServer(t *testing.T) {
var p *schema.Provider
resource.Test(t, resource.TestCase{
Steps: []resource.TestStep{
{
ExternalProviders: map[string]resource.ExternalProvider{
"vault": {
// 4.8.0 is not multiplexed
VersionConstraint: "4.8.0",
Source: "hashicorp/vault",
},
},
Config: testResourceApproleConfig_basic(),
Check: testResourceApproleLoginCheckAttrs(t),
},
{
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t, &p),
Config: testResourceApproleConfig_basic(),
PlanOnly: true,
},
},
})
}
func TestAccAuthLoginProviderConfigure(t *testing.T) {
var p *schema.Provider
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t, &p),
Steps: []resource.TestStep{
{
Config: testResourceApproleConfig_basic(),
@ -125,6 +183,9 @@ func TestAccAuthLoginProviderConfigure(t *testing.T) {
},
})
rootProviderResource := &schema.Resource{
Schema: p.Schema,
}
rootProviderData := rootProviderResource.TestResourceData()
if _, err := provider.NewProviderMeta(rootProviderData); err != nil {
t.Fatal(err)
@ -132,14 +193,11 @@ func TestAccAuthLoginProviderConfigure(t *testing.T) {
}
func TestTokenReadProviderConfigureWithHeaders(t *testing.T) {
rootProvider := Provider()
var p *schema.Provider
rootProviderResource := &schema.Resource{
Schema: rootProvider.Schema,
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProviderFactories: providerFactories,
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t, &p),
Steps: []resource.TestStep{
{
Config: testHeaderConfig("auth", "123"),
@ -148,6 +206,9 @@ func TestTokenReadProviderConfigureWithHeaders(t *testing.T) {
},
})
rootProviderResource := &schema.Resource{
Schema: p.Schema,
}
rootProviderData := rootProviderResource.TestResourceData()
if _, err := provider.NewProviderMeta(rootProviderData); err != nil {
t.Fatal(err)
@ -366,6 +427,7 @@ func TestAccProviderToken(t *testing.T) {
t.Fatal(err)
}
origTokenBytes, err := ioutil.ReadFile(tokenFilePath)
if err == nil {
// There is an existing token file. Ensure it is restored after this test.
info, err := os.Stat(tokenFilePath)
@ -403,15 +465,12 @@ func TestAccProviderToken(t *testing.T) {
name string
fileToken bool
helperToken bool
envToken bool
schemaToken bool
expectedToken string
}
tests := []testcase{
{
name: "None",
expectedToken: "",
},
{
// The p will read the token file "~/.vault-token".
name: "File",
@ -425,12 +484,21 @@ func TestAccProviderToken(t *testing.T) {
helperToken: true,
expectedToken: "helper-token",
},
{
// A VAULT_TOKEN env var or hardcoded token overrides all else.
name: "Env",
fileToken: true,
helperToken: true,
envToken: true,
expectedToken: os.Getenv("VAULT_TOKEN"),
},
{
// A VAULT_TOKEN env var or hardcoded token overrides all else.
name: "Schema",
fileToken: true,
helperToken: true,
schemaToken: true,
envToken: true,
expectedToken: "schema-token",
},
}
@ -458,6 +526,18 @@ func TestAccProviderToken(t *testing.T) {
}
d := providerResource.TestResourceData()
// Set up the env token.
if tc.envToken {
d.Set("token", os.Getenv("VAULT_TOKEN"))
} else {
// unset vault token env because it takes precedence over helper and file
resetConfigPathEnv, err := tempUnsetenv("VAULT_TOKEN")
defer failIfErr(t, resetConfigPathEnv)
if err != nil {
t.Fatal(err)
}
}
// Set up the schema token.
if tc.schemaToken {
d.Set("token", "schema-token")
@ -528,11 +608,12 @@ func TestAccTokenName(t *testing.T) {
},
}
var p *schema.Provider
for _, test := range tests {
t.Run(test.WantTokenName, func(t *testing.T) {
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t, &p),
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
PreConfig: func() {
@ -558,8 +639,6 @@ func TestAccTokenName(t *testing.T) {
}
func TestAccChildToken(t *testing.T) {
defer os.Unsetenv(consts.EnvVarSkipChildToken)
checkTokenUsed := func(expectChildToken bool) resource.TestCheckFunc {
if expectChildToken {
// If the default child token was created, we expect the token
@ -573,78 +652,34 @@ func TestAccChildToken(t *testing.T) {
}
tests := map[string]struct {
skipChildTokenEnv string
useChildTokenEnv bool
skipChildTokenSchema string
useChildTokenSchema bool
expectChildToken bool
}{
"tc1": {
"skip_child_token unset in config": {
useChildTokenSchema: false,
useChildTokenEnv: false,
expectChildToken: true,
},
"tc2": {
skipChildTokenEnv: "",
useChildTokenEnv: true,
expectChildToken: true,
},
"tc3": {
skipChildTokenEnv: "true",
useChildTokenEnv: true,
expectChildToken: false,
},
"tc4": {
skipChildTokenEnv: "false",
useChildTokenEnv: true,
expectChildToken: true,
},
"tc5": {
"skip_child_token true in config": {
skipChildTokenSchema: "true",
useChildTokenSchema: true,
expectChildToken: false,
},
"tc6": {
"skip_child_token false in config": {
skipChildTokenSchema: "false",
useChildTokenSchema: true,
expectChildToken: true,
},
"tc7": {
skipChildTokenEnv: "true",
useChildTokenEnv: true,
skipChildTokenSchema: "false",
useChildTokenSchema: true,
expectChildToken: true,
},
"tc8": {
skipChildTokenEnv: "false",
useChildTokenEnv: true,
skipChildTokenSchema: "true",
useChildTokenSchema: true,
expectChildToken: false,
},
}
var p *schema.Provider
for name, test := range tests {
t.Run(name, func(t *testing.T) {
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t, &p),
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
PreConfig: func() {
if test.useChildTokenEnv {
err := os.Setenv(consts.EnvVarSkipChildToken, test.skipChildTokenEnv)
if err != nil {
t.Fatal(err)
}
} else {
err := os.Unsetenv(consts.EnvVarSkipChildToken)
if err != nil {
t.Fatal(err)
}
}
},
Config: testProviderConfig(test.useChildTokenSchema,
consts.FieldSkipChildToken+` = `+test.skipChildTokenSchema,
),
@ -782,6 +817,15 @@ func TestAccProviderVaultAddrEnv(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// unset vault token env because add_address_to_env will only
// be set if the token is unset in the config and the
// VAULT_ADDR env variable
reset, err := tempUnsetenv(api.EnvVaultToken)
defer failIfErr(t, reset)
if err != nil {
t.Fatal(err)
}
}
cleanup := setupTestTokenHelper(t, echoBackTokenHelperScript)

View file

@ -7,6 +7,7 @@ import (
"context"
"database/sql"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"net/url"
"os"
"testing"
@ -92,6 +93,7 @@ func TestAccDatabaseSecretBackendStaticRole_credentialType(t *testing.T) {
}
func TestAccDatabaseSecretBackendStaticRole_credentialConfig(t *testing.T) {
var p *schema.Provider
connURL := testutil.SkipTestEnvUnset(t, "MYSQL_URL")[0]
backend := acctest.RandomWithPrefix("tf-test-db")
@ -105,9 +107,9 @@ func TestAccDatabaseSecretBackendStaticRole_credentialConfig(t *testing.T) {
}
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() { testutil.TestAccPreCheck(t) },
CheckDestroy: testAccDatabaseSecretBackendStaticRoleCheckDestroy,
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t, &p),
PreCheck: func() { testutil.TestAccPreCheck(t) },
CheckDestroy: testAccDatabaseSecretBackendStaticRoleCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccDatabaseSecretBackendStaticRoleConfig_credentialConfig(name, username, dbName, backend, connURL),

View file

@ -1,52 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package vault
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
)
var passwordPolicyAttributes = []string{"policy"}
func passwordPolicyResource() *schema.Resource {
return &schema.Resource{
Create: resourcePasswordPolicyWrite,
Update: resourcePasswordPolicyWrite,
Delete: resourcePasswordPolicyDelete,
Read: provider.ReadWrapper(resourcePasswordPolicyRead),
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the password policy.",
},
"policy": {
Type: schema.TypeString,
Required: true,
Description: "The password policy document",
},
},
}
}
func resourcePasswordPolicyWrite(d *schema.ResourceData, meta interface{}) error {
return passwordPolicyWrite(passwordPolicyAttributes, d, meta)
}
func resourcePasswordPolicyDelete(d *schema.ResourceData, meta interface{}) error {
return passwordPolicyDelete(d, meta)
}
func resourcePasswordPolicyRead(d *schema.ResourceData, meta interface{}) error {
return passwordPolicyRead(passwordPolicyAttributes, d, meta)
}

View file

@ -1,98 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package vault
import (
"fmt"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/terraform-provider-vault/testutil"
)
func TestAccPasswordPolicy(t *testing.T) {
policyName := acctest.RandomWithPrefix("test-policy")
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: testAccPasswordPolicyCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccPasswordPolicy(policyName, "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_password_policy.test", "name", policyName),
resource.TestCheckResourceAttrSet("vault_password_policy.test", "policy"),
),
},
{
Config: testAccPasswordPolicy(policyName, "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\nrule \"charset\" {\n charset = \"1234567890\"\nmin-chars = 1\n}\n"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_password_policy.test", "name", policyName),
resource.TestCheckResourceAttrSet("vault_password_policy.test", "policy"),
),
},
},
})
}
func TestAccPasswordPolicy_import(t *testing.T) {
policyName := acctest.RandomWithPrefix("test-policy")
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: testAccPasswordPolicyCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccPasswordPolicy(policyName, "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_password_policy.test", "name", policyName),
resource.TestCheckResourceAttrSet("vault_password_policy.test", "policy"),
),
},
{
ResourceName: "vault_password_policy.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccPasswordPolicyCheckDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "vault_password_policy" {
continue
}
client, e := provider.GetClient(rs.Primary, testProvider.Meta())
if e != nil {
return e
}
name := rs.Primary.Attributes["name"]
data, err := client.Logical().Read(fmt.Sprintf("sys/policies/password/%s", name))
if err != nil {
return err
}
if data != nil {
return fmt.Errorf("Password policy %s still exists", name)
}
}
return nil
}
func testAccPasswordPolicy(policyName string, policy string) string {
return fmt.Sprintf(`
resource "vault_password_policy" "test" {
name = "%s"
policy = <<EOT
%s
EOT
}`, policyName, policy)
}

View file

@ -9,7 +9,7 @@ description: |-
# Vault Provider
The Vault provider allows Terraform to read from, write to, and configure
[HashiCorp Vault](https://vaultproject.io/).
[HashiCorp Vault](https://developer.hashicorp.com/vault).
~> **Important** Interacting with Vault from Terraform causes any secrets
that you read and write to be persisted in both Terraform's state file
@ -158,12 +158,6 @@ variables in order to keep credential information out of the configuration.
a limited child token using auth/token/create in order to enforce a short
TTL and limit exposure. *[See usage details below.](#generic)*
* `client_auth` - (Optional) A configuration block, described below, that
provides credentials used by Terraform to authenticate with the Vault
server. At present there is little reason to set this, because Terraform
does not support the TLS certificate authentication mechanism.
*Deprecated, use `auth_login_cert` instead.
* `skip_tls_verify` - (Optional) Set this to `true` to disable verification
of the Vault server's TLS certificate. This is strongly discouraged except
in prototype or development environments, since it exposes the possibility
@ -212,10 +206,6 @@ variables in order to keep credential information out of the configuration.
* `use_root_namespace` - (Optional) Authenticate to the root Vault namespace. Conflicts with `namespace`.
* `set_namespace_from_token` -(Optional) Defaults to `true`. In the case where the Vault token is
for a specific namespace and the provider namespace is not configured, use the token namespace
as the root namespace for all resources.
* `skip_get_vault_version` - (Optional) Skip the dynamic fetching of the Vault server version.
Set to `true` when the */sys/seal-status* API endpoint is not available. See [vault_version_override](#vault_version_override)
for related info
@ -232,14 +222,6 @@ only ever use this option in the case where the server version cannot be dynamic
to be sent along with all requests to the Vault server. This block can be specified
multiple times.
The `client_auth` configuration block accepts the following arguments:
* `cert_file` - (Required) Path to a file on local disk that contains the
PEM-encoded certificate to present to the server.
* `key_file` - (Required) Path to a file on local disk that contains the
PEM-encoded private key for which the authentication certificate was issued.
The `headers` configuration block accepts the following arguments:
* `name` - (Required) The name of the header.
@ -741,9 +723,9 @@ provider "vault" {
The Vault provider supports managing [Namespaces][namespaces] (a feature of
Vault Enterprise), as well as creating resources in those namespaces by
utilizing [Provider Aliasing][aliasing]. The `namespace` option in the [provider
block][provider-block] enables the management of resources in the specified
namespace.
In addition, all resources and data sources support specifying their own `namespace`.
block](#provider-arguments) enables the management of resources in the specified
namespace.
In addition, all resources and data sources support specifying their own `namespace`.
All resource's `namespace` will be made relative to the `provider`'s configured namespace.
### Importing namespaced resources
@ -966,11 +948,19 @@ default
vault_team_policy
```
## Tutorials
### Token namespaces
In the case where the Vault token is for a specific namespace and the provider
namespace is not configured, the provider will use the token namespace as the
root namespace for all resources. This behavior can be disabled by setting the
`VAULT_SET_NAMESPACE_FROM_TOKEN ` environment variable to "false". The only
accepted values are "true" and "false".
## Tutorials
Refer to the [Codify Management of Vault Enterprise Using Terraform](https://learn.hashicorp.com/tutorials/vault/codify-mgmt-enterprise) tutorial for additional examples using Vault namespaces.
[namespaces]: https://www.vaultproject.io/docs/enterprise/namespaces#vault-enterprise-namespaces
[aliasing]: https://www.terraform.io/docs/configuration/providers.html#alias-multiple-provider-configurations
[provider-block]: /docs#provider-arguments
[namespaces]: https://developer.hashicorp.com/vault/docs/enterprise/namespaces#vault-enterprise-namespaces
[aliasing]: https://developer.hashicorp.com/terraform/language/providers/configuration#alias-multiple-provider-configurations