From f511382983bf0db6fc6a55a373f3404ca368ff5c Mon Sep 17 00:00:00 2001
From: Andre Arcaina
Date: Mon, 26 Oct 2026 13:41:36 -0400
Subject: [PATCH] Run go fix after v2.10.0 release
Signed-off-by: Andre Arcaina
---
.github/labels.yaml | 3 +
.github/workflows/backport.yaml | 2 +-
.github/workflows/cifuzz.yaml | 2 +-
.github/workflows/e2e.yaml | 26 +-
.github/workflows/release.yaml | 2 +-
.github/workflows/scan.yaml | 2 +-
.github/workflows/sync-labels.yaml | 2 +-
.github/workflows/test.yaml | 2 +-
.github/workflows/upgrade-fluxcd-pkg.yaml | 2 +-
.goreleaser.yaml | 7 +-
AGENTS.md | 1 -
CHANGELOG.md | 121 +++
Makefile | 8 +-
README.md | 1 -
api/go.mod | 2 +-
api/go.sum | 12 +-
api/v1/bucket_types.go | 8 +-
api/v1/ocirepository_types.go | 14 +-
.../source.toolkit.fluxcd.io_buckets.yaml | 4 +-
...rce.toolkit.fluxcd.io_ocirepositories.yaml | 6 +-
config/manager/deployment.yaml | 4 +-
config/manager/kustomization.yaml | 2 +-
docs/README.md | 50 +-
docs/api/v1/source.md | 20 +-
docs/spec/v1/buckets.md | 83 +-
docs/spec/v1/gitrepositories.md | 10 +-
docs/spec/v1/ocirepositories.md | 77 +-
go.mod | 318 +++---
go.sum | 779 +++++++-------
hack/ci/oci-zot-workload-identity-e2e.sh | 993 ++++++++++++++++++
internal/bucket/azure/blob.go | 12 +-
internal/bucket/azure/blob_test.go | 111 ++
internal/bucket/gcp/gcp.go | 6 +
internal/bucket/gcp/gcp_test.go | 36 +-
internal/bucket/minio/minio_test.go | 37 +-
internal/cache/cache.go | 10 +-
internal/controller/artifact_matchers_test.go | 6 +-
internal/controller/bucket_controller.go | 99 +-
.../bucket_controller_fetch_test.go | 2 +-
internal/controller/bucket_controller_test.go | 151 +--
.../controller/gitrepository_controller.go | 119 ++-
.../gitrepository_controller_test.go | 346 ++----
.../controller/helmchart_controller_test.go | 278 ++---
.../controller/helmrepository_controller.go | 26 +-
.../helmrepository_controller_test.go | 294 ++++--
.../controller/ocirepository_controller.go | 122 ++-
.../ocirepository_controller_test.go | 290 ++---
.../controller/ocirepository_verify_test.go | 13 +-
internal/controller/suite_test.go | 12 +-
internal/error/error.go | 28 +-
internal/features/features.go | 9 +-
internal/helm/chart/builder_local.go | 8 +-
internal/helm/chart/builder_local_test.go | 8 +-
internal/helm/chart/builder_remote.go | 6 +-
internal/helm/chart/builder_remote_test.go | 16 +-
.../helm/chart/secureloader/ignore/rules.go | 4 +-
internal/helm/getter/client_opts_test.go | 40 +-
internal/helm/registry/auth_test.go | 8 +-
internal/helm/repository/chart_repository.go | 17 +-
.../helm/repository/chart_repository_test.go | 3 -
.../repository/oci_chart_repository_test.go | 1 -
internal/index/digest.go | 9 +-
internal/mock/s3/server.go | 8 +-
internal/oci/notation/notation_test.go | 8 +-
internal/reconcile/event.go | 2 +-
internal/reconcile/reconcile_test.go | 4 +-
internal/reconcile/summarize/matchers_test.go | 12 +-
internal/reconcile/summarize/processor.go | 2 +-
.../reconcile/summarize/processor_test.go | 5 +-
internal/reconcile/summarize/summary_test.go | 10 +-
internal/util/temp_root.go | 113 ++
internal/util/temp_root_test.go | 126 +++
internal/util/temp_test.go | 11 +-
main.go | 214 +++-
tests/registry/registry.go | 2 +-
75 files changed, 3378 insertions(+), 1829 deletions(-)
create mode 100755 hack/ci/oci-zot-workload-identity-e2e.sh
create mode 100644 internal/util/temp_root.go
create mode 100644 internal/util/temp_root_test.go
diff --git a/.github/labels.yaml b/.github/labels.yaml
index 36332680e..c2e5febb4 100644
--- a/.github/labels.yaml
+++ b/.github/labels.yaml
@@ -46,3 +46,6 @@
- name: backport:release/v1.9.x
description: To be backported to release/v1.9.x
color: '#ffd700'
+- name: backport:release/v1.10.x
+ description: To be backported to release/v1.10.x
+ color: '#ffd700'
diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml
index f35ff5e9a..92aac065e 100644
--- a/.github/workflows/backport.yaml
+++ b/.github/workflows/backport.yaml
@@ -7,6 +7,6 @@ jobs:
permissions:
contents: write # for reading and creating branches.
pull-requests: write # for creating pull requests against release branches.
- uses: fluxcd/gha-workflows/.github/workflows/backport.yaml@v0.16.0
+ uses: fluxcd/gha-workflows/.github/workflows/backport.yaml@v0.17.0
secrets:
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/cifuzz.yaml b/.github/workflows/cifuzz.yaml
index 8e80fab19..83281156a 100644
--- a/.github/workflows/cifuzz.yaml
+++ b/.github/workflows/cifuzz.yaml
@@ -11,7 +11,7 @@ jobs:
contents: read # for reading the repository code.
steps:
- name: Test suite setup
- uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.16.0
+ uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.17.0
with:
go-version: 1.27.x
- name: Smoke test Fuzzers
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index d1563601c..f24d4f5e8 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -13,7 +13,7 @@ jobs:
contents: read # for reading the repository code.
steps:
- name: Test suite setup
- uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.16.0
+ uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.17.0
with:
go-version: 1.27.x
- name: Verify
@@ -33,3 +33,27 @@ jobs:
continue-on-error: true
run: |
kubectl -n source-system logs -l app=source-controller
+ zot-oci-workload-identity:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read # for reading the repository code.
+ steps:
+ - name: Test suite setup
+ uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.17.0
+ with:
+ go-version: 1.27.x
+ - name: Setup Flux CLI
+ uses: fluxcd/flux2/action@main
+ - name: Setup Helm
+ uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
+ with:
+ version: v4.3.1
+ - name: Build container image
+ run: |
+ make docker-build IMG=test/source-controller TAG=latest \
+ BUILD_PLATFORMS=linux/amd64 \
+ BUILD_ARGS="--load"
+ - name: Run Zot OCI workload identity e2e
+ run: hack/ci/oci-zot-workload-identity-e2e.sh
+ env:
+ IMG: test/source-controller:latest
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 039d46774..6a359d74f 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -15,7 +15,7 @@ jobs:
contents: write # for creating the GitHub release.
id-token: write # for creating OIDC tokens for signing.
packages: write # for pushing and signing container images.
- uses: fluxcd/gha-workflows/.github/workflows/controller-release.yaml@v0.16.0
+ uses: fluxcd/gha-workflows/.github/workflows/controller-release.yaml@v0.17.0
with:
controller: ${{ github.event.repository.name }}
release-candidate-prefix: ${{ github.event.inputs.tag }}
diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml
index da139cf90..e4c5bddaa 100644
--- a/.github/workflows/scan.yaml
+++ b/.github/workflows/scan.yaml
@@ -11,7 +11,7 @@ jobs:
permissions:
contents: read # for reading the repository code.
security-events: write # for uploading the CodeQL analysis results.
- uses: fluxcd/gha-workflows/.github/workflows/code-scan.yaml@v0.16.0
+ uses: fluxcd/gha-workflows/.github/workflows/code-scan.yaml@v0.17.0
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
fossa-token: ${{ secrets.FOSSA_TOKEN }}
diff --git a/.github/workflows/sync-labels.yaml b/.github/workflows/sync-labels.yaml
index 92bfacf01..445fdbfd9 100644
--- a/.github/workflows/sync-labels.yaml
+++ b/.github/workflows/sync-labels.yaml
@@ -11,6 +11,6 @@ jobs:
permissions:
contents: read # for reading the labels file.
issues: write # for creating and updating labels.
- uses: fluxcd/gha-workflows/.github/workflows/labels-sync.yaml@v0.16.0
+ uses: fluxcd/gha-workflows/.github/workflows/labels-sync.yaml@v0.17.0
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 52379ed2b..f6da63fe1 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Test suite setup
- uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.16.0
+ uses: fluxcd/gha-workflows/.github/actions/setup-kubernetes@v0.17.0
with:
go-version: 1.27.x
- name: Run tests
diff --git a/.github/workflows/upgrade-fluxcd-pkg.yaml b/.github/workflows/upgrade-fluxcd-pkg.yaml
index 08508fb0e..58b0d2366 100644
--- a/.github/workflows/upgrade-fluxcd-pkg.yaml
+++ b/.github/workflows/upgrade-fluxcd-pkg.yaml
@@ -5,6 +5,6 @@ on:
jobs:
upgrade-fluxcd-pkg:
- uses: fluxcd/gha-workflows/.github/workflows/upgrade-fluxcd-pkg.yaml@v0.16.0
+ uses: fluxcd/gha-workflows/.github/workflows/upgrade-fluxcd-pkg.yaml@v0.17.0
secrets:
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index 7b61ce0c1..5df799481 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -44,14 +44,11 @@ sboms:
# https://goreleaser.com/customization/sign
signs:
- cmd: cosign
- env:
- - COSIGN_EXPERIMENTAL=1
- certificate: "${artifact}.pem"
+ signature: "${artifact}.sigstore.json"
args:
- sign-blob
- "--yes"
- - "--output-certificate=${certificate}"
- - "--output-signature=${signature}"
+ - "--bundle=${signature}"
- "${artifact}"
artifacts: checksum
output: true
diff --git a/AGENTS.md b/AGENTS.md
index 211ac7010..8abbd4c22 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -135,7 +135,6 @@ Bump `fluxcd/pkg/*` modules as a set — version skew breaks `go.sum`. Run `make
- `make verify` is the CI gate — a dirty diff means you forgot to run codegen or tidy.
- The `replace` directives in `go.mod` (semver and go-digest) exist for correctness. Leave them alone.
- `Storage` serializes writes per object via `fluxcd/pkg/lockedfile` and expects `--storage-path` to be a real local directory. Never write artifacts outside `Storage.BasePath` — the file server exposes that path verbatim at `--storage-addr`.
-- Workload Identity is feature-gated by `auth.FeatureGateObjectLevelWorkloadIdentity` (from `fluxcd/pkg/auth`). Token caching is opt-in via `--token-cache-max-size`.
- `CacheSecretsAndConfigMaps` (in `internal/features`) is off by default; `Secret`/`ConfigMap` lookups bypass the cache and hit the API server directly. Mind that before adding new secret reads to a hot path.
- The controller watches a label-selected subset of its CRs — see `Cache.ByObject` in `mustSetupManager`. Adding a new kind requires updating both `main.go` and the scheme.
- `pkg/azure`, `pkg/gcp`, `pkg/minio` are importable by external consumers. Treat their exported surface as semi-public API.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3843579c1..f54cb26c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,127 @@
All notable changes to this project are documented in this file.
+## 1.10.1
+
+**Release date:** 2026-10-26
+
+This patch release hardens the controller's artifact server by setting a read
+header timeout, which also bounds the TLS handshake, and an idle timeout. As a
+result, connections that never send a request, or keep-alive connections from
+clients without an idle timeout, no longer stay open until the server shuts
+down. No timeout is set for reading or writing the whole request, so large
+artifacts can still be downloaded by slow clients.
+
+Improvements:
+- Update fluxcd/pkg dependencies
+ [#2217](https://github.com/fluxcd/source-controller/pull/2217)
+
+## 1.10.0
+
+**Release date:** 2026-10-24
+
+This minor release graduates object-level workload identity, now renamed to
+object identity, introduces SPIFFE mTLS between the controllers, and adds
+GitHub App Client ID support for Git repositories.
+
+### Object Identity
+
+Object-level workload identity is now generally available and renamed to object
+identity. Workload identity refers exclusively to identities assigned to Flux
+controllers, while object identity refers to identities assigned to Flux
+objects. The `ObjectLevelWorkloadIdentity` feature gate is retired and the
+feature is always enabled.
+
+⚠️ **Breaking change:** the default Flux RBAC no longer grants the `create`
+verb on the `serviceaccounts/token` resource. If your installation relies on
+the default RBAC, bind a ClusterRole with this permission to the controller
+ServiceAccount before upgrading. See
+[fluxcd/flux2#6139](https://github.com/fluxcd/flux2/pull/6139) for the required
+ClusterRole and ClusterRoleBinding, and the
+[object identity documentation](https://fluxcd.io/flux/integrations/object-identity/)
+for the API reference.
+
+Two credential providers can now supply the credential: `kubernetes`, which
+uses the Kubernetes TokenRequest API and was already available, and `spiffe`,
+which fetches a JWT-SVID from the SPIFFE Broker API. The provider is configured
+on the ServiceAccount with `credential.auth.fluxcd.io/provider`, independently
+of the service provider in `.spec.provider`.
+
+### Inter-Controller mTLS
+
+This release introduces SPIFFE mTLS for inter-controller communication. Flux
+controllers authenticate each other with X.509-SVIDs, and each traffic type is
+enabled independently by configuring the SPIFFE Workload API socket and the
+SPIFFE IDs that the controller authorizes. See the
+[inter-controller mTLS documentation](https://fluxcd.io/flux/installation/configuration/intercontroller-mtls/)
+for the controller flags and an example configuration.
+
+### GitRepository
+
+GitHub App authentication accepts a Client ID as an alternative to the numeric
+App ID (`githubAppClientID`). Signature verification is re-run when the trusted
+keys rotate, so a revoked or replaced key no longer leaves a stale
+`SourceVerified=True` condition.
+
+### OCIRepository
+
+Generic OCI repositories now support object identity. The credential is sent as
+a bearer token, or as the password in HTTP basic authentication when
+`credential.auth.fluxcd.io/username` is set. Audiences default to the registry
+host and can be overridden with `credential.auth.fluxcd.io/audiences`.
+
+Signature verification is re-run when the verification keys rotate, and the
+origin revision from OCI image metadata is forwarded in events.
+
+### ExternalArtifact
+
+A new `.status.exportedInputs` field exposes structured data extracted from the
+source resource, for consumers such as ResourceSet to implement templating.
+
+### General updates
+
+The controller is built with Kubernetes 1.37 and Go 1.27.
+
+Fixes:
+- Close GCP object streams on error paths
+ [#2053](https://github.com/fluxcd/source-controller/pull/2053)
+- Close Azure blob streams on error paths
+ [#2200](https://github.com/fluxcd/source-controller/pull/2200)
+- Remove leaked Helm index cache on reconcile errors
+ [#2201](https://github.com/fluxcd/source-controller/pull/2201)
+ [#2202](https://github.com/fluxcd/source-controller/pull/2202)
+- Purge stale temp dirs at startup
+ [#2176](https://github.com/fluxcd/source-controller/pull/2176)
+- Include the repository URL in Helm index parse errors
+ [#2063](https://github.com/fluxcd/source-controller/pull/2063)
+- Support the AWS `ap-southeast-6` region for Bucket sources
+ [#2183](https://github.com/fluxcd/source-controller/pull/2183)
+
+Improvements:
+- Support Kubernetes ServiceAccount tokens for `generic` OCI repositories
+ [#2192](https://github.com/fluxcd/source-controller/pull/2192)
+- Add the `spiffe` credential provider and SPIFFE Broker API
+ [#2197](https://github.com/fluxcd/source-controller/pull/2197)
+- Retire the `ObjectLevelWorkloadIdentity` feature gate
+ [#2197](https://github.com/fluxcd/source-controller/pull/2197)
+- Add SPIFFE mTLS between the controllers
+ [#2194](https://github.com/fluxcd/source-controller/pull/2194)
+- Add GitHub App Client ID support
+ [#2168](https://github.com/fluxcd/source-controller/pull/2168)
+- Reverify sources when verification keys rotate
+ [#2166](https://github.com/fluxcd/source-controller/pull/2166)
+ [#2179](https://github.com/fluxcd/source-controller/pull/2179)
+- Expose the OCI origin revision in events
+ [#2127](https://github.com/fluxcd/source-controller/pull/2127)
+- Add ExternalArtifact exported inputs
+ [#2182](https://github.com/fluxcd/source-controller/pull/2182)
+- Update to Kubernetes 1.37 and Go 1.27
+ [#2162](https://github.com/fluxcd/source-controller/pull/2162)
+ [#2186](https://github.com/fluxcd/source-controller/pull/2186)
+- Various dependency updates
+ [#2100](https://github.com/fluxcd/source-controller/pull/2100)
+ [#2203](https://github.com/fluxcd/source-controller/pull/2203)
+
## 1.9.6
**Release date:** 2026-10-01
diff --git a/Makefile b/Makefile
index eff4be3f3..5feba911e 100644
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,7 @@ manager: generate fmt vet
go build $(GO_STATIC_FLAGS) -o $(BUILD_DIR)/bin/manager main.go
KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)"
-test: install-envtest test-api ## Run all tests
+test: fix install-envtest test-api ## Run all tests
HTTPS_PROXY="" HTTP_PROXY="" \
KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) \
GIT_CONFIG_GLOBAL=/dev/null \
@@ -115,6 +115,10 @@ fmt: ## Run go fmt against code
go fmt ./...
cd api; go fmt ./...
+fix: ## Run go fix against code
+ go fix ./...
+ cd api ; go fix ./...
+
vet: ## Run go vet against code
go vet ./...
cd api; go vet ./...
@@ -204,7 +208,7 @@ fuzz-smoketest: fuzz-build
bash -c "/runner.sh"
# Run fuzz tests for the duration set in FUZZ_TIME.
-fuzz-native:
+fuzz-native:
KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) \
FUZZ_TIME=$(FUZZ_TIME) \
./tests/fuzz/native_go_run.sh
diff --git a/README.md b/README.md
index 5d6bccb90..7f84471e7 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,6 @@
[](https://bestpractices.coreinfrastructure.org/projects/4786)
[](https://github.com/fluxcd/source-controller/actions)
-[](https://goreportcard.com/report/github.com/fluxcd/source-controller)
[](https://github.com/fluxcd/source-controller/blob/main/LICENSE)
[](https://github.com/fluxcd/source-controller/releases)
diff --git a/api/go.mod b/api/go.mod
index 9dd52303e..5b5f12c8e 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -4,7 +4,7 @@ go 1.27.0
require (
github.com/fluxcd/pkg/apis/acl v0.12.0
- github.com/fluxcd/pkg/apis/meta v1.35.0
+ github.com/fluxcd/pkg/apis/meta v1.38.0
k8s.io/apiextensions-apiserver v0.37.1
k8s.io/apimachinery v0.37.1
)
diff --git a/api/go.sum b/api/go.sum
index b19ce7f9e..27bbc7f83 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -4,8 +4,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fluxcd/pkg/apis/acl v0.12.0 h1:UWpZDqKxpKDW38wdXIMHV8Uv3POPu2vUrra0JH1frH0=
github.com/fluxcd/pkg/apis/acl v0.12.0/go.mod h1:PJrGIu5Bw/6/siO95uhS+pi5oKSU+gVJqHqsPHb8Kok=
-github.com/fluxcd/pkg/apis/meta v1.35.0 h1:/k5d7uEFrxkz/hf6JTrdsKBr3UQWVHW2J4G6VSSae/k=
-github.com/fluxcd/pkg/apis/meta v1.35.0/go.mod h1:1MLvK2Xu3UdTKBzg+Q1Oj7H9PHeiKsUB1UW3uwxAwiM=
+github.com/fluxcd/pkg/apis/meta v1.38.0 h1:7t6/DuGFAPx2LE4MsRh1jskjnVE6qELKfr/LrfG7KE8=
+github.com/fluxcd/pkg/apis/meta v1.38.0/go.mod h1:lmdugeiZyt6w+DRm8ypkB+nwrzm+saMbqSfZKGBbTOE=
github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
@@ -21,8 +21,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU=
-github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg=
+github.com/onsi/gomega v1.44.0 h1:eAiGl3Pw5jz5GQdDff0BcxYpAX1JxW8xD7mFUuwNfZQ=
+github.com/onsi/gomega v1.44.0/go.mod h1:e/C2HwaZ1DhvjzXXuFhcR7hY7Sh9pl7MmoWKEjzwcdA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -36,8 +36,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
-go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
-go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
+go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw=
golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI=
golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc=
diff --git a/api/v1/bucket_types.go b/api/v1/bucket_types.go
index 398a453f9..cfe8e849f 100644
--- a/api/v1/bucket_types.go
+++ b/api/v1/bucket_types.go
@@ -34,10 +34,10 @@ const (
BucketProviderGeneric string = "generic"
// BucketProviderAmazon for an AWS S3 object storage Bucket.
// Provides support for retrieving credentials from the AWS EC2 service
- // and workload identity authentication.
+ // and for object identity.
BucketProviderAmazon string = "aws"
// BucketProviderGoogle for a Google Cloud Storage Bucket.
- // Provides support for authentication using a workload identity.
+ // Provides support for authentication using object identity.
BucketProviderGoogle string = "gcp"
// BucketProviderAzure for an Azure Blob Storage Bucket.
// Provides support for authentication using a Service Principal,
@@ -98,8 +98,8 @@ type BucketSpec struct {
// ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
// the bucket. This field is only supported for the 'gcp' and 'aws' providers.
- // For more information about workload identity:
- // https://fluxcd.io/flux/components/source/buckets/#workload-identity
+ // For more information about object identity:
+ // https://fluxcd.io/flux/integrations/object-identity/
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
diff --git a/api/v1/ocirepository_types.go b/api/v1/ocirepository_types.go
index 05d099fb9..10ec5e44e 100644
--- a/api/v1/ocirepository_types.go
+++ b/api/v1/ocirepository_types.go
@@ -90,7 +90,11 @@ type OCIRepositorySpec struct {
Verify *OCIRepositoryVerification `json:"verify,omitempty"`
// ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
- // the image pull if the service account has attached pull secrets. For more information:
+ // the image pull, either with the pull secrets attached to the service account or with
+ // an object identity.
+ // For more information about object identity:
+ // https://fluxcd.io/flux/integrations/object-identity/
+ // For more information about image pull secrets:
// https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
@@ -253,6 +257,14 @@ func (in *OCIRepository) GetArtifact() *meta.Artifact {
return in.Status.Artifact
}
+// GetProvider returns the OCI authentication provider, defaulting to generic.
+func (in *OCIRepository) GetProvider() string {
+ if in.Spec.Provider == "" {
+ return GenericOCIProvider
+ }
+ return in.Spec.Provider
+}
+
// GetLayerMediaType returns the media type layer selector if found in spec.
func (in *OCIRepository) GetLayerMediaType() string {
if in.Spec.LayerSelector == nil {
diff --git a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml
index 8b85220f9..032a877ba 100644
--- a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml
+++ b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml
@@ -151,8 +151,8 @@ spec:
description: |-
ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
the bucket. This field is only supported for the 'gcp' and 'aws' providers.
- For more information about workload identity:
- https://fluxcd.io/flux/components/source/buckets/#workload-identity
+ For more information about object identity:
+ https://fluxcd.io/flux/integrations/object-identity/
type: string
sts:
description: |-
diff --git a/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml
index b152ec384..5254d3732 100644
--- a/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml
+++ b/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml
@@ -178,7 +178,11 @@ spec:
serviceAccountName:
description: |-
ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
- the image pull if the service account has attached pull secrets. For more information:
+ the image pull, either with the pull secrets attached to the service account or with
+ an object identity.
+ For more information about object identity:
+ https://fluxcd.io/flux/integrations/object-identity/
+ For more information about image pull secrets:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account
type: string
suspend:
diff --git a/config/manager/deployment.yaml b/config/manager/deployment.yaml
index e354b00e3..24495671c 100644
--- a/config/manager/deployment.yaml
+++ b/config/manager/deployment.yaml
@@ -66,8 +66,8 @@ spec:
path: /healthz
readinessProbe:
httpGet:
- port: http
- path: /
+ path: /readyz
+ port: healthz
resources:
limits:
cpu: 1000m
diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml
index c204df0eb..661bf294a 100644
--- a/config/manager/kustomization.yaml
+++ b/config/manager/kustomization.yaml
@@ -6,4 +6,4 @@ resources:
images:
- name: fluxcd/source-controller
newName: fluxcd/source-controller
- newTag: v1.9.0
+ newTag: v1.10.0
diff --git a/docs/README.md b/docs/README.md
index eb02d5ee5..a7eb8d330 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -6,6 +6,8 @@
|---------------------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `--artifact-retention-records` | int | The maximum number of artifacts to be kept in storage after a garbage collection. (default 2) |
| `--artifact-retention-ttl` | duration | The duration of time that artifacts from previous reconciliations will be kept in storage before being garbage collected. (default 1m0s) |
+| `--authorized-artifact-client-spiffe-id` | strings | SPIFFE ID authorized to fetch artifacts from the artifact server. Can be repeated. When set, the artifact server uses SPIFFE mTLS. |
+| `--authorized-event-server-spiffe-id` | strings | SPIFFE ID of an event server authorized to receive events from source-controller. Can be repeated. When set, the event recorder uses SPIFFE mTLS. |
| `--concurrent` | int | The number of concurrent reconciles per controller. (default 2) |
| `--default-service-account` | string | Default service account to use for workload identity when not specified in resources. |
| `--enable-leader-election` | boolean | Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. |
@@ -34,15 +36,61 @@
| `--storage-adv-addr` | string | The advertised address of the static file server. |
| `--storage-path` | string | The local storage path. |
| `--token-cache-max-size` | int | The maximum amount of entries in the LRU cache used for tokens. (default 100, enabled) |
+| `--spiffe-broker-endpoint` | string | The gRPC URL of the SPIFFE Broker endpoint. |
+| `--spiffe-broker-id` | strings | SPIFFE ID of the SPIFFE Broker endpoint. Can be repeated. |
| `--token-cache-max-duration` | duration | The maximum duration for which a token would be considered unexpired. This is capped at 1h. (default 1h) |
| `--watch-all-namespaces` | boolean | Watch for custom resources in all namespaces, if set to false it will only watch the runtime namespace. (default true) |
| `--watch-label-selector` | string | Watch for resources with matching labels e.g. 'sharding.fluxcd.io/key=shard1'. |
| `--feature-gates` | mapStringBool | A comma separated list of key=value pairs defining the state of experimental features. |
+### SPIFFE mTLS
+
+When at least one of the repeatable flags `--authorized-artifact-client-spiffe-id`
+or `--authorized-event-server-spiffe-id` is set, source-controller acquires an
+X.509-SVID from the SPIFFE Workload API. The `SPIFFE_ENDPOINT_SOCKET` environment
+variable must point to the Workload API socket.
+
+- `--authorized-artifact-client-spiffe-id` authorizes the given SPIFFE IDs to
+ fetch artifacts from the artifact server. When set, the artifact server uses
+ mTLS.
+- `--authorized-event-server-spiffe-id` authorizes the given SPIFFE IDs of
+ event servers to which source-controller sends events. When set, the event
+ recorder uses mTLS.
+
+Each traffic type is protected independently. SPIFFE mTLS is transparent to the
+Flux API: the scheme of `.status.artifact.url` does not change.
+
+Each flag value is interpreted as follows:
+
+- `spiffe:///` authorizes exactly that SPIFFE ID.
+- `spiffe:////` (with a trailing slash) authorizes any
+ SPIFFE ID with that path prefix.
+- `spiffe://` (without a path) authorizes any SPIFFE ID in that
+ trust domain.
+
+Whenever `` equals the special value `self`, source-controller
+understands it as the trust domain of the controller's own X509-SVID.
+
+Invalid values cause source-controller to fail at startup.
+
+### SPIFFE Broker API
+
+When `--spiffe-broker-endpoint` and at least one `--spiffe-broker-id` are set,
+source-controller acquires an X.509-SVID from the SPIFFE Workload API and uses it to
+authenticate to the SPIFFE Broker API. The `SPIFFE_ENDPOINT_SOCKET` environment
+variable must point to the Workload API socket.
+
+The Broker is used to acquire JWT-SVIDs for object identity when a
+ServiceAccount sets `credential.auth.fluxcd.io/provider` to `spiffe`. The
+Broker endpoint is a TCP gRPC target, e.g.
+`dns:///spire-server.spire.svc.cluster.local:8443`.
+
+Each `--spiffe-broker-id` value is interpreted like the SPIFFE IDs used by the
+mTLS flags. Invalid values cause source-controller to fail at startup.
+
### Feature Gates
| Name | Default Value | Description |
|-------------------------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `CacheSecretsAndConfigMaps` | `false` | Configures the caching of Secrets and ConfigMaps by the controller-runtime client. When enabled, it will cache both object types, resulting in increased memory usage and cluster-wide RBAC permissions (list and watch). |
-| `ObjectLevelWorkloadIdentity` | `false` | Enables the use of object-level workload identity for the controller. |
| `OptimizedGitClones` | `true` | Optimises Git resource usage by only cloning repositories when the HEAD commit changed since last reconciliation. |
diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md
index 3fe0791b0..0c75239fd 100644
--- a/docs/api/v1/source.md
+++ b/docs/api/v1/source.md
@@ -191,8 +191,8 @@ string
(Optional)
ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
the bucket. This field is only supported for the ‘gcp’ and ‘aws’ providers.
-For more information about workload identity:
-https://fluxcd.io/flux/components/source/buckets/#workload-identity
+For more information about object identity:
+https://fluxcd.io/flux/integrations/object-identity/
@@ -1198,7 +1198,11 @@ string
|
(Optional)
ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
-the image pull if the service account has attached pull secrets. For more information:
+the image pull, either with the pull secrets attached to the service account or with
+an object identity.
+For more information about object identity:
+https://fluxcd.io/flux/integrations/object-identity/
+For more information about image pull secrets:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account
|
@@ -1555,8 +1559,8 @@ string
(Optional)
ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
the bucket. This field is only supported for the ‘gcp’ and ‘aws’ providers.
-For more information about workload identity:
-https://fluxcd.io/flux/components/source/buckets/#workload-identity
+For more information about object identity:
+https://fluxcd.io/flux/integrations/object-identity/
@@ -3471,7 +3475,11 @@ string
|
(Optional)
ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
-the image pull if the service account has attached pull secrets. For more information:
+the image pull, either with the pull secrets attached to the service account or with
+an object identity.
+For more information about object identity:
+https://fluxcd.io/flux/integrations/object-identity/
+For more information about image pull secrets:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account
|
diff --git a/docs/spec/v1/buckets.md b/docs/spec/v1/buckets.md
index eb02f5114..8caadbe58 100644
--- a/docs/spec/v1/buckets.md
+++ b/docs/spec/v1/buckets.md
@@ -275,14 +275,14 @@ data:
secretkey:
```
-##### AWS Controller-Level Workload Identity example
+##### AWS Workload Identity example
```yaml
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: Bucket
metadata:
- name: aws-controller-level-workload-identity
+ name: aws-workload-identity
namespace: default
spec:
interval: 5m0s
@@ -293,18 +293,14 @@ spec:
timeout: 30s
```
-##### AWS Object-Level Workload Identity example
-
-**Note:** To use Object-Level Workload Identity (`.spec.serviceAccountName` with
-cloud providers), the controller feature gate `ObjectLevelWorkloadIdentity` must
-be enabled.
+##### AWS Object Identity example
```yaml
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: Bucket
metadata:
- name: aws-object-level-workload-identity
+ name: aws-object-identity
namespace: default
spec:
interval: 5m0s
@@ -312,13 +308,13 @@ spec:
bucketName: podinfo
endpoint: s3.amazonaws.com
region: us-east-1
- serviceAccountName: aws-workload-identity-sa
+ serviceAccountName: aws-object-identity-sa
timeout: 30s
---
apiVersion: v1
kind: ServiceAccount
metadata:
- name: aws-workload-identity-sa
+ name: aws-object-identity-sa
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/flux-bucket-role
@@ -339,8 +335,7 @@ with:
with the `AZURE_CLIENT_ID`
- Managed Identity with a system-assigned identity
-is attempted by default. If no chain can be established, the bucket
-is assumed to be publicly reachable.
+is attempted by default.
When a reference is specified, it expects a Secret with one of the following
sets of `.data` fields:
@@ -359,23 +354,6 @@ For any Managed Identity and/or Microsoft Entra ID (Formerly Azure Active Direct
the base URL can be configured using `.data.authorityHost`. If not supplied,
[`AzurePublicCloud` is assumed](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AuthorityHost).
-##### Azure example
-
-```yaml
----
-apiVersion: source.toolkit.fluxcd.io/v1
-kind: Bucket
-metadata:
- name: azure-public
- namespace: default
-spec:
- interval: 5m0s
- provider: azure
- bucketName: podinfo
- endpoint: https://podinfoaccount.blob.core.windows.net
- timeout: 30s
-```
-
##### Azure Service Principal Secret example
```yaml
@@ -571,31 +549,27 @@ spec:
endpoint: https://testfluxwi.blob.core.windows.net
```
-##### Azure Object-Level Workload Identity example
-
-**Note:** To use Object-Level Workload Identity (`.spec.serviceAccountName` with
-cloud providers), the controller feature gate `ObjectLevelWorkloadIdentity` must
-be enabled.
+##### Azure Object Identity example
```yaml
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: Bucket
metadata:
- name: azure-object-level-workload-identity
+ name: azure-object-identity
namespace: default
spec:
interval: 5m0s
provider: azure
bucketName: testwi
endpoint: https://testfluxwi.blob.core.windows.net
- serviceAccountName: azure-workload-identity-sa
+ serviceAccountName: azure-object-identity-sa
timeout: 30s
---
apiVersion: v1
kind: ServiceAccount
metadata:
- name: azure-workload-identity-sa
+ name: azure-object-identity-sa
namespace: default
annotations:
azure.workload.identity/client-id:
@@ -656,14 +630,14 @@ Refer to the [Azure documentation](https://learn.microsoft.com/en-us/rest/api/st
For detailed setup instructions, see: https://fluxcd.io/flux/integrations/gcp/#for-google-cloud-storage
-##### GCP Controller-Level Workload Identity example
+##### GCP Workload Identity example
```yaml
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: Bucket
metadata:
- name: gcp-controller-level-workload-identity
+ name: gcp-workload-identity
namespace: default
spec:
interval: 5m0s
@@ -674,18 +648,14 @@ spec:
timeout: 30s
```
-##### GCP Object-Level Workload Identity example
-
-**Note:** To use Object-Level Workload Identity (`.spec.serviceAccountName` with
-cloud providers), the controller feature gate `ObjectLevelWorkloadIdentity` must
-be enabled.
+##### GCP Object Identity example
```yaml
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: Bucket
metadata:
- name: gcp-object-level-workload-identity
+ name: gcp-object-identity
namespace: default
spec:
interval: 5m0s
@@ -693,13 +663,13 @@ spec:
bucketName: podinfo
endpoint: storage.googleapis.com
region: us-east-1
- serviceAccountName: gcp-workload-identity-sa
+ serviceAccountName: gcp-object-identity-sa
timeout: 30s
---
apiVersion: v1
kind: ServiceAccount
metadata:
- name: gcp-workload-identity-sa
+ name: gcp-object-identity-sa
namespace: default
annotations:
iam.gke.io/gcp-service-account:
@@ -753,9 +723,9 @@ Where the (base64 decoded) value of `.data.serviceaccount` looks like this:
Only service account keys are accepted, i.e. the `type` field must be set to
`service_account`. Other Google credential configurations, such as
`external_account` (workload identity federation), are rejected. To authenticate
-without a static key, use Workload Identity as shown in the
-[GCP Controller-Level](#gcp-controller-level-workload-identity-example) and
-[GCP Object-Level](#gcp-object-level-workload-identity-example) examples.
+without a static key, use workload identity or object identity as shown in the
+[GCP Workload Identity](#gcp-workload-identity-example) and
+[GCP Object Identity](#gcp-object-identity-example) examples.
### Interval
@@ -1000,12 +970,15 @@ the `.spec.provider` field:
- When `.spec.provider` is set to `generic`, the controller will fetch the image
pull secrets attached to the Service Account and use them for authentication.
- When `.spec.provider` is set to `aws`, `azure`, or `gcp`, the Service Account
- will be used for Workload Identity authentication. In this case, the controller
- feature gate `ObjectLevelWorkloadIdentity` must be enabled, otherwise the
- controller will error out.
+ will be used to acquire an object identity.
+
+For a complete guide to the ServiceAccount annotations used for object
+identity, including the `spiffe` credential provider, see the
+[Object Identity](/flux/integrations/object-identity/) docs.
-**Note:** that for a publicly accessible object storage, you don't need to
-provide a `secretRef` nor `serviceAccountName`.
+**Note:** when `.spec.provider` is set to `generic` and the object storage
+allows anonymous access, you don't need to provide a `secretRef` nor a
+`serviceAccountName`. The cloud providers all require authentication.
**Important:** `.spec.secretRef` and `.spec.serviceAccountName` are mutually
exclusive and cannot be set at the same time. This constraint is enforced
diff --git a/docs/spec/v1/gitrepositories.md b/docs/spec/v1/gitrepositories.md
index a700c460a..a20ed9a20 100644
--- a/docs/spec/v1/gitrepositories.md
+++ b/docs/spec/v1/gitrepositories.md
@@ -308,7 +308,7 @@ For a full list of available regions and their endpoints, see the
spec:
interval: 5m0s
provider: aws
- serviceAccountName: my-tenant # optional (used for object-level workload identity)
+ serviceAccountName: my-tenant # optional (used for object identity)
url: https://git-codecommit..amazonaws.com/v1/repos/
ref:
branch: main
@@ -465,11 +465,13 @@ in the same namespace as GitRepository with purpose depending on the value of
the `.spec.provider` field:
- When `.spec.provider` is set to `azure`, the Service Account
- will be used for Workload Identity authentication. In this case, the controller
- feature gate `ObjectLevelWorkloadIdentity` must be enabled, otherwise the
- controller will error out. For Azure DevOps specific setup, see the
+ will be used to acquire an object identity. For Azure DevOps specific setup, see the
[Azure DevOps integration guide](https://fluxcd.io/flux/integrations/azure/#for-azure-devops).
+For a complete guide to the ServiceAccount annotations used for object
+identity, including the `spiffe` credential provider, see the
+[Object Identity](/flux/integrations/object-identity/) docs.
+
**Note:** that for a publicly accessible git repository, you don't need to
provide a `secretRef` nor `serviceAccountName`.
diff --git a/docs/spec/v1/ocirepositories.md b/docs/spec/v1/ocirepositories.md
index bb742be39..67fa8c584 100644
--- a/docs/spec/v1/ocirepositories.md
+++ b/docs/spec/v1/ocirepositories.md
@@ -116,9 +116,11 @@ Supported options are:
- `azure`
- `gcp`
-The `generic` provider can be used for public repositories or when
+The `generic` provider can be used for public repositories, when
static credentials are used for authentication, either with
-`spec.secretRef` or `spec.serviceAccountName`.
+`spec.secretRef` or `spec.serviceAccountName`, or when a Kubernetes
+ServiceAccount token is used for object identity, as described
+in the [Service Account reference](#service-account-reference) section.
If you do not specify `.spec.provider`, it defaults to `generic`.
For a complete guide on how to set up authentication for cloud providers,
@@ -274,16 +276,77 @@ kubectl create secret docker-registry ...
in the same namespace as OCIRepository with purpose depending on the value of
the `.spec.provider` field:
-- When `.spec.provider` is set to `generic`, the controller will fetch the image
- pull secrets attached to the Service Account and use them for authentication.
+- When `.spec.provider` is set to `generic`, the controller will use the image
+ pull secrets attached to the Service Account for static authentication, or
+ use the Service Account token for object identity when the
+ Service Account opts in with the credential annotations described below.
- When `.spec.provider` is set to `aws`, `azure`, or `gcp`, the Service Account
- will be used for Workload Identity authentication. In this case, the controller
- feature gate `ObjectLevelWorkloadIdentity` must be enabled, otherwise the
- controller will error out.
+ will be used to acquire an object identity.
+
+For a complete guide to the ServiceAccount annotations used for object
+identity, including the `spiffe` credential provider, see the
+[Object Identity](/flux/integrations/object-identity/) docs.
**Note:** that for a publicly accessible image repository, you don't need to
provide a `secretRef` nor `serviceAccountName`.
+#### Generic provider ServiceAccount tokens
+
+For the `generic` provider, the controller can authenticate to a registry
+using a short-lived Kubernetes ServiceAccount token. The token is presented
+to the registry as a bearer token by default, or as the password in basic
+authentication when `credential.auth.fluxcd.io/username` is set.
+
+The ServiceAccount must opt in with the following required annotations:
+
+- `credential.auth.fluxcd.io/provider`: must be set to `kubernetes`.
+- `credential.auth.fluxcd.io/type`: must be set to `jwt`.
+
+The following annotations are optional:
+
+- `credential.auth.fluxcd.io/audiences`: a comma or newline separated list of
+ token audiences. Defaults to the registry host derived from `.spec.url`.
+- `credential.auth.fluxcd.io/username`: the username to use when the registry
+ expects basic authentication. When unset, the token is sent as a bearer token.
+- `credential.auth.fluxcd.io/expiration`: the requested token expiration as a
+ Go duration, e.g. `10m`.
+
+A ServiceAccount that does not set both required annotations does not opt in
+and continues to use its `imagePullSecrets`, or anonymous access if it has none.
+Setting only one of the two required annotations is a configuration error. The
+credential annotations cannot be combined with `imagePullSecrets`.
+
+Example:
+
+```yaml
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: OCIRepository
+metadata:
+ name: app
+ namespace: apps
+spec:
+ interval: 5m
+ url: oci://registry.example.com/app
+ provider: generic
+ serviceAccountName: registry-puller
+ ref:
+ tag: latest
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: registry-puller
+ namespace: apps
+ annotations:
+ credential.auth.fluxcd.io/provider: kubernetes
+ credential.auth.fluxcd.io/type: jwt
+ # Optional. Defaults to the registry host from .spec.url.
+ credential.auth.fluxcd.io/audiences: registry.example.com
+ # Optional. Use when the registry expects basic authentication.
+ credential.auth.fluxcd.io/username: flux
+```
+
For a complete guide on how to set up authentication for cloud providers,
see the integration [docs](/flux/integrations/).
diff --git a/go.mod b/go.mod
index 630ece7bb..7551d2918 100644
--- a/go.mod
+++ b/go.mod
@@ -9,85 +9,92 @@ replace github.com/fluxcd/source-controller/api => ./api
replace github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be
require (
- cloud.google.com/go/auth v0.23.2
- cloud.google.com/go/compute/metadata v0.9.0
- cloud.google.com/go/storage v1.62.3
+ cloud.google.com/go/auth v0.24.1
+ cloud.google.com/go/compute/metadata v0.10.0
+ cloud.google.com/go/storage v1.70.0
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6
- github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.1
- github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.1
- github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.7.0
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.3
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.15.0
+ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.8.2
github.com/Masterminds/semver/v3 v3.5.0
github.com/cyphar/filepath-securejoin v0.7.0
github.com/distribution/distribution/v3 v3.1.2
- github.com/docker/cli v29.7.2+incompatible
+ github.com/docker/cli v29.9.2+incompatible
github.com/docker/go-units v0.5.0
- github.com/elazarl/goproxy v1.8.4
+ github.com/elazarl/goproxy v1.9.2
github.com/fluxcd/cli-utils v1.4.0
+ github.com/fluxcd/pkg/apis/crypto v0.5.0
github.com/fluxcd/pkg/apis/event v0.32.0
- github.com/fluxcd/pkg/apis/meta v1.35.0
- github.com/fluxcd/pkg/artifact v0.24.0
- github.com/fluxcd/pkg/auth v0.62.0
- github.com/fluxcd/pkg/cache v0.17.0
- github.com/fluxcd/pkg/git v0.55.0
- github.com/fluxcd/pkg/gittestserver v0.32.0
- github.com/fluxcd/pkg/helmtestserver v0.44.0
+ github.com/fluxcd/pkg/apis/meta v1.38.0
+ github.com/fluxcd/pkg/artifact v0.28.0
+ github.com/fluxcd/pkg/auth v0.66.0
+ github.com/fluxcd/pkg/cache v0.19.0
+ github.com/fluxcd/pkg/git v0.56.0
+ github.com/fluxcd/pkg/gittestserver v0.33.0
+ github.com/fluxcd/pkg/helmtestserver v0.45.0
github.com/fluxcd/pkg/http/transport v0.9.0
github.com/fluxcd/pkg/masktoken v0.10.0
- github.com/fluxcd/pkg/oci v0.72.0
- github.com/fluxcd/pkg/runtime v0.119.0
- github.com/fluxcd/pkg/sourceignore v0.21.0
- github.com/fluxcd/pkg/ssh v0.28.0
- github.com/fluxcd/pkg/tar v1.3.0
+ github.com/fluxcd/pkg/oci v0.73.0
+ github.com/fluxcd/pkg/runtime v0.122.0
+ github.com/fluxcd/pkg/sourceignore v0.22.0
+ github.com/fluxcd/pkg/spiffe v0.2.0
+ github.com/fluxcd/pkg/ssh v0.29.0
+ github.com/fluxcd/pkg/tar v1.4.0
github.com/fluxcd/pkg/testserver v0.15.0
- github.com/fluxcd/pkg/version v0.19.0
- github.com/fluxcd/source-controller/api v1.9.0
+ github.com/fluxcd/pkg/version v0.20.0
+ github.com/fluxcd/source-controller/api v1.10.0
github.com/go-git/go-billy/v5 v5.9.2
github.com/go-git/go-git/v5 v5.19.3
github.com/go-logr/logr v1.4.4
github.com/google/go-containerregistry v0.22.1
- github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20260602205845-4b7672c7705a
+ github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20261013193525-92aac6186bc4
github.com/google/uuid v1.6.0
- github.com/miekg/dns v1.1.72
- github.com/minio/minio-go/v7 v7.2.1
+ github.com/miekg/dns v1.1.73
+ github.com/minio/minio-go/v7 v7.4.1
github.com/notaryproject/notation-core-go v1.3.0
github.com/notaryproject/notation-go v1.3.2
- github.com/onsi/gomega v1.43.0
+ github.com/onsi/gomega v1.44.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.1
github.com/otiai10/copy v1.14.1
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
- github.com/prometheus/client_golang v1.24.1
- github.com/sigstore/cosign/v3 v3.0.6
- github.com/sigstore/rekor v1.5.2
- github.com/sigstore/sigstore v1.10.8
- github.com/sigstore/sigstore-go v1.2.1
+ github.com/prometheus/client_golang v1.25.0
+ github.com/sigstore/cosign/v3 v3.1.4
+ github.com/sigstore/rekor v1.5.5
+ github.com/sigstore/sigstore v1.11.1
+ github.com/sigstore/sigstore-go v1.3.0
github.com/sirupsen/logrus v1.10.2
github.com/spf13/pflag v1.0.10
+ github.com/spiffe/go-spiffe/v2 v2.9.0
golang.org/x/crypto v0.58.0
golang.org/x/sync v0.24.0
- google.golang.org/api v0.297.0
- helm.sh/helm/v4 v4.3.0
+ google.golang.org/api v0.308.0
+ helm.sh/helm/v4 v4.3.1
k8s.io/api v0.37.1
k8s.io/apimachinery v0.37.1
k8s.io/client-go v0.37.1
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3
- oras.land/oras-go/v2 v2.6.2
+ oras.land/oras-go/v2 v2.6.4
sigs.k8s.io/controller-runtime v0.25.2
sigs.k8s.io/yaml v1.6.0
)
require (
+ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260709200747-435963d16310.1 // indirect
cel.dev/expr v0.25.2 // indirect
cloud.google.com/go v0.123.0 // indirect
- cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
- cloud.google.com/go/iam v1.12.0 // indirect
+ cloud.google.com/go/auth/oauth2adapt v0.3.0 // indirect
+ cloud.google.com/go/iam v1.14.0 // indirect
cloud.google.com/go/monitoring v1.30.0 // indirect
+ connectrpc.com/connect v1.20.0 // indirect
dario.cat/mergo v1.0.2 // indirect
- github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 // indirect
+ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.18.1 // indirect
+ github.com/AliyunContainerService/ack-ram-tool/pkg/ecsmetadata v0.0.9 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.13.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/storage/internal v0.1.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.30 // indirect
@@ -98,54 +105,53 @@ require (
github.com/Azure/go-autorest/logger v0.2.2 // indirect
github.com/Azure/go-autorest/tracing v0.6.1 // indirect
github.com/Azure/go-ntlmssp v0.1.1 // indirect
- github.com/AzureAD/microsoft-authentication-library-for-go v1.8.0 // indirect
+ github.com/AzureAD/microsoft-authentication-library-for-go v1.10.1 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
- github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 // indirect
- github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
- github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect
+ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0 // indirect
+ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 // indirect
+ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/ProtonMail/go-crypto v1.4.1 // indirect
- github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
+ github.com/ProtonMail/go-crypto v1.5.2 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect
github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect
github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect
- github.com/alibabacloud-go/debug v1.0.0 // indirect
+ github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
- github.com/alibabacloud-go/tea v1.2.1 // indirect
+ github.com/alibabacloud-go/tea v1.3.12 // indirect
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
- github.com/aliyun/credentials-go v1.3.2 // indirect
+ github.com/aliyun/credentials-go v1.4.7 // indirect
+ github.com/apache/arrow-go/v18 v18.7.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
- github.com/aws/aws-sdk-go-v2 v1.46.0 // indirect
- github.com/aws/aws-sdk-go-v2/config v1.33.3 // indirect
- github.com/aws/aws-sdk-go-v2/credentials v1.20.3 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.19.2 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.2 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.2 // indirect
- github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.2 // indirect
- github.com/aws/aws-sdk-go-v2/service/ecr v1.64.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.46.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/eks v1.98.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.2 // indirect
- github.com/aws/aws-sdk-go-v2/service/signin v1.9.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.37.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.42.0 // indirect
- github.com/aws/aws-sdk-go-v2/service/sts v1.49.0 // indirect
- github.com/aws/smithy-go v1.28.1 // indirect
+ github.com/aws/aws-sdk-go-v2 v1.47.4 // indirect
+ github.com/aws/aws-sdk-go-v2/config v1.33.10 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.20.10 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.4 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.7 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.7 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.7 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ecr v1.66.6 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.47.6 // indirect
+ github.com/aws/aws-sdk-go-v2/service/eks v1.104.3 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.22 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.7 // indirect
+ github.com/aws/aws-sdk-go-v2/service/signin v1.10.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.38.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.51.5 // indirect
+ github.com/aws/smithy-go v1.28.6 // indirect
github.com/aws/smithy-go/aws-http-auth v1.2.1 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
- github.com/buildkite/agent/v3 v3.118.0 // indirect
- github.com/buildkite/go-pipeline v0.16.0 // indirect
+ github.com/buildkite/agent/v3 v3.130.0 // indirect
+ github.com/buildkite/go-pipeline v0.17.1 // indirect
github.com/buildkite/interpolate v0.1.5 // indirect
github.com/buildkite/roko v1.4.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
@@ -159,10 +165,8 @@ require (
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/coreos/go-oidc/v3 v3.21.0 // indirect
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
- github.com/creack/pty v1.1.24 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
@@ -172,6 +176,7 @@ require (
github.com/docker/go-metrics v0.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
+ github.com/eclipse-keypont/crypto11 v1.6.8 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
@@ -187,62 +192,66 @@ require (
github.com/fluxcd/pkg/lockedfile v0.9.0 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/fxamacker/cbor/v2 v2.9.4 // indirect
- github.com/gaganhr94/docker-credential-acr v1.0.2 // indirect
+ github.com/gaganhr94/docker-credential-acr v1.0.3 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
- github.com/go-chi/chi/v5 v5.3.0 // indirect
+ github.com/go-chi/chi/v5 v5.5.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
- github.com/go-jose/go-jose/v4 v4.1.5 // indirect
+ github.com/go-jose/go-jose/v4 v4.1.6 // indirect
github.com/go-ldap/ldap/v3 v3.4.10 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
- github.com/go-openapi/analysis v0.25.5 // indirect
- github.com/go-openapi/errors v0.22.8 // indirect
- github.com/go-openapi/jsonpointer v1.0.0 // indirect
- github.com/go-openapi/jsonreference v1.0.1 // indirect
- github.com/go-openapi/loads v0.25.0 // indirect
- github.com/go-openapi/runtime v0.33.0 // indirect
- github.com/go-openapi/runtime/server-middleware v0.30.0 // indirect
- github.com/go-openapi/spec v0.22.9 // indirect
- github.com/go-openapi/strfmt v0.27.0 // indirect
- github.com/go-openapi/swag v0.29.1 // indirect
- github.com/go-openapi/swag/cmdutils v0.29.1 // indirect
- github.com/go-openapi/swag/conv v0.29.1 // indirect
- github.com/go-openapi/swag/fileutils v0.29.1 // indirect
- github.com/go-openapi/swag/jsonutils v0.29.1 // indirect
- github.com/go-openapi/swag/loading v0.29.1 // indirect
- github.com/go-openapi/swag/mangling v0.29.1 // indirect
- github.com/go-openapi/swag/netutils v0.29.1 // indirect
- github.com/go-openapi/swag/pools v0.29.1 // indirect
- github.com/go-openapi/swag/stringutils v0.29.1 // indirect
- github.com/go-openapi/swag/typeutils v0.29.1 // indirect
- github.com/go-openapi/swag/yamlutils v0.29.1 // indirect
- github.com/go-openapi/validate v0.26.1 // indirect
+ github.com/go-openapi/analysis v1.0.0 // indirect
+ github.com/go-openapi/errors v0.22.9 // indirect
+ github.com/go-openapi/jsonpointer v1.0.1 // indirect
+ github.com/go-openapi/jsonreference v1.0.2 // indirect
+ github.com/go-openapi/loads v0.25.3 // indirect
+ github.com/go-openapi/runtime v0.33.3 // indirect
+ github.com/go-openapi/runtime/server-middleware v0.33.3 // indirect
+ github.com/go-openapi/spec v1.0.1 // indirect
+ github.com/go-openapi/strfmt v0.27.3 // indirect
+ github.com/go-openapi/swag v0.29.2 // indirect
+ github.com/go-openapi/swag/cmdutils v0.29.2 // indirect
+ github.com/go-openapi/swag/conv v0.29.2 // indirect
+ github.com/go-openapi/swag/fileutils v0.29.2 // indirect
+ github.com/go-openapi/swag/jsonutils v0.29.2 // indirect
+ github.com/go-openapi/swag/loading v0.29.2 // indirect
+ github.com/go-openapi/swag/mangling v0.29.2 // indirect
+ github.com/go-openapi/swag/netutils v0.29.2 // indirect
+ github.com/go-openapi/swag/pools v0.29.2 // indirect
+ github.com/go-openapi/swag/stringutils v0.29.2 // indirect
+ github.com/go-openapi/swag/typeutils v0.29.2 // indirect
+ github.com/go-openapi/swag/yamlutils v0.29.2 // indirect
+ github.com/go-openapi/validate v1.0.0 // indirect
github.com/go-piv/piv-go/v2 v2.6.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
+ github.com/gobuffalo/flect v1.0.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
- github.com/gofrs/flock v0.13.0 // indirect
+ github.com/goccy/go-json v0.10.6 // indirect
+ github.com/godbus/dbus/v5 v5.2.2 // indirect
+ github.com/gofrs/flock v0.13.1 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
- github.com/golang/snappy v0.0.4 // indirect
+ github.com/golang/snappy v1.0.0 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/certificate-transparency-go v1.3.3 // indirect
+ github.com/google/flatbuffers v25.12.19+incompatible // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20250225234217-098045d5e61f // indirect
- github.com/google/go-github/v73 v73.0.0 // indirect
github.com/google/go-github/v87 v87.0.0 // indirect
+ github.com/google/go-github/v88 v88.0.0 // indirect
github.com/google/go-querystring v1.2.0 // indirect
- github.com/google/s2a-go v0.1.9 // indirect
- github.com/googleapis/enterprise-certificate-proxy v0.3.20 // indirect
- github.com/googleapis/gax-go/v2 v2.24.0 // indirect
+ github.com/google/s2a-go v0.1.11 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.3.23 // indirect
+ github.com/googleapis/gax-go/v2 v2.26.2 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gosuri/uitable v0.0.4 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 // indirect
@@ -258,18 +267,17 @@ require (
github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.6.0 // indirect
- github.com/klauspost/compress v1.19.2 // indirect
- github.com/klauspost/cpuid/v2 v2.3.0 // indirect
+ github.com/klauspost/compress v1.20.1 // indirect
+ github.com/klauspost/cpuid/v2 v2.4.0 // indirect
github.com/klauspost/crc32 v1.3.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
- github.com/letsencrypt/boulder v0.20260309.0 // indirect
github.com/lib/pq v1.12.3 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
- github.com/mattn/go-colorable v0.1.14 // indirect
- github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.23 // indirect
+ github.com/mattn/go-colorable v0.1.15 // indirect
+ github.com/mattn/go-isatty v0.0.22 // indirect
+ github.com/mattn/go-runewidth v0.0.24 // indirect
github.com/miekg/pkcs11 v1.1.2 // indirect
github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
@@ -281,19 +289,22 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
- github.com/mozillazg/docker-credential-acr-helper v0.4.0 // indirect
+ github.com/mozillazg/docker-credential-acr-helper v0.4.1 // indirect
+ github.com/mozillazg/docker-credential-acr-helper/pkg/acr v0.2.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/notaryproject/notation-plugin-framework-go v1.0.0 // indirect
github.com/notaryproject/tspclient-go v1.0.0 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
- github.com/oklog/ulid/v2 v2.1.1 // indirect
+ github.com/oklog/ulid/v2 v2.1.2 // indirect
github.com/oleiade/reflections v1.1.0 // indirect
- github.com/opencontainers/go-digest/blake3 v0.0.0-20250813155314-89707e38ad1a // indirect
+ github.com/opencontainers/go-digest/blake3 v0.0.0-20261015205711-63db54280247 // indirect
github.com/otiai10/mint v1.6.3 // indirect
github.com/pborman/uuid v1.2.1 // indirect
- github.com/pelletier/go-toml/v2 v2.3.1 // indirect
+ github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/philhofer/fwd v1.2.0 // indirect
+ github.com/phuslu/lru v1.0.18 // indirect
+ github.com/pierrec/lz4/v4 v4.1.28 // indirect
github.com/pjbgf/sha1cd v0.7.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
@@ -305,37 +316,34 @@ require (
github.com/prometheus/procfs v0.22.0 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.5.3 // indirect
github.com/redis/go-redis/extra/redisotel/v9 v9.5.3 // indirect
- github.com/redis/go-redis/v9 v9.18.0 // indirect
+ github.com/redis/go-redis/v9 v9.22.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/rubenv/sql-migrate v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 // indirect
- github.com/sassoftware/relic v7.2.1+incompatible // indirect
- github.com/secure-systems-lab/go-securesystemslib v0.11.0 // indirect
+ github.com/sassoftware/relic/v8 v8.2.0 // indirect
+ github.com/secure-systems-lab/go-securesystemslib v0.11.1 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
- github.com/sigstore/fulcio v1.8.6 // indirect
- github.com/sigstore/protobuf-specs v0.5.1 // indirect
- github.com/sigstore/rekor-tiles/v2 v2.2.2-0.20260601073857-5d098a2b6443 // indirect
- github.com/sigstore/timestamp-authority/v2 v2.1.2 // indirect
+ github.com/sigstore/protobuf-specs v0.5.2 // indirect
+ github.com/sigstore/rekor-tiles/v2 v2.3.0 // indirect
+ github.com/sigstore/timestamp-authority/v2 v2.1.5 // indirect
github.com/skeema/knownhosts v1.3.2 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/viper v1.21.0 // indirect
- github.com/spiffe/go-spiffe/v2 v2.7.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 // indirect
github.com/tetratelabs/wazero v1.12.0 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
github.com/theupdateframework/go-tuf v0.7.0 // indirect
- github.com/theupdateframework/go-tuf/v2 v2.4.2-0.20260407074541-7e8f69f906ef // indirect
- github.com/tinylib/msgp v1.6.1 // indirect
- github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
+ github.com/theupdateframework/go-tuf/v2 v2.4.2 // indirect
+ github.com/tinylib/msgp v1.6.4 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/transparency-dev/formats v0.1.1 // indirect
github.com/transparency-dev/merkle v0.0.2 // indirect
@@ -346,54 +354,54 @@ require (
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
github.com/zeebo/xxh3 v1.1.0 // indirect
- gitlab.com/gitlab-org/api/client-go v1.46.0 // indirect
+ gitlab.com/gitlab-org/api/client-go/v3 v3.13.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/contrib/bridges/prometheus v0.70.0 // indirect
- go.opentelemetry.io/contrib/detectors/gcp v1.44.0 // indirect
- go.opentelemetry.io/contrib/exporters/autoexport v0.70.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0 // indirect
- go.opentelemetry.io/otel v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/prometheus v0.67.0 // indirect
- go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0 // indirect
- go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.45.0 // indirect
- go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0 // indirect
- go.opentelemetry.io/otel/log v0.21.0 // indirect
- go.opentelemetry.io/otel/metric v1.45.0 // indirect
- go.opentelemetry.io/otel/sdk v1.45.0 // indirect
- go.opentelemetry.io/otel/sdk/log v0.21.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.45.0 // indirect
- go.opentelemetry.io/otel/trace v1.45.0 // indirect
- go.opentelemetry.io/proto/otlp v1.11.0 // indirect
+ go.opentelemetry.io/contrib/bridges/prometheus v0.72.0 // indirect
+ go.opentelemetry.io/contrib/detectors/gcp v1.45.0 // indirect
+ go.opentelemetry.io/contrib/exporters/autoexport v0.72.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 // indirect
+ go.opentelemetry.io/otel v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.23.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.23.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/prometheus v0.69.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.23.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.47.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.47.0 // indirect
+ go.opentelemetry.io/otel/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/metric v1.47.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.47.0 // indirect
+ go.opentelemetry.io/otel/sdk/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.47.0 // indirect
+ go.opentelemetry.io/otel/trace v1.47.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.11.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.28.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
- golang.org/x/mod v0.41.0 // indirect
+ golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba // indirect
+ golang.org/x/mod v0.42.0 // indirect
golang.org/x/net v0.61.0 // indirect
golang.org/x/oauth2 v0.37.0 // indirect
golang.org/x/sys v0.49.0 // indirect
golang.org/x/term v0.47.0 // indirect
golang.org/x/text v0.43.0 // indirect
- golang.org/x/time v0.15.0 // indirect
- golang.org/x/tools v0.51.0 // indirect
+ golang.org/x/time v0.16.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 // indirect
- google.golang.org/grpc v1.83.2 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20261019180522-ce908d29299b // indirect
+ google.golang.org/grpc v1.84.0 // indirect
google.golang.org/protobuf v1.36.12 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/ini.v1 v1.67.2 // indirect
+ gopkg.in/ini.v1 v1.67.3 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.37.1 // indirect
@@ -407,7 +415,7 @@ require (
sigs.k8s.io/kustomize/api v0.21.2 // indirect
sigs.k8s.io/kustomize/kyaml v0.21.2 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
- sigs.k8s.io/release-utils v0.12.4 // indirect
+ sigs.k8s.io/release-utils v0.12.5 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect
)
diff --git a/go.sum b/go.sum
index d4cceb29c..c54d75d7d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,30 +1,32 @@
-al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA=
-al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
+buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260709200747-435963d16310.1 h1:fXh8CsdNpjRr8R5vFdqtIxPt/Lno2IIJlYOdZBIZn0w=
+buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260709200747-435963d16310.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
-cloud.google.com/go/auth v0.23.2 h1:pxSCpfiji41hpzpPdMCftEUCezpgpqmmDdYiAjCKXxo=
-cloud.google.com/go/auth v0.23.2/go.mod h1:4DhBRcqvtljQN3dJ57qtqbib5ZGCYE5f2crfiiC2EM0=
-cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
-cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
-cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
-cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
-cloud.google.com/go/iam v1.12.0 h1:Aki3bX9aHUDKPHfnRJfDcTdVedvy6quGBQcTqx3DRXk=
-cloud.google.com/go/iam v1.12.0/go.mod h1:FEZ4lXpADAC2AIpQY7LANNjjwyQ2jK439CI2VaD+sLY=
-cloud.google.com/go/kms v1.32.0 h1:s+rEluaaZKhLVjrIWG7uNBsnWbiitElzNzFGyp6+nIg=
-cloud.google.com/go/kms v1.32.0/go.mod h1:CSGvW6GnMQbY+1nOHcIzhMtHSbExXlOmCKjWtYVjcpA=
+cloud.google.com/go/auth v0.24.1 h1:NTmd2iJb4DsGIav0KiqFMYI88nMshA2wnFMBatRmoCs=
+cloud.google.com/go/auth v0.24.1/go.mod h1:1dmBXa9xfBvBr39ZnDUDkaaA91ccq9CcqENDgJA4d7c=
+cloud.google.com/go/auth/oauth2adapt v0.3.0 h1:FY8oSZpCYoUNv6QxVODuMjQz4IlSOVeiQtZ08vLPz88=
+cloud.google.com/go/auth/oauth2adapt v0.3.0/go.mod h1:7+2uCm7++XFO+/lN06c2HXpDXb/NMNn2/UwyBPbTnkk=
+cloud.google.com/go/compute/metadata v0.10.0 h1:pyKMUQSwchgkIBBJGdILqQbs/BNJXqwSA7Ej6LAvvtY=
+cloud.google.com/go/compute/metadata v0.10.0/go.mod h1:rGFHRrIif570kSibjFTMbt6/4/tzgJWFGI/HVol4GIk=
+cloud.google.com/go/iam v1.14.0 h1:YRIB1/4xxwJ+NfI6RQr1WaOoHHeV0MizJEj940nBXJA=
+cloud.google.com/go/iam v1.14.0/go.mod h1:JTPZfbHdGXJrOYREtkRoFzCDGaBdbA7ILLKO/DDuav0=
+cloud.google.com/go/kms v1.33.0 h1:pG0X78m212b2pv9N4fdMoUO69LuZGQ9kSvn8sHBOFAo=
+cloud.google.com/go/kms v1.33.0/go.mod h1:CSGvW6GnMQbY+1nOHcIzhMtHSbExXlOmCKjWtYVjcpA=
cloud.google.com/go/logging v1.19.0 h1:NCqhdVUg3wQ8Cobdf16FDSuTGi3+6+hdSBHrY5TsR6Q=
cloud.google.com/go/logging v1.19.0/go.mod h1:i40NZCHC9Gqvod4yE+yQfDWwlgwW/SrshkkGibCHxcA=
cloud.google.com/go/longrunning v1.2.0 h1:WjYH3YHBGCxGJP9M4dWGHBfXr/cFIjMkNgWcJj7/iMM=
cloud.google.com/go/longrunning v1.2.0/go.mod h1:5KMQALFGOCtFoi2xSOA1u3H7WKlhmckgiyFw7+LGQp0=
cloud.google.com/go/monitoring v1.30.0 h1:r/d+JUbyKmJ8b07iznuKfzVzrIXTWxHQ3lBRm3x2LlY=
cloud.google.com/go/monitoring v1.30.0/go.mod h1:htlUR0QWVMrjFzZmN4LGnMAve9xB/eduwjmINxVZ8RM=
-cloud.google.com/go/storage v1.62.3 h1:SZq1t23NCI+e96dH77Dg3PEfsNNEjqO8zE5AnD8gVD0=
-cloud.google.com/go/storage v1.62.3/go.mod h1:cpYz/kRVZ+UQAF1uHeea10/9ewcRbxGoGNKsS9daSXA=
+cloud.google.com/go/storage v1.70.0 h1:LQNHn0rRF94jVFfF3e416IzdQqIufa5GfF6HilQxb80=
+cloud.google.com/go/storage v1.70.0/go.mod h1:W84cNa070TZIegvTW67CBY+f5rxux8EJMb7YyiHdrls=
cloud.google.com/go/trace v1.16.0 h1:GmQovzFc5F0CNfl0VLgL64aoTtu7xsM0YajW2GlG9+E=
cloud.google.com/go/trace v1.16.0/go.mod h1:r+bdAn16dKLSV1G2D5v3e58IlQlizfxWrUfjx7kM7X0=
+connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
+connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
@@ -36,20 +38,23 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg=
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM=
-github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 h1:kcnfY4vljxXliXDBrA9K9lwF8IoEZ4Up6Eg9kWTIm28=
-github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0/go.mod h1:tlqp9mUGbsP+0z3Q+c0Q5MgSdq/OMwQhm5bffR3Q3ss=
+github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.18.1 h1:YWDC5K6uH/hUB9iBqNMzcbYw/mpySDyRiMv4auyB7xY=
+github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.18.1/go.mod h1:eoheXiZu1MD1WqNrjd6QCzH9eNc564OBZhwmPpIHWfw=
+github.com/AliyunContainerService/ack-ram-tool/pkg/ecsmetadata v0.0.7/go.mod h1:QM3VKYNyD5thMEWqKef+uOfpNmZG7RjG7wOsCdavj9w=
+github.com/AliyunContainerService/ack-ram-tool/pkg/ecsmetadata v0.0.9 h1:LW8G8Zf9R6+F0ZpV1FLimv2rVaBRRX+mR1b6N6vIpJc=
+github.com/AliyunContainerService/ack-ram-tool/pkg/ecsmetadata v0.0.9/go.mod h1:QM3VKYNyD5thMEWqKef+uOfpNmZG7RjG7wOsCdavj9w=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.1 h1:zvXfGJCWvywnCA814d8ZiVyt+fm9nnTE8xSb99zRyfo=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.1/go.mod h1:iptorS+VYKFL2N6PnebpS91dubG35eAOEERnT4PJbQU=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.1 h1:u93s+zU2JD62im61Bm5CZIc1ZrOJaIAWEg0WOrMVkEo=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.1/go.mod h1:oXtinPO4OLj9d1DOTrqrL1oRwGhcqadvAmrl6wTeGlk=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.3 h1:qgnWTiWs1G7AqcKZegFvkJD1bmXJcaDU3uC0ELSgZ5U=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.3/go.mod h1:XtxD48QPInqoj+GMlcRlXHEYsoOxFnP6w2JgIZ9rDS4=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.15.0 h1:w3gDUJlJ0BfBsHH02DCBDwbkmMSXJqBj6nBOCo9iocY=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.15.0/go.mod h1:7scl8mG/IFLVjJ9ef/ltdND2T1z0CkgVSaQoUxLvmeU=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.4.0 h1:xFaZZ+IubdftrDHnGGwZ6QvQ3KHTtWl2MCK+GMt2vxs=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.4.0/go.mod h1:mCBhUhlMjLLJKr5aqw2TNS/VqJOie8MzWq3DAMJeKso=
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 h1:ldKsKtEIblsgsr6mPwrd9yRntoX6uLz/K89wsldwx/k=
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3/go.mod h1:MAm7bk0oDLmD8yIkvfbxPW04fxzphPyL+7GzwHxOp6Y=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.13.0 h1:Terj1CMW4+NY5CpWjSRkqLoxh2DkYDdv/FH2z0897Uc=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.13.0/go.mod h1:7Ut2Qw9vcwpLW5Q4MBy43uSxXS7tK2yjs94OJ6j5thE=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 h1:figxyQZXzZQIcP3njhC68bYUiTw45J8/SsHaLW8Ax0M=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0/go.mod h1:TmlMW4W5OvXOmOyKNnor8nlMMiO1ctIyzmHme/VHsrA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=
@@ -58,8 +63,10 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.5.0 h1:MaKvxE6
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.5.0/go.mod h1:i2h9fsTFKZorh8RdV2IcSUf/Qj98GlTkrTvUbX/s8as=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA=
-github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.7.0 h1:BM85pSYlVYQHdq00nxyPoOkyLF5NArJG3bOsrmbwr4k=
-github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.7.0/go.mod h1:QYjP2cB7ZYtS/8jAbE0VSBZde/tjExqGjp+8JY6/+ts=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.8.2 h1:tQJdgQjbKKffEiMOKJmcQPkY01eFHRqWIZVefqP44nI=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.8.2/go.mod h1:kTkpJchXAdO7LGkKZP97a+Ou8TgaF4NT6MHwOIy5uSQ=
+github.com/Azure/azure-sdk-for-go/sdk/storage/internal v0.1.0 h1:X/bTwe0qpvmvPPutc+LWo7T4cKMqDP9JHP4k+Co9ZB4=
+github.com/Azure/azure-sdk-for-go/sdk/storage/internal v0.1.0/go.mod h1:+kX7ahyFelQ42F3RScM2CFgHJljp0phc/FieKLYVpFI=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
@@ -93,21 +100,21 @@ github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDP
github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.8.0 h1:Nljr4q1GRA/5vCrMONS+g4u4LRHNgOXVSh3O43J2CnI=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.8.0/go.mod h1:Y33QHnf0FfdVewFFISOGe20mkZbxX4H839o955/PoeI=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.10.1 h1:0O6j18nQDoIff6/mtosT5LNU2WehEwp+LqfX6699oqY=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.10.1/go.mod h1:xdYAf5bjkOpsd3auA8riiJW4vneBubt9caavL7626jQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 h1:l7+6kwRMJNwdCvYdDl7Eax+wzEYHSnNY7zrrfbhDdTA=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0/go.mod h1:pJTkW8hEUIIi3Pf65lPZOnn4Y81yCllX6IWk2jNXdkM=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk=
-github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0 h1:bN1gA3of5bXtbnLsRPrwfmbbe7A5UWFlcTHseujLnpc=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0/go.mod h1:Yj5vHEz/aAepZGliRJsA6uvHAVAQyEwajq9ORCHPxzM=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 h1:jLdiS1vO+XJFyDSWRHBx56r4s/NNtcl5J6KyCcWUX/w=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0/go.mod h1:8lmpHY+1VRoteiOwyrQMDt1YGXOrFKCz+1wJW7n3ODY=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0 h1:cSjUzZ7KU8hicTgzaSv9NmSyM9fTVK3y5lsBUl3wOis=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0/go.mod h1:dzcEjy1WJ0Q4u9twNR3LcLhNoYMRCrMCMafpxa0TjPQ=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 h1:RoO5+d7uCmDqovLrHCr2/BuViUXvdcrNxyNM1pN9dDQ=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0/go.mod h1:YqwkQPrWSC7+byyc1VlKbWLBF5JsW5IoL6xUkemYSXk=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
@@ -121,10 +128,8 @@ github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
-github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
-github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E=
-github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
+github.com/ProtonMail/go-crypto v1.5.2 h1:cucYnvqcY7UOXVD//mSyjeaPY0SSN3v5cDkYPxumINk=
+github.com/ProtonMail/go-crypto v1.5.2/go.mod h1:/RaSu30DaKO4RY+XdV/ACcCcZkGr7AhUIduq5sjzzCo=
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/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
@@ -140,8 +145,9 @@ github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+N
github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY=
github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
-github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA=
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
+github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
+github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8=
github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
@@ -156,86 +162,93 @@ github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeG
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
-github.com/alibabacloud-go/tea v1.2.1 h1:rFF1LnrAdhaiPmKwH5xwYOKlMh66CqRwPUTzIK74ask=
-github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
+github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
+github.com/alibabacloud-go/tea v1.3.12 h1:ir2Io80UlBy1JHf7t+uCTxmaGQtiEta1WpV29NGJTkE=
+github.com/alibabacloud-go/tea v1.3.12/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils v1.3.9/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA=
github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
-github.com/aliyun/credentials-go v1.3.2 h1:L4WppI9rctC8PdlMgyTkF8bBsy9pyKQEzBD1bHMRl+g=
-github.com/aliyun/credentials-go v1.3.2/go.mod h1:tlpz4uys4Rn7Ik4/piGRrTbXy2uLKvePgQJJduE+Y5c=
+github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
+github.com/aliyun/credentials-go v1.4.7 h1:T17dLqEtPUFvjDRRb5giVvLh6dFT8IcNFJJb7MeyCxw=
+github.com/aliyun/credentials-go v1.4.7/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
+github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM=
+github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
+github.com/apache/arrow-go/v18 v18.7.0 h1:Vw/i+cJyebUofT7JlqFpe65LrmwxULn166jjwStM4HY=
+github.com/apache/arrow-go/v18 v18.7.0/go.mod h1:PM6IigLJkdMwIpeHXnymo+xZ52f42a9EYiLtRel4p/A=
+github.com/apache/thrift v0.24.0 h1:zy31L1a49QTNB2bG1BBfMXol3yJrTH975G3pPubQVLQ=
+github.com/apache/thrift v0.24.0/go.mod h1:zPt6WxgvTOM6hF92y8C+MkEM5LMxZuk4JcQOiU4Esvs=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/aws/aws-sdk-go-v2 v1.46.0 h1:1kt7m/EKcEHt5mlyyxx9cSlMddRPIKbjb6DIQsu4HPk=
-github.com/aws/aws-sdk-go-v2 v1.46.0/go.mod h1:bttEH6JqnUL8LepvDVfdrds/fZ5bCIxzpe3abyUrhDU=
-github.com/aws/aws-sdk-go-v2/config v1.33.3 h1:h090b3O5S17bF87/0ysHZuIT/7DCb4EBRFQX2PMVPCw=
-github.com/aws/aws-sdk-go-v2/config v1.33.3/go.mod h1:YYDB1kTejxbfAbEVUqgCtkVp26xvNCHev9cLKABMGAk=
-github.com/aws/aws-sdk-go-v2/credentials v1.20.3 h1:tToOYM/LXev4NpfWlIYGDvBvjHmJ3HXpRU9ppl+pM6k=
-github.com/aws/aws-sdk-go-v2/credentials v1.20.3/go.mod h1:wfGneWyncO7p67wqXV2IQhPk14JqIc25woKlaArT3WI=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.19.2 h1:Ldv7RPHs7qwwTscRjAl3YBud32f3BvdAGRmSvAx5L38=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.19.2/go.mod h1:XyK6UV8xbo66ysVqLd2783C09pBYHOm8aKTRV5DVJ30=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.2 h1:q/PSLGuRWCChWg+dLnb9dWOnrCxJtnboXbBtFoqqRrI=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.2/go.mod h1:TD1jvU2LvXkJexct5vBqcd8QlNXh5EmRUeL/Z32p0n4=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.2 h1:6fl86IPqKEXoySqiOWdfgbEp9OVbn44zTfEICNEBDhY=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.2/go.mod h1:63HDfhFkdzBpI8WGXTSKUHPKS6mqldj4u3LJW7RZtSU=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.2 h1:XMgIRS+uW9F3yFKnXGRrI9pkHi99CXTmoz2kz2/TGBA=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.2/go.mod h1:vorxDzK+n3jiv9a5ST/LG0Eu9cSv1CRdKTpG6pDMs+M=
-github.com/aws/aws-sdk-go-v2/service/ecr v1.64.0 h1:iOYGE9bHGhMQYtbjEcgDJEobWIhKoUvE71m+Jm0vZgU=
-github.com/aws/aws-sdk-go-v2/service/ecr v1.64.0/go.mod h1:5ccNgipT/aF9MWzTrKkyGJaCozPt+D6LOD4RFIdP22k=
-github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.46.0 h1:15LYA7aTaqNWQzV0c7IRujt4mAUavcRckNz600RE6c8=
-github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.46.0/go.mod h1:Kh1VyF4gwzKAvjGtG66pHyIhfSGxNRGA1wsbbd0NKSs=
-github.com/aws/aws-sdk-go-v2/service/eks v1.98.0 h1:/VGWZHBd1+pGuLOzZCp+MXLY6O63HxeCHRk+Db6JPyc=
-github.com/aws/aws-sdk-go-v2/service/eks v1.98.0/go.mod h1:e+m9ew4EU+j7X2GWWbB85Tg2WEnFRvWnwq/KnsG6RKI=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19 h1:bAdDl/HkGCcGPoe25ToSHEw23VIxt6CT5fLcg111BKg=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19/go.mod h1:KaUzbLxv4CeSxh6ZCl9B4m7CuFenS8kUEaDs+f/DQr4=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.2 h1:ZtHYnumr6QyxhzEzNZwzQTFJEXOswrZqTTkRxthwvr4=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.2/go.mod h1:a1NXrYpBd311gBzn1UI5UzJyyvXktM4xNh/ydPiPpqY=
-github.com/aws/aws-sdk-go-v2/service/kms v1.52.0 h1:QNtg+Mtj1zmepk568+UKBD5DFfqh+ESTUUqQT27JkQc=
-github.com/aws/aws-sdk-go-v2/service/kms v1.52.0/go.mod h1:Y0+uxvxz6ib4KktRdK0V4X45Vcs/JyYoz8H71pO8xeI=
-github.com/aws/aws-sdk-go-v2/service/signin v1.9.0 h1:c3k+k/CS4L+sAIH6fxikL+g5g2LpeNczaoyjjw1iMKI=
-github.com/aws/aws-sdk-go-v2/service/signin v1.9.0/go.mod h1:AGIoQg99fBrOIQnF78TLx4lj18mc4gZ0hJx1UaLIFM4=
-github.com/aws/aws-sdk-go-v2/service/sso v1.37.0 h1:+rqBaOq7jzInjY8M12hr+zEe85JpRll9BjMx38r33Ok=
-github.com/aws/aws-sdk-go-v2/service/sso v1.37.0/go.mod h1:XFlVwUsw3sYh8Hw37umYVJnrcWrwXWRxbNw/JY0bblw=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.42.0 h1:hzM3GslEAOBcLn3DHH6ENToFi+vXP+n02W+x6zejAIM=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.42.0/go.mod h1:588e7skMkYIYkSUseT8E3WKFfbAfrA1bj3Zf+qxJtJY=
-github.com/aws/aws-sdk-go-v2/service/sts v1.49.0 h1:N7Ey8obY3uSui+cxl0OUzFlFmkxSucoJnrniFhw+cLc=
-github.com/aws/aws-sdk-go-v2/service/sts v1.49.0/go.mod h1:zMBwjSf4Pt8a1OHYiZ5rPD0PJRK1kQrUaxhS/Dbld8E=
-github.com/aws/smithy-go v1.28.1 h1:R/nXH00c8qcfCzQVELtRw+eLQWtzv+VAIEFJ1/xxXlQ=
-github.com/aws/smithy-go v1.28.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
+github.com/aws/aws-sdk-go-v2 v1.47.4 h1:bTvk6UdSSSvaQsfLVj1JRDEEqj/PDRwGf1KanaRzau0=
+github.com/aws/aws-sdk-go-v2 v1.47.4/go.mod h1:XkrjAZvr705Nytv6PkPUhoSB2W9+vVHBp5oAWpkh8Ak=
+github.com/aws/aws-sdk-go-v2/config v1.33.10 h1:RRb0GghYqq2ikMXzfT4r9NO9lVhOld3FIhJJWDIdk+w=
+github.com/aws/aws-sdk-go-v2/config v1.33.10/go.mod h1:BDSA7QGh6yrNQA5Z5aBnHWKMWdJDMD4IOlB4QjYSp5E=
+github.com/aws/aws-sdk-go-v2/credentials v1.20.10 h1:ItSjcLk+2M15RnRxO105uVIqLiVQn8y3gaeHC7W0iqs=
+github.com/aws/aws-sdk-go-v2/credentials v1.20.10/go.mod h1:eO4GlmGXB+gx+zDbhu3IENEFOmjrbVKJtOptJiIhngc=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.4 h1:7ksj/zMap9+831SmNQZkcpmfuATp3DKr4BfLNnBdYXM=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.4/go.mod h1:zhi8vDrD1dj76ysTWS6Ny1y6/EEW1Jrq2y8lzKeoqfs=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.7 h1:fSNAt6hs4qLjb9tMZc6vj3PHlOCYGXK2JjJZ7AW2tf4=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.7/go.mod h1:TMav+EuXQu5kNpZZz/6rIC8xx4mCsW+6AKHrjvOSAsE=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.7 h1:7NS6kqBjkWIN8P/AEdmtyq6eQGAhN1oHTZdzXclpH6Y=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.7/go.mod h1:1PFqtAUsIgF1nEVojzRJSf/v88zjzqrGW+w+UAtkXyQ=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.7 h1:wYu55QUHARwu9YzeuY5yEJUTsIu8ahkmp1l3QmbzHn8=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.7/go.mod h1:OteEkhFAgFwQtZft/3myWo3tVWxdAo7cwV+7AbcpAtQ=
+github.com/aws/aws-sdk-go-v2/service/ecr v1.66.6 h1:BLPDoTpiLhoMZd2QfAbSC6QWbLEd/KYcsps9rKrqlig=
+github.com/aws/aws-sdk-go-v2/service/ecr v1.66.6/go.mod h1:hbHHpYZ/29gAnar+fh7C0BpL/ELXMwxh2q7ZqXSZePI=
+github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.47.6 h1:3YzoAsrxJOZe0yn+fajdDO2Ja/3v9wVBWLQXLT6t88w=
+github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.47.6/go.mod h1:m2T51VB7nSFOpDI8T3kNBwBVSwJrYfLlLm87AP+Wh08=
+github.com/aws/aws-sdk-go-v2/service/eks v1.104.3 h1:WqkUjchX5c5Ya1l7I22po00NXfeImCe7M/FxTXk2bMs=
+github.com/aws/aws-sdk-go-v2/service/eks v1.104.3/go.mod h1:yqmvzWK8FGGbWvjhW1wIpbjxpJNXgz0ciG2ISBXho+Q=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.22 h1:qHfXn1Tm2Rh8kic/DvdKaiSVlHQRSr5C+rMuBR29D44=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.22/go.mod h1:D4ytxJbGXu82l+2XF0q60bibysf+KkIbWfAOldAQwf8=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.7 h1:6MSlRo7aiUVBftQ8XmW7XIh3EZqCbkN9zI0YlGW8nl0=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.7/go.mod h1:OqapjZfp6VW4YJKKO4l68UdPvS4FIEYuEoq1JNkxCL0=
+github.com/aws/aws-sdk-go-v2/service/kms v1.61.4 h1:vW7497x7W6ucLJAqDt96jIdO4+IWLMB3p98UubwjdqM=
+github.com/aws/aws-sdk-go-v2/service/kms v1.61.4/go.mod h1:Vz59N7x42VGLXZ5dGL9b10QhrU4GQv7MqnO7wc8bl9U=
+github.com/aws/aws-sdk-go-v2/service/signin v1.10.5 h1:oFsZ3u5PPFSO1YZDGKFgyDuwgpbv/sTmVShEZfRnyaE=
+github.com/aws/aws-sdk-go-v2/service/signin v1.10.5/go.mod h1:P+IzYJeldxO0mHt8fX4cglzexP3akO94C/UuEA2ojP0=
+github.com/aws/aws-sdk-go-v2/service/sso v1.38.5 h1:EYD6E6CsgRQPazaOfZ6suyTgfZjg07HoT4S3qB9Exkg=
+github.com/aws/aws-sdk-go-v2/service/sso v1.38.5/go.mod h1:hHg7OZNN1/U62f3Q5mebJYKO4f97vZC+s0fNAsPLnMk=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.5 h1:v6V0AnJ0aDmivAIie/6iT7sGpjnNmzaAdxZwZ0dhwqI=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.5/go.mod h1:P2Lqn27Kph9z400MFOYIebFnKjZEwyUIAva6fFFMiRY=
+github.com/aws/aws-sdk-go-v2/service/sts v1.51.5 h1:OuyNaMncYP4ftrvcnOHJ9j3AxO3zsC5C/ewD0HoHdjQ=
+github.com/aws/aws-sdk-go-v2/service/sts v1.51.5/go.mod h1:Bhu66tgvf94uunUSiAc0Ew0avhnpSm0J8Hl1MYocRbo=
+github.com/aws/smithy-go v1.28.6 h1:Pj+/sUviNYjow8ELRtNwKHZ9ECeF+7pATX3+shjLIrw=
+github.com/aws/smithy-go v1.28.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aws/smithy-go/aws-http-auth v1.2.1 h1:uRP2q0BGnhpE1/8iriH3yHVMCg6nhFNaVCDvKYPQVmQ=
github.com/aws/smithy-go/aws-http-auth v1.2.1/go.mod h1:KL46VTjVK9De3jurMqDLBkXCP9vrAvD03zQrmyzyrQ0=
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0 h1:JFWXO6QPihCknDdnL6VaQE57km4ZKheHIGd9YiOGcTo=
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0/go.mod h1:046/oLyFlYdAghYQE2yHXi/E//VM5Cf3/dFmA+3CZ0c=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
-github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
-github.com/buildkite/agent/v3 v3.118.0 h1:wZiuvzku7oCzfzwePq7Zw8nPQxQkoEBQwLdI7b9r3CM=
-github.com/buildkite/agent/v3 v3.118.0/go.mod h1:B4+s7ulBypyMmga4X8WrQmosF20UFpTIUt8au9seRGQ=
-github.com/buildkite/go-pipeline v0.16.0 h1:wEgWUMRAgSg1ZnWOoA3AovtYYdTvN0dLY1zwUWmPP+4=
-github.com/buildkite/go-pipeline v0.16.0/go.mod h1:VE37qY3X5pmAKKUMoDZvPsHOQuyakB9cmXj9Qn6QasA=
+github.com/buildkite/agent/v3 v3.130.0 h1:fYo5iTrYAK6OTBWBoF7M627tnCKhZaRTD+Ex186dJZ0=
+github.com/buildkite/agent/v3 v3.130.0/go.mod h1:vdR/SLbzWakWhK4wQO7SRW1YrMGQvP+5ARNXgVXw0LE=
+github.com/buildkite/go-pipeline v0.17.1 h1:m7+a2SF9hLjqsbe6HShmzm9M4rDk4QtanKTF2LD6LG0=
+github.com/buildkite/go-pipeline v0.17.1/go.mod h1:VE37qY3X5pmAKKUMoDZvPsHOQuyakB9cmXj9Qn6QasA=
github.com/buildkite/interpolate v0.1.5 h1:v2Ji3voik69UZlbfoqzx+qfcsOKLA61nHdU79VV+tPU=
github.com/buildkite/interpolate v0.1.5/go.mod h1:dHnrwHew5O8VNOAgMDpwRlFnhL5VSN6M1bHVmRZ9Ccc=
github.com/buildkite/roko v1.4.0 h1:DxixoCdpNqxu4/1lXrXbfsKbJSd7r1qoxtef/TT2J80=
github.com/buildkite/roko v1.4.0/go.mod h1:0vbODqUFEcVf4v2xVXRfZZRsqJVsCCHTG/TBRByGK4E=
-github.com/cenkalti/backoff v1.1.1-0.20171020064038-309aa717adbf h1:yxlp0s+Sge9UsKEK0Bsvjiopb9XRk+vxylmZ9eGBfm8=
+github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
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/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
@@ -286,8 +299,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 h1:foGzavPWwtoyBvjWyKJYDYsyzy+23iBV7NKTwdk+LRY=
github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936/go.mod h1:ttKPnOepYt4LLzD+loXQ1rT6EmpyIYHro7TAJuIIlHo=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc=
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE=
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc=
@@ -299,10 +310,10 @@ github.com/distribution/distribution/v3 v3.1.2 h1:/Bv2YIqqSR00HiO49FT93hovy6r9Il
github.com/distribution/distribution/v3 v3.1.2/go.mod h1:Oz0Drs2Tx3iTXzK3DhUD4otfTfqlCxlWVC7QJeXWBP0=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
-github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
-github.com/docker/cli v29.7.2+incompatible h1:dlkwallR8XqfeVnA2ELEhdwvb4lsSwuB4IgsG8Q9cLY=
-github.com/docker/cli v29.7.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/docker/cli v29.9.2+incompatible h1:trup/vUxx5uUo2t+87Cd9AmITR+DvKUe4H2tTtZN8FY=
+github.com/docker/cli v29.9.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=
github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/go-events v0.0.0-20250808211157-605354379745 h1:yOn6Ze6IbYI/KAw2lw/83ELYvZh6hvsygTVkD0dzMC4=
@@ -315,8 +326,10 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a h1:UwSIFv5g5lIvbGgtf3tVwC7Ky9rmMFBp0RMs+6f6YqE=
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a/go.mod h1:C8DzXehI4zAbrdlbtOByKX6pfivJTBiV9Jjqv56Yd9Q=
-github.com/elazarl/goproxy v1.8.4 h1:tIHKhYHXf8gQracfoHl8Zy7PG/jhvmIMUR5j8OlPUIM=
-github.com/elazarl/goproxy v1.8.4/go.mod h1:b5xm6W48AUHNpRTCvlnd0YVh+JafCCtsLsJZvvNTz+E=
+github.com/eclipse-keypont/crypto11 v1.6.8 h1:4OE1GSUYFWbZb27S2+Glj6bQpiPND5BfnPIFxOCIkKU=
+github.com/eclipse-keypont/crypto11 v1.6.8/go.mod h1:NIBgfiTuqvCyaktz22yE33PB4Aa0dU0M2Uf6QUTfDFk=
+github.com/elazarl/goproxy v1.9.2 h1:+vXRRSWrznMtBrAb559qfqC+Cny1Q3rR0l51Yu/3WUw=
+github.com/elazarl/goproxy v1.9.2/go.mod h1:THdE5ix2clxX9lZzcICPpZ67d6CdrPZxdOYsNgU5e30=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@@ -350,42 +363,46 @@ github.com/fluxcd/gitkit v0.6.0 h1:iNg5LTx6ePo+Pl0ZwqHTAkhbUHxGVSY3YCxCdw7VIFg=
github.com/fluxcd/gitkit v0.6.0/go.mod h1:svOHuKi0fO9HoawdK4HfHAJJseZDHHjk7I3ihnCIqNo=
github.com/fluxcd/pkg/apis/acl v0.12.0 h1:UWpZDqKxpKDW38wdXIMHV8Uv3POPu2vUrra0JH1frH0=
github.com/fluxcd/pkg/apis/acl v0.12.0/go.mod h1:PJrGIu5Bw/6/siO95uhS+pi5oKSU+gVJqHqsPHb8Kok=
+github.com/fluxcd/pkg/apis/crypto v0.5.0 h1:buy9YCvrD8IpKqOVCSV9k2wlF2iVPaETLOZBqsbyfVs=
+github.com/fluxcd/pkg/apis/crypto v0.5.0/go.mod h1:bEwkDgBjLXMVJ2BwmVbbj32PkirmNSicabgl2Jvw7Dk=
github.com/fluxcd/pkg/apis/event v0.32.0 h1:3zyjdUspwQN+EQJPlUXwCvCMbeqtB+azlNmeenAcbuE=
github.com/fluxcd/pkg/apis/event v0.32.0/go.mod h1:ALma8dTqo+NbI+z4BawSzt0pAPjetCSNNUSSS/9p0VU=
-github.com/fluxcd/pkg/apis/meta v1.35.0 h1:/k5d7uEFrxkz/hf6JTrdsKBr3UQWVHW2J4G6VSSae/k=
-github.com/fluxcd/pkg/apis/meta v1.35.0/go.mod h1:1MLvK2Xu3UdTKBzg+Q1Oj7H9PHeiKsUB1UW3uwxAwiM=
-github.com/fluxcd/pkg/artifact v0.24.0 h1:j/3JrNDThWRwtkkU9u2N7wOFkSVwZjnMYQWHNG51PEA=
-github.com/fluxcd/pkg/artifact v0.24.0/go.mod h1:D1VCIh95degPgcfOOfVmRDHRqJqgRb2Z+PCCVODcHws=
-github.com/fluxcd/pkg/auth v0.62.0 h1:ZhrkfoLTaH5Q095sNGLZ47zLYw/AHw4nVnPAspGwT/c=
-github.com/fluxcd/pkg/auth v0.62.0/go.mod h1:46lKYjDvx5Q7fsq09ZC1BxXJcstTOfm2X/NFLLFn7wA=
-github.com/fluxcd/pkg/cache v0.17.0 h1:197ST7bSJD2Nw4G01y5cMjtWQpwQsyjpl2ox4MaGeU8=
-github.com/fluxcd/pkg/cache v0.17.0/go.mod h1:OW3fncHhPnPZFZav5FdEa//cyMHSndI0JS+IM69LXOU=
-github.com/fluxcd/pkg/git v0.55.0 h1:jMdW0uAYuzcwIL5rJq5pmDd+jSrgOe6eIOZfdrcAvO8=
-github.com/fluxcd/pkg/git v0.55.0/go.mod h1:s9AK9ZEG9CtAgkcX4QhQphLsaDBTje32tT5V3knpj1I=
-github.com/fluxcd/pkg/gittestserver v0.32.0 h1:y1wbnEaOXpEYqAxGMxcsXZTH6W4QjFyTj6m1d1ytjY0=
-github.com/fluxcd/pkg/gittestserver v0.32.0/go.mod h1:Cp4hpAePUXnSaeESHKitnvORCn+xT4fOKuZljkRBqVo=
-github.com/fluxcd/pkg/helmtestserver v0.44.0 h1:VaJegpUI6KXxGQkiVoMAwzVkvWHNmqdEk77Y74S2vRE=
-github.com/fluxcd/pkg/helmtestserver v0.44.0/go.mod h1:EttjvMWJWNSuQqdpLIlLDSXk1+1mocIJLVKioCk5qlU=
+github.com/fluxcd/pkg/apis/meta v1.38.0 h1:7t6/DuGFAPx2LE4MsRh1jskjnVE6qELKfr/LrfG7KE8=
+github.com/fluxcd/pkg/apis/meta v1.38.0/go.mod h1:lmdugeiZyt6w+DRm8ypkB+nwrzm+saMbqSfZKGBbTOE=
+github.com/fluxcd/pkg/artifact v0.28.0 h1:k6/KjWQtHvLJ+KR2kciXJoL87vE6EuBZuZVzpaN4Uak=
+github.com/fluxcd/pkg/artifact v0.28.0/go.mod h1:h4bURFRXHpl6ASHRgjqyPQJg4mh+8iQVMgM4Nyk1geM=
+github.com/fluxcd/pkg/auth v0.66.0 h1:fNS6cf1WOVxVCdEKfCfDgbEgk2t3kzepaI1IKuiXuYo=
+github.com/fluxcd/pkg/auth v0.66.0/go.mod h1:eD0iXDzt4BCHVNoBoDkYCsD3+LD39WN/r1qaqsgPJWk=
+github.com/fluxcd/pkg/cache v0.19.0 h1:gcpASwfXLkaHTq8dv9AkXD+IvD54IfskRwGv3SDwC+E=
+github.com/fluxcd/pkg/cache v0.19.0/go.mod h1:HYfYegfUsGBIttmTDZDFa0xmbeba4wPyND1YKitXm0w=
+github.com/fluxcd/pkg/git v0.56.0 h1:DYsgOthnW0FtHAeosvJYQGCa/5PTbWwnDZdML7wt4YI=
+github.com/fluxcd/pkg/git v0.56.0/go.mod h1:C3dgIpk8DXkgAE3tjxzkg/d4f+8DqY6GXmWbEpTBTT4=
+github.com/fluxcd/pkg/gittestserver v0.33.0 h1:/MKs5Yf3w4BR91fJ4hH6W3E+saQYPDB3toViyDpQXpA=
+github.com/fluxcd/pkg/gittestserver v0.33.0/go.mod h1:l6PPC/CuAbHn1YHniEulzbU/UWuHHQQegJmWzuz/sz0=
+github.com/fluxcd/pkg/helmtestserver v0.45.0 h1:erSSj767Z3+LX1oq8Fuu1ybO1da0alg4PiIKW43yc3I=
+github.com/fluxcd/pkg/helmtestserver v0.45.0/go.mod h1:Rc+VEXsTqfmcluj2IIVkujsOFaHxZ49leVBvr46/Rso=
github.com/fluxcd/pkg/http/transport v0.9.0 h1:kDnqhfHNzSu5rfohC/saE97yS+Ubx1ASvUPMw97AhTI=
github.com/fluxcd/pkg/http/transport v0.9.0/go.mod h1:6x2keN0cT/4s2DNpYjibEZTcBvRhE9B9ZXvmQCHmABE=
github.com/fluxcd/pkg/lockedfile v0.9.0 h1:bjm/kUjYpdMBBz/5Hw0nTSLwsZwrithTrH8gMyZjbzI=
github.com/fluxcd/pkg/lockedfile v0.9.0/go.mod h1:xtSyl0R6g01ItVGOTRqzjPZTXqFwCvkQTuWA52oudQg=
github.com/fluxcd/pkg/masktoken v0.10.0 h1:jY9tuBIS1T7z9F8nJc9ozT0QrI391Se9vMu0eMd/wvE=
github.com/fluxcd/pkg/masktoken v0.10.0/go.mod h1:zOCZp3trYmD5/csLOizvIGTi4gn76nnkTFu+vKOJufo=
-github.com/fluxcd/pkg/oci v0.72.0 h1:nUTGHTd/2qq2yT66anHfXiwE19uJl6VL36zm74iFwbU=
-github.com/fluxcd/pkg/oci v0.72.0/go.mod h1:5ngbB6SDvo6daD29HZtBbC6CcnHxuI+5JJR/YqtZhKM=
-github.com/fluxcd/pkg/runtime v0.119.0 h1:cY2KpQ4WwpQKG+pFToslSIXUjKK8ckHQ7cvPUc/QHiY=
-github.com/fluxcd/pkg/runtime v0.119.0/go.mod h1:7LJFbZPXwl++ATADx6bt63Jh9CverBoXQxbluxPwspw=
-github.com/fluxcd/pkg/sourceignore v0.21.0 h1:p65j81RzXAeL4KJKgbkFRou+xiA0841CUdAsOCSAb5o=
-github.com/fluxcd/pkg/sourceignore v0.21.0/go.mod h1:N9NFuxbEMm+UPtP9t+Oyx5LEs0uHu7W+WVPmdlIbCeY=
-github.com/fluxcd/pkg/ssh v0.28.0 h1:DbqDtvJGKzrSfXfB8Hi9T2mbTnNBodijpRZRfxx59wE=
-github.com/fluxcd/pkg/ssh v0.28.0/go.mod h1:FyaNc49GQcFIHdyZzwmG/9UApGaD5nKXT6CtzWAsaE0=
-github.com/fluxcd/pkg/tar v1.3.0 h1:PbL5jNN5q/F6nXA8aCH+msM75BS6lSnPX2RNd48f8ls=
-github.com/fluxcd/pkg/tar v1.3.0/go.mod h1:CbN3lQVWrYBZ4CwcK7ZzpxA++WiiM1RQHDOtNPJWuno=
+github.com/fluxcd/pkg/oci v0.73.0 h1:3A3jJEpQdR+dgCXDGwmKFYRfx10lvDJPrwHSm4lvbsQ=
+github.com/fluxcd/pkg/oci v0.73.0/go.mod h1:ckLyhq6xOi9kI2csdYwMPfqxU/xf+plJMs3IL598j6c=
+github.com/fluxcd/pkg/runtime v0.122.0 h1:5nT+3PqbRvnzIMBNW6g/lIqsg6B715zaF12J3KnvjJY=
+github.com/fluxcd/pkg/runtime v0.122.0/go.mod h1:46y8/GVMFotQkQxzzePecv7cn09DLbQhq6cl2VQ5l9A=
+github.com/fluxcd/pkg/sourceignore v0.22.0 h1:GFvVgEA8HW4mZL26NFxhry3ZzCA8nR12MQovvZvbXm0=
+github.com/fluxcd/pkg/sourceignore v0.22.0/go.mod h1:rEEyPqhc5u1t0fDkonqzGTKVuGOvp3v33boxg0Uw5VA=
+github.com/fluxcd/pkg/spiffe v0.2.0 h1:UM5USXRkl92nZZov3R5gAfPxnRpudowsCprqPG/GNaA=
+github.com/fluxcd/pkg/spiffe v0.2.0/go.mod h1:zLRMyp/vOwQEGWLhe04qKOBorUuTQvwBKBgpmWwkKQE=
+github.com/fluxcd/pkg/ssh v0.29.0 h1:sw25lljJsA54Lcr1oiw7sBLU1c3vWroZf9uLy87rltg=
+github.com/fluxcd/pkg/ssh v0.29.0/go.mod h1:193HoPaYQ/SJ9zsJZSMwVsQA/XL02ouOwAHj7jekHCw=
+github.com/fluxcd/pkg/tar v1.4.0 h1:E6LKORT7ZBd/1ekX4N/gS9LeKfyLui1lBgne8e5PC8I=
+github.com/fluxcd/pkg/tar v1.4.0/go.mod h1:20lDnHLNj/mgTUA494YWkxldX8zyyFexSKpuipX+6Tk=
github.com/fluxcd/pkg/testserver v0.15.0 h1:6Pao9oK1Cu5ssh9c7QoDnnyfPUtxHbw7gJ+5tSOmkWc=
github.com/fluxcd/pkg/testserver v0.15.0/go.mod h1:uSiItABsGd13YQDkYpIWeV1mww6KEYcH9wk/L4p2PKw=
-github.com/fluxcd/pkg/version v0.19.0 h1:mTTsGs6V8OPlmh46FqsXdjQtPdURmtefnI5hxE6g9/E=
-github.com/fluxcd/pkg/version v0.19.0/go.mod h1:zW3uCyPPNV5Gk3W2IVp5qG0dsBf7oAqIrehL3xnJUSg=
+github.com/fluxcd/pkg/version v0.20.0 h1:uPT60sOPMPd0q3n1Go7dYC1fOjkq8wznwNwZ5vv7AJ0=
+github.com/fluxcd/pkg/version v0.20.0/go.mod h1:n+JDY4+3Wb2NpFF3jWTSEEKvJC97ed+hN+o7QnBCHDA=
github.com/foxcpp/go-mockdns v1.2.0 h1:omK3OrHRD1IWJz1FuFBCFquhXslXoF17OvBS6JPzZF0=
github.com/foxcpp/go-mockdns v1.2.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
@@ -397,14 +414,14 @@ github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx5
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo=
github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
-github.com/gaganhr94/docker-credential-acr v1.0.2 h1:0eMFjVqRUmwINbhFxb5xLTWLJpdNta34TGuInVGtEGk=
-github.com/gaganhr94/docker-credential-acr v1.0.2/go.mod h1:8yd2V0GhCyd17MpMxfAJzcZqldu1ghFmrUV0GS7qcGc=
+github.com/gaganhr94/docker-credential-acr v1.0.3 h1:zIXZrP1sm+Y7Qdk1wBID6u09LJH0sbmdqnOOS9pXItk=
+github.com/gaganhr94/docker-credential-acr v1.0.3/go.mod h1:YsMgIr11zzK6lDE/w89aAfXszmWtmxp4J1V+1GegKOs=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
-github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM=
-github.com/go-chi/chi/v5 v5.3.0/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
+github.com/go-chi/chi/v5 v5.5.0 h1:xdKQ1dJmVJsmgahrXSKhUx8NyVPzpwdlyrrQFpMPJgg=
+github.com/go-chi/chi/v5 v5.5.0/go.mod h1:d1IG7GtKPSjPyBP365PH8sAGVHk3qfB/IhjFNRH1wWM=
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@@ -417,8 +434,8 @@ github.com/go-git/go-git/v5 v5.19.3 h1:qHttbZ+Am7wEjdTpR1XMQ4rl42FK9SIXzZ4o9x7s6
github.com/go-git/go-git/v5 v5.19.3/go.mod h1:Ye4C8dVigkqrv9UsB4NMdSLV4yAIkLiIhW61gcOyhl4=
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
-github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA=
-github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
+github.com/go-jose/go-jose/v4 v4.1.6 h1:sNRkftxFJxwsILiQukqp5z83QBSmntVwmgRY7AqBDO4=
+github.com/go-jose/go-jose/v4 v4.1.6/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU=
github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -428,63 +445,63 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-openapi/analysis v0.25.5 h1:xPYEvTb90o1y0epuiOPAoG4QqahjP3cdp5xNlHeKJRI=
-github.com/go-openapi/analysis v0.25.5/go.mod h1:d3UGtQC5uq5Kqqqis2VH09Km/v3vwsWrYkbp4gdm+Rc=
-github.com/go-openapi/errors v0.22.8 h1:oP7sW7TWc3wFFjrzzj0nI83H2qMBkNjNfSd+XRejk/I=
-github.com/go-openapi/errors v0.22.8/go.mod h1:BuUoHcYrU6E7V9gfj1I5wLQqgtIHnup/alXZ8KdgQ0w=
-github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s=
-github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y=
-github.com/go-openapi/jsonreference v1.0.1 h1:4zJ7AmYDKNmD3aSpfPnFNCFA5E80/xMHUNKgydaLh38=
-github.com/go-openapi/jsonreference v1.0.1/go.mod h1:dYplQXa6p5lXprLcJ8LE2iU7vNpXsAHDQ5ZAgL+Qx3A=
-github.com/go-openapi/loads v0.25.0 h1:74Bc2snfaVlsHzwdQj/3gsA9XJz3daXTJVs+4ZaK7jI=
-github.com/go-openapi/loads v0.25.0/go.mod h1:JFBw4SIB9+PTIFHDfcXuSSy5h6aWzjtUCrPYyx3qWU8=
-github.com/go-openapi/runtime v0.33.0 h1:Dd3Oj2ig+WH8ckK95l0Wn2V8a4bH/UqWPRZVT0vc8yU=
-github.com/go-openapi/runtime v0.33.0/go.mod h1:+rsupH3+TFKqmFysqkmgBOTxpVJV8eV+j9myvvea2Xw=
-github.com/go-openapi/runtime/server-middleware v0.30.0 h1:8rPoJ/xv7JL8BsovaqboKETlpWBArVh8n+0L/GyePog=
-github.com/go-openapi/runtime/server-middleware v0.30.0/go.mod h1:OYNT/TxNvB/VK5oe4htM2jDTwlEXuejVJmu0DVZfAMs=
-github.com/go-openapi/spec v0.22.9 h1:/vKIFDcGKp0ktZWGbym/tJEWbk6/XOEmAVU0kqKMH+w=
-github.com/go-openapi/spec v0.22.9/go.mod h1:b/mNUYIOQOyIiUzUzXEE8xzyZqf93KvM9hQGP91yfl0=
-github.com/go-openapi/strfmt v0.27.0 h1:kbcTeaD9TXuXD0hhMXzuYa1sdTo6+dWGvwjW93E80IM=
-github.com/go-openapi/strfmt v0.27.0/go.mod h1:s/qhDqfY72irigXUGJmtgid2Rm+3tnz3k8hZaRmvWYc=
-github.com/go-openapi/swag v0.29.1 h1:C6EeWzUwQtcWEhE9eqBdUubGXxhWY4PlzHMLD7kLaiQ=
-github.com/go-openapi/swag v0.29.1/go.mod h1:BzxEXKiPlSXRsRTv1KSBF/BpGKHxA/YciCnr4tv9bvA=
-github.com/go-openapi/swag/cmdutils v0.29.1 h1:3DorPGfUdE80BogKY22EzoHBcHMrkVomZMoV7kS4ANY=
-github.com/go-openapi/swag/cmdutils v0.29.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
-github.com/go-openapi/swag/conv v0.29.1 h1:AC4Eh/5c/eUDOUCzzsRC9ghmFgOSBHeRMGIngY0ZUGA=
-github.com/go-openapi/swag/conv v0.29.1/go.mod h1:S1X7/ZrBEZOC0Wc8AGxjbcGS92l3WEjA7aPtpl+RaqM=
-github.com/go-openapi/swag/fileutils v0.29.1 h1:ZcPzMceVhU1WPbK6N1G6sNQKdd1CWJlf3cA08UHuoM0=
-github.com/go-openapi/swag/fileutils v0.29.1/go.mod h1:/wofKYckbtRl2p3+EwQsosie5CT1B38+dQ+PS579BzI=
-github.com/go-openapi/swag/jsonutils v0.29.1 h1:AFCxs0eQZ24/QyfhVHM2t49rMz7Vv3XCsZQI6yrNy+c=
-github.com/go-openapi/swag/jsonutils v0.29.1/go.mod h1:u3+sCfJpttDpcmS5kpm0yxL6GK0eWgODsx8Yw8fcqNM=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.1 h1:BiiXE31Bx9SfpsMmOQj5KYpUhTZBpLVriVhJDuLuY2o=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.1/go.mod h1:julgTUKZ9/D0j6O7GKajmRs+812FWxQg/mMpGunWSjg=
-github.com/go-openapi/swag/loading v0.29.1 h1:FCv5fG8UhTdDJa2R7w+5O9Ekpcbw7tt0nFWvmDKGBjc=
-github.com/go-openapi/swag/loading v0.29.1/go.mod h1:N0ESuem4p2oedKal8EJhciqnJ9Q9Wmt83L1CRB3Fouw=
-github.com/go-openapi/swag/mangling v0.29.1 h1:lHALtvYCdxVnRl4GrHmFPwfBTZYIObqdGNSKyu/8D6I=
-github.com/go-openapi/swag/mangling v0.29.1/go.mod h1:SAop9pB7PUjQ/CGCNf/JmCKTRK+GDO+RqE9UHqC/N6s=
-github.com/go-openapi/swag/netutils v0.29.1 h1:IjIvdEP5duKcghFqJEPSUraRnkKYHoM65kTluTu+Jb4=
-github.com/go-openapi/swag/netutils v0.29.1/go.mod h1:DUde7x4Bx00k5jYl2AdRpNAO0m7atUvD2x6X+bWkbno=
-github.com/go-openapi/swag/pools v0.29.1 h1:NRogYxdEW9SjRM4mkAOji9iefO4MRXq3p/ZJcoQbUKg=
-github.com/go-openapi/swag/pools v0.29.1/go.mod h1:leDcaghjkRAhCuCRv9NfJU5f0mjoU3cT/XZObhMk3pc=
-github.com/go-openapi/swag/stringutils v0.29.1 h1:1ykunK7iJQk1uOO7+oUH1ukbsK85fFCOiCFMOVSY+F0=
-github.com/go-openapi/swag/stringutils v0.29.1/go.mod h1:7fSqZ+z8Qc0tOfAAK0jVa5qFGrnIlRi6n7NeGGrr1vc=
-github.com/go-openapi/swag/typeutils v0.29.1 h1:Nzv9nhnlLCRBPQqfOX+7lB6Guju370or8StT+lIOf6M=
-github.com/go-openapi/swag/typeutils v0.29.1/go.mod h1:hxpgDZJVBkBsi/d3MIUosafoFdE5exaQRmVp0zwu3YE=
-github.com/go-openapi/swag/yamlutils v0.29.1 h1:69w3tsBajm7MR/fejLy7HD/3J68Ys1SeeZMEzZ3w2sk=
-github.com/go-openapi/swag/yamlutils v0.29.1/go.mod h1:rgsp3vT/QdWzKwn43CigDwjOGIenPyTZMKnxEM8jZOA=
-github.com/go-openapi/testify/enable/yaml/v2 v2.6.1 h1:Jm+/ze2rMtbD98yen92AhATGLGREDYXG56Xr4gMjEtE=
-github.com/go-openapi/testify/enable/yaml/v2 v2.6.1/go.mod h1:YDPnwCRDu38/oJBVMBVXOUDiJ9cIeBHWvfImHaXqnv4=
-github.com/go-openapi/testify/v2 v2.6.1 h1:6CNJhTjMzgaeaH8WhshcsZNPIvRemiOcFpU7seO/y7Q=
-github.com/go-openapi/testify/v2 v2.6.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
-github.com/go-openapi/validate v0.26.1 h1:pZSbvtRO8G2R2FpWTYRn3w8LrsNwbtaVhP2dWiBa0Us=
-github.com/go-openapi/validate v0.26.1/go.mod h1:B8UMgXiQiwwQWIbmuROlwJZDPGlikPuh7iHV1vPX9Oo=
+github.com/go-openapi/analysis v1.0.0 h1:sNvbAGCJqUTqIAodr9IVqJMmuZas3YS9ms1dGK9yiJ4=
+github.com/go-openapi/analysis v1.0.0/go.mod h1:NhYjJ57fnE+bcE7UwrJyMkhWA3Dfz7TdiBfTVAnos4Y=
+github.com/go-openapi/errors v0.22.9 h1:HI9+SyVYiRzyeBQGv0CbWbQa+u2S0nny7G7AhY+UMiM=
+github.com/go-openapi/errors v0.22.9/go.mod h1:R73q66sXP2smzAGgFOI4nqtusRK2xN5pYCjsij+KX58=
+github.com/go-openapi/jsonpointer v1.0.1 h1:2KxywRmNwJkT/FMBa3iRNHEaAxSJvjqoufQZy3au1Mg=
+github.com/go-openapi/jsonpointer v1.0.1/go.mod h1:wI7ZYsFmbIi9nBXOZqgDaS/bqOchRGZjqxFli7FBYxY=
+github.com/go-openapi/jsonreference v1.0.2 h1:oS4et8FOf3p3UQxEo4Xt0esijmBUM+F259Xl72OSZsc=
+github.com/go-openapi/jsonreference v1.0.2/go.mod h1:TbUNSOo+fcorZjFaNoiSDSoaNnnZtqJtLGR1PuvE/Cs=
+github.com/go-openapi/loads v0.25.3 h1:V+jKy/thXWdLJUuYC8sZX2dICyAa8M3DokF70jj34P0=
+github.com/go-openapi/loads v0.25.3/go.mod h1:LgLyCSOLBL2Qnj0Ps1oo2YH8jZoEKsMeVZCc+ALIxFo=
+github.com/go-openapi/runtime v0.33.3 h1:qVgTDaFH+pzO8UqlwYNVmx2DD+nwVK3rB65V29ednD0=
+github.com/go-openapi/runtime v0.33.3/go.mod h1:57crQFXXnCtT68LuAd+NOELX5tSF4ZE1GFW3Z+r/KCk=
+github.com/go-openapi/runtime/server-middleware v0.33.3 h1:Td5UBla/J/KCjlsD0tmZYWQWxnT4gHpfXbueLQv9Umw=
+github.com/go-openapi/runtime/server-middleware v0.33.3/go.mod h1:dopwrwqIqXe4xWtovDZkkXJzYqKw+Ybmy7G/hIDUWKY=
+github.com/go-openapi/spec v1.0.1 h1:lj2vdGpNDcVgwRc6qXdw6qt/KQpCtSa9tnUH6vpDPDk=
+github.com/go-openapi/spec v1.0.1/go.mod h1:M//GWQGtDUAjnP37gE6fInLgaczB+FatoipV3H1fYw8=
+github.com/go-openapi/strfmt v0.27.3 h1:cyf4J5Wjpd6bFpAs44MF8PsbWF/mWXhn82Ck/hgQZgw=
+github.com/go-openapi/strfmt v0.27.3/go.mod h1:Bl+xadPLa3nhBiaCAxNND1vrQfzyEjF0vBrLx96n/4E=
+github.com/go-openapi/swag v0.29.2 h1:9n8frkcsuQRA0INU31VbxNxt1zBaHxrHYGEf5BUjFi4=
+github.com/go-openapi/swag v0.29.2/go.mod h1:RkCiX1gCVXWgLOavDXE3ALJrQ/VO2ziiIzOUs3z10xo=
+github.com/go-openapi/swag/cmdutils v0.29.2 h1:cXEzX/nWCODon251f+1HgL75/R4XXML5IZxgLCWMoro=
+github.com/go-openapi/swag/cmdutils v0.29.2/go.mod h1:XziaSVzYqkDvpWXzASfWajw2YvJrLscq610O2XiyqJw=
+github.com/go-openapi/swag/conv v0.29.2 h1:8c9shoB8l0QRSR6ymq1llHdBWDqpIgJfjTGHx3Vuhm0=
+github.com/go-openapi/swag/conv v0.29.2/go.mod h1:AZS0YigTNf8qNtD6WqJz/N4RUNmpr76SyjFGkq4+p6Q=
+github.com/go-openapi/swag/fileutils v0.29.2 h1:mdUL+Vw5ah1fO1AvFCoHeIyv7YZsCz2MN3KNqd/lLVI=
+github.com/go-openapi/swag/fileutils v0.29.2/go.mod h1:7QKmmodjAebaq61lGVJa8ldLdGeMF4DSgYv8tXOGGo0=
+github.com/go-openapi/swag/jsonutils v0.29.2 h1:uZNSD2/rJDYAfvsLYkykTzXuyxM3QpDKV9jhRHrMu6k=
+github.com/go-openapi/swag/jsonutils v0.29.2/go.mod h1:ONTdNvj3Y+IXRzfa17E+Rgt2ns/qiSOYjIo2K7v2yDs=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2 h1:w+Fd6EBOMGlC74GYGHqCLGyb3Bpams8TtNrgM/SG4jo=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2/go.mod h1:HC2egPORFzbj/gf05Zrfgz8Mgplx3oW7hgGi7pjZVhM=
+github.com/go-openapi/swag/loading v0.29.2 h1:QU1ry24e6r6Shoxe380Nx0X5iKkpRO+hJffsyJ2dVlY=
+github.com/go-openapi/swag/loading v0.29.2/go.mod h1:DqilDjuiJKETecsS4TRopWG1acUDsfqN39ZmQhPu6uI=
+github.com/go-openapi/swag/mangling v0.29.2 h1:ltdo3K0tTP4P6zWhVVWDU9D37/YYBuMJRdZxiS2Dtog=
+github.com/go-openapi/swag/mangling v0.29.2/go.mod h1:RjDi4TnItAenS3cgCXSpIl1kKbjG7il6pnmQVl/8bp8=
+github.com/go-openapi/swag/netutils v0.29.2 h1:dBli6jyUa93sDS/XYWShJzf4+nnVfFKfvY9SLUaUzB8=
+github.com/go-openapi/swag/netutils v0.29.2/go.mod h1:1pM6Xg/Um8E1eps3umWl8Hme3ByWXOtHsvFC0CULHUE=
+github.com/go-openapi/swag/pools v0.29.2 h1:PlGoDRF8WtSyXkedZZkpW3f9wDhFf3u8KtaBcmgmh8c=
+github.com/go-openapi/swag/pools v0.29.2/go.mod h1:V3lhxVT4qDYRqc2MRSSbLsTYIYV/2HlHafhyEkmzLIc=
+github.com/go-openapi/swag/stringutils v0.29.2 h1:lcnBxwAaysT3bMUVBfn9V/PkfVqkurpqufKU6rTUMGk=
+github.com/go-openapi/swag/stringutils v0.29.2/go.mod h1:i9cdh7sGaa0nm3CqIvH5IM5h2QClk1wns2ktKeILvRI=
+github.com/go-openapi/swag/typeutils v0.29.2 h1:O7aVvkTs3pXwikgtrPLenigEMdQFgONKRooQA9pgf2I=
+github.com/go-openapi/swag/typeutils v0.29.2/go.mod h1:7+GDG+uz9Ke+eVt4rClZg7wklSDp8hT/mKNh/pC26TE=
+github.com/go-openapi/swag/yamlutils v0.29.2 h1:IFKFFeDnuIwzfsuWRQU+rI8iL3g4XyAYjV/RlnlxPLM=
+github.com/go-openapi/swag/yamlutils v0.29.2/go.mod h1:7MGqtcrK73sxQ4ceiyIf8qiXS/s09JLMdR5esK5euYQ=
+github.com/go-openapi/testify/enable/yaml/v2 v2.8.0 h1:dvOQNZ2ovOdogn902NYq7i6jUI9Dma4qyjTXABY5YTY=
+github.com/go-openapi/testify/enable/yaml/v2 v2.8.0/go.mod h1:3VwZZUT6nWcAjhIr2RypXxlsxd3mPPtXh3T8z65aRlQ=
+github.com/go-openapi/testify/v2 v2.8.0 h1:19QDx5b57p8KjO2E4sgs/woL4Akp+FGLRlVm2xn0Rho=
+github.com/go-openapi/testify/v2 v2.8.0/go.mod h1:4gUN8jC+RqOE2qjW/vDmfyTvl5BCht4qL7oca0odrak=
+github.com/go-openapi/validate v1.0.0 h1:dFsYCLVUQUL6Vi2lQSexgwmCXDuHe7eWRDhQxkE+xYA=
+github.com/go-openapi/validate v1.0.0/go.mod h1:wwXGRqMQzOZ7PCqBcgNk+DD9+Cacnxv7we5T0M/eA3Y=
github.com/go-piv/piv-go/v2 v2.6.0 h1:/Z+uqlv5luC8aqLh/uO05egk23UH4KT/ldvPHXpnKls=
github.com/go-piv/piv-go/v2 v2.6.0/go.mod h1:gcsS2WGbToZk5PwtsCIlCWzV/R+r/wN+Xi+6O6IlU3c=
github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA=
github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
-github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
-github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
+github.com/go-sql-driver/mysql v1.10.1 h1:arlSnNLq6a5yxGxV7qg9lF4j0C+KwD6NbQyKr9QL6ME=
+github.com/go-sql-driver/mysql v1.10.1/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -493,12 +510,16 @@ 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/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4=
+github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
+github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
-github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
-github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
+github.com/gofrs/flock v0.13.1 h1:jjREztyBeSKBZYAC+mgc1laB+xsgy4kYMf3FbKF2UBo=
+github.com/gofrs/flock v0.13.1/go.mod h1:sf4BFiHwnvgxa25DlQoDqXQnwRMEOwqxRq37P6MzzmE=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
@@ -525,12 +546,15 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
+github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/certificate-transparency-go v1.3.3 h1:hq/rSxztSkXN2tx/3jQqF6Xc0O565UQPdHrOWvZwybo=
github.com/google/certificate-transparency-go v1.3.3/go.mod h1:iR17ZgSaXRzSa5qvjFl8TnVD5h8ky2JMVio+dzoKMgA=
+github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=
+github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -543,14 +567,14 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-containerregistry v0.22.1 h1:RZuuSYhTvlDvtsK+NkutoCZ//C0X2ebLK8X8l3ULs84=
github.com/google/go-containerregistry v0.22.1/go.mod h1:bJR35SK8XgisYmhg/FMQ/5RK0S/XrOAqLBV5/LR2XE0=
-github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20260602205845-4b7672c7705a h1:/Q1YXihxN5BQfLnzVr01Z6CARmIxe7B3PfcpZ0wcRk0=
-github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20260602205845-4b7672c7705a/go.mod h1:SUZDppd0UtyRvoL0do5jUQqBUK+trwLQBg4EKF76WdI=
+github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20261013193525-92aac6186bc4 h1:RaBbASFWNjSeFBUCKzbAmyP9sxxmTryISLgMTlBp4bE=
+github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20261013193525-92aac6186bc4/go.mod h1:ADikmEMSYuH3sNMpDIgjc3iw1lLqurwd+iAL2dMN64I=
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20250225234217-098045d5e61f h1:GJRzEBoJv/A/E7JbTekq1Q0jFtAfY7TIxUFAK89Mmic=
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20250225234217-098045d5e61f/go.mod h1:ZT74/OE6eosKneM9/LQItNxIMBV6CI5S46EXAnvkTBI=
-github.com/google/go-github/v73 v73.0.0 h1:aR+Utnh+Y4mMkS+2qLQwcQ/cF9mOTpdwnzlaw//rG24=
-github.com/google/go-github/v73 v73.0.0/go.mod h1:fa6w8+/V+edSU0muqdhCVY7Beh1M8F1IlQPZIANKIYw=
github.com/google/go-github/v87 v87.0.0 h1:9Ck3dcOxWJyfsN8tzdah4YvmqB/7ZsstMglv/PkOsl0=
github.com/google/go-github/v87 v87.0.0/go.mod h1:hGUoT5pwm/ck5uLL+wroSVQfg8mpe+buxllCcGV4VaM=
+github.com/google/go-github/v88 v88.0.0 h1:dZA9IKkPK1eXZj4ypngnpRj5FwdpTv4whix2PrQMP7M=
+github.com/google/go-github/v88 v88.0.0/go.mod h1:rufTDgn2N45wjhukLTyxmvc9nilSp3mr3Rgtt6b1MPw=
github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -559,19 +583,19 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
-github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
-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/trillian v1.7.3 h1:hziW+vo4czis48tzx2GK5xRBl/ZxBA9B0/UR5avXOro=
-github.com/google/trillian v1.7.3/go.mod h1:qh8iy4x/GvnVXUBd5pK4oncuT1Y9vVYfibQVsR/WpKg=
+github.com/google/pprof v0.0.0-20260604005048-7023385849c0 h1:h1QTMDl6q9wDvDCJVpKQSjgleGFYnd2fOxmg2K+6BGE=
+github.com/google/pprof v0.0.0-20260604005048-7023385849c0/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
+github.com/google/s2a-go v0.1.11 h1:7v1V1TraNGP63WptsAkNqr2w8jgm4vM6A6qx6Lsw9iM=
+github.com/google/s2a-go v0.1.11/go.mod h1:pz4tyvwXvJLLbyrkh6FW1eS2zPUXMaTmyNhYtyP2tNw=
+github.com/google/trillian v1.8.0 h1:AnbjOFFMQyvqpPAARj97CKEXmoSpCy2hZw0T7Y1Y0BA=
+github.com/google/trillian v1.8.0/go.mod h1:E9eOXWvvyzIMLXLBgYmwklSl2RORBqGX1hDJkEoHdRc=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/enterprise-certificate-proxy v0.3.20 h1:t/xL64VUoN69MuMRQuJETqYGOw4Z9mSRJK9epIEtwFk=
-github.com/googleapis/enterprise-certificate-proxy v0.3.20/go.mod h1:L3D/IQExI6LqEjBdXcZQ1WluSgigQmSwBboFstVPM4w=
-github.com/googleapis/gax-go/v2 v2.24.0 h1:myMaPYyF9MecEmvQqMqomIwn9t/4KCZN9qnwsS76wlg=
-github.com/googleapis/gax-go/v2 v2.24.0/go.mod h1:IaTHBDd7NHxSCiu0vEs8pQZu4dGZrWwuSoxCnk16OFM=
+github.com/googleapis/enterprise-certificate-proxy v0.3.23 h1:J+VGF1wjAM2dU2kKUXZxJdDppRLReWP7KWcclfngQhc=
+github.com/googleapis/enterprise-certificate-proxy v0.3.23/go.mod h1:Y8NO/15GNLkrXI3OR5xOFmeU3XLX1sLSdtlXgJ0zmIw=
+github.com/googleapis/gax-go/v2 v2.26.2 h1:ydkmNXxj7bEmmeK5AihkKnWxyOyBR9TDebvp5L5izk8=
+github.com/googleapis/gax-go/v2 v2.26.2/go.mod h1:sMKqnMesnKH+3wiRJROcttA+cJoZoGbZl1vDQ8XYtGk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
@@ -582,12 +606,11 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
-github.com/graph-gophers/graphql-go v1.9.0 h1:yu0ucKHLc5qGpRwLYKIWtr9bOoxovkWasuBrPQwlHls=
-github.com/graph-gophers/graphql-go v1.9.0/go.mod h1:23olKZ7duEvHlF/2ELEoSZaY1aNPfShjP782SOoNTyM=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
-github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.4 h1:9ZJYjPEJpcleIKcqysXOo14NLQYwu23fzmKRFpIjPjc=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.4/go.mod h1:0xydIeg2omQ9DH6zYMP24Kk57793rnLUvP8fwdbFvz8=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 h1:Bd7KaOxzULLxtZ/K5s1aLbWhR0+5RToO65TXHsf3bqQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0/go.mod h1:nN7ts3dFXKtCZWc//yfkpcQNKJABg16/uDVAZpLDalo=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
@@ -615,8 +638,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
-github.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0=
-github.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM=
+github.com/hashicorp/vault/api v1.23.0 h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A=
+github.com/hashicorp/vault/api v1.23.0/go.mod h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko=
github.com/hiddeco/sshsig v0.2.0 h1:gMWllgKCITXdydVkDL+Zro0PU96QI55LwUwebSwNTSw=
github.com/hiddeco/sshsig v0.2.0/go.mod h1:nJc98aGgiH6Yql2doqH4CTBVHexQA40Q+hMMLHP4EqE=
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM=
@@ -633,14 +656,6 @@ github.com/in-toto/in-toto-golang v0.11.0 h1:nfidMYBFx+E0lnmX5KUnN2Pdm8zdNKal1ay
github.com/in-toto/in-toto-golang v0.11.0/go.mod h1:u3PjTnwFKjp5a1YCcw8SJg0G+tMeKfVoWsWeFMDCMtw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
-github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
-github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo=
-github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw=
-github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
-github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
@@ -657,10 +672,8 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY=
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E=
-github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
-github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
-github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=
-github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=
+github.com/jellydator/ttlcache/v3 v3.4.1 h1:bOdXmXiycyK6E6Qjyuj5vl+/vU3SCOoDs8a86NbHjAQ=
+github.com/jellydator/ttlcache/v3 v3.4.1/go.mod h1:j7LO12PNghFg5+0v9budMAT4rDK4JY969jb9vOdOBBk=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -671,12 +684,12 @@ github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRg
github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
-github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
-github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
+github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
-github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
-github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
+github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw=
+github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU=
github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM=
github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -692,33 +705,30 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
-github.com/letsencrypt/boulder v0.20260309.0 h1:kZynrxK3QfqLGx6hhoz+Rfs3hgltJs1p9Mp+4+VwnY0=
-github.com/letsencrypt/boulder v0.20260309.0/go.mod h1:yG8lj8pNPZ8taq3oNdTpfBS+eC74IaEuiewqzVpXiWE=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
-github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
-github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
+github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
+github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
+github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
+github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
-github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
-github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
-github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/miekg/dns v1.1.73 h1:uhT8nJxmTrPJYClxVxTCX+CVn6qnzSiybRk72Z6DgrE=
+github.com/miekg/dns v1.1.73/go.mod h1:RW2Obtfd5NZHvOFe3zYG0W8koWOQtAzyHaLo8vASBuQ=
github.com/miekg/pkcs11 v1.1.2 h1:/VxmeAX5qU6Q3EwafypogwWbYryHFmF2RpkJmw3m4MQ=
github.com/miekg/pkcs11 v1.1.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
-github.com/minio/minio-go/v7 v7.2.1 h1:PfBfwvKB/MmqyN8Vb1G9voWisaM9OrLv+WwOvMwS9Dw=
-github.com/minio/minio-go/v7 v7.2.1/go.mod h1:EU9hENAStx/xXduNdrGO5e4X5vk19NtgB+RIPjZO8o0=
+github.com/minio/minio-go/v7 v7.4.1 h1:PtU/zIOfQRWZ+QydXAZysc+xZYHdG+BBR4Z6TUvy73w=
+github.com/minio/minio-go/v7 v7.4.1/go.mod h1:nQnQi7zTfXR4lREtYXZQWqo5aw0Rqv+ZqCGrTORygRk=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -741,8 +751,10 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
-github.com/mozillazg/docker-credential-acr-helper v0.4.0 h1:Uoh3Z9CcpEDnLiozDx+D7oDgRq7X+R296vAqAumnOcw=
-github.com/mozillazg/docker-credential-acr-helper v0.4.0/go.mod h1:2kiicb3OlPytmlNC9XGkLvVC+f0qTiJw3f/mhmeeQBg=
+github.com/mozillazg/docker-credential-acr-helper v0.4.1 h1:f8MOoueAItLW++oIuyHALHZVQU5RB9yOjgec6HPGFu8=
+github.com/mozillazg/docker-credential-acr-helper v0.4.1/go.mod h1:dZ74CN1sQBbHqsx2LHvqmo+xV18Ml5e3LCGW5hmNQek=
+github.com/mozillazg/docker-credential-acr-helper/pkg/acr v0.2.2 h1:kpucZE0Et2zh2/hObaMV4XqIF/UeZt0cLuD76Y7AYyo=
+github.com/mozillazg/docker-credential-acr-helper/pkg/acr v0.2.2/go.mod h1:VN6/2/Qgpgh9nvVVQfslzVsBv7A3I4WnuYAxNv9mAzE=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
@@ -762,8 +774,8 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
-github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
-github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
+github.com/oklog/ulid/v2 v2.1.2 h1:IEclFb9JNvzYA6MW2SCxbLzcHTVsfqm3PrqGQJH5zec=
+github.com/oklog/ulid/v2 v2.1.2/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/oleiade/reflections v1.1.0 h1:D+I/UsXQB4esMathlt0kkZRJZdUDmhv5zGi/HOwYTWo=
github.com/oleiade/reflections v1.1.0/go.mod h1:mCxx0QseeVCHs5Um5HhJeCKVC7AwS8kO67tky4rdisA=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -778,12 +790,12 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
-github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU=
-github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg=
+github.com/onsi/gomega v1.44.0 h1:eAiGl3Pw5jz5GQdDff0BcxYpAX1JxW8xD7mFUuwNfZQ=
+github.com/onsi/gomega v1.44.0/go.mod h1:e/C2HwaZ1DhvjzXXuFhcR7hY7Sh9pl7MmoWKEjzwcdA=
github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be h1:f2PlhC9pm5sqpBZFvnAoKj+KzXRzbjFMA+TqXfJdgho=
github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/go-digest/blake3 v0.0.0-20250813155314-89707e38ad1a h1:IAncDmJeD90l6+YR1Gf6r0HrmnRmOatzPfUpMS80ZTI=
-github.com/opencontainers/go-digest/blake3 v0.0.0-20250813155314-89707e38ad1a/go.mod h1:kqQaIc6bZstKgnGpL7GD5dWoLKbA6mH1Y9ULjGImBnM=
+github.com/opencontainers/go-digest/blake3 v0.0.0-20261015205711-63db54280247 h1:S7t62qL81QHcqEVKklPO5Epd5YwYIo7+rj6ec6gscsM=
+github.com/opencontainers/go-digest/blake3 v0.0.0-20261015205711-63db54280247/go.mod h1:kqQaIc6bZstKgnGpL7GD5dWoLKbA6mH1Y9ULjGImBnM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
@@ -793,19 +805,22 @@ github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAq
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc=
-github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
+github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
+github.com/phuslu/lru v1.0.18 h1:ioKRYLym7nv6UmaKHXSR0Z8s2KCEra+mcWcn9zXQnlM=
+github.com/phuslu/lru v1.0.18/go.mod h1:ci5hb8dRIa+2I+KcPl4958OWCg09FxwZCP8InU1L1ME=
+github.com/pierrec/lz4/v4 v4.1.28 h1:pPEPwRJ4kybBTfGt28q7lQsRJQHhC08axprdLD5Ppio=
+github.com/pierrec/lz4/v4 v4.1.28/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pjbgf/sha1cd v0.7.0 h1:ZRNPKHj+gfkLBf0KJv/p1Hmz+7bqCT5o311YX0nq+DA=
github.com/pjbgf/sha1cd v0.7.0/go.mod h1:pKR5Li+qTCo+ebqITZfwPlJGoCFCvSO00qxjbNtTUFQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
@@ -815,8 +830,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
-github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU=
-github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE=
+github.com/prometheus/client_golang v1.25.0 h1:cDtW1TcFsMi1RJc8khwCKB4VhzwV04aKqbYtNOXuiK0=
+github.com/prometheus/client_golang v1.25.0/go.mod h1:j2X/4/kaQHLPnmyEU8zjmkndo1T317VpCIQEml8LTKk=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo=
github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM=
@@ -830,10 +845,10 @@ github.com/redis/go-redis/extra/rediscmd/v9 v9.5.3 h1:1/BDligzCa40GTllkDnY3Y5DTH
github.com/redis/go-redis/extra/rediscmd/v9 v9.5.3/go.mod h1:3dZmcLn3Qw6FLlWASn1g4y+YO9ycEFUOM+bhBmzLVKQ=
github.com/redis/go-redis/extra/redisotel/v9 v9.5.3 h1:kuvuJL/+MZIEdvtb/kTBRiRgYaOmx1l+lYJyVdrRUOs=
github.com/redis/go-redis/extra/redisotel/v9 v9.5.3/go.mod h1:7f/FMrf5RRRVHXgfk7CzSVzXHiWeuOQUu2bsVqWoa+g=
-github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
-github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
-github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
-github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
+github.com/redis/go-redis/v9 v9.22.0 h1:laDvpYXTJtZLloinw1fA5Kqd6HAEH2XKxOkG/PDq2F0=
+github.com/redis/go-redis/v9 v9.22.0/go.mod h1:y2g0Wj8rQvuK0ELM+oxSudcLtC09JScs98I/X9gRWY4=
+github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g=
+github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rubenv/sql-migrate v1.8.1 h1:EPNwCvjAowHI3TnZ+4fQu3a915OpnQoPAjTXCGOy2U0=
@@ -846,42 +861,38 @@ github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDc
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
-github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A=
-github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk=
-github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4=
-github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k=
-github.com/secure-systems-lab/go-securesystemslib v0.11.0 h1:iuCR9kcMFD4QurdKrGvPLoKZLv9YvwPYVr0473BdtFs=
-github.com/secure-systems-lab/go-securesystemslib v0.11.0/go.mod h1:+PMOTjUGwHj2vcZ+TFKlb1tXRbrdWE1LYDT5i9JC80Q=
+github.com/sassoftware/relic/v8 v8.2.0 h1:9/L4S4I6an/JsPNhmcTpqfiOIsLb/iJaePZD1xR+ulE=
+github.com/sassoftware/relic/v8 v8.2.0/go.mod h1:pZy7hLT9WCOKPonV8G/fplvtBLOZd6/kWtKqeHR6nKc=
+github.com/secure-systems-lab/go-securesystemslib v0.11.1 h1:ayahDPjfSIqKegyt5YVGEvQ7SAi72GHXTy+b2YjUd5w=
+github.com/secure-systems-lab/go-securesystemslib v0.11.1/go.mod h1:UyOjhoZLi76ir63u1ptubEevVe6dlNPmNxwgVvKqFFY=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
-github.com/sigstore/cosign/v3 v3.0.6 h1:k8XaUd9pmLknHBst/v0rUGHVdB4D9cfaBmWUaMAOocE=
-github.com/sigstore/cosign/v3 v3.0.6/go.mod h1:ckLRkVecfUCYxL8isHODY9lwyKmDaRCPn00p6yFxHg0=
-github.com/sigstore/fulcio v1.8.6 h1:vkvRpdhVAZjZHa0ltiJeLSILG9U8ADJoe5Z+RdZSLJk=
-github.com/sigstore/fulcio v1.8.6/go.mod h1:7RwoGdMM0xpc9qc382sjSw7P9OLKbKIwQZXvYz4JPb4=
-github.com/sigstore/protobuf-specs v0.5.1 h1:/5OPaNuolRJmQfeZLayJGFXMpsRJEdgC6ah1/+7Px7U=
-github.com/sigstore/protobuf-specs v0.5.1/go.mod h1:DRBzpFuE+LnvQMN10/dU6nBeKwVLGEQ6o2FovN2Rats=
-github.com/sigstore/rekor v1.5.2 h1:k6pX4o1zFAzAvDbXiVIp5IHj1b0wcDaxsbsbNpuRO8o=
-github.com/sigstore/rekor v1.5.2/go.mod h1:WkMnITBccOFauPkT6yte74tF5gC83pefKRGZvNOsbjI=
-github.com/sigstore/rekor-tiles/v2 v2.2.2-0.20260601073857-5d098a2b6443 h1:/CO8F6m3Bo/f59bZo5dv1sTIfUnQqVnepIdDV24KoDw=
-github.com/sigstore/rekor-tiles/v2 v2.2.2-0.20260601073857-5d098a2b6443/go.mod h1:w1h8wF8vq9lHjmtRdwJiEaoVxhP+WHIMpj4M39pkzp0=
-github.com/sigstore/sigstore v1.10.8 h1:1Mgkxvkw4AXMfIP1DOjc6kw0GkUgA8pGVpveN/EfOq4=
-github.com/sigstore/sigstore v1.10.8/go.mod h1:f9+B/4iaYimvUkySyb2mvc73n3RLqNn24grHZM/ET8M=
-github.com/sigstore/sigstore-go v1.2.1 h1:YWP/rDbBaEBvtbkj6xtwsSj38ZCFEhTVVadNOXjVe3A=
-github.com/sigstore/sigstore-go v1.2.1/go.mod h1:I8BqVwAb/SaQJ5pBu5IDFY+ksq8O/1/kCag8XUgrsko=
-github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.8 h1:tofVQ+UWJgad/69I5zbqxdFCN5gpIn9tRQP7iBzIpBw=
-github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.8/go.mod h1:73AfJE8H6w5KGCFPBu4x/OG+i1Yxgmh0L/FtV7prd88=
-github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.8 h1:8Mt7J36GcUEmbiJaiFhz2tud5ZIgkfVVCe2H/WJCHmw=
-github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.8/go.mod h1:YiTpAsxoWXhF9KlLOVWCh7BckN5cYO8X01WufDq1ido=
-github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.8 h1:MxpAIMZVzn0Tpbarc9ax1I498oQBp7oYSMgoMSsOmKI=
-github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.8/go.mod h1:bnAUEkFNam6STvkVZhptVwWzWR5pS24CEtQ+lhxu7S0=
-github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.8 h1:1DGe4/clcdOnkz5MINEczWlmEvjUtZd+AjPPT/cBhQ8=
-github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.8/go.mod h1:6IDFhpgxtzqbnzrFkyegbj7RfWwKeRrb3/+xAD1Wp+Y=
-github.com/sigstore/timestamp-authority/v2 v2.1.2 h1:7DDhnknLL4w8VwomyvW2W8qblOS9LDR8oihna+jc7Ls=
-github.com/sigstore/timestamp-authority/v2 v2.1.2/go.mod h1:o6rAVZceFyejClIj/uStRNIemP16bVMZtbMmhk6pr0U=
+github.com/sigstore/cosign/v3 v3.1.4 h1:d3UHS8oJebMf6XUhPtWv9weU1ZYRyXq9HJ7QPccmqvY=
+github.com/sigstore/cosign/v3 v3.1.4/go.mod h1:ZKgAdeS65uMLm3uoY8TiQGdzA8BoKYBSEIo2DEd1/4s=
+github.com/sigstore/protobuf-specs v0.5.2 h1:RSWWUY8QrVTxbYH00jY/jg2e7YnjzrpwP+PeHTMll0E=
+github.com/sigstore/protobuf-specs v0.5.2/go.mod h1:DRBzpFuE+LnvQMN10/dU6nBeKwVLGEQ6o2FovN2Rats=
+github.com/sigstore/rekor v1.5.5 h1:nZKTBT0uRlKaFW4PafFIE7F5H26PInFF2qOlWouKYYA=
+github.com/sigstore/rekor v1.5.5/go.mod h1:A0e/gTyJ5qCQn6/Zz2T0+TE+W3akuaLF5O0HJ4ogjgA=
+github.com/sigstore/rekor-tiles/v2 v2.3.0 h1:HhMgH61UP0t899V8Fjt7pz1YdgOBptbaQdnCF+79cdc=
+github.com/sigstore/rekor-tiles/v2 v2.3.0/go.mod h1:DEFiKSyQ4nF75QRVNdOPaIH3cmvMkO2B6xDZjNYngPc=
+github.com/sigstore/sigstore v1.11.1 h1:kPqGeoOk3IGCJH76ssgX5PKMm8mbHNnM9fhKLDc6M8E=
+github.com/sigstore/sigstore v1.11.1/go.mod h1:0jewOSMygmxdOaBIOhD1teBSIleg7RExQ1baacNrv4A=
+github.com/sigstore/sigstore-go v1.3.0 h1:hnIMHREyCNTYFtOE1o7ae3Axa9B5W5EjUSBJICP2NBE=
+github.com/sigstore/sigstore-go v1.3.0/go.mod h1:AyRQXfpH89py1twjE3kEZxlRersng90GSYqQV9zGJE8=
+github.com/sigstore/sigstore/pkg/signature/kms/aws v1.11.1 h1:Xw+W6YvW/bQ3zSAYK6hsOQplGz/X9yOvCGeQLfkNy4c=
+github.com/sigstore/sigstore/pkg/signature/kms/aws v1.11.1/go.mod h1:agtjJMPuI6q2rBTM0XZiOFsZjlcZnTi7xkBFQt0NISY=
+github.com/sigstore/sigstore/pkg/signature/kms/azure v1.11.1 h1:UfIJOml1Y9uJwTy8cDbP7a6x/0By+fXIV7dyUHvEZlA=
+github.com/sigstore/sigstore/pkg/signature/kms/azure v1.11.1/go.mod h1:xQ5RXq7EDorvH2+1cNQLXQUjXVlhz64q+CZf5Jol8FU=
+github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.11.1 h1:Ab4K/QqBmlmOu5X05qLTeQnPblVqqzrC//F7J/imzoI=
+github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.11.1/go.mod h1:db/U8Hp9wrarN12CE99SdDEef9FCsgyGTD2gaFRfep4=
+github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.11.1 h1:WIgn5z+Wx9ZM8MPTZlMIJ5YXZq36VrcYXFfCCokMqGc=
+github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.11.1/go.mod h1:byZFStGl4JcpWux75DD7gmpYyYjyy2BmkjsJhdSA8UE=
+github.com/sigstore/timestamp-authority/v2 v2.1.5 h1:VryyxIBepZ2ALtvkAAjBf9IF33iI6wX7ifiVWeBVhog=
+github.com/sigstore/timestamp-authority/v2 v2.1.5/go.mod h1:/rLXKc3T8+DtQYGqVNoCw/Z4OOcEe8Y8ED8/dXetaWw=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo=
github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q=
@@ -903,8 +914,8 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
-github.com/spiffe/go-spiffe/v2 v2.7.0 h1:uXe1MflJoHw58wAUvxVlcM7WpKtijWG7I1UidcGh6g4=
-github.com/spiffe/go-spiffe/v2 v2.7.0/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U=
+github.com/spiffe/go-spiffe/v2 v2.9.0 h1:g5qTg3qIP1HXV+GzuyEfSJFVxUCpEP5Ui1OINVJHPB4=
+github.com/spiffe/go-spiffe/v2 v2.9.0/go.mod h1:w2CLWKLMTX/PPYUEUPv3ltH0RXsw5S8suwNF46w9/Aw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -939,20 +950,18 @@ github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gt
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI=
github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug=
-github.com/theupdateframework/go-tuf/v2 v2.4.2-0.20260407074541-7e8f69f906ef h1:jJac5InhEfD0Z46/d5RayZjoavf/se7bPZpOgg8GLrM=
-github.com/theupdateframework/go-tuf/v2 v2.4.2-0.20260407074541-7e8f69f906ef/go.mod h1:cLUSJ2cgR194lNWfp+TJT4P8PX7qGleCXdudqlCMtOE=
+github.com/theupdateframework/go-tuf/v2 v2.4.2 h1:w7976/W8uTwlsegP5nRymlpjPgrwSh+AXUf85is6nJk=
+github.com/theupdateframework/go-tuf/v2 v2.4.2/go.mod h1:JqBrIUnNLAaNq/8GmBcEMFWfAFBbqp/MkJEJseXKbks=
github.com/tink-crypto/tink-go-awskms/v3 v3.0.0 h1:XSohRhCkXAVI0iaCnWB/GS05TEmpnKurQmzaY1jzt3Y=
github.com/tink-crypto/tink-go-awskms/v3 v3.0.0/go.mod h1:+7MXsShLzVbSQ6dI0Pe4JuZM52jD1jQ1itAygd/MDsA=
-github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0=
-github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw=
+github.com/tink-crypto/tink-go-gcpkms/v2 v2.4.0 h1:xpI5pnEQ0erFCS3JmcEl7Blluo8ZieEPNOURqy9uD70=
+github.com/tink-crypto/tink-go-gcpkms/v2 v2.4.0/go.mod h1:wDDAhjfd1t4TjeJCSsmFK7CARPUs/ITi16ZZ8kmAaFQ=
github.com/tink-crypto/tink-go-hcvault/v2 v2.5.0 h1:eXuNqgrcYelxU1MVikOJDP3wTS5lvihM4ntoAbAMfvs=
github.com/tink-crypto/tink-go-hcvault/v2 v2.5.0/go.mod h1:3RhcxAqek6xUlRFmJifvU4CYLZN60KMQdIKqpZAZJG0=
-github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4=
-github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8=
-github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY=
-github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
-github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
-github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
+github.com/tink-crypto/tink-go/v2 v2.9.0 h1:uvjgS1IYDB4zhDK0Zow8ZFB73IjzMAoSqW0JkFnvkrc=
+github.com/tink-crypto/tink-go/v2 v2.9.0/go.mod h1:aNXZeyxjQU9iqAeARRNmbESXUW6Mao1HRCCTY8B1TFM=
+github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ=
+github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
@@ -970,12 +979,12 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
-github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
-github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
+github.com/ysmood/fetchup v0.3.0 h1:UhYz9xnLEVn2ukSuK3KCgcznWpHMdrmbsPpllcylyu8=
+github.com/ysmood/fetchup v0.3.0/go.mod h1:hbysoq65PXL0NQeNzUczNYIKpwpkwFL4LXMDEvIQq9A=
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
-github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q=
-github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg=
+github.com/ysmood/got v0.42.0 h1:CMRoknemO2nkZBpZmRgsWs79UoQz5eDfWmKIAGGFm94=
+github.com/ysmood/got v0.42.0/go.mod h1:uFF8sPWgVvWIGrjASUgtH0AbnU7ipaXGVaFtWdl3yP0=
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=
@@ -986,8 +995,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
-github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s=
-github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI=
+github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs=
+github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
@@ -997,64 +1006,64 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
-gitlab.com/gitlab-org/api/client-go v1.46.0 h1:YxBWFZIFYKcGESCb9fpkwzouo+apyB9pr/XTWzNoL24=
-gitlab.com/gitlab-org/api/client-go v1.46.0/go.mod h1:FtgyU6g2HS5+fMhw6nLK96GBEEBx5MzntOiJWfIaiN8=
+gitlab.com/gitlab-org/api/client-go/v3 v3.13.0 h1:CTUXvcL6OrGjYNafbws5C1lJwlXrxGJHWQGMF+hCdz0=
+gitlab.com/gitlab-org/api/client-go/v3 v3.13.0/go.mod h1:k7uYxRoIeuSqyWZSJfAPZlf0L32OH0lUBImAl4gWUFc=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/contrib/bridges/prometheus v0.70.0 h1:qU2CqTGdlstwoVhu1WfjJJ3z2ntcNjTJO0ksTsFKzPI=
-go.opentelemetry.io/contrib/bridges/prometheus v0.70.0/go.mod h1:Ekh3I2XXfhdWkqbRq4PrivJS4BS/se7Er9ZsbK6YEtQ=
-go.opentelemetry.io/contrib/detectors/gcp v1.44.0 h1:NmLfL734pJhM0JKaYd2Y28+nY9dPRWYAAbxhRCrKXPw=
-go.opentelemetry.io/contrib/detectors/gcp v1.44.0/go.mod h1:tNAsgd8avTGke1+MndXlU5Cru4PQ9Ai/cCNWQv/ZJ/s=
-go.opentelemetry.io/contrib/exporters/autoexport v0.70.0 h1:wpCLEJ/4RHUadR11UOdznbmyyih5/OPYFcsehAh6PYI=
-go.opentelemetry.io/contrib/exporters/autoexport v0.70.0/go.mod h1:x7MbNOwoKV5Hj6uYMXQksHlQdTNOP3hoFPvqWISiu6s=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0 h1:oECp5f+hN7nkwjU/8BxQ/q23bGPb8FIrD839owX222E=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0/go.mod h1:DqEFwLumhzMBDQv9PcWbyoDxHI/4lAk6CM4nJBH39sc=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0 h1:LMuyCAyfalSjDyjdC65nK6N0zoTT63+E/u95X0JovZI=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0/go.mod h1:085m8qbm4hgc8rZWGDEa4vmyyo2c3nPxUslYUKUIU04=
-go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU=
-go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 h1:WseeVYf5dJZTsyPiyW5L14k5qsSibqXAMTSiFEDiWr0=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0/go.mod h1:SiLZnQS6Qk2eCpvr2CH/XMAOa64TWGXxEZJZCpD2Lmc=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0 h1:fvNHGyo3CdRv/DQveXqhqBxnKTDyRaC5sMSQxilX/A0=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0/go.mod h1:zyGrjRKL2B/6+Jc/m4/otPoZqV2MY9ZjC/aBraRO7zc=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.45.0 h1:klTViGcsvLCd1xN3rZzfZ12NslC/OimbmR+k+A006RI=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.45.0/go.mod h1:jRsK04CWmXuY8A0O+wMpSf+t90RHZ53o5Qmxn2PQPfk=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.45.0 h1:pnxy6c/kvNBWdNNFzqpjuJLm9Hjhgk/Q0nY221rwuk0=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.45.0/go.mod h1:qw6YsFapotRwoDhXRZvljzaOvCQB7UfnafEJagpN2TA=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0 h1:QBajQ2SrwQijzHyZbQlPsuIzpl/ll8DY6wPWsajeGcI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0/go.mod h1:08ZQLjrPLQ6R4kAXvuOvODEer5Yh4CoFvll5qB2BCI8=
-go.opentelemetry.io/otel/exporters/prometheus v0.67.0 h1:7IefDa35e6V3NoiqIeLDMDxMFyZDk5qcoC0Ax4cC16E=
-go.opentelemetry.io/otel/exporters/prometheus v0.67.0/go.mod h1:nsPI1awTg5Vmg1YrommL2mVarVGlqc4yXOoKAkPRD0c=
-go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0 h1:2lpf4hnrasYIsUyEXwnTZq5lsxrMm4T2Bwb06IctAZQ=
-go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0/go.mod h1:YWOW6h7jwApz9Pl76ie/izUsSPj0s2MdIlpqbPqaf3U=
-go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.45.0 h1:dm9iyzn6tioYZtwqaiBSU0TSI8Yu/8dTIbfG0+B49DY=
-go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.45.0/go.mod h1:xAvxYjYK28qvt+yu4BYZ/zMmAjwMXINXD6JiMyeB8iI=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0 h1:lsA/S1bxgdbyFGkTj+3meEdJ6ADVU7QoFstV6MXgE68=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0/go.mod h1:L7u+MirGoB1bjeLH66+xDykF4RC8C3RN7lIFpBiewUo=
-go.opentelemetry.io/otel/log v0.21.0 h1:SLsVDGmtyBrdw8/a2Z0bOIxou/+bN4z56GebH7T0LvA=
-go.opentelemetry.io/otel/log v0.21.0/go.mod h1:iReetQrZL9Wyg84cCkOoCmqDHS5RCFfyxC7J+r8fn8g=
-go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M=
-go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s=
-go.opentelemetry.io/otel/metric/x v0.67.0 h1:PcicCNZFkZ4bXfSooXdo3WN7RBOVOtjVdo1wD358Uns=
-go.opentelemetry.io/otel/metric/x v0.67.0/go.mod h1:FBjCWZe6wgcqxcMtjdGiClDKXb2YxxXii0CXftE4QtI=
-go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw=
-go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA=
-go.opentelemetry.io/otel/sdk/log v0.21.0 h1:QsE7XSR0ktQdKmRKGnR+f1ObGF32WG+7MER/P9KgmYc=
-go.opentelemetry.io/otel/sdk/log v0.21.0/go.mod h1:m9mApjCoD2/1QuKCAptjv+BrG9WKOvQLVdNx+iBldTo=
-go.opentelemetry.io/otel/sdk/log/logtest v0.21.0 h1:X+JBBgKlswCGYsmgL0CnoUUtlE//VB345c84jYAYkdQ=
-go.opentelemetry.io/otel/sdk/log/logtest v0.21.0/go.mod h1:HD1575K8e6sIFBBDd5tZB3t9DlMytWXq9FuR+Y4rfjE=
-go.opentelemetry.io/otel/sdk/metric v1.45.0 h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o=
-go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA=
-go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag=
-go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc=
-go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
-go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
-go.step.sm/crypto v0.81.0 h1:e+ouzpNt3Xm4dp7HGXhgYB5y4iFik3vh3phHKWmvugU=
-go.step.sm/crypto v0.81.0/go.mod h1:fsTizqQeASjTXnbv9O00XtRlIuXRkCdoRiJNyXGQujc=
+go.opentelemetry.io/contrib/bridges/prometheus v0.72.0 h1:OUIUu7ovHCEvG4IE5LQd2PNBH2eVYh50w/1ROwHEM7M=
+go.opentelemetry.io/contrib/bridges/prometheus v0.72.0/go.mod h1:pCrnkC07AZ5+h+0A0Z/1GYyqB+xu3A8LaEEhxvv9s6o=
+go.opentelemetry.io/contrib/detectors/gcp v1.45.0 h1:9jR0ZPRok9ryaOQ2Wx8rg5F7Aon59mxrqbVI60/vlBk=
+go.opentelemetry.io/contrib/detectors/gcp v1.45.0/go.mod h1:VSme3o2fvSg5bVg0dRzyHaj4Z5EVhG+g2Fde6LKzmQA=
+go.opentelemetry.io/contrib/exporters/autoexport v0.72.0 h1:TPXrl7vEkmh69tp7dHTpz+Y6AUenFg1Du3Nx3a6dlxY=
+go.opentelemetry.io/contrib/exporters/autoexport v0.72.0/go.mod h1:0jE6K8nsOgeiF53rcEhy71cgakek+XEWi4OPROUqLoI=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 h1:B2h3uqicet1CT2N5TOFhS+Gq++9i0/CLmaxvhmhtP5s=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0/go.mod h1:dylvB+ZiiwMvsDij9O84Uy7SijLgHMX4mbkncds+4Sw=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 h1:LxwW/9ctSCv+QkE/cLR7M91ZIkXNMqJtEMi1vCw9U8s=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0/go.mod h1:tOsftB4SslBwwErVEPaenU2RpThXWPIU8DoJHEC4dyw=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.23.0 h1:5Ek4qQ5XX0PSQfY7lMW3CvcR36yy8YFDfGnYnaku8zE=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.23.0/go.mod h1:NUKIMOKSexQdTmS1pSxOQBDiVes3DHRier2ePsGW/gQ=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.23.0 h1:5WVp40k2fJHuc5BtNTgKk+EugKFT8Eg3lywFfCPI/nE=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.23.0/go.mod h1:59nH0RYCGHRlwt15WyioeSYINBbuObeBpTowPhEKWHY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0 h1:LaLVGJtIzHcvHjVs2OftmKcc+M9mdOqS8vZ1fBD1Yes=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0/go.mod h1:vF6H5sNDuQBJWgSX00iZgbIqk2MZZoVMH0ar5t5bOpw=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0 h1:7kszRN4Ze5GeAkUnBjBSUIunVBMA+mZIG04auueqguM=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0/go.mod h1:CLzakYy8jOdkBfcveCWYkeKJxujcF4xPhh2Z7IfE98U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 h1:julhjPeUH/q/7hinbSdDdqt5h7Zw9YWmRlWRhI0jd54=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0/go.mod h1:Ao2mz688LH/tFf0yMAenidq6k2YNSx6SIY2q6jDACck=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0 h1:UFpxOpYPmMNUtOWhdb+nC1WELIgVf8z9higURrbzYU4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0/go.mod h1:YBGjxe3lt0jtXoEXxGrGhv/jM7oUBUDVK7zhAvNyEjc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0 h1:aXZXsZ012wOgVkqaiQv+Z/d8V0xKjmg70F6m4CE94lc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0/go.mod h1:ziu1gUIJhAaxM3EV1e3Ralk5AAyL1UOYz3lJJ4VSI38=
+go.opentelemetry.io/otel/exporters/prometheus v0.69.0 h1:LQVBTGnHvzrfGJpDoCSVTY7eaLZArvaTSq5l84Skxew=
+go.opentelemetry.io/otel/exporters/prometheus v0.69.0/go.mod h1:moif0nlgj/M16NRT8lDZVt8MC52+EOAJfR8EKRJ8LyU=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.23.0 h1:PW/E9Tw6ZykC88pey0MZY8hKOUeEw+hX6PU+oXA4A9o=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.23.0/go.mod h1:hUw4VNfiOnQ/yzGgy6ZdWVnudXw7iRfImhd6FjXOnvI=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.47.0 h1:ww5DYBpMKcqLdxjWrhGUIh6O+ZfvZUaMk4niVyNQPEQ=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.47.0/go.mod h1:Av5t+Ezx5S/Ks2dsEfWhny+GK+wrZ1K7NZ6aHSWnX3U=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.47.0 h1:N3YQCxjxQ/bMjyc3heladfRm9t9RTksGQH8z4w6yU/0=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.47.0/go.mod h1:Mp8HOFqcaUyypCuGv9IhDdTHnJ56lSudSHMd+pVSCEA=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM=
+go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
+go.opentelemetry.io/otel/sdk/log v1.47.0 h1:W4N/ZfgpkRRnmARnqYoQ6BrWA0mrj8IzVDNLlpmUJZY=
+go.opentelemetry.io/otel/sdk/log v1.47.0/go.mod h1:Wu74Z2EmOKXi2FleSNAb0Hyau2G+r5kubSEMJw5aAMs=
+go.opentelemetry.io/otel/sdk/log/logtest v0.23.0 h1:j3pm42QCrKYYLLkI6OrV1QHFkUfDA6/4EP+Y1PzggLg=
+go.opentelemetry.io/otel/sdk/log/logtest v0.23.0/go.mod h1:zt0gEnuTZgDvqvczHwYswz93eqMaIr6upTTsdV/HUlU=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
+go.opentelemetry.io/proto/otlp v1.11.1 h1:SCrPqH9NE5CmBrOqpjNCiT0X5mGwMyGERXdogfR7Yjw=
+go.opentelemetry.io/proto/otlp v1.11.1/go.mod h1:wq8W4aSf6bOy8RZyESOeQFr9Pu7wydWX/TY4sgvrTPg=
+go.step.sm/crypto v0.91.0 h1:0mN0DwVOvUuh7VbyTnxABZuAkxwak/Grp8Y/b4YaZDU=
+go.step.sm/crypto v0.91.0/go.mod h1:NxxObRBymdbyXLoTCW5Ea6sLxuy5yI/xr9+hSBlbU/Q=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -1078,16 +1087,18 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54=
golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba h1:Ck8QetSgk912qxWLMCKxd0in+aiyBQyDSMae6e/xmpU=
+golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba/go.mod h1:50RgIsmK7OwqzTTeqcSXQW8SswW0o8fRcDxmqGluJ8E=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -1098,8 +1109,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
-golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
+golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg=
+golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1122,11 +1133,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw=
golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI=
@@ -1172,14 +1183,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.16.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA=
golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
@@ -1188,12 +1198,12 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
-golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
-golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.47.0 h1:cpyOwQkr2Nzxe2p6KnrTG7Ei2wtzjsuSjhpXXepZ/BM=
golang.org/x/term v0.47.0/go.mod h1:efAfAuG6RKABvg1ArGebRkvX6LXul14SM67o2e4mUCY=
@@ -1204,15 +1214,15 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.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.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc=
golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s=
-golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
-golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE=
+golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -1237,24 +1247,24 @@ gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
-google.golang.org/api v0.297.0 h1:WktxTsnnx0yZNnsR6j0q6hR21RnnK81FHTOPy/ux4OE=
-google.golang.org/api v0.297.0/go.mod h1:S4m8x0M6OkQpkOzGk1y9JG2sm4fFQrMh6dxzjCTszhE=
+google.golang.org/api v0.308.0 h1:iGb+4qT3nVb3uuIzwor3yP2nyu+rMZr31PvLFiRNJQk=
+google.golang.org/api v0.308.0/go.mod h1:4XMH+b/ZEfuTbK7FnrFRY9c4xfFHVflGTKuy/i5wUmE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d h1:C9v1o0/4quuhOAfmRXA2j+we0PqZIp8traLdeogF3Ms=
google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d/go.mod h1:Wz2wFJntZFmLGo7pLDXZ3wYk5hyc0Mb+SkHhDDXT+lU=
-google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc=
-google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 h1:cYNAzI2sUwhmCcoj9TxvihSrqsxt6uIkj3rDRhSDmW4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA=
+google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc h1:rZHRz0ogq4Pid1IKtA/ivHi8XONVF5tqUQXA2TtgpkE=
+google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:K/n0XLazCJHjD73YuMyNJsN38BPPy1kfFnKxUXaThFU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20261019180522-ce908d29299b h1:6WNWHZk91dp4gZ25642OALkuG1UVNZbwENJD19DnB8k=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20261019180522-ce908d29299b/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
-google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
+google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0=
+google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1276,8 +1286,9 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.67.2 h1:JtOSMb9OuaCZKr7h5D/h6iii14sK0hLbplTc6frx4Ss=
-gopkg.in/ini.v1 v1.67.2/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.3 h1:iM9Lhz5MRSGhHVGGwCuzG9KO8PoirCXj/m/qTmOJJQw=
+gopkg.in/ini.v1 v1.67.3/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
@@ -1292,8 +1303,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
-helm.sh/helm/v4 v4.3.0 h1:wLRTNXzy96ro7waurWMsymlUPaCQOj5nokpJZJNen/w=
-helm.sh/helm/v4 v4.3.0/go.mod h1:p6SMo6BMyg+4H52fJXvRNg1To0a0KGfiPxjVEcHHSk0=
+helm.sh/helm/v4 v4.3.1 h1:UndCoLe9UPmNoL7IvWzaUXveL7T5t/ijoorEmgJdI9g=
+helm.sh/helm/v4 v4.3.1/go.mod h1:Z663D/wNQG1UsG3X7svSEBPvosFVel4SIw4YIMZwmuY=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.37.1 h1:l6N77U7tjwB5L056bgrBTJIEdevac/naBZ3iSvDNfpM=
@@ -1318,8 +1329,8 @@ k8s.io/kubectl v0.37.1 h1:n1VCIntOJiX943uByXCThSZQmE+4v9jGS8S9u94/aHU=
k8s.io/kubectl v0.37.1/go.mod h1:66cc4Bz8PxBTxlrHzBuzXEzGIytAnNasKQPeEcpuaV8=
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE=
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM=
-oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo=
-oras.land/oras-go/v2 v2.6.2/go.mod h1:PlTtg4JTDJkDe8yVHpM2wz7/YDc00GVas+i4jAW2TZ4=
+oras.land/oras-go/v2 v2.6.4 h1:l4uv+UT7QK4Hju+KOEZ/c8iOjq3iZH7cULoRpUnSDAU=
+oras.land/oras-go/v2 v2.6.4/go.mod h1:imXEFiYkTZUVVYkfv/r5GVmWeiLkGtNQA8FU4F/sjKs=
sigs.k8s.io/controller-runtime v0.25.2 h1:bEkK3PVOIVK9X8QWLGVhJgmFc++47vfT6wakSzAOLsQ=
sigs.k8s.io/controller-runtime v0.25.2/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc=
sigs.k8s.io/json v0.0.0-20260909141634-11ed52e25bc5 h1:k9jo7ED/fsfOcz3L1P20P5tjTNtsdQNwMOG2aKzHrl8=
@@ -1330,11 +1341,11 @@ sigs.k8s.io/kustomize/kyaml v0.21.2 h1:1javwStFk7cgOeLU7yJtPmXcgMEhQgC2X0WjFT6U0
sigs.k8s.io/kustomize/kyaml v0.21.2/go.mod h1:zX3qwtuouXd2K1fMiCV0VSFReX06a+CY1rhyf5Dy7hQ=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/release-utils v0.12.4 h1:kuG6WTWGCKx5uUrJwl2uFErOKOw+4Ba8WrPmOQh5J3g=
-sigs.k8s.io/release-utils v0.12.4/go.mod h1:Tc3iM9DVM3W9oJu/6rEI+LnREuhy8lZ7wInQhRBtUoo=
+sigs.k8s.io/release-utils v0.12.5 h1:/Ybntn/M7sK+6XjaH88y3pfx3tpJod3WKiItxoS4igg=
+sigs.k8s.io/release-utils v0.12.5/go.mod h1:rL6dEVB93VNU8Bd3l8tnh98hR9yoqMMn/puxlCU5buw=
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q=
sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
-software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
-software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
+software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M=
+software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
diff --git a/hack/ci/oci-zot-workload-identity-e2e.sh b/hack/ci/oci-zot-workload-identity-e2e.sh
new file mode 100755
index 000000000..e5b71d742
--- /dev/null
+++ b/hack/ci/oci-zot-workload-identity-e2e.sh
@@ -0,0 +1,993 @@
+#!/usr/bin/env bash
+# End-to-end test for OCI registry authentication with Kubernetes ServiceAccount
+# tokens, using Zot's OIDC bearer authentication.
+#
+# It creates a dedicated kind cluster with a ServiceAccount issuer reachable
+# from a Zot container on the kind network, deploys source-controller, and
+# verifies that an OCIRepository using the generic provider authenticates to
+# Zot with a projected ServiceAccount token. It also installs SPIRE with the
+# SPIFFE Broker API and verifies the same using JWT-SVIDs.
+set -euo pipefail
+
+IMG="${IMG:-test/source-controller:latest}"
+ZOT_IMAGE="${ZOT_IMAGE:-ghcr.io/project-zot/zot-linux-amd64:v2.1.22}"
+CLUSTER="${CLUSTER:-zot-oidc}"
+ZOT_CONTAINER="${ZOT_CONTAINER:-zot-oidc}"
+ZOT_PORT="${ZOT_PORT:-5000}"
+ZOT_HOST_PORT="${ZOT_HOST_PORT:-5050}"
+AUDIENCE="zot-registry"
+NS="source-system"
+APP_NS="zot-e2e"
+SA_NAME="zot-puller"
+SA_NAME_B="zot-puller-b"
+WRONG_AUD_SA_NAME="zot-puller-wrong-aud"
+REPO_A="zot-e2e-a"
+REPO_B="zot-e2e-b"
+OCIREPO_A="zot-oidc-a"
+OCIREPO_B="zot-oidc-b"
+REV="test"
+
+# SPIFFE Broker API test setup.
+SPIRE_NAMESPACE="spire"
+SPIRE_TRUST_DOMAIN="example.org"
+SPIRE_SERVER_IMAGE="${SPIRE_SERVER_IMAGE:-ghcr.io/spiffe/spire-server:1.15.5}"
+SPIRE_AGENT_IMAGE="${SPIRE_AGENT_IMAGE:-ghcr.io/spiffe/spire-agent:1.15.5}"
+SPIRE_OIDC_IMAGE="${SPIRE_OIDC_IMAGE:-ghcr.io/spiffe/oidc-discovery-provider:1.15.5}"
+BROKER_SA="default"
+SPIRE_BROKER_ENDPOINT="dns:///spire-broker.spire:8443"
+SPIRE_BROKER_ID="spiffe://${SPIRE_TRUST_DOMAIN}/spire/agent/k8s_psat/broker-cluster/"
+SPIRE_OIDC_ISSUER="http://${CLUSTER}-control-plane:8082"
+JWT_SA_NAME="zot-puller-jwt"
+JWT_SA_NAME_B="zot-puller-jwt-b"
+JWT_OBJ_TYPE="ocirepositories.source.toolkit.fluxcd.io"
+JWT_OCIREPO_A="zot-jwt-a"
+JWT_OCIREPO_B="zot-jwt-b"
+JWT_OCIREPO_A_CROSS="zot-jwt-a-cross"
+JWT_SPIFFE_A="spiffe://${SPIRE_TRUST_DOMAIN}/zot/ocirepositories/${JWT_OCIREPO_A}"
+JWT_SPIFFE_B="spiffe://${SPIRE_TRUST_DOMAIN}/zot/ocirepositories/${JWT_OCIREPO_B}"
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+WORKDIR="$(mktemp -d)"
+CREATED_CLUSTER=false
+
+log() { echo -e "\n\033[1;34m==> $*\033[0m"; }
+info() { echo " $*"; }
+fail() { echo -e "\033[1;31mFAIL: $*\033[0m" >&2; exit 1; }
+
+cleanup() {
+ local code=$?
+ if [ "$code" -ne 0 ]; then
+ log "FAILURE (exit ${code}) — dumping diagnostics"
+ kubectl -n "${NS}" logs deploy/source-controller --tail=120 2>/dev/null || true
+ kubectl -n "${APP_NS}" get ocirepositories -o yaml 2>/dev/null || true
+ docker logs --tail=80 "${ZOT_CONTAINER}" 2>/dev/null || true
+ fi
+ if [ -n "${KEEP:-}" ]; then
+ log "KEEP set — leaving cluster, container and ${WORKDIR} for inspection"
+ exit "${code}"
+ fi
+ log "Cleaning up"
+ docker rm -f "${ZOT_CONTAINER}" >/dev/null 2>&1 || true
+ if [ "${CREATED_CLUSTER}" = "true" ]; then
+ kind delete cluster --name "${CLUSTER}" >/dev/null 2>&1 || true
+ fi
+ rm -rf "${WORKDIR}" 2>/dev/null || sudo rm -rf "${WORKDIR}" 2>/dev/null || true
+ exit "${code}"
+}
+trap cleanup EXIT
+
+require() { command -v "$1" >/dev/null 2>&1 || fail "required tool '$1' not found in PATH"; }
+for bin in docker kind kubectl kustomize flux helm; do require "$bin"; done
+
+start_zot() {
+ local config="$1"
+ docker rm -f "${ZOT_CONTAINER}" >/dev/null 2>&1 || true
+ docker run -d --name "${ZOT_CONTAINER}" --network kind \
+ -p "127.0.0.1:${ZOT_HOST_PORT}:${ZOT_PORT}" \
+ -v "${config}:/etc/zot/config.json:ro" \
+ -v "${WORKDIR}/zot-data:/var/lib/zot" \
+ "${ZOT_IMAGE}" serve /etc/zot/config.json >/dev/null
+
+ local code
+ for _ in $(seq 1 60); do
+ code="$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:${ZOT_HOST_PORT}/v2/" 2>/dev/null || echo 000)"
+ case "${code}" in
+ 200|401) return 0 ;;
+ esac
+ sleep 1
+ done
+ docker logs --tail=80 "${ZOT_CONTAINER}" 2>/dev/null || true
+ fail "Zot did not become ready (last HTTP status: ${code})"
+}
+
+##############################################################################
+log "Creating kind cluster '${CLUSTER}' with an externally reachable issuer"
+##############################################################################
+if kind get clusters 2>/dev/null | grep -qx "${CLUSTER}"; then
+ info "Deleting pre-existing cluster"
+ kind delete cluster --name "${CLUSTER}"
+fi
+cat </dev/null
+kubectl wait --for=condition=Ready nodes --all --timeout=180s
+
+OIDC_ISSUER="https://${CLUSTER}-control-plane:6443"
+info "OIDC issuer: ${OIDC_ISSUER}"
+
+log "Allowing unauthenticated OIDC discovery"
+kubectl create clusterrolebinding oidc-reviewer \
+ --clusterrole=system:service-account-issuer-discovery \
+ --group=system:unauthenticated >/dev/null 2>&1 || true
+
+log "Exporting the kind CA certificate"
+docker cp "${CLUSTER}-control-plane:/etc/kubernetes/pki/ca.crt" "${WORKDIR}/kind-ca.pem"
+mkdir -p "${WORKDIR}/zot-data"
+chmod 0777 "${WORKDIR}/zot-data"
+
+##############################################################################
+log "Seeding Zot with an artifact while authentication is disabled"
+##############################################################################
+cat > "${WORKDIR}/zot-open.json" < "${WORKDIR}/artifact-a/index.txt"
+echo "artifact for ${SA_NAME_B}" > "${WORKDIR}/artifact-b/index.txt"
+flux push artifact "oci://localhost:${ZOT_HOST_PORT}/${REPO_A}:${REV}" \
+ --path="${WORKDIR}/artifact-a" \
+ --source=zot-oidc-e2e-a \
+ --revision="${REV}"
+flux push artifact "oci://localhost:${ZOT_HOST_PORT}/${REPO_B}:${REV}" \
+ --path="${WORKDIR}/artifact-b" \
+ --source=zot-oidc-e2e-b \
+ --revision="${REV}"
+docker rm -f "${ZOT_CONTAINER}" >/dev/null
+
+
+##############################################################################
+log "Installing SPIRE with the SPIFFE Broker API and OIDC discovery"
+##############################################################################
+kubectl create namespace "${SPIRE_NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
+
+kubectl apply -f - >/dev/null </dev/null
+}
+
+create_entry "spiffe://${SPIRE_TRUST_DOMAIN}/oidc-discovery-provider" \
+ -selector "k8s:ns:${SPIRE_NAMESPACE}" \
+ -selector "k8s:sa:spire-agent" \
+ -selector "k8s:container-name:oidc-discovery-provider"
+create_entry "spiffe://${SPIRE_TRUST_DOMAIN}/ns/${NS}/sa/${BROKER_SA}" \
+ -selector "k8s:ns:${NS}" \
+ -selector "k8s:sa:${BROKER_SA}"
+create_entry "${JWT_SPIFFE_A}" \
+ -selector "k8s:resource:${JWT_OBJ_TYPE}" \
+ -selector "k8s:namespace:${APP_NS}" \
+ -selector "k8s:name:${JWT_OCIREPO_A}"
+create_entry "${JWT_SPIFFE_B}" \
+ -selector "k8s:resource:${JWT_OBJ_TYPE}" \
+ -selector "k8s:namespace:${APP_NS}" \
+ -selector "k8s:name:${JWT_OCIREPO_B}"
+
+kubectl apply -f - >/dev/null </dev/null 2>&1 || true
+helm repo update spiffe >/dev/null
+helm upgrade --install spire-csi spiffe/spire \
+ --version "${SPIRE_CHART_VERSION:-0.30.3}" \
+ --namespace "${SPIRE_NAMESPACE}" \
+ --set global.spire.trustDomain="${SPIRE_TRUST_DOMAIN}" \
+ --set global.spire.namespaces.create=false \
+ --set spire-server.enabled=false \
+ --set spire-agent.enabled=false \
+ --set spiffe-csi-driver.enabled=true \
+ --set spiffe-csi-driver.agentSocketPath=/run/spire/agent-sockets/api.sock \
+ --set spiffe-oidc-discovery-provider.enabled=false \
+ --wait --timeout 5m
+kubectl -n "${SPIRE_NAMESPACE}" rollout status daemonset/spire-csi-spiffe-csi-driver --timeout=5m
+
+##############################################################################
+log "Starting Zot with OIDC bearer authentication"
+##############################################################################
+cat > "${WORKDIR}/zot-auth.json" </dev/null
+
+for _ in $(seq 1 60); do
+ code="$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:${ZOT_HOST_PORT}/v2/" 2>/dev/null || echo 000)"
+ [ "${code}" = "401" ] && break
+ sleep 1
+done
+[ "${code}" = "401" ] || fail "Zot did not start with bearer auth (last HTTP status: ${code})"
+
+##############################################################################
+log "Deploying source-controller"
+##############################################################################
+kind load docker-image "${IMG}" --name "${CLUSTER}"
+make -C "${ROOT_DIR}" install >/dev/null
+make -C "${ROOT_DIR}" dev-deploy IMG="${IMG%:*}" TAG="${IMG##*:}" >/dev/null
+kubectl -n "${NS}" patch deploy/source-controller --type=json -p "$(cat </dev/null
+kubectl -n "${NS}" patch deploy/source-controller --type=strategic -p "$(cat </dev/null
+kubectl -n "${NS}" rollout status deploy/source-controller --timeout=2m
+for _ in $(seq 1 30); do
+ logs="$(kubectl -n "${NS}" logs deploy/source-controller)"
+ if grep -qF "object-level workload identity will use the SPIFFE Broker API" <<<"${logs}"; then
+ break
+ fi
+ sleep 1
+done
+grep -qF "object-level workload identity will use the SPIFFE Broker API" <<<"${logs}" \
+ || fail "source-controller did not log SPIFFE Broker API usage"
+
+##############################################################################
+log "Creating ServiceAccounts and OCIRepositories"
+##############################################################################
+kubectl create namespace "${APP_NS}" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
+kubectl -n "${APP_NS}" apply -f - >/dev/null </dev/null </dev/null || true)"
+ msg="$(kubectl -n "${APP_NS}" get "ocirepository/${name}" \
+ -o jsonpath='{.status.conditions[?(@.type=="Ready")].message}' 2>/dev/null || true)"
+ if [ "${status}" = "True" ]; then
+ fail "OCIRepository ${name} unexpectedly succeeded"
+ fi
+ if [ "${status}" = "False" ] && printf '%s' "${msg}" | grep -qiE '401|403|unauthorized|forbidden|denied|authentication|permission|svid|spiffe'; then
+ info "OCIRepository ${name} correctly denied"
+ return 0
+ fi
+ sleep 2
+ done
+ fail "OCIRepository ${name} did not fail in time (status=${status:-unknown}; message=${msg:-})"
+}
+
+log "Verifying cross-ServiceAccount access is denied"
+expect_denied "${OCIREPO_A}-cross"
+expect_denied "${OCIREPO_B}-cross"
+expect_denied "${OCIREPO_A}-wrong-audience"
+expect_denied "${JWT_OCIREPO_A_CROSS}"
+
+log "SUCCESS: each ServiceAccount and JWT-SVID identity accessed only its own repository"
diff --git a/internal/bucket/azure/blob.go b/internal/bucket/azure/blob.go
index ad70acb4e..4bbb9584d 100644
--- a/internal/bucket/azure/blob.go
+++ b/internal/bucket/azure/blob.go
@@ -30,7 +30,6 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
- "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
@@ -259,7 +258,7 @@ func ValidateSecret(secret *corev1.Secret) error {
// exists, or returns a (client) error.
func (c *BlobClient) BucketExists(ctx context.Context, bucketName string) (bool, error) {
items := c.Client.NewListBlobsFlatPager(bucketName, &azblob.ListBlobsFlatOptions{
- MaxResults: to.Ptr(int32(1)),
+ MaxResults: new(int32(1)),
})
// We call next page only once since we just want to see if we get an error
if _, err := items.NextPage(ctx); err != nil {
@@ -311,6 +310,11 @@ func (c *BlobClient) FGetObject(ctx context.Context, bucketName, objectName, loc
if err != nil {
return "", err
}
+ defer func() {
+ if cerr := res.Body.Close(); cerr != nil {
+ ctrl.LoggerFrom(ctx).Error(cerr, "failed to close object reader")
+ }
+ }()
// Prepare target file.
f, err := os.OpenFile(localPath, os.O_CREATE|os.O_WRONLY, 0o600)
@@ -326,8 +330,8 @@ func (c *BlobClient) FGetObject(ctx context.Context, bucketName, objectName, loc
// Off we go.
mw := io.MultiWriter(f, hash)
if _, err = io.Copy(mw, res.Body); err != nil {
- if err = f.Close(); err != nil {
- ctrl.LoggerFrom(ctx).Error(err, "failed to close file after copy error")
+ if cerr := f.Close(); cerr != nil {
+ ctrl.LoggerFrom(ctx).Error(cerr, "failed to close file after copy error")
}
return "", err
}
diff --git a/internal/bucket/azure/blob_test.go b/internal/bucket/azure/blob_test.go
index 21ab3d7d5..36d2189b4 100644
--- a/internal/bucket/azure/blob_test.go
+++ b/internal/bucket/azure/blob_test.go
@@ -25,6 +25,7 @@ import (
"encoding/pem"
"errors"
"fmt"
+ "io"
"math/big"
"net/http"
"net/url"
@@ -669,6 +670,90 @@ func TestBlobClient_FGetObject_MissingEtag(t *testing.T) {
g.Expect(os.ReadFile(localPath)).To(BeEquivalentTo("file contents"))
}
+// A short response body makes io.Copy fail after some bytes are written.
+// Closing that file succeeds, and the close must not replace the copy error.
+func TestBlobClient_FGetObject_CopyError(t *testing.T) {
+ g := NewWithT(t)
+
+ bucketName := "test-bucket"
+ objectName := "file.txt"
+
+ bucketListener, bucketAddr, _ := testlistener.New(t)
+ bucketEndpoint := fmt.Sprintf("http://%s", bucketAddr)
+ bucketHandler := http.NewServeMux()
+ bucketHandler.HandleFunc(fmt.Sprintf("GET /%s/%s", bucketName, objectName), func(w http.ResponseWriter, r *http.Request) {
+ hj, ok := w.(http.Hijacker)
+ g.Expect(ok).To(BeTrue())
+ conn, bufrw, err := hj.Hijack()
+ g.Expect(err).ToNot(HaveOccurred())
+ _, err = bufrw.WriteString("HTTP/1.1 200 OK\r\nContent-Length: 64\r\nETag: \"abc\"\r\n\r\npartial")
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(bufrw.Flush()).To(Succeed())
+ g.Expect(conn.Close()).To(Succeed())
+ })
+ bucketServer := &http.Server{
+ Addr: bucketAddr,
+ Handler: bucketHandler,
+ }
+ go bucketServer.Serve(bucketListener)
+ defer bucketServer.Shutdown(context.Background())
+
+ bucket := &sourcev1.Bucket{
+ Spec: sourcev1.BucketSpec{
+ Endpoint: bucketEndpoint,
+ },
+ }
+ client, err := NewClient(t.Context(),
+ bucket,
+ withoutCredentials(),
+ withoutRetries())
+ g.Expect(err).ToNot(HaveOccurred())
+
+ localPath := filepath.Join(t.TempDir(), objectName)
+ _, err = client.FGetObject(t.Context(), bucketName, objectName, localPath)
+ g.Expect(err).To(HaveOccurred())
+}
+
+// The Get Blob response body must be closed so the connection can be reused.
+func TestBlobClient_FGetObject_ClosesResponseBody(t *testing.T) {
+ g := NewWithT(t)
+
+ bucketName := "test-bucket"
+ objectName := "file.txt"
+
+ bucketListener, bucketAddr, _ := testlistener.New(t)
+ bucketEndpoint := fmt.Sprintf("http://%s", bucketAddr)
+ bucketHandler := http.NewServeMux()
+ bucketHandler.HandleFunc(fmt.Sprintf("GET /%s/%s", bucketName, objectName), func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("ETag", `"abc"`)
+ _, err := w.Write([]byte("file contents"))
+ g.Expect(err).ToNot(HaveOccurred())
+ })
+ bucketServer := &http.Server{
+ Addr: bucketAddr,
+ Handler: bucketHandler,
+ }
+ go bucketServer.Serve(bucketListener)
+ defer bucketServer.Shutdown(context.Background())
+
+ tracker := &bodyCloseTracker{base: http.DefaultTransport}
+ clientOpts := &azblob.ClientOptions{}
+ clientOpts.Transport = &http.Client{Transport: tracker}
+ clientOpts.Retry.ShouldRetry = func(*http.Response, error) bool {
+ return false
+ }
+ raw, err := azblob.NewClientWithNoCredential(bucketEndpoint, clientOpts)
+ g.Expect(err).ToNot(HaveOccurred())
+ client := &BlobClient{Client: raw}
+
+ localPath := filepath.Join(t.TempDir(), objectName)
+ etag, err := client.FGetObject(t.Context(), bucketName, objectName, localPath)
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(etag).To(Equal(`"abc"`))
+ g.Expect(os.ReadFile(localPath)).To(BeEquivalentTo("file contents"))
+ g.Expect(tracker.closed).To(BeTrue())
+}
+
func TestBlobClient_VisitObjects_MissingFields(t *testing.T) {
g := NewWithT(t)
@@ -780,6 +865,32 @@ func Test_extractAccountNameFromEndpoint1(t *testing.T) {
}
}
+// bodyCloseTracker records whether the response body from a blob
+// download was closed.
+type bodyCloseTracker struct {
+ base http.RoundTripper
+ closed bool
+}
+
+func (b *bodyCloseTracker) RoundTrip(req *http.Request) (*http.Response, error) {
+ resp, err := b.base.RoundTrip(req)
+ if err != nil || resp == nil || resp.Body == nil {
+ return resp, err
+ }
+ resp.Body = &closeNotifier{ReadCloser: resp.Body, onClose: func() { b.closed = true }}
+ return resp, nil
+}
+
+type closeNotifier struct {
+ io.ReadCloser
+ onClose func()
+}
+
+func (c *closeNotifier) Close() error {
+ c.onClose()
+ return c.ReadCloser.Close()
+}
+
func endpointURL(accountName string) string {
return fmt.Sprintf("https://%s.blob.core.windows.net", accountName)
}
diff --git a/internal/bucket/gcp/gcp.go b/internal/bucket/gcp/gcp.go
index 7467d5c56..8ccf4f17e 100644
--- a/internal/bucket/gcp/gcp.go
+++ b/internal/bucket/gcp/gcp.go
@@ -282,6 +282,9 @@ func (c *GCSClient) FGetObject(ctx context.Context, bucketName, objectName, loca
GenerationMatch: objAttr.Generation,
}).NewReader(ctx)
if err != nil {
+ if cerr := objectFile.Close(); cerr != nil {
+ ctrl.LoggerFrom(ctx).Error(cerr, "failed to close file after reader error")
+ }
return "", err
}
defer func() {
@@ -292,6 +295,9 @@ func (c *GCSClient) FGetObject(ctx context.Context, bucketName, objectName, loca
// Write Object to file.
if _, err := io.Copy(objectFile, objectReader); err != nil {
+ if cerr := objectFile.Close(); cerr != nil {
+ ctrl.LoggerFrom(ctx).Error(cerr, "failed to close file after copy error")
+ }
return "", err
}
diff --git a/internal/bucket/gcp/gcp_test.go b/internal/bucket/gcp/gcp_test.go
index 296212652..0832fe751 100644
--- a/internal/bucket/gcp/gcp_test.go
+++ b/internal/bucket/gcp/gcp_test.go
@@ -35,7 +35,6 @@ import (
"cloud.google.com/go/compute/metadata"
gcpstorage "cloud.google.com/go/storage"
. "github.com/onsi/gomega"
- "google.golang.org/api/googleapi"
"google.golang.org/api/option"
raw "google.golang.org/api/storage/v1"
corev1 "k8s.io/api/core/v1"
@@ -61,40 +60,32 @@ var (
close func()
err error
secret = corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "gcp-secret",
- Namespace: "default",
- },
+ Name: "gcp-secret",
+ Namespace: "default",
Data: map[string][]byte{
"serviceaccount": []byte(serviceAccountJSON),
},
Type: "Opaque",
}
badSecret = corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "gcp-secret",
- Namespace: "default",
- },
+ Name: "gcp-secret",
+ Namespace: "default",
Data: map[string][]byte{
"username": []byte("test-user"),
},
Type: "Opaque",
}
malformedSecret = corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "gcp-secret",
- Namespace: "default",
- },
+ Name: "gcp-secret",
+ Namespace: "default",
Data: map[string][]byte{
"serviceaccount": []byte("not-json"),
},
Type: "Opaque",
}
externalAccountSecret = corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "gcp-secret",
- Namespace: "default",
- },
+ Name: "gcp-secret",
+ Namespace: "default",
Data: map[string][]byte{
"serviceaccount": []byte(externalAccountJSON),
},
@@ -134,10 +125,8 @@ const externalAccountJSON = `{
// createTestBucket creates a test bucket for testing purposes
func createTestBucket() *sourcev1.Bucket {
return &sourcev1.Bucket{
- ObjectMeta: v1.ObjectMeta{
- Name: "test-bucket",
- Namespace: "default",
- },
+ Name: "test-bucket",
+ Namespace: "default",
Spec: sourcev1.BucketSpec{
BucketName: bucketName,
Endpoint: "storage.googleapis.com",
@@ -293,7 +282,7 @@ func TestNewClientWithProxyErr(t *testing.T) {
bucketAttrs, err := gcpClient.Client.Bucket("some-bucket").Attrs(context.Background())
g.Expect(err).To(HaveOccurred())
g.Expect(bucketAttrs).To(BeNil())
- g.Expect(err.Error()).To(ContainSubstring("failed to create provider access token"))
+ g.Expect(err.Error()).To(ContainSubstring("failed to create provider access credential"))
})
}
@@ -325,7 +314,6 @@ func TestProxy(t *testing.T) {
}
for _, tt := range tests {
- tt := tt
t.Run(tt.name, func(t *testing.T) {
opts := []Option{WithProxyURL(tt.proxyURL)}
opts = append(opts, func(o *options) {
@@ -567,7 +555,7 @@ func getBucket() *raw.Bucket {
},
Condition: &raw.BucketLifecycleRuleCondition{
Age: &age,
- IsLive: googleapi.Bool(true),
+ IsLive: new(true),
CreatedBefore: "2021-01-02",
MatchesStorageClass: matchClasses,
NumNewerVersions: 3,
diff --git a/internal/bucket/minio/minio_test.go b/internal/bucket/minio/minio_test.go
index 8d5878f49..039c7dcab 100644
--- a/internal/bucket/minio/minio_test.go
+++ b/internal/bucket/minio/minio_test.go
@@ -38,7 +38,6 @@ import (
"github.com/minio/minio-go/v7/pkg/credentials"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/sourceignore"
@@ -80,10 +79,8 @@ var (
bucketName = "test-bucket-minio" + uuid.New().String()
prefix = ""
secret = corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "minio-secret",
- Namespace: "default",
- },
+ Name: "minio-secret",
+ Namespace: "default",
Data: map[string][]byte{
"accesskey": []byte(testAccessKey),
"secretkey": []byte(testSecretKey),
@@ -91,18 +88,14 @@ var (
Type: "Opaque",
}
emptySecret = corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "minio-secret",
- Namespace: "default",
- },
- Data: map[string][]byte{},
- Type: "Opaque",
+ Name: "minio-secret",
+ Namespace: "default",
+ Data: map[string][]byte{},
+ Type: "Opaque",
}
bucket = sourcev1.Bucket{
- ObjectMeta: v1.ObjectMeta{
- Name: "minio-test-bucket",
- Namespace: "default",
- },
+ Name: "minio-test-bucket",
+ Namespace: "default",
Spec: sourcev1.BucketSpec{
BucketName: bucketName,
Provider: "generic",
@@ -112,10 +105,8 @@ var (
},
}
bucketAwsProvider = sourcev1.Bucket{
- ObjectMeta: v1.ObjectMeta{
- Name: "minio-test-bucket",
- Namespace: "default",
- },
+ Name: "minio-test-bucket",
+ Namespace: "default",
Spec: sourcev1.BucketSpec{
BucketName: bucketName,
Provider: "aws",
@@ -193,10 +184,8 @@ func TestNewClientEmptySecret(t *testing.T) {
func TestNewClientAWSProvider(t *testing.T) {
t.Run("with secret", func(t *testing.T) {
validSecret := corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: "valid-secret",
- Namespace: "default",
- },
+ Name: "valid-secret",
+ Namespace: "default",
Data: map[string][]byte{
"accesskey": []byte(testAccessKey),
"secretkey": []byte(testSecretKey),
@@ -716,7 +705,7 @@ func TestValidateSTSSecret(t *testing.T) {
{
name: "empty ldap secret",
provider: "ldap",
- secret: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Name: "ldap-secret"}},
+ secret: &corev1.Secret{Name: "ldap-secret"},
err: "invalid 'ldap-secret' secret data for 'ldap' STS provider: required fields username, password",
},
{
diff --git a/internal/cache/cache.go b/internal/cache/cache.go
index 6f8ee8608..beb143396 100644
--- a/internal/cache/cache.go
+++ b/internal/cache/cache.go
@@ -27,7 +27,7 @@ type Cache struct {
// Item is an item stored in the cache.
type Item struct {
// Object is the item's value.
- Object interface{}
+ Object any
// Expiration is the item's expiration time.
Expiration int64
}
@@ -50,7 +50,7 @@ func (c *cache) ItemCount() int {
return n
}
-func (c *cache) set(key string, value interface{}, expiration time.Duration) {
+func (c *cache) set(key string, value any, expiration time.Duration) {
var e int64
if expiration > 0 {
e = time.Now().Add(expiration).UnixNano()
@@ -65,7 +65,7 @@ func (c *cache) set(key string, value interface{}, expiration time.Duration) {
// Set adds an item to the cache, replacing any existing item.
// If expiration is zero, the item never expires.
// If the cache is full, Set will return an error.
-func (c *cache) Set(key string, value interface{}, expiration time.Duration) error {
+func (c *cache) Set(key string, value any, expiration time.Duration) error {
c.mu.Lock()
_, found := c.Items[key]
if found {
@@ -87,7 +87,7 @@ func (c *cache) Set(key string, value interface{}, expiration time.Duration) err
// Add an item to the cache, existing items will not be overwritten.
// To overwrite existing items, use Set.
// If the cache is full, Add will return an error.
-func (c *cache) Add(key string, value interface{}, expiration time.Duration) error {
+func (c *cache) Add(key string, value any, expiration time.Duration) error {
c.mu.Lock()
_, found := c.Items[key]
if found {
@@ -107,7 +107,7 @@ func (c *cache) Add(key string, value interface{}, expiration time.Duration) err
// Get an item from the cache. Returns the item or nil, and a bool indicating
// whether the key was found.
-func (c *cache) Get(key string) (interface{}, bool) {
+func (c *cache) Get(key string) (any, bool) {
c.mu.RLock()
item, found := c.Items[key]
if !found {
diff --git a/internal/controller/artifact_matchers_test.go b/internal/controller/artifact_matchers_test.go
index af716e086..36a688e68 100644
--- a/internal/controller/artifact_matchers_test.go
+++ b/internal/controller/artifact_matchers_test.go
@@ -36,7 +36,7 @@ type matchArtifact struct {
expected *meta.Artifact
}
-func (m matchArtifact) Match(actual interface{}) (success bool, err error) {
+func (m matchArtifact) Match(actual any) (success bool, err error) {
actualArtifact, ok := actual.(*meta.Artifact)
if !ok {
return false, fmt.Errorf("actual should be a pointer to an Artifact")
@@ -59,10 +59,10 @@ func (m matchArtifact) Match(actual interface{}) (success bool, err error) {
return ok, err
}
-func (m matchArtifact) FailureMessage(actual interface{}) (message string) {
+func (m matchArtifact) FailureMessage(actual any) (message string) {
return fmt.Sprintf("expected\n\t%#v\nto match\n\t%#v\n", actual, m.expected)
}
-func (m matchArtifact) NegatedFailureMessage(actual interface{}) (message string) {
+func (m matchArtifact) NegatedFailureMessage(actual any) (message string) {
return fmt.Sprintf("expected\n\t%#v\nto not match\n\t%#v\n", actual, m.expected)
}
diff --git a/internal/controller/bucket_controller.go b/internal/controller/bucket_controller.go
index 8044875b8..a90e5608c 100644
--- a/internal/controller/bucket_controller.go
+++ b/internal/controller/bucket_controller.go
@@ -41,6 +41,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
+ cryptov1 "github.com/fluxcd/pkg/apis/crypto/v1"
eventv1 "github.com/fluxcd/pkg/apis/event/v1"
"github.com/fluxcd/pkg/apis/meta"
intdigest "github.com/fluxcd/pkg/artifact/digest"
@@ -56,6 +57,7 @@ import (
rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
"github.com/fluxcd/pkg/runtime/secrets"
"github.com/fluxcd/pkg/sourceignore"
+ fluxbroker "github.com/fluxcd/pkg/spiffe/broker"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/fluxcd/source-controller/internal/bucket/azure"
@@ -132,6 +134,9 @@ type BucketReconciler struct {
ControllerName string
TokenCache *cache.TokenCache
+ DefaultServiceAccount string
+ SPIFFEBroker fluxbroker.Interface
+
patchOptions []patch.Option
}
@@ -433,18 +438,6 @@ func (r *BucketReconciler) reconcileStorage(ctx context.Context, sp *patch.Seria
// the provider. If this fails, it records v1.FetchFailedCondition=True on
// the object and returns early.
func (r *BucketReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.Bucket, index *index.Digester, dir string) (sreconcile.Result, error) {
- usesObjectLevelWorkloadIdentity := obj.Spec.Provider != "" && obj.Spec.Provider != sourcev1.BucketProviderGeneric && obj.Spec.ServiceAccountName != ""
- if usesObjectLevelWorkloadIdentity {
- if !auth.IsObjectLevelWorkloadIdentityEnabled() {
- const gate = auth.FeatureGateObjectLevelWorkloadIdentity
- const msgFmt = "to use spec.serviceAccountName for provider authentication please enable the %s feature gate in the controller"
- err := fmt.Errorf(msgFmt, gate)
- e := serror.NewStalling(err, meta.FeatureGateDisabledReason)
- conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
- return sreconcile.ResultEmpty, e
- }
- }
-
creds, err := r.setupCredentials(ctx, obj)
if err != nil {
e := serror.NewGeneric(err, sourcev1.AuthenticationFailedReason)
@@ -454,12 +447,10 @@ func (r *BucketReconciler) reconcileSource(ctx context.Context, sp *patch.Serial
provider, err := r.createBucketProvider(ctx, obj, creds)
if err != nil {
- var stallingErr *serror.Stalling
- var genericErr *serror.Generic
- if errors.As(err, &stallingErr) {
+ if stallingErr, ok := errors.AsType[*serror.Stalling](err); ok {
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, stallingErr.Reason, "%s", stallingErr)
return sreconcile.ResultEmpty, stallingErr
- } else if errors.As(err, &genericErr) {
+ } else if genericErr, ok := errors.AsType[*serror.Generic](err); ok {
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, genericErr.Reason, "%s", genericErr)
return sreconcile.ResultEmpty, genericErr
} else {
@@ -839,35 +830,79 @@ func (r *BucketReconciler) setupCredentials(ctx context.Context, obj *sourcev1.B
// createBucketProvider creates a provider-specific bucket client using the given credentials and configuration.
// It handles different bucket providers (AWS, GCP, Azure, generic) and returns the appropriate client.
func (r *BucketReconciler) createBucketProvider(ctx context.Context, obj *sourcev1.Bucket, creds *bucketCredentials) (BucketProvider, error) {
- authOpts := []auth.Option{
- auth.WithClient(r.Client),
- auth.WithServiceAccountNamespace(obj.GetNamespace()),
+ // Determine the cryptov1 service provider and resolve the ServiceAccount
+ // once, applying the default ServiceAccount when the object does not
+ // specify one. The generic provider does not support a ServiceAccount.
+ var serviceProvider string
+ switch obj.Spec.Provider {
+ case sourcev1.BucketProviderAmazon:
+ serviceProvider = cryptov1.ProviderAWS
+ case sourcev1.BucketProviderGoogle:
+ serviceProvider = cryptov1.ProviderGCP
+ case sourcev1.BucketProviderAzure:
+ serviceProvider = cryptov1.ProviderAzure
}
- if obj.Spec.ServiceAccountName != "" {
- authOpts = append(authOpts, auth.WithServiceAccountName(obj.Spec.ServiceAccountName))
+ var sa *corev1.ServiceAccount
+ if serviceProvider != "" {
+ saName := obj.Spec.ServiceAccountName
+ if saName == "" {
+ saName = r.DefaultServiceAccount
+ }
+ if saName != "" {
+ sa = &corev1.ServiceAccount{}
+ saRef := client.ObjectKey{Namespace: obj.GetNamespace(), Name: saName}
+ if err := r.Get(ctx, saRef, sa); err != nil {
+ return nil, fmt.Errorf("failed to get service account '%s': %w", saRef, err)
+ }
+ }
}
- if r.TokenCache != nil {
- involvedObject := cache.InvolvedObject{
- Kind: sourcev1.BucketKind,
- Name: obj.GetName(),
- Namespace: obj.GetNamespace(),
- Operation: cache.OperationReconcile,
+ var cryptoSpec *cryptov1.Spec
+ if sa != nil {
+ buildOpts := []cryptov1.Option{
+ cryptov1.WithAnnotations(sa.Annotations),
+ cryptov1.WithServiceProvider(serviceProvider),
+ }
+ if sts := obj.Spec.STS; sts != nil {
+ buildOpts = append(buildOpts, cryptov1.WithSTSEndpoint(sts.Provider, sts.Endpoint))
+ }
+ if obj.Spec.CertSecretRef != nil ||
+ (obj.Spec.STS != nil && obj.Spec.STS.CertSecretRef != nil) {
+ buildOpts = append(buildOpts, cryptov1.WithCertSecretRef())
+ }
+ var err error
+ cryptoSpec, err = cryptov1.BuildSpec(buildOpts...)
+ if err != nil {
+ return nil, fmt.Errorf("failed to build spec for service account '%s/%s': %w",
+ sa.Namespace, sa.Name, err)
}
- authOpts = append(authOpts, auth.WithCache(*r.TokenCache, involvedObject))
}
+ var authOpts []auth.Option
+ if cryptoSpec != nil {
+ authOpts = auth.OptionsFromSpec(cryptoSpec.Auth)
+ }
+ authOpts = append(authOpts,
+ auth.WithClient(r.Client),
+ auth.WithObject(sourcev1.GroupVersion.Group, sourcev1.BucketKind, obj),
+ auth.WithSPIFFEBroker(r.SPIFFEBroker))
+ if sa != nil {
+ authOpts = append(authOpts, auth.WithServiceAccountName(sa.Name))
+ }
+ if r.TokenCache != nil {
+ authOpts = append(authOpts,
+ auth.WithCache(*r.TokenCache),
+ auth.WithCacheOperation(cache.OperationReconcile))
+ }
if creds.proxyURL != nil {
authOpts = append(authOpts, auth.WithProxyURL(*creds.proxyURL))
}
-
if obj.Spec.Region != "" {
- authOpts = append(authOpts, auth.WithSTSRegion(obj.Spec.Region))
+ authOpts = append(authOpts, auth.WithAWSRegion(obj.Spec.Region))
}
-
if sts := obj.Spec.STS; sts != nil {
- authOpts = append(authOpts, auth.WithSTSEndpoint(sts.Endpoint))
+ authOpts = append(authOpts, auth.WithAWSSTSEndpoint(sts.Endpoint))
}
switch obj.Spec.Provider {
diff --git a/internal/controller/bucket_controller_fetch_test.go b/internal/controller/bucket_controller_fetch_test.go
index 9f9c31a12..2c21bb73f 100644
--- a/internal/controller/bucket_controller_fetch_test.go
+++ b/internal/controller/bucket_controller_fetch_test.go
@@ -319,7 +319,7 @@ func Test_fetchFiles(t *testing.T) {
tmp := t.TempDir()
client := mockBucketClient{bucketName: bucketName}
- for i := 0; i < 2*maxConcurrentBucketFetches; i++ {
+ for i := range 2 * maxConcurrentBucketFetches {
f := fmt.Sprintf("file-%d", i)
client.addObject(f, mockBucketObject{etag: f, data: f})
}
diff --git a/internal/controller/bucket_controller_test.go b/internal/controller/bucket_controller_test.go
index 494c53303..6fbd50d2b 100644
--- a/internal/controller/bucket_controller_test.go
+++ b/internal/controller/bucket_controller_test.go
@@ -40,7 +40,6 @@ import (
"github.com/fluxcd/pkg/apis/meta"
intdigest "github.com/fluxcd/pkg/artifact/digest"
"github.com/fluxcd/pkg/artifact/storage"
- "github.com/fluxcd/pkg/auth"
"github.com/fluxcd/pkg/runtime/conditions"
conditionscheck "github.com/fluxcd/pkg/runtime/conditions/check"
"github.com/fluxcd/pkg/runtime/events"
@@ -63,7 +62,7 @@ func TestBucketReconciler_deleteBeforeFinalizer(t *testing.T) {
namespaceName := "bucket-" + randStringRunes(5)
namespace := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
+ Name: namespaceName,
}
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
t.Cleanup(func() {
@@ -114,10 +113,8 @@ func TestBucketReconciler_Reconcile(t *testing.T) {
g.Expect(err).NotTo(HaveOccurred())
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "bucket-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "bucket-reconcile-",
+ Namespace: "default",
Data: map[string][]byte{
"accesskey": []byte("key"),
"secretkey": []byte("secret"),
@@ -127,10 +124,8 @@ func TestBucketReconciler_Reconcile(t *testing.T) {
defer testEnv.Delete(ctx, secret)
origObj := &sourcev1.Bucket{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "bucket-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "bucket-reconcile-",
+ Namespace: "default",
Spec: sourcev1.BucketSpec{
Provider: "generic",
BucketName: s3Server.BucketName,
@@ -235,7 +230,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) {
Revision: "d",
Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4",
URL: testStorage.Hostname + "/reconcile-storage/d.txt",
- Size: int64p(int64(len("d"))),
+ Size: new(int64(len("d"))),
},
assertPaths: []string{
"/reconcile-storage/d.txt",
@@ -364,7 +359,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) {
Revision: "f",
Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80",
URL: testStorage.Hostname + "/reconcile-storage/hostname.txt",
- Size: int64p(int64(len("file"))),
+ Size: new(int64(len("file"))),
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReadyCondition, "foo", "bar"),
@@ -390,10 +385,8 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) {
}
obj := &sourcev1.Bucket{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: 1,
- },
+ GenerateName: "test-",
+ Generation: 1,
}
if tt.beforeFunc != nil {
g.Expect(tt.beforeFunc(obj, testStorage)).To(Succeed())
@@ -494,9 +487,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) {
name: "Observes invalid secretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.SecretRef = &meta.LocalObjectReference{
@@ -535,9 +526,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) {
name: "Observes invalid certSecretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.CertSecretRef = &meta.LocalObjectReference{
@@ -576,9 +565,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) {
name: "Observes invalid proxySecretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
Data: map[string][]byte{},
},
beforeFunc: func(obj *sourcev1.Bucket) {
@@ -618,9 +605,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) {
name: "Observes invalid sts.secretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.Provider = "generic"
@@ -662,9 +647,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) {
name: "Observes invalid sts.certSecretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.Provider = "generic"
@@ -927,10 +910,8 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) {
tmpDir := t.TempDir()
obj := &sourcev1.Bucket{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-bucket-",
- Generation: 1,
- },
+ GenerateName: "test-bucket-",
+ Generation: 1,
Spec: sourcev1.BucketSpec{
Timeout: &metav1.Duration{Duration: timeout},
},
@@ -1004,17 +985,16 @@ const gcsExternalAccountConfig = `{
func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
tests := []struct {
- name string
- bucketName string
- bucketObjects []*gcsmock.Object
- secret *corev1.Secret
- serviceAccount *corev1.ServiceAccount
- beforeFunc func(obj *sourcev1.Bucket)
- want sreconcile.Result
- wantErr bool
- assertIndex *index.Digester
- assertConditions []metav1.Condition
- disableObjectLevelWorkloadIdentity bool
+ name string
+ bucketName string
+ bucketObjects []*gcsmock.Object
+ secret *corev1.Secret
+ serviceAccount *corev1.ServiceAccount
+ beforeFunc func(obj *sourcev1.Bucket)
+ want sreconcile.Result
+ wantErr bool
+ assertIndex *index.Digester
+ assertConditions []metav1.Condition
}{
{
name: "Reconciles GCS source",
@@ -1028,9 +1008,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
},
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
Data: map[string][]byte{
"accesskey": []byte("key"),
"secretkey": []byte("secret"),
@@ -1074,9 +1052,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
name: "Observes invalid secretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.SecretRef = &meta.LocalObjectReference{
@@ -1098,9 +1074,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
name: "Observes unsupported credential type in secretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
Data: map[string][]byte{
"serviceaccount": []byte(gcsExternalAccountConfig),
},
@@ -1145,9 +1119,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
name: "Observes invalid proxySecretRef",
bucketName: "dummy",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy",
- },
+ Name: "dummy",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.ProxySecretRef = &meta.LocalObjectReference{
@@ -1357,9 +1329,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
},
},
serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-sa",
- },
+ Name: "test-sa",
},
beforeFunc: func(obj *sourcev1.Bucket) {
obj.Spec.ServiceAccountName = "test-sa"
@@ -1396,29 +1366,6 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new upstream revision 'sha256:b4c2a60ce44b67f5b659a95ce4e4cc9e2a86baf13afb72bd397c5384cbc0e479'"),
},
},
- {
- name: "GCS Object-Level fails when feature gate disabled",
- bucketName: "dummy",
- serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-sa",
- },
- },
- beforeFunc: func(obj *sourcev1.Bucket) {
- obj.Spec.ServiceAccountName = "test-sa"
- conditions.MarkReconciling(obj, meta.ProgressingReason, "foo")
- conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar")
- },
- want: sreconcile.ResultEmpty,
- wantErr: true,
- assertIndex: index.NewDigester(),
- assertConditions: []metav1.Condition{
- *conditions.TrueCondition(sourcev1.FetchFailedCondition, meta.FeatureGateDisabledReason, "to use spec.serviceAccountName for provider authentication please enable the ObjectLevelWorkloadIdentity feature gate in the controller"),
- *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"),
- *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"),
- },
- disableObjectLevelWorkloadIdentity: true,
- },
// TODO: Middleware for mock server to test authentication using secret.
}
for _, tt := range tests {
@@ -1444,20 +1391,12 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) {
patchOptions: getPatchOptions(bucketReadyCondition.Owned, "sc"),
}
- // Handle ObjectLevelWorkloadIdentity feature gate
- if !tt.disableObjectLevelWorkloadIdentity {
- auth.EnableObjectLevelWorkloadIdentity()
- t.Cleanup(auth.DisableObjectLevelWorkloadIdentity)
- }
-
tmpDir := t.TempDir()
// Test bucket object.
obj := &sourcev1.Bucket{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-bucket-",
- Generation: 1,
- },
+ GenerateName: "test-bucket-",
+ Generation: 1,
Spec: sourcev1.BucketSpec{
BucketName: tt.bucketName,
Timeout: &metav1.Duration{Duration: timeout},
@@ -1648,10 +1587,8 @@ func TestBucketReconciler_reconcileArtifact(t *testing.T) {
}
obj := &sourcev1.Bucket{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-bucket-",
- Generation: 1,
- },
+ GenerateName: "test-bucket-",
+ Generation: 1,
Spec: sourcev1.BucketSpec{
Timeout: &metav1.Duration{Duration: timeout},
},
@@ -1742,14 +1679,10 @@ func TestBucketReconciler_statusConditions(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.Bucket{
- TypeMeta: metav1.TypeMeta{
- APIVersion: sourcev1.GroupVersion.String(),
- Kind: sourcev1.BucketKind,
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-bucket",
- Namespace: "foo",
- },
+ APIVersion: sourcev1.GroupVersion.String(),
+ Kind: sourcev1.BucketKind,
+ Name: "test-bucket",
+ Namespace: "foo",
}
c := fakeclient.NewClientBuilder().
@@ -2045,10 +1978,8 @@ func TestBucketReconciler_APIServerValidation_STS(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.Bucket{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "bucket-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "bucket-reconcile-",
+ Namespace: "default",
Spec: sourcev1.BucketSpec{
Provider: tt.bucketProvider,
BucketName: "test",
diff --git a/internal/controller/gitrepository_controller.go b/internal/controller/gitrepository_controller.go
index 8228037e3..eaefa27f0 100644
--- a/internal/controller/gitrepository_controller.go
+++ b/internal/controller/gitrepository_controller.go
@@ -34,6 +34,7 @@ import (
"github.com/fluxcd/pkg/runtime/events"
"github.com/fluxcd/pkg/runtime/logger"
"github.com/fluxcd/pkg/runtime/secrets"
+ fluxbroker "github.com/fluxcd/pkg/spiffe/broker"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/opencontainers/go-digest"
ssh "golang.org/x/crypto/ssh"
@@ -49,6 +50,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
+ cryptov1 "github.com/fluxcd/pkg/apis/crypto/v1"
eventv1 "github.com/fluxcd/pkg/apis/event/v1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/artifact/storage"
@@ -66,7 +68,6 @@ import (
sourcev1 "github.com/fluxcd/source-controller/api/v1"
serror "github.com/fluxcd/source-controller/internal/error"
- "github.com/fluxcd/source-controller/internal/features"
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
"github.com/fluxcd/source-controller/internal/util"
@@ -173,8 +174,10 @@ type GitRepositoryReconciler struct {
ControllerName string
TokenCache *cache.TokenCache
+ DefaultServiceAccount string
+ SPIFFEBroker fluxbroker.Interface
+
requeueDependency time.Duration
- features map[string]bool
patchOptions []patch.Option
}
@@ -193,10 +196,6 @@ func (r *GitRepositoryReconciler) SetupWithManager(mgr ctrl.Manager, opts GitRep
r.requeueDependency = opts.DependencyRequeueInterval
- if r.features == nil {
- r.features = features.FeatureGates()
- }
-
return ctrl.NewControllerManagedBy(mgr).
For(&sourcev1.GitRepository{}, builder.WithPredicates(
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
@@ -694,8 +693,7 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
// Check if SSH identity key is encrypted but no password was provided.
if opts.Transport == git.SSH && len(opts.Identity) > 0 && opts.Password == "" {
_, err := ssh.ParseRawPrivateKey(opts.Identity)
- var missingErr *ssh.PassphraseMissingError
- if errors.As(err, &missingErr) {
+ if _, ok := errors.AsType[*ssh.PassphraseMissingError](err); ok {
e := serror.NewGeneric(
fmt.Errorf("SSH identity key is encrypted but no 'password' field was provided in the secret '%s/%s'",
obj.GetNamespace(), obj.Spec.SecretRef.Name),
@@ -707,45 +705,86 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
}
// Configure provider authentication if specified.
+ provider := obj.GetProvider()
+ withCerts := len(opts.ClientCert) > 0 || len(opts.ClientKey) > 0 || len(opts.CAFile) > 0
+ withAuth := obj.Spec.SecretRef != nil &&
+ (opts.Username != "" || opts.Password != "" || opts.BearerToken != "" || len(opts.Identity) > 0 ||
+ len(authData[githubapp.KeyAppID]) > 0 || len(authData[githubapp.KeyAppClientID]) > 0)
+
+ // Resolve the ServiceAccount once, applying the default ServiceAccount when
+ // the object does not specify one.
+ saName := obj.Spec.ServiceAccountName
+ if saName == "" {
+ saName = r.DefaultServiceAccount
+ }
+ var sa *corev1.ServiceAccount
+ if saName != "" {
+ sa = &corev1.ServiceAccount{}
+ saRef := types.NamespacedName{Namespace: obj.GetNamespace(), Name: saName}
+ if err := r.Get(ctx, saRef, sa); err != nil {
+ e := serror.NewGeneric(
+ fmt.Errorf("failed to get service account '%s': %w", saRef, err),
+ sourcev1.AuthenticationFailedReason,
+ )
+ conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
+ return nil, e
+ }
+ }
+
+ // Build the authentication spec. This is done even when no
+ // ServiceAccount is specified, as some inputs are validated regardless.
+ var cryptoSpec *cryptov1.Spec
+ if sa != nil || (provider != "" && provider != sourcev1.GitProviderGeneric) {
+ buildOpts := []cryptov1.Option{
+ cryptov1.WithServiceProvider(provider),
+ }
+ if sa != nil {
+ buildOpts = append(buildOpts, cryptov1.WithAnnotations(sa.Annotations))
+ }
+ if withCerts {
+ buildOpts = append(buildOpts, cryptov1.WithSecretRefCerts())
+ }
+ if withAuth {
+ buildOpts = append(buildOpts, cryptov1.WithSecretRefAuth())
+ }
+ if provider == sourcev1.GitProviderGitHub && len(authData[githubapp.KeyAppBaseURL]) > 0 {
+ buildOpts = append(buildOpts, cryptov1.WithGitHubEnterpriseServer())
+ }
+ var err error
+ cryptoSpec, err = cryptov1.BuildSpec(buildOpts...)
+ if err != nil {
+ e := serror.NewGeneric(
+ fmt.Errorf("failed to validate configuration: %w", err),
+ sourcev1.AuthenticationFailedReason,
+ )
+ conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
+ return nil, e
+ }
+ }
+
var getCreds func() (*auth.GitCredentials, error)
- switch provider := obj.GetProvider(); provider {
+ switch provider {
// If other providers (GCP, etc.) are added in the future they can be added here separated by a comma.
case sourcev1.GitProviderAzure, sourcev1.GitProviderAWS:
getCreds = func() (*auth.GitCredentials, error) {
- opts := []auth.Option{
+ authOpts := auth.OptionsFromSpec(cryptoSpec.Auth)
+ authOpts = append(authOpts,
auth.WithClient(r.Client),
- auth.WithServiceAccountNamespace(obj.GetNamespace()),
auth.WithGitURL(u),
+ auth.WithObject(sourcev1.GroupVersion.Group, sourcev1.GitRepositoryKind, obj),
+ auth.WithSPIFFEBroker(r.SPIFFEBroker))
+ if sa != nil {
+ authOpts = append(authOpts, auth.WithServiceAccountName(sa.Name))
}
-
- if obj.Spec.ServiceAccountName != "" {
- // Check object-level workload identity feature gate.
- if !auth.IsObjectLevelWorkloadIdentityEnabled() {
- const gate = auth.FeatureGateObjectLevelWorkloadIdentity
- const msgFmt = "to use spec.serviceAccountName for provider authentication please enable the %s feature gate in the controller"
- err := serror.NewStalling(fmt.Errorf(msgFmt, gate), meta.FeatureGateDisabledReason)
- conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, meta.FeatureGateDisabledReason, "%s", err)
- return nil, err
- }
- // Set ServiceAccountName only if explicitly specified
- opts = append(opts, auth.WithServiceAccountName(obj.Spec.ServiceAccountName))
- }
-
if r.TokenCache != nil {
- involvedObject := cache.InvolvedObject{
- Kind: sourcev1.GitRepositoryKind,
- Name: obj.GetName(),
- Namespace: obj.GetNamespace(),
- Operation: cache.OperationReconcile,
- }
- opts = append(opts, auth.WithCache(*r.TokenCache, involvedObject))
+ authOpts = append(authOpts,
+ auth.WithCache(*r.TokenCache),
+ auth.WithCacheOperation(cache.OperationReconcile))
}
-
if proxyURL != nil {
- opts = append(opts, auth.WithProxyURL(*proxyURL))
+ authOpts = append(authOpts, auth.WithProxyURL(*proxyURL))
}
-
- return authutils.GetGitCredentials(ctx, provider, opts...)
+ return authutils.GetGitCredentials(ctx, provider, authOpts...)
}
case sourcev1.GitProviderGitHub:
// if provider is github, but secret ref is not specified
@@ -779,8 +818,12 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
}
if r.TokenCache != nil {
- appOpts = append(appOpts, githubapp.WithCache(r.TokenCache, sourcev1.GitRepositoryKind,
- obj.GetName(), obj.GetNamespace(), cache.OperationReconcile))
+ appOpts = append(appOpts, githubapp.WithCache(r.TokenCache, cache.InvolvedObject{
+ Kind: sourcev1.GitRepositoryKind,
+ Name: obj.GetName(),
+ Namespace: obj.GetNamespace(),
+ Operation: cache.OperationReconcile,
+ }))
}
if authMethods.HasTLS() {
diff --git a/internal/controller/gitrepository_controller_test.go b/internal/controller/gitrepository_controller_test.go
index 4a18c8e37..93d44c50f 100644
--- a/internal/controller/gitrepository_controller_test.go
+++ b/internal/controller/gitrepository_controller_test.go
@@ -39,7 +39,6 @@ import (
sshtestdata "golang.org/x/crypto/ssh/testdata"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -48,7 +47,6 @@ import (
kstatus "github.com/fluxcd/cli-utils/pkg/kstatus/status"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/artifact/storage"
- "github.com/fluxcd/pkg/auth"
"github.com/fluxcd/pkg/auth/githubapp"
"github.com/fluxcd/pkg/git"
"github.com/fluxcd/pkg/gittestserver"
@@ -62,7 +60,6 @@ import (
sourcev1 "github.com/fluxcd/source-controller/api/v1"
serror "github.com/fluxcd/source-controller/internal/error"
- "github.com/fluxcd/source-controller/internal/features"
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
)
@@ -210,7 +207,7 @@ func TestGitRepositoryReconciler_deleteBeforeFinalizer(t *testing.T) {
namespaceName := "gitrepo-" + randStringRunes(5)
namespace := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
+ Name: namespaceName,
}
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
t.Cleanup(func() {
@@ -255,10 +252,8 @@ func TestGitRepositoryReconciler_Reconcile(t *testing.T) {
g.Expect(err).NotTo(HaveOccurred())
origObj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "gitrepository-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "gitrepository-reconcile-",
+ Namespace: "default",
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
URL: server.HTTPAddress() + repoPath,
@@ -328,10 +323,8 @@ func TestGitRepositoryReconciler_reconcileSource_emptyRepository(t *testing.T) {
defer server.StopHTTP()
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "empty-",
- Generation: 1,
- },
+ GenerateName: "empty-",
+ Generation: 1,
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -407,9 +400,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
password: "1234",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "basic-auth",
- },
+ Name: "basic-auth",
Data: map[string][]byte{
"username": []byte("git"),
"password": []byte("1234"),
@@ -433,9 +424,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "mtls-certs",
- },
+ Name: "mtls-certs",
Data: map[string][]byte{
"ca.crt": tlsCA,
"tls.crt": clientPublicKey,
@@ -460,9 +449,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalid-mtls-certs",
- },
+ Name: "invalid-mtls-certs",
Data: map[string][]byte{
"ca.crt": tlsCA,
"tls.crt": clientPublicKey,
@@ -490,9 +477,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"caFile": tlsCA,
},
@@ -515,9 +500,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"ca.crt": tlsCA,
"caFile": []byte("invalid"),
@@ -541,9 +524,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalid-ca",
- },
+ Name: "invalid-ca",
Data: map[string][]byte{
"caFile": []byte("invalid"),
},
@@ -574,7 +555,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "gh-app-no-ca"},
+ Name: "gh-app-no-ca",
Data: map[string][]byte{
githubapp.KeyAppID: []byte("123"),
githubapp.KeyAppInstallationID: []byte("456"),
@@ -609,7 +590,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
password: "some-enterprise-token",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "gh-app-ca"},
+ Name: "gh-app-ca",
Data: map[string][]byte{
githubapp.KeyAppID: []byte("123"),
githubapp.KeyAppInstallationID: []byte("456"),
@@ -654,9 +635,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
username: "git",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "private-key",
- },
+ Name: "private-key",
Data: map[string][]byte{
"username": []byte("git"),
"identity": sshtestdata.PEMBytes["rsa"],
@@ -678,9 +657,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
username: "git",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "private-key",
- },
+ Name: "private-key",
Data: map[string][]byte{
"username": []byte("git"),
"identity": sshtestdata.PEMEncryptedKeys[2].PEMBytes,
@@ -722,9 +699,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
password: "1234",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "basic-auth",
- },
+ Name: "basic-auth",
Data: map[string][]byte{
"username": []byte("git"),
"password": []byte("1234"),
@@ -770,9 +745,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
name: "empty provider with github app data in secret makes FetchFailed=True",
protocol: "http",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "github-app-secret",
- },
+ Name: "github-app-secret",
Data: map[string][]byte{
githubapp.KeyAppID: []byte("1111"),
},
@@ -796,9 +769,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
name: "github provider without github app data in secret makes FetchFailed=True",
protocol: "http",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "github-basic-auth",
- },
+ Name: "github-basic-auth",
Data: map[string][]byte{
"username": []byte("abc"),
"password": []byte("1234"),
@@ -825,10 +796,8 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "auth-strategy-",
- Generation: 1,
- },
+ GenerateName: "auth-strategy-",
+ Generation: 1,
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -954,15 +923,6 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
},
wantErr: "ManagedIdentityCredential",
},
- {
- name: "azure provider with service account and feature gate for object-level identity disabled",
- url: "https://dev.azure.com/foo/bar/_git/baz",
- beforeFunc: func(obj *sourcev1.GitRepository) {
- obj.Spec.Provider = sourcev1.GitProviderAzure
- obj.Spec.ServiceAccountName = "azure-sa"
- },
- wantErr: auth.FeatureGateObjectLevelWorkloadIdentity,
- },
{
name: "aws provider with non codecommit URL",
url: "https://github.com/org/repo.git",
@@ -971,15 +931,6 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
},
wantErr: "invalid AWS CodeCommit Git URL: github.com",
},
- {
- name: "aws provider with service account and feature gate for object-level identity disabled",
- url: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-repo",
- beforeFunc: func(obj *sourcev1.GitRepository) {
- obj.Spec.Provider = sourcev1.GitProviderAWS
- obj.Spec.ServiceAccountName = "aws-sa"
- },
- wantErr: auth.FeatureGateObjectLevelWorkloadIdentity,
- },
{
name: "github provider with no secret ref",
url: "https://github.com/org/repo.git",
@@ -992,9 +943,7 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
name: "github provider with github app data in secret",
url: "https://example.com/org/repo",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "githubAppSecret",
- },
+ Name: "githubAppSecret",
Data: map[string][]byte{
githubapp.KeyAppID: []byte("123"),
githubapp.KeyAppInstallationID: []byte("456"),
@@ -1013,9 +962,7 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
name: "generic provider with github app data in secret",
url: "https://example.com/org/repo",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "githubAppSecret",
- },
+ Name: "githubAppSecret",
Data: map[string][]byte{
githubapp.KeyAppID: []byte("123"),
},
@@ -1032,9 +979,7 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
name: "generic provider with github app client id in secret",
url: "https://example.com/org/repo",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "githubAppSecret",
- },
+ Name: "githubAppSecret",
Data: map[string][]byte{
githubapp.KeyAppClientID: []byte("Iv23liXXXXXXX"),
},
@@ -1051,9 +996,7 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
name: "github provider with basic auth secret",
url: "https://github.com/org/repo.git",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "basic-auth-secret",
- },
+ Name: "basic-auth-secret",
Data: map[string][]byte{
"username": []byte("abc"),
"password": []byte("1234"),
@@ -1105,7 +1048,6 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
r := &GitRepositoryReconciler{
Recorder: events.NewFakeRecorder(32, false),
Client: clientBuilder.Build(),
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
@@ -1277,7 +1219,7 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T)
},
beforeFunc: func(obj *sourcev1.GitRepository, latestRev string) {
// Set new ignore value.
- obj.Spec.Ignore = ptr.To("foo")
+ obj.Spec.Ignore = new("foo")
// Add existing artifact on the object and storage.
obj.Status = sourcev1.GitRepositoryStatus{
Artifact: &meta.Artifact{
@@ -1334,10 +1276,8 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T)
g := NewWithT(t)
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "checkout-strategy-",
- Generation: 1,
- },
+ GenerateName: "checkout-strategy-",
+ Generation: 1,
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -1451,7 +1391,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
dir: "testdata/git/repository",
beforeFunc: func(obj *sourcev1.GitRepository) {
obj.Spec.Interval = metav1.Duration{Duration: interval}
- obj.Spec.Ignore = ptr.To("!**.txt\n")
+ obj.Spec.Ignore = new("!**.txt\n")
},
afterFunc: func(t *WithT, obj *sourcev1.GitRepository) {
t.Expect(obj.GetArtifact()).ToNot(BeNil())
@@ -1530,16 +1470,13 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
r := &GitRepositoryReconciler{
Recorder: events.NewFakeRecorder(32, false),
Storage: testStorage,
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "reconcile-artifact-",
- Generation: 1,
- },
- Status: sourcev1.GitRepositoryStatus{},
+ GenerateName: "reconcile-artifact-",
+ Generation: 1,
+ Status: sourcev1.GitRepositoryStatus{},
}
if tt.beforeFunc != nil {
@@ -1651,9 +1588,7 @@ func TestGitRepositoryReconciler_reconcileInclude(t *testing.T) {
var depObjs []client.Object
for _, d := range tt.dependencies {
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: d.name,
- },
+ Name: d.name,
Status: sourcev1.GitRepositoryStatus{
Conditions: d.conditions,
},
@@ -1682,14 +1617,11 @@ func TestGitRepositoryReconciler_reconcileInclude(t *testing.T) {
Recorder: events.NewFakeRecorder(32, false),
Storage: storage,
requeueDependency: dependencyInterval,
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "reconcile-include",
- },
+ Name: "reconcile-include",
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
},
@@ -1787,7 +1719,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) {
Revision: "d",
Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4",
URL: testStorage.Hostname + "/reconcile-storage/d.txt",
- Size: int64p(int64(len("d"))),
+ Size: new(int64(len("d"))),
},
assertPaths: []string{
"/reconcile-storage/d.txt",
@@ -1916,7 +1848,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) {
Revision: "f",
Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80",
URL: testStorage.Hostname + "/reconcile-storage/hostname.txt",
- Size: int64p(int64(len("file"))),
+ Size: new(int64(len("file"))),
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReadyCondition, "foo", "bar"),
@@ -1938,15 +1870,12 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) {
Build(),
Recorder: events.NewFakeRecorder(32, false),
Storage: testStorage,
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: 1,
- },
+ GenerateName: "test-",
+ Generation: 1,
}
if tt.beforeFunc != nil {
g.Expect(tt.beforeFunc(obj, testStorage)).To(Succeed())
@@ -1992,17 +1921,14 @@ func TestGitRepositoryReconciler_reconcileDelete(t *testing.T) {
r := &GitRepositoryReconciler{
Recorder: events.NewFakeRecorder(32, false),
Storage: testStorage,
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "reconcile-delete-",
- DeletionTimestamp: &metav1.Time{Time: time.Now()},
- Finalizers: []string{
- sourcev1.SourceFinalizer,
- },
+ Name: "reconcile-delete-",
+ DeletionTimestamp: &metav1.Time{Time: time.Now()},
+ Finalizers: []string{
+ sourcev1.SourceFinalizer,
},
Status: sourcev1.GitRepositoryStatus{},
}
@@ -2032,9 +1958,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid commit with mode=HEAD makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2054,7 +1978,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- commit 'shasum' with key '5982D0279C227FFD'"),
},
@@ -2062,9 +1986,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid commit with mode=head makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2084,7 +2006,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- commit 'shasum' with key '5982D0279C227FFD'"),
},
@@ -2092,9 +2014,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid tag with mode=tag makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2120,7 +2040,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTag),
+ wantSourceVerificationMode: new(sourcev1.ModeGitTag),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- tag 'v0.1.0@shasum' with key '5982D0279C227FFD'"),
},
@@ -2128,9 +2048,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid tag and commit with mode=TagAndHEAD makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2159,7 +2077,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTagAndHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitTagAndHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- tag 'v0.1.0@shasum' with key '5982D0279C227FFD'\n\t- commit 'shasum' with key '5982D0279C227FFD'"),
},
@@ -2167,7 +2085,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Source verification mode in status is unset if there's no verification in spec",
beforeFunc: func(obj *sourcev1.GitRepository) {
- obj.Status.SourceVerificationMode = ptrToVerificationMode(sourcev1.ModeGitHEAD)
+ obj.Status.SourceVerificationMode = new(sourcev1.ModeGitHEAD)
obj.Status.SourceVerificationFingerprint = "stale-fingerprint"
obj.Spec.Verification = nil
},
@@ -2176,9 +2094,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Verification of tag with no tag ref SourceVerifiedCondition=False and returns a stalling error",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2207,9 +2123,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Unsigned tag with mode=tag makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2241,9 +2155,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Partially successful verification makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2279,9 +2191,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "No PGP keys in secret makes SourceVerifiedCondition=False and returns error",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
},
commit: git.Commit{
Hash: []byte("shasum"),
@@ -2305,9 +2215,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Invalid tag signature with mode=tag makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2340,9 +2248,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Invalid PGP key makes SourceVerifiedCondition=False and returns error",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalid",
- },
+ Name: "invalid",
Data: map[string][]byte{
"foo": []byte("invalid PGP public key"),
},
@@ -2404,9 +2310,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid SSH-signed commit with mode=HEAD makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ssh-keys",
- },
+ Name: "ssh-keys",
Data: map[string][]byte{
"author1.sshpub": []byte(sshAuthorizedKeysFixture),
},
@@ -2426,7 +2330,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- commit 'shasum' with key 'SHA256:SDB4adE/BP2VLwX9Pdf7aFUwW9JNdzoPSsHjd/wZIw4'"),
},
@@ -2434,9 +2338,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid SSH-signed tag with mode=Tag makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ssh-keys",
- },
+ Name: "ssh-keys",
Data: map[string][]byte{
"author1.sshpub": []byte(sshAuthorizedKeysFixture),
},
@@ -2462,7 +2364,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTag),
+ wantSourceVerificationMode: new(sourcev1.ModeGitTag),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- tag 'v0.1.0@shasum' with key 'SHA256:SDB4adE/BP2VLwX9Pdf7aFUwW9JNdzoPSsHjd/wZIw4'"),
},
@@ -2470,9 +2372,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid SSH-signed tag and commit with mode=TagAndHEAD makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ssh-keys",
- },
+ Name: "ssh-keys",
Data: map[string][]byte{
"author1.sshpub": []byte(sshAuthorizedKeysFixture),
},
@@ -2501,7 +2401,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTagAndHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitTagAndHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- tag 'v0.1.0@shasum' with key 'SHA256:SDB4adE/BP2VLwX9Pdf7aFUwW9JNdzoPSsHjd/wZIw4'\n\t- commit 'shasum' with key 'SHA256:SDB4adE/BP2VLwX9Pdf7aFUwW9JNdzoPSsHjd/wZIw4'"),
},
@@ -2509,9 +2409,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "SSH-signed commit but Secret only has .asc keys makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pgp-keys-only",
- },
+ Name: "pgp-keys-only",
Data: map[string][]byte{
"author1.asc": []byte(armoredKeyRingFixture),
},
@@ -2538,9 +2436,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "PGP-signed commit but Secret only has .sshpub keys makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ssh-keys-only",
- },
+ Name: "ssh-keys-only",
Data: map[string][]byte{
"author1.sshpub": []byte(sshAuthorizedKeysFixture),
},
@@ -2567,9 +2463,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "SSH-signed tag but Secret only has .asc keys makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pgp-keys-only",
- },
+ Name: "pgp-keys-only",
Data: map[string][]byte{
"author1.asc": []byte(armoredKeyRingFixture),
},
@@ -2602,9 +2496,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Invalid SSH key in .sshpub entry makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalid-ssh-key",
- },
+ Name: "invalid-ssh-key",
Data: map[string][]byte{
"author1.sshpub": []byte("ssh-ed25519 INVALIDKEY test@example.com"),
},
@@ -2631,9 +2523,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Mixed: PGP-signed tag and SSH-signed commit with both key types in Secret and mode=TagAndHEAD makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "mixed-keys",
- },
+ Name: "mixed-keys",
Data: map[string][]byte{
"author1.asc": []byte(armoredKeyRingFixture),
"author1.sshpub": []byte(sshAuthorizedKeysFixture),
@@ -2663,7 +2553,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTagAndHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitTagAndHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- tag 'v0.1.0@shasum' with key '5982D0279C227FFD'\n\t- commit 'shasum' with key 'SHA256:SDB4adE/BP2VLwX9Pdf7aFUwW9JNdzoPSsHjd/wZIw4'"),
},
@@ -2671,9 +2561,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Mixed: SSH-signed tag and PGP-signed commit with both key types in Secret and mode=TagAndHEAD makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "mixed-keys-reverse",
- },
+ Name: "mixed-keys-reverse",
Data: map[string][]byte{
"author1.asc": []byte(armoredKeyRingFixture),
"author1.sshpub": []byte(sshAuthorizedKeysFixture),
@@ -2703,7 +2591,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTagAndHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitTagAndHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- tag 'v0.1.0@shasum' with key 'SHA256:SDB4adE/BP2VLwX9Pdf7aFUwW9JNdzoPSsHjd/wZIw4'\n\t- commit 'shasum' with key '5982D0279C227FFD'"),
},
@@ -2711,9 +2599,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Unsupported signature type makes SourceVerifiedCondition=False",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "existing",
- },
+ Name: "existing",
Data: map[string][]byte{
"foo": []byte(armoredKeyRingFixture),
},
@@ -2740,9 +2626,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
{
name: "Valid commit with explicit .asc key suffix makes SourceVerifiedCondition=True",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "explicit-asc",
- },
+ Name: "explicit-asc",
Data: map[string][]byte{
"foo.asc": []byte(armoredKeyRingFixture),
},
@@ -2762,7 +2646,7 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
},
want: sreconcile.ResultSuccess,
- wantSourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ wantSourceVerificationMode: new(sourcev1.ModeGitHEAD),
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of\n\t- commit 'shasum' with key '5982D0279C227FFD'"),
},
@@ -2784,16 +2668,13 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
r := &GitRepositoryReconciler{
Recorder: events.NewFakeRecorder(32, false),
Client: clientBuilder.Build(),
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "verify-commit-",
- Generation: 1,
- },
- Status: sourcev1.GitRepositoryStatus{},
+ GenerateName: "verify-commit-",
+ Generation: 1,
+ Status: sourcev1.GitRepositoryStatus{},
}
if tt.beforeFunc != nil {
@@ -2916,11 +2797,9 @@ func TestGitRepositoryReconciler_ConditionsUpdate(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "condition-update",
- Namespace: "default",
- Finalizers: []string{sourcev1.SourceFinalizer},
- },
+ Name: "condition-update",
+ Namespace: "default",
+ Finalizers: []string{sourcev1.SourceFinalizer},
Spec: sourcev1.GitRepositorySpec{
URL: server.HTTPAddress() + repoPath,
Interval: metav1.Duration{Duration: interval},
@@ -2941,7 +2820,6 @@ func TestGitRepositoryReconciler_ConditionsUpdate(t *testing.T) {
Client: clientBuilder.Build(),
Recorder: events.NewFakeRecorder(32, false),
Storage: testStorage,
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
@@ -3165,14 +3043,10 @@ func TestGitRepositoryReconciler_statusConditions(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.GitRepository{
- TypeMeta: metav1.TypeMeta{
- APIVersion: sourcev1.GroupVersion.String(),
- Kind: sourcev1.GitRepositoryKind,
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "gitrepo",
- Namespace: "foo",
- },
+ APIVersion: sourcev1.GroupVersion.String(),
+ Kind: sourcev1.GitRepositoryKind,
+ Name: "gitrepo",
+ Namespace: "foo",
}
clientBuilder := fakeclient.NewClientBuilder().
@@ -3347,7 +3221,6 @@ func TestGitRepositoryReconciler_notify(t *testing.T) {
reconciler := &GitRepositoryReconciler{
Recorder: recorder,
- features: features.FeatureGates(),
patchOptions: getPatchOptions(gitRepositoryReadyCondition.Owned, "sc"),
}
reconciler.notify(ctx, oldObj, newObj, tt.commit, tt.res, tt.resErr)
@@ -3466,9 +3339,7 @@ func TestGitRepositoryReconciler_fetchIncludes(t *testing.T) {
var depObjs []client.Object
for _, d := range tt.dependencies {
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: d.name,
- },
+ Name: d.name,
Status: sourcev1.GitRepositoryStatus{
Conditions: d.conditions,
},
@@ -3498,9 +3369,7 @@ func TestGitRepositoryReconciler_fetchIncludes(t *testing.T) {
}
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "reconcile-include",
- },
+ Name: "reconcile-include",
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
},
@@ -3708,15 +3577,15 @@ func TestGitContentConfigChanged(t *testing.T) {
{
name: "unobserved ignore",
obj: sourcev1.GitRepository{
- Spec: sourcev1.GitRepositorySpec{Ignore: ptr.To("foo")},
+ Spec: sourcev1.GitRepositorySpec{Ignore: new("foo")},
},
want: true,
},
{
name: "observed ignore",
obj: sourcev1.GitRepository{
- Spec: sourcev1.GitRepositorySpec{Ignore: ptr.To("foo")},
- Status: sourcev1.GitRepositoryStatus{ObservedIgnore: ptr.To("foo")},
+ Spec: sourcev1.GitRepositorySpec{Ignore: new("foo")},
+ Status: sourcev1.GitRepositoryStatus{ObservedIgnore: new("foo")},
},
want: false,
},
@@ -4045,7 +3914,7 @@ func Test_requiresVerification(t *testing.T) {
},
},
Status: sourcev1.GitRepositoryStatus{
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTag),
+ SourceVerificationMode: new(sourcev1.ModeGitTag),
},
},
want: true,
@@ -4059,7 +3928,7 @@ func Test_requiresVerification(t *testing.T) {
},
},
Status: sourcev1.GitRepositoryStatus{
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTag),
+ SourceVerificationMode: new(sourcev1.ModeGitTag),
},
},
want: true,
@@ -4073,7 +3942,7 @@ func Test_requiresVerification(t *testing.T) {
},
},
Status: sourcev1.GitRepositoryStatus{
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ SourceVerificationMode: new(sourcev1.ModeGitHEAD),
},
},
want: true,
@@ -4087,7 +3956,7 @@ func Test_requiresVerification(t *testing.T) {
},
},
Status: sourcev1.GitRepositoryStatus{
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ SourceVerificationMode: new(sourcev1.ModeGitHEAD),
},
},
want: true,
@@ -4101,7 +3970,7 @@ func Test_requiresVerification(t *testing.T) {
},
},
Status: sourcev1.GitRepositoryStatus{
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTagAndHEAD),
+ SourceVerificationMode: new(sourcev1.ModeGitTagAndHEAD),
},
},
want: false,
@@ -4115,7 +3984,7 @@ func Test_requiresVerification(t *testing.T) {
},
},
Status: sourcev1.GitRepositoryStatus{
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitTagAndHEAD),
+ SourceVerificationMode: new(sourcev1.ModeGitTagAndHEAD),
},
},
want: false,
@@ -4161,17 +4030,17 @@ func Test_verificationFingerprint(t *testing.T) {
func TestGitRepositoryReconciler_verificationPolicyChanged(t *testing.T) {
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "keys", Namespace: "default"},
- Data: map[string][]byte{"foo": []byte(armoredKeyRingFixture)},
+ Name: "keys", Namespace: "default",
+ Data: map[string][]byte{"foo": []byte(armoredKeyRingFixture)},
}
rotatedSecret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "keys", Namespace: "default"},
- Data: map[string][]byte{"foo": []byte(armoredKeyRingFixture + "\n")},
+ Name: "keys", Namespace: "default",
+ Data: map[string][]byte{"foo": []byte(armoredKeyRingFixture + "\n")},
}
newObj := func(mode sourcev1.GitVerificationMode, fingerprint string) *sourcev1.GitRepository {
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{Name: "repo", Namespace: "default"},
+ Name: "repo", Namespace: "default",
Spec: sourcev1.GitRepositorySpec{
Verification: &sourcev1.GitRepositoryVerification{
Mode: mode,
@@ -4262,8 +4131,8 @@ func TestGitRepositoryReconciler_reconcileSource_verificationPolicyChange(t *tes
g.Expect(remoteBranchForHead(localRepo, headRef, "staging")).To(Succeed())
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "keys", Namespace: "default"},
- Data: map[string][]byte{"foo": []byte(armoredKeyRingFixture)},
+ Name: "keys", Namespace: "default",
+ Data: map[string][]byte{"foo": []byte(armoredKeyRingFixture)},
}
tests := []struct {
@@ -4287,11 +4156,9 @@ func TestGitRepositoryReconciler_reconcileSource_verificationPolicyChange(t *tes
g := NewWithT(t)
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "verification-policy-",
- Namespace: "default",
- Generation: 1,
- },
+ GenerateName: "verification-policy-",
+ Namespace: "default",
+ Generation: 1,
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -4309,7 +4176,7 @@ func TestGitRepositoryReconciler_reconcileSource_verificationPolicyChange(t *tes
Revision: "staging@sha1:" + headRef.Hash().String(),
Path: randStringRunes(10),
},
- SourceVerificationMode: ptrToVerificationMode(sourcev1.ModeGitHEAD),
+ SourceVerificationMode: new(sourcev1.ModeGitHEAD),
SourceVerificationFingerprint: tt.fingerprint,
},
}
@@ -4344,6 +4211,7 @@ func TestGitRepositoryReconciler_reconcileSource_verificationPolicyChange(t *tes
}
}
+//go:fix inline
func ptrToVerificationMode(mode sourcev1.GitVerificationMode) *sourcev1.GitVerificationMode {
- return &mode
+ return new(mode)
}
diff --git a/internal/controller/helmchart_controller_test.go b/internal/controller/helmchart_controller_test.go
index 762dce5c6..c10943c60 100644
--- a/internal/controller/helmchart_controller_test.go
+++ b/internal/controller/helmchart_controller_test.go
@@ -86,7 +86,7 @@ func TestHelmChartReconciler_deleteBeforeFinalizer(t *testing.T) {
namespaceName := "helmchart-" + randStringRunes(5)
namespace := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
+ Name: namespaceName,
}
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
t.Cleanup(func() {
@@ -293,10 +293,8 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
repository := sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- Namespace: ns.Name,
- },
+ GenerateName: "helmrepository-",
+ Namespace: ns.Name,
Spec: sourcev1.HelmRepositorySpec{
URL: server.URL(),
},
@@ -310,10 +308,8 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, &repository)).To(Succeed()) }()
obj := sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-reconcile-",
- Namespace: ns.Name,
- },
+ GenerateName: "helmrepository-reconcile-",
+ Namespace: ns.Name,
Spec: sourcev1.HelmChartSpec{
Chart: chartName,
Version: chartVersion,
@@ -371,7 +367,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) {
Revision: "d",
Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4",
URL: testStorage.Hostname + "/reconcile-storage/d.txt",
- Size: int64p(int64(len("d"))),
+ Size: new(int64(len("d"))),
},
assertPaths: []string{
"/reconcile-storage/d.txt",
@@ -500,7 +496,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) {
Revision: "f",
Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80",
URL: testStorage.Hostname + "/reconcile-storage/hostname.txt",
- Size: int64p(int64(len("file"))),
+ Size: new(int64(len("file"))),
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReadyCondition, "foo", "bar"),
@@ -526,10 +522,8 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) {
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: 1,
- },
+ GenerateName: "test-",
+ Generation: 1,
}
if tt.beforeFunc != nil {
g.Expect(tt.beforeFunc(obj, testStorage)).To(Succeed())
@@ -602,10 +596,8 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) {
{
name: "Observes Artifact revision and build result",
source: &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gitrepository",
- Namespace: "default",
- },
+ Name: "gitrepository",
+ Namespace: "default",
Status: sourcev1.GitRepositoryStatus{
Artifact: gitArtifact,
},
@@ -637,10 +629,8 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) {
{
name: "Existing artifact makes AritfactOutdated=True",
source: &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gitrepository",
- Namespace: "default",
- },
+ Name: "gitrepository",
+ Namespace: "default",
Status: sourcev1.GitRepositoryStatus{
Artifact: gitArtifact,
},
@@ -718,10 +708,8 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) {
{
name: "Stalling on persistent build error",
source: &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gitrepository",
- Namespace: "default",
- },
+ Name: "gitrepository",
+ Namespace: "default",
Status: sourcev1.GitRepositoryStatus{
Artifact: gitArtifact,
},
@@ -751,11 +739,9 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) {
{
name: "ResultRequeue when source artifact is unavailable",
source: &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gitrepository",
- Namespace: "default",
- },
- Status: sourcev1.GitRepositoryStatus{},
+ Name: "gitrepository",
+ Namespace: "default",
+ Status: sourcev1.GitRepositoryStatus{},
},
beforeFunc: func(obj *sourcev1.HelmChart) {
obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz"
@@ -801,12 +787,10 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) {
}
obj := sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "chart",
- Namespace: "default",
- Generation: 1,
- },
- Spec: sourcev1.HelmChartSpec{},
+ GenerateName: "chart",
+ Namespace: "default",
+ Generation: 1,
+ Spec: sourcev1.HelmChartSpec{},
}
if tt.beforeFunc != nil {
tt.beforeFunc(&obj)
@@ -901,9 +885,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) {
password: "bar",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth",
- },
+ Name: "auth",
Data: map[string][]byte{
"username": []byte("foo"),
"password": []byte("bar"),
@@ -1139,9 +1121,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) {
}
repository := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
+ GenerateName: "helmrepository-",
Spec: sourcev1.HelmRepositorySpec{
URL: server.URL(),
Timeout: &metav1.Duration{Duration: timeout},
@@ -1153,10 +1133,8 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) {
},
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
- Spec: sourcev1.HelmChartSpec{},
+ GenerateName: "helmrepository-",
+ Spec: sourcev1.HelmChartSpec{},
}
if tt.beforeFunc != nil {
@@ -1229,9 +1207,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
{
name: "Reconciles chart build with docker repository credentials",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth",
- },
+ Name: "auth",
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{
".dockerconfigjson": []byte(`{"auths":{"` +
@@ -1258,9 +1234,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
{
name: "Reconciles chart build with repository credentials",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth",
- },
+ Name: "auth",
Data: map[string][]byte{
"username": []byte(testRegistryUsername),
"password": []byte(testRegistryPassword),
@@ -1301,9 +1275,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
{
name: "Forces build on generation change",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth",
- },
+ Name: "auth",
Data: map[string][]byte{
"username": []byte(testRegistryUsername),
"password": []byte(testRegistryPassword),
@@ -1392,9 +1364,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
}
repository := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
+ GenerateName: "helmrepository-",
Spec: sourcev1.HelmRepositorySpec{
URL: fmt.Sprintf("oci://%s/testrepo", testRegistryServer.registryHost),
Timeout: &metav1.Duration{Duration: timeout},
@@ -1404,10 +1374,8 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
},
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
- Spec: sourcev1.HelmChartSpec{},
+ GenerateName: "helmrepository-",
+ Spec: sourcev1.HelmChartSpec{},
}
if tt.beforeFunc != nil {
@@ -1634,11 +1602,9 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) {
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- Name: "artifact",
- Namespace: "default",
- },
- Spec: sourcev1.HelmChartSpec{},
+ Name: "artifact",
+ Namespace: "default",
+ Spec: sourcev1.HelmChartSpec{},
}
if tt.beforeFunc != nil {
tt.beforeFunc(obj)
@@ -1844,11 +1810,9 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) {
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "reconcile-artifact-",
- Generation: 1,
- },
- Status: sourcev1.HelmChartStatus{},
+ GenerateName: "reconcile-artifact-",
+ Generation: 1,
+ Status: sourcev1.HelmChartStatus{},
}
if tt.beforeFunc != nil {
tt.beforeFunc(obj)
@@ -1875,34 +1839,22 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) {
func TestHelmChartReconciler_getSource(t *testing.T) {
mocks := []client.Object{
&sourcev1.HelmRepository{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.HelmRepositoryKind,
- APIVersion: sourcev1.GroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "helmrepository",
- Namespace: "foo",
- },
+ Kind: sourcev1.HelmRepositoryKind,
+ APIVersion: sourcev1.GroupVersion.String(),
+ Name: "helmrepository",
+ Namespace: "foo",
},
&sourcev1.GitRepository{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.GitRepositoryKind,
- APIVersion: sourcev1.GroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "gitrepository",
- Namespace: "foo",
- },
+ Kind: sourcev1.GitRepositoryKind,
+ APIVersion: sourcev1.GroupVersion.String(),
+ Name: "gitrepository",
+ Namespace: "foo",
},
&sourcev1.Bucket{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.BucketKind,
- APIVersion: sourcev1.GroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "bucket",
- Namespace: "foo",
- },
+ Kind: sourcev1.BucketKind,
+ APIVersion: sourcev1.GroupVersion.String(),
+ Name: "bucket",
+ Namespace: "foo",
},
}
@@ -1925,9 +1877,7 @@ func TestHelmChartReconciler_getSource(t *testing.T) {
{
name: "Get HelmRepository source for reference",
obj: &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: mocks[0].GetNamespace(),
- },
+ Namespace: mocks[0].GetNamespace(),
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: mocks[0].GetName(),
@@ -1940,9 +1890,7 @@ func TestHelmChartReconciler_getSource(t *testing.T) {
{
name: "Get GitRepository source for reference",
obj: &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: mocks[1].GetNamespace(),
- },
+ Namespace: mocks[1].GetNamespace(),
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: mocks[1].GetName(),
@@ -1955,9 +1903,7 @@ func TestHelmChartReconciler_getSource(t *testing.T) {
{
name: "Get Bucket source for reference",
obj: &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: mocks[2].GetNamespace(),
- },
+ Namespace: mocks[2].GetNamespace(),
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: mocks[2].GetName(),
@@ -1970,9 +1916,7 @@ func TestHelmChartReconciler_getSource(t *testing.T) {
{
name: "Error on client error",
obj: &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: mocks[2].GetNamespace(),
- },
+ Namespace: mocks[2].GetNamespace(),
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: mocks[1].GetName(),
@@ -2035,12 +1979,10 @@ func TestHelmChartReconciler_reconcileDelete(t *testing.T) {
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- Name: "reconcile-delete-",
- DeletionTimestamp: &metav1.Time{Time: time.Now()},
- Finalizers: []string{
- sourcev1.SourceFinalizer,
- },
+ Name: "reconcile-delete-",
+ DeletionTimestamp: &metav1.Time{Time: time.Now()},
+ Finalizers: []string{
+ sourcev1.SourceFinalizer,
},
Status: sourcev1.HelmChartStatus{},
}
@@ -2173,10 +2115,8 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) {
patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"),
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: tt.generation,
- },
+ GenerateName: "test-",
+ Generation: tt.generation,
Status: sourcev1.HelmChartStatus{
ObservedGeneration: tt.observedGeneration,
},
@@ -2275,14 +2215,10 @@ func TestHelmChartReconciler_statusConditions(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.HelmChart{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.HelmChartKind,
- APIVersion: sourcev1.GroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "helmchart",
- Namespace: "foo",
- },
+ Kind: sourcev1.HelmChartKind,
+ APIVersion: sourcev1.GroupVersion.String(),
+ Name: "helmchart",
+ Namespace: "foo",
}
clientBuilder := fakeclient.NewClientBuilder().
@@ -2493,9 +2429,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
password: testRegistryPassword,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-secretref",
- },
+ Name: "auth-secretref",
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{},
},
@@ -2517,9 +2451,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
password: "wrong-pass",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-secretref",
- },
+ Name: "auth-secretref",
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{},
},
@@ -2534,7 +2466,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
provider: "aws",
providerImg: "oci://123456789000.dkr.ecr.us-east-2.amazonaws.com/test",
assertConditions: []metav1.Condition{
- *conditions.TrueCondition(sourcev1.FetchFailedCondition, "Unknown", "unknown build error: unable to get authentication data from OIDC: failed to get access token for artifact registry"),
+ *conditions.TrueCondition(sourcev1.FetchFailedCondition, "Unknown", "unknown build error: unable to get authentication data from OIDC: failed to get access credential for artifact registry"),
},
},
{
@@ -2549,9 +2481,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
password: testRegistryPassword,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-secretref",
- },
+ Name: "auth-secretref",
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{},
},
@@ -2573,16 +2503,12 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
password: testRegistryPassword,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-secretref",
- },
+ Name: "auth-secretref",
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{},
},
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "certs-secretref",
- },
+ Name: "certs-secretref",
Data: map[string][]byte{
"ca.crt": []byte("invalid caFile"),
},
@@ -2598,9 +2524,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
withTLS: true,
},
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "certs-secretref",
- },
+ Name: "certs-secretref",
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"ca.crt": tlsCA,
@@ -2619,9 +2543,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
withClientCertAuth: true,
},
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "certs-secretref",
- },
+ Name: "certs-secretref",
Data: map[string][]byte{
"ca.crt": tlsCA,
"tls.crt": clientPublicKey,
@@ -2643,9 +2565,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
withClientCertAuth: true,
},
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "certs-secretref",
- },
+ Name: "certs-secretref",
Data: map[string][]byte{
"ca.crt": tlsCA,
"tls.crt": clientInvalidPublicKey,
@@ -2683,9 +2603,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
g.Expect(err).ToNot(HaveOccurred())
repo := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "auth-strategy-",
- },
+ GenerateName: "auth-strategy-",
Spec: sourcev1.HelmRepositorySpec{
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -2728,9 +2646,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
clientBuilder.WithObjects(repo)
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "auth-strategy-",
- },
+ GenerateName: "auth-strategy-",
Spec: sourcev1.HelmChartSpec{
Chart: metadata.Name,
Version: metadata.Version,
@@ -2889,9 +2805,7 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t
clientBuilder := fakeclient.NewClientBuilder()
repository := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
+ GenerateName: "helmrepository-",
Spec: sourcev1.HelmRepositorySpec{
URL: "oci://ghcr.io/stefanprodan/charts",
Timeout: &metav1.Duration{Duration: timeout},
@@ -2911,9 +2825,7 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmchart-",
- },
+ GenerateName: "helmchart-",
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Kind: sourcev1.HelmRepositoryKind,
@@ -3158,9 +3070,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t
clientBuilder := fakeclient.NewClientBuilder()
repository := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
+ GenerateName: "helmrepository-",
Spec: sourcev1.HelmRepositorySpec{
URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost),
Timeout: &metav1.Duration{Duration: timeout},
@@ -3190,17 +3100,13 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t
}
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "notation-config",
- },
+ Name: "notation-config",
Data: data,
}
caSecret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "valid-trust-store",
- Generation: 1,
- },
+ Name: "valid-trust-store",
+ Generation: 1,
Data: map[string][]byte{
"ca.crt": tlsCA,
},
@@ -3218,9 +3124,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmchart-",
- },
+ GenerateName: "helmchart-",
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Kind: sourcev1.HelmRepositoryKind,
@@ -3250,10 +3154,8 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t
signatureMediaType := cose.MediaTypeEnvelope
signOptions := notation.SignOptions{
- SignerSignOptions: notation.SignerSignOptions{
- SignatureMediaType: signatureMediaType,
- },
- ArtifactReference: artifact,
+ SignatureMediaType: signatureMediaType,
+ ArtifactReference: artifact,
}
_, err = notation.Sign(ctx, sg, repo, signOptions)
@@ -3440,9 +3342,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes
clientBuilder := fakeclient.NewClientBuilder()
repository := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- },
+ GenerateName: "helmrepository-",
Spec: sourcev1.HelmRepositorySpec{
URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost),
Timeout: &metav1.Duration{Duration: timeout},
@@ -3453,9 +3353,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes
}
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "cosign-key",
- },
+ Name: "cosign-key",
Data: map[string][]byte{
"cosign.pub": keys.PublicBytes,
}}
@@ -3472,9 +3370,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes
}
obj := &sourcev1.HelmChart{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmchart-",
- },
+ GenerateName: "helmchart-",
Spec: sourcev1.HelmChartSpec{
SourceRef: sourcev1.LocalHelmChartSourceReference{
Kind: sourcev1.HelmRepositoryKind,
diff --git a/internal/controller/helmrepository_controller.go b/internal/controller/helmrepository_controller.go
index 7266e6e89..d3a966fe3 100644
--- a/internal/controller/helmrepository_controller.go
+++ b/internal/controller/helmrepository_controller.go
@@ -390,7 +390,7 @@ func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *pat
// v1.FetchFailedCondition is removed, and the repository.ChartRepository
// pointer is set to the newly fetched index.
func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher,
- obj *sourcev1.HelmRepository, artifact *meta.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) {
+ obj *sourcev1.HelmRepository, artifact *meta.Artifact, chartRepo *repository.ChartRepository) (_ sreconcile.Result, retErr error) {
// Ensure it's not an OCI URL. API validation ensures that only
// http/https/oci scheme are allowed.
if helmreg.IsOCI(obj.Spec.URL) {
@@ -461,6 +461,16 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc
}
*chartRepo = *newChartRepo
+ // reconcileArtifact removes the cached index on success. On error the
+ // deferred cleanup below removes it, covering error paths added later.
+ defer func() {
+ if retErr != nil {
+ if err := chartRepo.Clear(); err != nil {
+ ctrl.LoggerFrom(ctx).Error(err, "failed to remove temporary cached index file")
+ }
+ }
+ }()
+
// Early comparison to current Artifact.
if curArtifact := obj.GetArtifact(); curArtifact != nil {
curRev := digest.Digest(curArtifact.Revision)
@@ -478,7 +488,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc
// Load the cached repository index to ensure it passes validation.
if err := chartRepo.LoadFromPath(); err != nil {
e := serror.NewGeneric(
- fmt.Errorf("failed to load Helm repository from index YAML: %w", err),
+ fmt.Errorf("failed to load Helm repository from index YAML at %s: %w", redactURL(obj.Spec.URL), err),
sourcev1.IndexationFailedReason,
)
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
@@ -491,7 +501,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc
revision := chartRepo.Digest(intdigest.Canonical)
if revision.Validate() != nil {
e := serror.NewGeneric(
- fmt.Errorf("failed to calculate revision: %w", err),
+ fmt.Errorf("failed to calculate revision: invalid digest '%s'", revision),
sourcev1.IndexationFailedReason,
)
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
@@ -722,3 +732,13 @@ func (r *HelmRepositoryReconciler) migrationToStatic(ctx context.Context, sp *pa
return ctrl.Result{}, nil
}
+
+// redactURL returns the given URL with the password of its user info
+// replaced, so it can be added to conditions and events.
+func redactURL(repoURL string) string {
+ u, err := url.Parse(repoURL)
+ if err != nil {
+ return ""
+ }
+ return u.Redacted()
+}
diff --git a/internal/controller/helmrepository_controller_test.go b/internal/controller/helmrepository_controller_test.go
index c34c49d27..fb6a628f5 100644
--- a/internal/controller/helmrepository_controller_test.go
+++ b/internal/controller/helmrepository_controller_test.go
@@ -38,6 +38,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
+ "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
kstatus "github.com/fluxcd/cli-utils/pkg/kstatus/status"
@@ -64,7 +65,7 @@ func TestHelmRepositoryReconciler_deleteBeforeFinalizer(t *testing.T) {
namespaceName := "helmrepo-" + randStringRunes(5)
namespace := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
+ Name: namespaceName,
}
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
t.Cleanup(func() {
@@ -108,10 +109,8 @@ func TestHelmRepositoryReconciler_Reconcile(t *testing.T) {
defer testServer.Stop()
origObj := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "helmrepository-reconcile-",
+ Namespace: "default",
Spec: sourcev1.HelmRepositorySpec{
Interval: metav1.Duration{Duration: interval},
URL: testServer.URL(),
@@ -210,7 +209,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) {
Revision: "d",
Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4",
URL: testStorage.Hostname + "/reconcile-storage/d.txt",
- Size: int64p(int64(len("d"))),
+ Size: new(int64(len("d"))),
},
assertPaths: []string{
"/reconcile-storage/d.txt",
@@ -342,7 +341,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) {
Revision: "f",
Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80",
URL: testStorage.Hostname + "/reconcile-storage/hostname.txt",
- Size: int64p(int64(len("file"))),
+ Size: new(int64(len("file"))),
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReadyCondition, "foo", "bar"),
@@ -366,10 +365,8 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) {
}
obj := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: 1,
- },
+ GenerateName: "test-",
+ Generation: 1,
}
if tt.beforeFunc != nil {
g.Expect(tt.beforeFunc(obj, testStorage)).To(Succeed())
@@ -450,10 +447,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
want: sreconcile.ResultSuccess,
wantErr: false,
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- Namespace: "default",
- },
+ Name: "ca-file",
+ Namespace: "default",
Data: map[string][]byte{
"ca.crt": tlsCA,
},
@@ -475,10 +470,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- Namespace: "default",
- },
+ Name: "ca-file",
+ Namespace: "default",
Data: map[string][]byte{
"ca.crt": tlsCA,
},
@@ -527,10 +520,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- Namespace: "default",
- },
+ Name: "ca-file",
+ Namespace: "default",
Data: map[string][]byte{
"caFile": tlsCA,
},
@@ -580,10 +571,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- Namespace: "default",
- },
+ Name: "ca-file",
+ Namespace: "default",
Data: map[string][]byte{
"caFile": tlsCA,
},
@@ -664,10 +653,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
password: "1234",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "basic-auth",
- Namespace: "default",
- },
+ Name: "basic-auth",
+ Namespace: "default",
Data: map[string][]byte{
"username": []byte("git"),
"password": []byte("1234"),
@@ -718,10 +705,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
password: "1234",
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "basic-auth",
- Namespace: "default",
- },
+ Name: "basic-auth",
+ Namespace: "default",
Data: map[string][]byte{
"username": []byte("git"),
"password": []byte("1234"),
@@ -773,10 +758,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
ca: tlsCA,
},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalid-ca",
- Namespace: "default",
- },
+ Name: "invalid-ca",
+ Namespace: "default",
Data: map[string][]byte{
"ca.crt": []byte("invalid"),
},
@@ -868,10 +851,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
name: "Malformed secret returns FetchFailed=True and returns error",
protocol: "http",
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "malformed-basic-auth",
- Namespace: "default",
- },
+ Name: "malformed-basic-auth",
+ Namespace: "default",
Data: map[string][]byte{
"username": []byte("git"),
},
@@ -977,11 +958,9 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
for _, tt := range tests {
obj := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "auth-strategy-",
- Generation: 1,
- Namespace: "default",
- },
+ GenerateName: "auth-strategy-",
+ Generation: 1,
+ Namespace: "default",
Spec: sourcev1.HelmRepositorySpec{
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -1089,6 +1068,161 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
}
}
+func TestHelmRepositoryReconciler_reconcileSource_cachedIndexFile(t *testing.T) {
+ newReconciler := func(g *WithT, c client.Client) *HelmRepositoryReconciler {
+ return &HelmRepositoryReconciler{
+ Recorder: events.NewFakeRecorder(32, false),
+ Client: c,
+ Storage: testStorage,
+ Getters: testGetters,
+ patchOptions: getPatchOptions(helmRepositoryReadyCondition.Owned, "sc"),
+ }
+ }
+
+ startServer := func(g *WithT, index []byte) *helmtestserver.HelmServer {
+ server, err := helmtestserver.NewTempHelmServer()
+ g.Expect(err).NotTo(HaveOccurred())
+ if index == nil {
+ g.Expect(server.PackageChart("testdata/charts/helmchart")).To(Succeed())
+ g.Expect(server.GenerateIndex()).To(Succeed())
+ } else {
+ g.Expect(os.WriteFile(filepath.Join(server.Root(), "index.yaml"), index, 0o600)).To(Succeed())
+ }
+ server.Start()
+ return server
+ }
+
+ newObject := func(url string) *sourcev1.HelmRepository {
+ return &sourcev1.HelmRepository{
+ Name: "index-cache",
+ Namespace: "default",
+ Generation: 1,
+ Spec: sourcev1.HelmRepositorySpec{
+ Interval: metav1.Duration{Duration: interval},
+ Timeout: &metav1.Duration{Duration: timeout},
+ URL: url,
+ },
+ }
+ }
+
+ chartIndexFiles := func(g *WithT, dir string) []string {
+ matches, err := filepath.Glob(filepath.Join(dir, "chart-index-*.yaml"))
+ g.Expect(err).NotTo(HaveOccurred())
+ return matches
+ }
+
+ t.Run("invalid index removes cached file", func(t *testing.T) {
+ g := NewWithT(t)
+ dir := t.TempDir()
+ t.Setenv("TMPDIR", dir)
+
+ // HTTP 200 with a body that is not a Helm index. Download succeeds
+ // and LoadFromPath fails.
+ server := startServer(g, []byte("{}\n"))
+ defer server.Stop()
+ defer os.RemoveAll(server.Root())
+
+ c := fakeclient.NewClientBuilder().
+ WithScheme(testEnv.GetScheme()).
+ WithStatusSubresource(&sourcev1.HelmRepository{}).
+ Build()
+ obj := newObject(server.URL())
+ g.Expect(c.Create(context.TODO(), obj)).To(Succeed())
+
+ var chartRepo repository.ChartRepository
+ got, err := newReconciler(g, c).reconcileSource(context.TODO(), patch.NewSerialPatcher(obj, c), obj, &meta.Artifact{}, &chartRepo)
+
+ g.Expect(err).To(HaveOccurred())
+ g.Expect(err.Error()).To(ContainSubstring("failed to load Helm repository from index YAML at " + server.URL() + ":"))
+ g.Expect(got).To(Equal(sreconcile.ResultEmpty))
+ g.Expect(conditions.IsTrue(obj, sourcev1.FetchFailedCondition)).To(BeTrue())
+ g.Expect(conditions.GetMessage(obj, sourcev1.FetchFailedCondition)).To(ContainSubstring("failed to load Helm repository from index YAML at " + server.URL() + ":"))
+ g.Expect(chartIndexFiles(g, dir)).To(BeEmpty())
+ })
+
+ t.Run("invalid index message redacts credentials in the URL", func(t *testing.T) {
+ g := NewWithT(t)
+ dir := t.TempDir()
+ t.Setenv("TMPDIR", dir)
+
+ server := startServer(g, []byte("{}\n"))
+ defer server.Stop()
+ defer os.RemoveAll(server.Root())
+
+ c := fakeclient.NewClientBuilder().
+ WithScheme(testEnv.GetScheme()).
+ WithStatusSubresource(&sourcev1.HelmRepository{}).
+ Build()
+ obj := newObject(strings.Replace(server.URL(), "http://", "http://user:s3cr3t@", 1))
+ g.Expect(c.Create(context.TODO(), obj)).To(Succeed())
+
+ var chartRepo repository.ChartRepository
+ _, err := newReconciler(g, c).reconcileSource(context.TODO(), patch.NewSerialPatcher(obj, c), obj, &meta.Artifact{}, &chartRepo)
+
+ g.Expect(err).To(HaveOccurred())
+ g.Expect(err.Error()).To(ContainSubstring("failed to load Helm repository from index YAML at"))
+ g.Expect(err.Error()).To(ContainSubstring("user:xxxxx@"))
+ g.Expect(err.Error()).ToNot(ContainSubstring("s3cr3t"))
+ g.Expect(conditions.GetMessage(obj, sourcev1.FetchFailedCondition)).ToNot(ContainSubstring("s3cr3t"))
+ })
+
+ t.Run("status patch failure removes cached file", func(t *testing.T) {
+ g := NewWithT(t)
+ dir := t.TempDir()
+ t.Setenv("TMPDIR", dir)
+
+ server := startServer(g, nil)
+ defer server.Stop()
+ defer os.RemoveAll(server.Root())
+
+ base := fakeclient.NewClientBuilder().
+ WithScheme(testEnv.GetScheme()).
+ WithStatusSubresource(&sourcev1.HelmRepository{}).
+ Build()
+ c := interceptor.NewClient(base, interceptor.Funcs{
+ SubResourcePatch: func(context.Context, client.Client, string, client.Object, client.Patch, ...client.SubResourcePatchOption) error {
+ return errors.New("injected patch failure")
+ },
+ })
+ obj := newObject(server.URL())
+ g.Expect(c.Create(context.TODO(), obj)).To(Succeed())
+
+ var chartRepo repository.ChartRepository
+ got, err := newReconciler(g, c).reconcileSource(context.TODO(), patch.NewSerialPatcher(obj, c), obj, &meta.Artifact{}, &chartRepo)
+
+ g.Expect(err).To(HaveOccurred())
+ g.Expect(err.Error()).To(ContainSubstring("injected patch failure"))
+ g.Expect(got).To(Equal(sreconcile.ResultEmpty))
+ g.Expect(chartIndexFiles(g, dir)).To(BeEmpty())
+ })
+
+ t.Run("successful fetch keeps cached file", func(t *testing.T) {
+ g := NewWithT(t)
+ dir := t.TempDir()
+ t.Setenv("TMPDIR", dir)
+
+ server := startServer(g, nil)
+ defer server.Stop()
+ defer os.RemoveAll(server.Root())
+
+ c := fakeclient.NewClientBuilder().
+ WithScheme(testEnv.GetScheme()).
+ WithStatusSubresource(&sourcev1.HelmRepository{}).
+ Build()
+ obj := newObject(server.URL())
+ g.Expect(c.Create(context.TODO(), obj)).To(Succeed())
+
+ var chartRepo repository.ChartRepository
+ got, err := newReconciler(g, c).reconcileSource(context.TODO(), patch.NewSerialPatcher(obj, c), obj, &meta.Artifact{}, &chartRepo)
+ defer os.Remove(chartRepo.Path)
+
+ g.Expect(err).NotTo(HaveOccurred())
+ g.Expect(got).To(Equal(sreconcile.ResultSuccess))
+ matches := chartIndexFiles(g, dir)
+ g.Expect(matches).To(Equal([]string{chartRepo.Path}))
+ })
+}
+
func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) {
// The cache is at capacity with the previous revision and an index of
// another repository, the new revision can only be added after eviction.
@@ -1226,14 +1360,10 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) {
}
obj := &sourcev1.HelmRepository{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.HelmRepositoryKind,
- },
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-bucket-",
- Generation: 1,
- Namespace: "default",
- },
+ Kind: sourcev1.HelmRepositoryKind,
+ GenerateName: "test-bucket-",
+ Generation: 1,
+ Namespace: "default",
Spec: sourcev1.HelmRepositorySpec{
Timeout: &metav1.Duration{Duration: timeout},
URL: "https://example.com/index.yaml",
@@ -1303,13 +1433,9 @@ func TestHelmRepositoryReconciler_garbageCollectEvictsCache(t *testing.T) {
}
obj := &sourcev1.HelmRepository{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.HelmRepositoryKind,
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "cache-evict",
- Namespace: "default",
- },
+ Kind: sourcev1.HelmRepositoryKind,
+ Name: "cache-evict",
+ Namespace: "default",
}
artifact := testStorage.NewArtifactFor(obj.Kind, obj, "existing", "index-existing.yaml")
obj.Status.Artifact = &artifact
@@ -1441,10 +1567,8 @@ func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) {
patchOptions: getPatchOptions(helmRepositoryReadyCondition.Owned, "sc"),
}
obj := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: tt.generation,
- },
+ GenerateName: "test-",
+ Generation: tt.generation,
Status: sourcev1.HelmRepositoryStatus{
ObservedGeneration: tt.observedGeneration,
},
@@ -1520,14 +1644,10 @@ func TestHelmRepositoryReconciler_statusConditions(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.HelmRepository{
- TypeMeta: metav1.TypeMeta{
- Kind: sourcev1.HelmRepositoryKind,
- APIVersion: sourcev1.GroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "helmrepo",
- Namespace: "foo",
- },
+ Kind: sourcev1.HelmRepositoryKind,
+ APIVersion: sourcev1.GroupVersion.String(),
+ Name: "helmrepo",
+ Namespace: "foo",
}
clientBuilder := fakeclient.NewClientBuilder().
@@ -1715,10 +1835,8 @@ func TestHelmRepositoryReconciler_ReconcileTypeUpdatePredicateFilter(t *testing.
defer testServer.Stop()
obj := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "helmrepository-reconcile-",
+ Namespace: "default",
Spec: sourcev1.HelmRepositorySpec{
Interval: metav1.Duration{Duration: interval},
URL: testServer.URL(),
@@ -1804,10 +1922,8 @@ func TestHelmRepositoryReconciler_ReconcileSpecUpdatePredicateFilter(t *testing.
defer testServer.Stop()
obj := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-reconcile-",
- Namespace: "default",
- },
+ GenerateName: "helmrepository-reconcile-",
+ Namespace: "default",
Spec: sourcev1.HelmRepositorySpec{
Interval: metav1.Duration{Duration: interval},
URL: testServer.URL(),
@@ -1906,10 +2022,8 @@ func TestHelmRepositoryReconciler_InMemoryCaching(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
helmRepo := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "helmrepository-",
- Namespace: ns.Name,
- },
+ GenerateName: "helmrepository-",
+ Namespace: ns.Name,
Spec: sourcev1.HelmRepositorySpec{
URL: testServer.URL(),
},
@@ -1965,10 +2079,8 @@ func TestHelmRepositoryReconciler_ociMigration(t *testing.T) {
})
hr := &sourcev1.HelmRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("hr-%s", randStringRunes(5)),
- Namespace: testns.Name,
- },
+ Name: fmt.Sprintf("hr-%s", randStringRunes(5)),
+ Namespace: testns.Name,
}
hrKey := client.ObjectKeyFromObject(hr)
diff --git a/internal/controller/ocirepository_controller.go b/internal/controller/ocirepository_controller.go
index cbd4f7777..5329432e3 100644
--- a/internal/controller/ocirepository_controller.go
+++ b/internal/controller/ocirepository_controller.go
@@ -47,6 +47,7 @@ import (
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
+ cryptov1 "github.com/fluxcd/pkg/apis/crypto/v1"
eventv1 "github.com/fluxcd/pkg/apis/event/v1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/artifact/storage"
@@ -62,6 +63,7 @@ import (
rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
"github.com/fluxcd/pkg/runtime/secrets"
"github.com/fluxcd/pkg/sourceignore"
+ fluxbroker "github.com/fluxcd/pkg/spiffe/broker"
"github.com/fluxcd/pkg/tar"
"github.com/fluxcd/pkg/version"
ctrl "sigs.k8s.io/controller-runtime"
@@ -144,7 +146,10 @@ type OCIRepositoryReconciler struct {
ControllerName string
TokenCache *cache.TokenCache
CosignVerifierFactory *scosign.CosignVerifierFactory
- requeueDependency time.Duration
+ DefaultServiceAccount string
+ SPIFFEBroker fluxbroker.Interface
+
+ requeueDependency time.Duration
patchOptions []patch.Option
}
@@ -340,8 +345,67 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
conditions.Delete(obj, sourcev1.SourceVerifiedCondition)
}
- // Generate the registry credential keychain either from static credentials or using cloud OIDC
- keychain, err := r.keychain(ctx, obj)
+ provider := obj.GetProvider()
+
+ // Apply the default ServiceAccount when the object does not specify one, so
+ // that both the keychain and the auth library are aware of it.
+ saName := obj.Spec.ServiceAccountName
+ if saName == "" {
+ saName = r.DefaultServiceAccount
+ }
+
+ // Fetch the ServiceAccount once.
+ var sa *corev1.ServiceAccount
+ if saName != "" {
+ sa = &corev1.ServiceAccount{}
+ saRef := types.NamespacedName{Namespace: obj.GetNamespace(), Name: saName}
+ if err := r.Get(ctx, saRef, sa); err != nil {
+ e := serror.NewGeneric(
+ fmt.Errorf("failed to get service account '%s': %w", saRef, err),
+ sourcev1.AuthenticationFailedReason,
+ )
+ conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
+ return sreconcile.ResultEmpty, e
+ }
+ }
+
+ // Build the authentication spec. BuildSpec is safe to call even when there
+ // is no ServiceAccount or provider-specific configuration: it returns a
+ // spec with a nil Auth in that case.
+ buildOpts := []cryptov1.Option{
+ cryptov1.WithServiceProvider(provider),
+ cryptov1.WithOCI(),
+ }
+ if obj.Spec.SecretRef != nil {
+ buildOpts = append(buildOpts, cryptov1.WithSecretRefAuth())
+ }
+ if sa != nil {
+ buildOpts = append(buildOpts, cryptov1.WithAnnotations(sa.Annotations))
+ if len(sa.ImagePullSecrets) > 0 {
+ buildOpts = append(buildOpts, cryptov1.WithImagePullSecrets())
+ }
+ }
+ if obj.Spec.CertSecretRef != nil {
+ buildOpts = append(buildOpts, cryptov1.WithCertSecretRef())
+ }
+ cryptoSpec, err := cryptov1.BuildSpec(buildOpts...)
+ if err != nil {
+ e := serror.NewGeneric(
+ fmt.Errorf("failed to validate configuration: %w", err),
+ sourcev1.AuthenticationFailedReason,
+ )
+ conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
+ return sreconcile.ResultEmpty, e
+ }
+
+ // Generate the registry credential keychain either from static credentials
+ // or using cloud OIDC. The ServiceAccount is only used for its image pull
+ // secrets when it has any.
+ var keychainSA *corev1.ServiceAccount
+ if sa != nil && len(sa.ImagePullSecrets) > 0 {
+ keychainSA = sa
+ }
+ keychain, err := r.keychain(ctx, obj, keychainSA)
if err != nil {
e := serror.NewGeneric(
fmt.Errorf("failed to get credential: %w", err),
@@ -368,40 +432,30 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
}
}
- if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != "" && obj.Spec.Provider != sourcev1.GenericOCIProvider && ok {
- opts := []auth.Option{
+ // Workload identity kicks in when the provider is not generic or
+ // the SA has opted into object-level workload identity.
+ if _, ok := keychain.(soci.Anonymous); ok && (provider != sourcev1.GenericOCIProvider || cryptoSpec.Auth.OptedIn()) {
+ opts := auth.OptionsFromSpec(cryptoSpec.Auth)
+ opts = append(opts,
auth.WithClient(r.Client),
- auth.WithServiceAccountNamespace(obj.GetNamespace()),
- }
-
- if obj.Spec.ServiceAccountName != "" {
- // Check object-level workload identity feature gate.
- if !auth.IsObjectLevelWorkloadIdentityEnabled() {
- const gate = auth.FeatureGateObjectLevelWorkloadIdentity
- const msgFmt = "to use spec.serviceAccountName for provider authentication please enable the %s feature gate in the controller"
- err := fmt.Errorf(msgFmt, gate)
- return sreconcile.ResultEmpty, serror.NewStalling(err, meta.FeatureGateDisabledReason)
- }
- // Set ServiceAccountName only if explicitly specified
- opts = append(opts, auth.WithServiceAccountName(obj.Spec.ServiceAccountName))
+ auth.WithObject(sourcev1.GroupVersion.Group, sourcev1.OCIRepositoryKind, obj),
+ auth.WithSPIFFEBroker(r.SPIFFEBroker))
+ if sa != nil {
+ opts = append(opts, auth.WithServiceAccountName(sa.Name))
}
if r.TokenCache != nil {
- involvedObject := cache.InvolvedObject{
- Kind: sourcev1.OCIRepositoryKind,
- Name: obj.GetName(),
- Namespace: obj.GetNamespace(),
- Operation: cache.OperationReconcile,
- }
- opts = append(opts, auth.WithCache(*r.TokenCache, involvedObject))
+ opts = append(opts,
+ auth.WithCache(*r.TokenCache),
+ auth.WithCacheOperation(cache.OperationReconcile))
}
if proxyURL != nil {
opts = append(opts, auth.WithProxyURL(*proxyURL))
}
var authErr error
- authenticator, authErr = soci.OIDCAuth(ctxTimeout, obj.Spec.URL, obj.Spec.Provider, opts...)
+ authenticator, authErr = soci.OIDCAuth(ctxTimeout, obj.Spec.URL, provider, opts...)
if authErr != nil {
e := serror.NewGeneric(
- fmt.Errorf("failed to get credential from %s: %w", obj.Spec.Provider, authErr),
+ fmt.Errorf("failed to get credential from %s: %w", provider, authErr),
sourcev1.AuthenticationFailedReason,
)
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
@@ -1079,8 +1133,11 @@ func convertOCIToSemVerTag(ociTag, mediaType string) string {
// keychain generates the credential keychain based on the resource
// configuration. If no auth is specified a default keychain with
-// anonymous access is returned
-func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *sourcev1.OCIRepository) (authn.Keychain, error) {
+// anonymous access is returned.
+//
+// The ServiceAccount is only used for its image pull secrets and must be
+// resolved and validated by the caller beforehand.
+func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *sourcev1.OCIRepository, sa *corev1.ServiceAccount) (authn.Keychain, error) {
var imagePullSecrets []corev1.Secret
// lookup auth secret
@@ -1096,10 +1153,9 @@ func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *sourcev1.OC
imagePullSecrets = append(imagePullSecrets, imagePullSecret)
}
- // lookup service account
- if obj.Spec.ServiceAccountName != "" {
- saRef := types.NamespacedName{Namespace: obj.Namespace, Name: obj.Spec.ServiceAccountName}
- saSecrets, err := secrets.PullSecretsFromServiceAccountRef(ctx, r.Client, saRef)
+ // lookup service account image pull secrets
+ if sa != nil {
+ saSecrets, err := secrets.PullSecretsFromServiceAccount(ctx, r.Client, sa)
if err != nil {
return nil, err
}
diff --git a/internal/controller/ocirepository_controller_test.go b/internal/controller/ocirepository_controller_test.go
index c3cfb2712..41c7f45eb 100644
--- a/internal/controller/ocirepository_controller_test.go
+++ b/internal/controller/ocirepository_controller_test.go
@@ -52,7 +52,6 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/utils/ptr"
oras "oras.land/oras-go/v2/registry/remote"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -60,11 +59,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
kstatus "github.com/fluxcd/cli-utils/pkg/kstatus/status"
+ cryptov1 "github.com/fluxcd/pkg/apis/crypto/v1"
eventv1 "github.com/fluxcd/pkg/apis/event/v1"
"github.com/fluxcd/pkg/apis/meta"
intdigest "github.com/fluxcd/pkg/artifact/digest"
"github.com/fluxcd/pkg/artifact/storage"
- "github.com/fluxcd/pkg/auth"
"github.com/fluxcd/pkg/git"
"github.com/fluxcd/pkg/oci"
"github.com/fluxcd/pkg/runtime/conditions"
@@ -90,7 +89,7 @@ func TestOCIRepositoryReconciler_deleteBeforeFinalizer(t *testing.T) {
namespaceName := "ocirepo-" + randStringRunes(5)
namespace := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
+ Name: namespaceName,
}
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
t.Cleanup(func() {
@@ -126,7 +125,7 @@ func TestOCIRepository_CELValidation(t *testing.T) {
namespaceName := "ocirepo-" + randStringRunes(5)
namespace := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
+ Name: namespaceName,
}
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
t.Cleanup(func() {
@@ -135,7 +134,7 @@ func TestOCIRepository_CELValidation(t *testing.T) {
tests := []struct {
name string
- spec map[string]interface{}
+ spec map[string]any
wantErr []string
}{
{
@@ -144,26 +143,26 @@ func TestOCIRepository_CELValidation(t *testing.T) {
},
{
name: "empty spec",
- spec: map[string]interface{}{},
+ spec: map[string]any{},
wantErr: []string{"spec.url is required", "spec.interval is required"},
},
{
name: "missing url",
- spec: map[string]interface{}{
+ spec: map[string]any{
"interval": "1m",
},
wantErr: []string{"spec.url is required"},
},
{
name: "missing interval",
- spec: map[string]interface{}{
+ spec: map[string]any{
"url": "oci://example.com",
},
wantErr: []string{"spec.interval is required"},
},
{
name: "valid",
- spec: map[string]interface{}{
+ spec: map[string]any{
"url": "oci://example.com",
"interval": "1m",
},
@@ -269,10 +268,8 @@ func TestOCIRepository_Reconcile(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
origObj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "ocirepository-reconcile",
- Namespace: ns.Name,
- },
+ GenerateName: "ocirepository-reconcile",
+ Namespace: ns.Name,
Spec: sourcev1.OCIRepositorySpec{
URL: tt.url,
Interval: &metav1.Duration{Duration: 60 * time.Minute},
@@ -437,10 +434,8 @@ func TestOCIRepository_Reconcile_MediaType(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "ocirepository-reconcile",
- Namespace: ns.Name,
- },
+ GenerateName: "ocirepository-reconcile",
+ Namespace: ns.Name,
Spec: sourcev1.OCIRepositorySpec{
URL: tt.url,
Interval: &metav1.Duration{Duration: 60 * time.Minute},
@@ -655,9 +650,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
}),
},
tlsCertSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"ca.crt": tlsCA,
},
@@ -680,9 +673,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
}),
},
tlsCertSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"caFile": tlsCA,
},
@@ -723,9 +714,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
}),
},
tlsCertSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"ca.crt": []byte("invalid"),
},
@@ -747,9 +736,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
}),
},
tlsCertSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"ca.crt": tlsCA,
"caFile": []byte("invalid"),
@@ -769,7 +756,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
crane.Insecure,
},
assertConditions: []metav1.Condition{
- *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "%s", "failed to get access token for artifact registry"),
+ *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "%s", "failed to get access credential for artifact registry"),
},
},
{
@@ -808,10 +795,8 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
WithStatusSubresource(&sourcev1.OCIRepository{})
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "auth-strategy-",
- Generation: 1,
- },
+ GenerateName: "auth-strategy-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
Interval: &metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
@@ -844,9 +829,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
if tt.secretOpts.username != "" && tt.secretOpts.password != "" {
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-secretref",
- },
+ Name: "auth-secretref",
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{
".dockerconfigjson": fmt.Appendf(nil, `{"auths": {%q: {"username": %q, "password": %q}}}`,
@@ -857,9 +840,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
if tt.secretOpts.includeSA {
serviceAccount := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "sa-ocitest",
- },
+ Name: "sa-ocitest",
ImagePullSecrets: []corev1.LocalObjectReference{{Name: secret.Name}},
}
clientBuilder.WithObjects(serviceAccount)
@@ -1014,11 +995,9 @@ func TestOCIRepository_CertSecret(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "ocirepository-test-resource",
- Namespace: ns.Name,
- Generation: 1,
- },
+ GenerateName: "ocirepository-test-resource",
+ Namespace: ns.Name,
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: tt.url,
Interval: &metav1.Duration{Duration: 60 * time.Minute},
@@ -1140,11 +1119,9 @@ func TestOCIRepository_ProxySecret(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "ocirepository-test-resource",
- Namespace: ns.Name,
- Generation: 1,
- },
+ GenerateName: "ocirepository-test-resource",
+ Namespace: ns.Name,
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: tt.url,
Interval: &metav1.Duration{Duration: 60 * time.Minute},
@@ -1354,10 +1331,8 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "checkout-strategy-",
- Generation: 1,
- },
+ GenerateName: "checkout-strategy-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Interval: &metav1.Duration{Duration: interval},
@@ -1598,10 +1573,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
g.Expect(err).NotTo(HaveOccurred())
caSecret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "valid-trust-store",
- Generation: 1,
- },
+ Name: "valid-trust-store",
+ Generation: 1,
Data: map[string][]byte{
"ca.crt": tlsCA,
},
@@ -1623,10 +1596,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
})
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "verify-oci-source-signature-",
- Generation: 1,
- },
+ GenerateName: "verify-oci-source-signature-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Verify: &sourcev1.OCIRepositoryVerification{
@@ -1652,10 +1623,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
data["trustpolicy.json"] = policy
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "notation-config-",
- },
- Data: data,
+ GenerateName: "notation-config-",
+ Data: data,
}
g.Expect(r.Create(ctx, secret)).NotTo(HaveOccurred())
@@ -1681,7 +1650,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
obj.Spec.Reference.Digest = podinfoVersions[tt.reference.Tag].digest.String()
}
- keychain, err := r.keychain(ctx, obj)
+ keychain, err := r.keychain(ctx, obj, nil)
if err != nil {
g.Expect(err).ToNot(HaveOccurred())
}
@@ -1717,10 +1686,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
signatureMediaType := cose.MediaTypeEnvelope
signOptions := notation.SignOptions{
- SignerSignOptions: notation.SignerSignOptions{
- SignatureMediaType: signatureMediaType,
- },
- ArtifactReference: artifactRef.String(),
+ SignatureMediaType: signatureMediaType,
+ ArtifactReference: artifactRef.String(),
}
_, err = notation.Sign(ctx, signer, repo, signOptions)
@@ -1960,10 +1927,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes
})
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "verify-oci-source-signature-",
- Generation: 1,
- },
+ GenerateName: "verify-oci-source-signature-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Verify: &sourcev1.OCIRepositoryVerification{
@@ -2005,10 +1970,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes
data["notation.crt"] = certTuple.Cert.Raw
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "notation-",
- },
- Data: data,
+ GenerateName: "notation-",
+ Data: data,
}
g.Expect(r.Create(ctx, secret)).NotTo(HaveOccurred())
@@ -2028,7 +1991,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes
obj.Spec.Reference.Digest = podinfoVersions[tt.reference.Tag].digest.String()
}
- keychain, err := r.keychain(ctx, obj)
+ keychain, err := r.keychain(ctx, obj, nil)
if err != nil {
g.Expect(err).ToNot(HaveOccurred())
}
@@ -2048,10 +2011,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes
signatureMediaType := cose.MediaTypeEnvelope
signOptions := notation.SignOptions{
- SignerSignOptions: notation.SignerSignOptions{
- SignatureMediaType: signatureMediaType,
- },
- ArtifactReference: artifactRef.String(),
+ SignatureMediaType: signatureMediaType,
+ ArtifactReference: artifactRef.String(),
}
_, err = notation.Sign(ctx, signer, repo, signOptions)
@@ -2268,9 +2229,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing
g.Expect(err).ToNot(HaveOccurred())
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "cosign-key",
- },
+ Name: "cosign-key",
Data: map[string][]byte{
"cosign.pub": keys.PublicBytes,
}}
@@ -2278,10 +2237,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing
g.Expect(r.Create(ctx, secret)).NotTo(HaveOccurred())
caSecret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-cert-cosign",
- Generation: 1,
- },
+ Name: "ca-cert-cosign",
+ Generation: 1,
Data: map[string][]byte{
"ca.crt": tlsCA,
},
@@ -2304,10 +2261,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing
})
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "verify-oci-source-signature-",
- Generation: 1,
- },
+ GenerateName: "verify-oci-source-signature-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Verify: &sourcev1.OCIRepositoryVerification{
@@ -2337,7 +2292,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing
podinfoVersions, err := pushMultiplePodinfoImages(server.registryHost, tt.insecure, tt.reference.Tag)
g.Expect(err).ToNot(HaveOccurred())
- keychain, err := r.keychain(ctx, obj)
+ keychain, err := r.keychain(ctx, obj, nil)
if err != nil {
g.Expect(err).ToNot(HaveOccurred())
}
@@ -2534,10 +2489,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi
g := NewWithT(t)
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "verify-oci-source-signature-",
- Generation: 1,
- },
+ GenerateName: "verify-oci-source-signature-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: "oci://ghcr.io/stefanprodan/manifests/podinfo",
Verify: &sourcev1.OCIRepositoryVerification{
@@ -2626,7 +2579,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
{
name: "full reconcile - same rev, unobserved ignore",
beforeFunc: func(obj *sourcev1.OCIRepository) {
- obj.Status.ObservedIgnore = ptr.To("aaa")
+ obj.Status.ObservedIgnore = new("aaa")
obj.Status.Artifact = &meta.Artifact{
Revision: testRevision,
}
@@ -2638,8 +2591,8 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
{
name: "noop - same rev, observed ignore",
beforeFunc: func(obj *sourcev1.OCIRepository) {
- obj.Spec.Ignore = ptr.To("aaa")
- obj.Status.ObservedIgnore = ptr.To("aaa")
+ obj.Spec.Ignore = new("aaa")
+ obj.Status.ObservedIgnore = new("aaa")
obj.Status.Artifact = &meta.Artifact{
Revision: testRevision,
}
@@ -2719,10 +2672,8 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "noop-",
- Generation: 1,
- },
+ GenerateName: "noop-",
+ Generation: 1,
Spec: sourcev1.OCIRepositorySpec{
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.5"},
@@ -2794,7 +2745,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) {
targetPath: "testdata/oci/repository",
artifact: &meta.Artifact{Revision: "revision"},
beforeFunc: func(obj *sourcev1.OCIRepository) {
- obj.Spec.Ignore = ptr.To("foo.txt")
+ obj.Spec.Ignore = new("foo.txt")
},
want: sreconcile.ResultSuccess,
assertPaths: []string{
@@ -2834,7 +2785,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) {
},
beforeFunc: func(obj *sourcev1.OCIRepository) {
obj.Status.Artifact = &meta.Artifact{Revision: "revision"}
- obj.Spec.Ignore = ptr.To("aaa")
+ obj.Spec.Ignore = new("aaa")
},
want: sreconcile.ResultSuccess,
assertPaths: []string{
@@ -2901,10 +2852,10 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) {
Revision: "revision",
},
beforeFunc: func(obj *sourcev1.OCIRepository) {
- obj.Spec.Ignore = ptr.To("aaa")
+ obj.Spec.Ignore = new("aaa")
obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"}
obj.Status.Artifact = &meta.Artifact{Revision: "revision"}
- obj.Status.ObservedIgnore = ptr.To("aaa")
+ obj.Status.ObservedIgnore = new("aaa")
obj.Status.ObservedLayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"}
},
want: sreconcile.ResultSuccess,
@@ -2953,10 +2904,8 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) {
_ = resetChmod(tt.targetPath, 0o755, 0o644)
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "reconcile-artifact-",
- Generation: 1,
- },
+ GenerateName: "reconcile-artifact-",
+ Generation: 1,
}
if tt.beforeFunc != nil {
tt.beforeFunc(obj)
@@ -3114,9 +3063,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "artifact-url-",
- },
+ GenerateName: "artifact-url-",
Spec: sourcev1.OCIRepositorySpec{
URL: tt.url,
Interval: &metav1.Duration{Duration: interval},
@@ -3152,10 +3099,8 @@ func TestOCIRepository_invalidURL(t *testing.T) {
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "ocirepository-reconcile",
- Namespace: ns.Name,
- },
+ GenerateName: "ocirepository-reconcile",
+ Namespace: ns.Name,
Spec: sourcev1.OCIRepositorySpec{
URL: "oci://ghcr.io/test/test:v1",
Interval: &metav1.Duration{Duration: 60 * time.Minute},
@@ -3186,30 +3131,30 @@ func TestOCIRepository_invalidURL(t *testing.T) {
g.Expect(stalledCondition.Reason).Should(Equal(sourcev1.URLInvalidReason))
}
-func TestOCIRepository_objectLevelWorkloadIdentityFeatureGate(t *testing.T) {
+func TestOCIRepository_genericWorkloadIdentity(t *testing.T) {
g := NewWithT(t)
- ns, err := testEnv.CreateNamespace(ctx, "ocirepository-olwifg-test")
+ ns, err := testEnv.CreateNamespace(ctx, "ocirepository-generic-olwi-test")
g.Expect(err).ToNot(HaveOccurred())
defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }()
err = testEnv.Create(ctx, &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: ns.Name,
- Name: "test",
+ Namespace: ns.Name,
+ Name: "test",
+ Annotations: map[string]string{
+ cryptov1.AnnotationCredentialProvider: cryptov1.CredentialProviderKubernetes,
+ cryptov1.AnnotationCredentialType: cryptov1.CredentialTypeJWT,
},
})
g.Expect(err).NotTo(HaveOccurred())
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "ocirepository-reconcile",
- Namespace: ns.Name,
- },
+ GenerateName: "ocirepository-generic-olwi-",
+ Namespace: ns.Name,
Spec: sourcev1.OCIRepositorySpec{
URL: "oci://ghcr.io/stefanprodan/manifests/podinfo",
Interval: &metav1.Duration{Duration: 60 * time.Minute},
- Provider: "aws",
+ Provider: sourcev1.GenericOCIProvider,
ServiceAccountName: "test",
},
}
@@ -3219,21 +3164,6 @@ func TestOCIRepository_objectLevelWorkloadIdentityFeatureGate(t *testing.T) {
key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace}
resultobj := &sourcev1.OCIRepository{}
- g.Eventually(func() bool {
- if err := testEnv.Get(ctx, key, resultobj); err != nil {
- return false
- }
- return conditions.IsStalled(resultobj)
- }).Should(BeTrue())
-
- stalledCondition := conditions.Get(resultobj, meta.StalledCondition)
- g.Expect(stalledCondition).ToNot(BeNil())
- g.Expect(stalledCondition.Reason).Should(Equal(meta.FeatureGateDisabledReason))
- g.Expect(stalledCondition.Message).Should(Equal("to use spec.serviceAccountName for provider authentication please enable the ObjectLevelWorkloadIdentity feature gate in the controller"))
-
- auth.EnableObjectLevelWorkloadIdentity()
- t.Cleanup(auth.DisableObjectLevelWorkloadIdentity)
-
g.Eventually(func() bool {
if err := testEnv.Get(ctx, key, resultobj); err != nil {
return false
@@ -3251,7 +3181,7 @@ func TestOCIRepository_objectLevelWorkloadIdentityFeatureGate(t *testing.T) {
logOCIRepoStatus(t, resultobj)
return !conditions.IsReady(resultobj) &&
conditions.GetReason(resultobj, meta.ReadyCondition) == sourcev1.OCIPullFailedReason
- }).Should(BeTrue())
+ }, timeout).Should(BeTrue())
}
func TestOCIRepository_reconcileStorage(t *testing.T) {
@@ -3297,7 +3227,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) {
Revision: "d",
Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4",
URL: testStorage.Hostname + "/oci-reconcile-storage/d.txt",
- Size: int64p(int64(len("d"))),
+ Size: new(int64(len("d"))),
},
assertPaths: []string{
"/oci-reconcile-storage/d.txt",
@@ -3426,7 +3356,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) {
Revision: "f",
Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80",
URL: testStorage.Hostname + "/oci-reconcile-storage/hostname.txt",
- Size: int64p(int64(len("file"))),
+ Size: new(int64(len("file"))),
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReadyCondition, "foo", "bar"),
@@ -3450,10 +3380,8 @@ func TestOCIRepository_reconcileStorage(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: 1,
- },
+ GenerateName: "test-",
+ Generation: 1,
}
if tt.beforeFunc != nil {
@@ -3510,12 +3438,10 @@ func TestOCIRepository_ReconcileDelete(t *testing.T) {
}
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{
- Name: "reconcile-delete-",
- DeletionTimestamp: &metav1.Time{Time: time.Now()},
- Finalizers: []string{
- sourcev1.SourceFinalizer,
- },
+ Name: "reconcile-delete-",
+ DeletionTimestamp: &metav1.Time{Time: time.Now()},
+ Finalizers: []string{
+ sourcev1.SourceFinalizer,
},
Status: sourcev1.OCIRepositoryStatus{},
}
@@ -3565,10 +3491,8 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) {
}
},
wantEvent: &corev1.Event{
- ObjectMeta: metav1.ObjectMeta{
- Annotations: map[string]string{
- fmt.Sprintf("%s/%s", sourcev1.GroupVersion.Group, eventv1.MetaOriginRevisionKey): "6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872",
- },
+ Annotations: map[string]string{
+ fmt.Sprintf("%s/%s", sourcev1.GroupVersion.Group, eventv1.MetaOriginRevisionKey): "6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872",
},
Type: corev1.EventTypeNormal,
Reason: sourcev1.NewArtifactReason,
@@ -3597,10 +3521,8 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) {
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready")
},
wantEvent: &corev1.Event{
- ObjectMeta: metav1.ObjectMeta{
- Annotations: map[string]string{
- fmt.Sprintf("%s/%s", sourcev1.GroupVersion.Group, eventv1.MetaOriginRevisionKey): "6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872",
- },
+ Annotations: map[string]string{
+ fmt.Sprintf("%s/%s", sourcev1.GroupVersion.Group, eventv1.MetaOriginRevisionKey): "6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872",
},
Type: corev1.EventTypeNormal,
Reason: meta.SucceededReason,
@@ -3771,7 +3693,7 @@ func pushMultiplePodinfoImages(serverURL string, insecure bool, versions ...stri
}
opts = append(opts, crane.WithTransport(transport))
}
- for i := 0; i < len(versions); i++ {
+ for i := range versions {
pi, err := createPodinfoImageFromTar(fmt.Sprintf("podinfo-%s.tar", versions[i]), versions[i], serverURL, opts...)
if err != nil {
return nil, err
@@ -3802,34 +3724,34 @@ func TestOCIContentConfigChanged(t *testing.T) {
{
name: "same ignore, no layer selector",
spec: sourcev1.OCIRepositorySpec{
- Ignore: ptr.To("nnn"),
+ Ignore: new("nnn"),
},
status: sourcev1.OCIRepositoryStatus{
- ObservedIgnore: ptr.To("nnn"),
+ ObservedIgnore: new("nnn"),
},
want: false,
},
{
name: "different ignore, no layer selector",
spec: sourcev1.OCIRepositorySpec{
- Ignore: ptr.To("nnn"),
+ Ignore: new("nnn"),
},
status: sourcev1.OCIRepositoryStatus{
- ObservedIgnore: ptr.To("mmm"),
+ ObservedIgnore: new("mmm"),
},
want: true,
},
{
name: "same ignore, same layer selector",
spec: sourcev1.OCIRepositorySpec{
- Ignore: ptr.To("nnn"),
+ Ignore: new("nnn"),
LayerSelector: &sourcev1.OCILayerSelector{
MediaType: "foo",
Operation: sourcev1.OCILayerExtract,
},
},
status: sourcev1.OCIRepositoryStatus{
- ObservedIgnore: ptr.To("nnn"),
+ ObservedIgnore: new("nnn"),
ObservedLayerSelector: &sourcev1.OCILayerSelector{
MediaType: "foo",
Operation: sourcev1.OCILayerExtract,
@@ -3840,14 +3762,14 @@ func TestOCIContentConfigChanged(t *testing.T) {
{
name: "same ignore, different layer selector operation",
spec: sourcev1.OCIRepositorySpec{
- Ignore: ptr.To("nnn"),
+ Ignore: new("nnn"),
LayerSelector: &sourcev1.OCILayerSelector{
MediaType: "foo",
Operation: sourcev1.OCILayerCopy,
},
},
status: sourcev1.OCIRepositoryStatus{
- ObservedIgnore: ptr.To("nnn"),
+ ObservedIgnore: new("nnn"),
ObservedLayerSelector: &sourcev1.OCILayerSelector{
MediaType: "foo",
Operation: sourcev1.OCILayerExtract,
@@ -3858,14 +3780,14 @@ func TestOCIContentConfigChanged(t *testing.T) {
{
name: "same ignore, different layer selector mediatype",
spec: sourcev1.OCIRepositorySpec{
- Ignore: ptr.To("nnn"),
+ Ignore: new("nnn"),
LayerSelector: &sourcev1.OCILayerSelector{
MediaType: "bar",
Operation: sourcev1.OCILayerExtract,
},
},
status: sourcev1.OCIRepositoryStatus{
- ObservedIgnore: ptr.To("nnn"),
+ ObservedIgnore: new("nnn"),
ObservedLayerSelector: &sourcev1.OCILayerSelector{
MediaType: "foo",
Operation: sourcev1.OCILayerExtract,
@@ -3962,17 +3884,17 @@ func Test_verificationMaterialFingerprint(t *testing.T) {
func TestOCIRepositoryReconciler_verificationPolicyChanged(t *testing.T) {
secret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "cosign-key", Namespace: "default"},
- Data: map[string][]byte{"cosign.pub": []byte("key")},
+ Name: "cosign-key", Namespace: "default",
+ Data: map[string][]byte{"cosign.pub": []byte("key")},
}
rotatedSecret := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{Name: "cosign-key", Namespace: "default"},
- Data: map[string][]byte{"cosign.pub": []byte("rotated-key")},
+ Name: "cosign-key", Namespace: "default",
+ Data: map[string][]byte{"cosign.pub": []byte("rotated-key")},
}
newObj := func(secretRef *meta.LocalObjectReference, fingerprint string) *sourcev1.OCIRepository {
obj := &sourcev1.OCIRepository{
- ObjectMeta: metav1.ObjectMeta{Name: "oci", Namespace: "default"},
+ Name: "oci", Namespace: "default",
Spec: sourcev1.OCIRepositorySpec{
Verify: &sourcev1.OCIRepositoryVerification{Provider: "cosign"},
},
diff --git a/internal/controller/ocirepository_verify_test.go b/internal/controller/ocirepository_verify_test.go
index 1c347027e..7429eab3d 100644
--- a/internal/controller/ocirepository_verify_test.go
+++ b/internal/controller/ocirepository_verify_test.go
@@ -23,7 +23,6 @@ import (
"github.com/fluxcd/pkg/apis/meta"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
@@ -45,10 +44,8 @@ func TestReadTrustedRootFromSecret(t *testing.T) {
namespace: "default",
ref: &meta.LocalObjectReference{Name: "sigstore-root"},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "sigstore-root",
- Namespace: "default",
- },
+ Name: "sigstore-root",
+ Namespace: "default",
Data: map[string][]byte{
"trusted_root.json": []byte(`{"mediaType":"application/vnd.dev.sigstore.trustedroot+json;version=0.1"}`),
},
@@ -66,10 +63,8 @@ func TestReadTrustedRootFromSecret(t *testing.T) {
namespace: "default",
ref: &meta.LocalObjectReference{Name: "no-key-secret"},
secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "no-key-secret",
- Namespace: "default",
- },
+ Name: "no-key-secret",
+ Namespace: "default",
Data: map[string][]byte{
"other-key": []byte("data"),
},
diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go
index 91d999c60..56b9294a7 100644
--- a/internal/controller/suite_test.go
+++ b/internal/controller/suite_test.go
@@ -87,6 +87,8 @@ var (
testServer *testserver.ArtifactServer
testMetricsH controller.Metrics
ctx = ctrl.SetupSignalHandler()
+
+ testOCIRepositoryReconciler *OCIRepositoryReconciler
)
var (
@@ -167,7 +169,7 @@ func setupRegistryServer(ctx context.Context, workspaceDir string, opts registry
config.HTTP.Addr = fmt.Sprintf(":%d", port)
config.HTTP.DrainTimeout = time.Duration(10) * time.Second
- config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
+ config.Storage = map[string]configuration.Parameters{"inmemory": map[string]any{}}
if opts.withBasicAuth {
// create htpasswd file (w BCrypt, which is required)
@@ -345,12 +347,13 @@ func TestMain(m *testing.M) {
testCache = cache.New(5, 1*time.Second)
cacheRecorder := cache.MustMakeMetrics()
- if err := (&OCIRepositoryReconciler{
+ testOCIRepositoryReconciler = &OCIRepositoryReconciler{
Client: testEnv,
Recorder: events.NewFakeRecorder(32, false),
Metrics: testMetricsH,
Storage: testStorage,
- }).SetupWithManager(testEnv, OCIRepositoryReconcilerOptions{
+ }
+ if err := testOCIRepositoryReconciler.SetupWithManager(testEnv, OCIRepositoryReconcilerOptions{
RateLimiter: controller.GetDefaultRateLimiter(),
}); err != nil {
panic(fmt.Sprintf("Failed to start OCIRepositoryReconciler: %v", err))
@@ -510,8 +513,9 @@ func randStringRunes(n int) string {
return string(b)
}
+//go:fix inline
func int64p(i int64) *int64 {
- return &i
+ return new(i)
}
func logOCIRepoStatus(t *testing.T, obj *sourcev1.OCIRepository) {
diff --git a/internal/error/error.go b/internal/error/error.go
index cb3a8cd78..650ffb26a 100644
--- a/internal/error/error.go
+++ b/internal/error/error.go
@@ -80,13 +80,11 @@ func NewStalling(err error, reason string) *Stalling {
// Stalling errors are not returned to the runtime. Log it explicitly.
// Since this failure requires user interaction, send warning notification.
return &Stalling{
- Reason: reason,
- Err: err,
- Config: Config{
- Event: corev1.EventTypeWarning,
- Log: true,
- Notification: true,
- },
+ Reason: reason,
+ Err: err,
+ Event: corev1.EventTypeWarning,
+ Log: true,
+ Notification: true,
}
}
@@ -124,10 +122,8 @@ func NewWaiting(err error, reason string) *Waiting {
return &Waiting{
Reason: reason,
Err: err,
- Config: Config{
- Event: corev1.EventTypeNormal,
- Log: true,
- },
+ Event: corev1.EventTypeNormal,
+ Log: true,
}
}
@@ -157,11 +153,9 @@ func NewGeneric(err error, reason string) *Generic {
// Since it's a generic error, it'll be returned to the runtime and logged
// automatically, do not log it. Send failure notification.
return &Generic{
- Reason: reason,
- Err: err,
- Config: Config{
- Event: corev1.EventTypeWarning,
- Notification: true,
- },
+ Reason: reason,
+ Err: err,
+ Event: corev1.EventTypeWarning,
+ Notification: true,
}
}
diff --git a/internal/features/features.go b/internal/features/features.go
index edb9beb17..bc4855075 100644
--- a/internal/features/features.go
+++ b/internal/features/features.go
@@ -38,14 +38,15 @@ var features = map[string]bool{
CacheSecretsAndConfigMaps: false,
}
-func init() {
- auth.SetFeatureGates(features)
+var retiredFeatures = map[string]string{
+ // Retired in Flux 2.10.
+ auth.FeatureGateObjectLevelWorkloadIdentity: auth.FeatureGateObjectLevelWorkloadIdentityRetirementReason,
}
// FeatureGates contains a list of all supported feature gates and
// their default values.
-func FeatureGates() map[string]bool {
- return features
+func FeatureGates() (map[string]bool, map[string]string) {
+ return features, retiredFeatures
}
// Enabled verifies whether the feature is enabled or not.
diff --git a/internal/helm/chart/builder_local.go b/internal/helm/chart/builder_local.go
index 44399a80a..d9638c559 100644
--- a/internal/helm/chart/builder_local.go
+++ b/internal/helm/chart/builder_local.go
@@ -146,7 +146,7 @@ func (b *localChartBuilder) Build(ctx context.Context, ref Reference, p string,
// Merge chart values, if instructed
var (
- mergedValues map[string]interface{}
+ mergedValues map[string]any
valuesFiles []string
)
if len(opts.GetValuesFiles()) > 0 {
@@ -199,8 +199,8 @@ func (b *localChartBuilder) Build(ctx context.Context, ref Reference, p string,
// file is considered an error. If ignoreMissing is true, missing files are ignored.
// It returns the merge result and the list of files that contributed to that result,
// or an error.
-func mergeFileValues(baseDir string, paths []string, ignoreMissing bool) (map[string]interface{}, []string, error) {
- mergedValues := make(map[string]interface{})
+func mergeFileValues(baseDir string, paths []string, ignoreMissing bool) (map[string]any, []string, error) {
+ mergedValues := make(map[string]any)
valuesFiles := make([]string, 0, len(paths))
for _, p := range paths {
secureP, err := securejoin.SecureJoin(baseDir, p)
@@ -222,7 +222,7 @@ func mergeFileValues(baseDir string, paths []string, ignoreMissing bool) (map[st
if err != nil {
return nil, nil, fmt.Errorf("could not read values from file '%s': %w", p, err)
}
- values := make(map[string]interface{})
+ values := make(map[string]any)
err = yaml.Unmarshal(b, &values)
if err != nil {
return nil, nil, fmt.Errorf("unmarshaling values from '%s' failed: %w", p, err)
diff --git a/internal/helm/chart/builder_local_test.go b/internal/helm/chart/builder_local_test.go
index cf9d6a742..9b8b5b512 100644
--- a/internal/helm/chart/builder_local_test.go
+++ b/internal/helm/chart/builder_local_test.go
@@ -285,7 +285,7 @@ func Test_mergeFileValues(t *testing.T) {
files []*common.File
paths []string
ignoreMissing bool
- wantValues map[string]interface{}
+ wantValues map[string]any
wantFiles []string
wantErr string
}{
@@ -297,7 +297,7 @@ func Test_mergeFileValues(t *testing.T) {
{Name: "c.yaml", Data: []byte("b: d")},
},
paths: []string{"a.yaml", "b.yaml", "c.yaml"},
- wantValues: map[string]interface{}{
+ wantValues: map[string]any{
"a": "b",
"b": "d",
},
@@ -328,7 +328,7 @@ func Test_mergeFileValues(t *testing.T) {
},
paths: []string{"a.yaml", "b.yaml"},
ignoreMissing: true,
- wantValues: map[string]interface{}{
+ wantValues: map[string]any{
"a": "b",
},
wantFiles: []string{"a.yaml"},
@@ -337,7 +337,7 @@ func Test_mergeFileValues(t *testing.T) {
name: "all files missing",
paths: []string{"a.yaml"},
ignoreMissing: true,
- wantValues: map[string]interface{}{},
+ wantValues: map[string]any{},
wantFiles: []string{},
},
}
diff --git a/internal/helm/chart/builder_remote.go b/internal/helm/chart/builder_remote.go
index dbe3addca..2cd76c112 100644
--- a/internal/helm/chart/builder_remote.go
+++ b/internal/helm/chart/builder_remote.go
@@ -235,8 +235,8 @@ func setBuildMetaData(version, versionMetadata string) (*semver.Version, error)
// missing files are ignored.
// It returns the merge result and the list of files that contributed to that result,
// or an error.
-func mergeChartValues(chart *helmchart.Chart, paths []string, ignoreMissing bool) (map[string]interface{}, []string, error) {
- mergedValues := make(map[string]interface{})
+func mergeChartValues(chart *helmchart.Chart, paths []string, ignoreMissing bool) (map[string]any, []string, error) {
+ mergedValues := make(map[string]any)
valuesFiles := make([]string, 0, len(paths))
for _, p := range paths {
cfn := filepath.Clean(p)
@@ -258,7 +258,7 @@ func mergeChartValues(chart *helmchart.Chart, paths []string, ignoreMissing bool
}
return nil, nil, fmt.Errorf("no values file found at path '%s'", p)
}
- values := make(map[string]interface{})
+ values := make(map[string]any)
if err := yaml.Unmarshal(b, &values); err != nil {
return nil, nil, fmt.Errorf("unmarshaling values from '%s' failed: %w", p, err)
}
diff --git a/internal/helm/chart/builder_remote_test.go b/internal/helm/chart/builder_remote_test.go
index 4301f0630..bf6534606 100644
--- a/internal/helm/chart/builder_remote_test.go
+++ b/internal/helm/chart/builder_remote_test.go
@@ -456,7 +456,7 @@ func Test_mergeChartValues(t *testing.T) {
chart *helmchart.Chart
paths []string
ignoreMissing bool
- wantValues map[string]interface{}
+ wantValues map[string]any
wantFiles []string
wantErr string
}{
@@ -470,7 +470,7 @@ func Test_mergeChartValues(t *testing.T) {
},
},
paths: []string{"a.yaml", "b.yaml", "c.yaml"},
- wantValues: map[string]interface{}{
+ wantValues: map[string]any{
"a": "b",
"b": "d",
},
@@ -482,12 +482,12 @@ func Test_mergeChartValues(t *testing.T) {
Files: []*common.File{
{Name: "c.yaml", Data: []byte("b: d")},
},
- Values: map[string]interface{}{
+ Values: map[string]any{
"a": "b",
},
},
paths: []string{chartutil.ValuesfileName, "c.yaml"},
- wantValues: map[string]interface{}{
+ wantValues: map[string]any{
"a": "b",
"b": "d",
},
@@ -518,7 +518,7 @@ func Test_mergeChartValues(t *testing.T) {
},
paths: []string{"a.yaml", "b.yaml"},
ignoreMissing: true,
- wantValues: map[string]interface{}{
+ wantValues: map[string]any{
"a": "b",
},
wantFiles: []string{"a.yaml"},
@@ -528,19 +528,19 @@ func Test_mergeChartValues(t *testing.T) {
chart: &helmchart.Chart{},
paths: []string{"a.yaml"},
ignoreMissing: true,
- wantValues: map[string]interface{}{},
+ wantValues: map[string]any{},
wantFiles: []string{},
},
{
name: "uses chart values ignoring missing file",
chart: &helmchart.Chart{
- Values: map[string]interface{}{
+ Values: map[string]any{
"a": "b",
},
},
paths: []string{chartutil.ValuesfileName, "c.yaml"},
ignoreMissing: true,
- wantValues: map[string]interface{}{
+ wantValues: map[string]any{
"a": "b",
},
wantFiles: []string{chartutil.ValuesfileName},
diff --git a/internal/helm/chart/secureloader/ignore/rules.go b/internal/helm/chart/secureloader/ignore/rules.go
index d8054b44d..57858f432 100644
--- a/internal/helm/chart/secureloader/ignore/rules.go
+++ b/internal/helm/chart/secureloader/ignore/rules.go
@@ -170,10 +170,10 @@ func (r *Rules) parseRule(rule string) error {
rule = strings.TrimSuffix(rule, "/")
}
- if strings.HasPrefix(rule, "/") {
+ if after, ok := strings.CutPrefix(rule, "/"); ok {
// Require path matches the root path.
p.match = func(n string, fi os.FileInfo) bool {
- rule = strings.TrimPrefix(rule, "/")
+ rule = after
ok, err := filepath.Match(rule, n)
if err != nil {
log.Printf("Failed to compile %q: %s", rule, err)
diff --git a/internal/helm/getter/client_opts_test.go b/internal/helm/getter/client_opts_test.go
index 87247b6a8..5d18b9873 100644
--- a/internal/helm/getter/client_opts_test.go
+++ b/internal/helm/getter/client_opts_test.go
@@ -51,17 +51,13 @@ func TestGetClientOpts(t *testing.T) {
{
name: "HelmRepository with certSecretRef discards TLS config in secretRef",
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"ca.crt": tlsCA,
},
},
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth",
- },
+ Name: "auth",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
@@ -75,9 +71,7 @@ func TestGetClientOpts(t *testing.T) {
{
name: "HelmRepository with TLS config only in secretRef is marked as deprecated",
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-tls",
- },
+ Name: "auth-tls",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
@@ -93,9 +87,7 @@ func TestGetClientOpts(t *testing.T) {
{
name: "OCI HelmRepository with secretRef has auth configured",
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-oci",
- },
+ Name: "auth-oci",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
@@ -117,9 +109,7 @@ func TestGetClientOpts(t *testing.T) {
{
name: "OCI HelmRepository with insecure repository",
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-oci",
- },
+ Name: "auth-oci",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
@@ -192,17 +182,13 @@ func TestGetClientOpts_registryTLSLoginOption(t *testing.T) {
{
name: "with valid caFile",
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{
"ca.crt": tlsCA,
},
},
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-oci",
- },
+ Name: "auth-oci",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
@@ -214,15 +200,11 @@ func TestGetClientOpts_registryTLSLoginOption(t *testing.T) {
{
name: "without caFile",
certSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "ca-file",
- },
+ Name: "ca-file",
Data: map[string][]byte{},
},
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-oci",
- },
+ Name: "auth-oci",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
@@ -234,9 +216,7 @@ func TestGetClientOpts_registryTLSLoginOption(t *testing.T) {
name: "without cert secret",
certSecret: nil,
authSecret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth-oci",
- },
+ Name: "auth-oci",
Data: map[string][]byte{
"username": []byte("user"),
"password": []byte("pass"),
diff --git a/internal/helm/registry/auth_test.go b/internal/helm/registry/auth_test.go
index c0e3ffde5..b61d1b523 100644
--- a/internal/helm/registry/auth_test.go
+++ b/internal/helm/registry/auth_test.go
@@ -123,10 +123,10 @@ func TestLoginOptionFromSecret(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
- secret := corev1.Secret{}
- secret.Name = "test-secret"
- secret.Data = tt.secretData
- secret.Type = tt.secretType
+ secret := corev1.Secret{
+ Name: "test-secret",
+ Data: tt.secretData,
+ Type: tt.secretType}
_, err := KeychainFromSecret(tt.url, secret)
g.Expect(err != nil).To(Equal(tt.wantErr))
diff --git a/internal/helm/repository/chart_repository.go b/internal/helm/repository/chart_repository.go
index 4e2f7dfc4..e82f93f90 100644
--- a/internal/helm/repository/chart_repository.go
+++ b/internal/helm/repository/chart_repository.go
@@ -27,6 +27,7 @@ import (
"net/url"
"os"
"path"
+ "slices"
"sort"
"strings"
"sync"
@@ -88,19 +89,19 @@ func IndexFromBytes(b []byte) (*repo.IndexFile, error) {
}
for name, cvs := range i.Entries {
- for idx := len(cvs) - 1; idx >= 0; idx-- {
- if cvs[idx] == nil {
+ for idx, cv := range slices.Backward(cvs) {
+ if cv == nil {
cvs = append(cvs[:idx], cvs[idx+1:]...)
continue
}
// When metadata section missing, initialize with no data
- if cvs[idx].Metadata == nil {
- cvs[idx].Metadata = &chart.Metadata{}
+ if cv.Metadata == nil {
+ cv.Metadata = &chart.Metadata{}
}
- if cvs[idx].APIVersion == "" {
- cvs[idx].APIVersion = chart.APIVersionV1
+ if cv.APIVersion == "" {
+ cv.APIVersion = chart.APIVersionV1
}
- if err := cvs[idx].Validate(); ignoreSkippableChartValidationError(err) != nil {
+ if err := cv.Validate(); ignoreSkippableChartValidationError(err) != nil {
cvs = append(cvs[:idx], cvs[idx+1:]...)
}
}
@@ -503,7 +504,7 @@ func (r *ChartRepository) VerifyChart(_ context.Context, _ *repo.ChartVersion) (
//
// Can potentially be replaced when Helm PR for JSON support has been merged.
// xref: https://github.com/helm/helm/pull/12245
-func jsonOrYamlUnmarshal(b []byte, i interface{}) error {
+func jsonOrYamlUnmarshal(b []byte, i any) error {
if json.Valid(b) {
return json.Unmarshal(b, i)
}
diff --git a/internal/helm/repository/chart_repository_test.go b/internal/helm/repository/chart_repository_test.go
index c9aadf8a2..cb41acf68 100644
--- a/internal/helm/repository/chart_repository_test.go
+++ b/internal/helm/repository/chart_repository_test.go
@@ -94,7 +94,6 @@ func TestIndexFromFile(t *testing.T) {
}
for _, tt := range tests {
- tt := tt
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
@@ -158,7 +157,6 @@ entries:
},
}
for _, tt := range tests {
- tt := tt
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
t.Parallel()
@@ -366,7 +364,6 @@ func TestChartRepository_DownloadChart(t *testing.T) {
},
}
for _, tt := range tests {
- tt := tt
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
t.Parallel()
diff --git a/internal/helm/repository/oci_chart_repository_test.go b/internal/helm/repository/oci_chart_repository_test.go
index b63aef8da..b10f25be6 100644
--- a/internal/helm/repository/oci_chart_repository_test.go
+++ b/internal/helm/repository/oci_chart_repository_test.go
@@ -255,7 +255,6 @@ func TestOCIChartRepository_DownloadChart(t *testing.T) {
}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
diff --git a/internal/index/digest.go b/internal/index/digest.go
index 1f7bd642f..de9ea1f8e 100644
--- a/internal/index/digest.go
+++ b/internal/index/digest.go
@@ -19,6 +19,7 @@ package index
import (
"fmt"
"io"
+ "maps"
"sort"
"strings"
"sync"
@@ -54,9 +55,7 @@ func WithIndex(i map[string]string) DigesterOption {
if d.index == nil {
d.index = make(map[string]string, len(i))
}
- for k, v := range i {
- d.index[k] = v
- }
+ maps.Copy(d.index, i)
d.reset()
}
}
@@ -118,9 +117,7 @@ func (i *Digester) Index() map[string]string {
defer i.mu.RUnlock()
index := make(map[string]string, len(i.index))
- for k, v := range i.index {
- index[k] = v
- }
+ maps.Copy(index, i.index)
return index
}
diff --git a/internal/mock/s3/server.go b/internal/mock/s3/server.go
index ae5835308..b5e0644fa 100644
--- a/internal/mock/s3/server.go
+++ b/internal/mock/s3/server.go
@@ -103,17 +103,17 @@ func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
return
}
- contents := ""
+ var contents strings.Builder
for _, o := range s.Objects {
etag := md5.Sum(o.Content)
- contents += fmt.Sprintf(`
+ contents.WriteString(fmt.Sprintf(`
%s
%s
%d
"%x"
STANDARD
- `, o.Key, o.LastModified.UTC().Format(time.RFC3339), len(o.Content), etag)
+ `, o.Key, o.LastModified.UTC().Format(time.RFC3339), len(o.Content), etag))
}
fmt.Fprintf(w, `
@@ -127,7 +127,7 @@ func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
false
%s
- `, s.BucketName, len(s.Objects), contents)
+ `, s.BucketName, len(s.Objects), contents.String())
default:
if !strings.HasPrefix(r.URL.Path, "/"+s.BucketName+"/") {
writeError(w, r, http.StatusNotFound, "NoSuchBucket", "The specified bucket does not exist")
diff --git a/internal/oci/notation/notation_test.go b/internal/oci/notation/notation_test.go
index 1a547617d..3a3b2fa61 100644
--- a/internal/oci/notation/notation_test.go
+++ b/internal/oci/notation/notation_test.go
@@ -654,7 +654,7 @@ func TestRemoteRepoAuthTokenReuse(t *testing.T) {
// setting the scope hint on the context exactly like the ORAS repository
// methods do during verification.
doRequests := func(client *oauth.Client, n int) {
- for i := 0; i < n; i++ {
+ for range n {
ctx := oauth.WithScopesForHost(context.Background(), host, scope)
req, err := http.NewRequestWithContext(ctx, http.MethodGet,
fmt.Sprintf("%s/v2/%s/manifests/latest", baseURL, repository), nil)
@@ -787,15 +787,15 @@ func (t *testLogger) Enabled(level int) bool {
return true
}
-func (t *testLogger) Info(level int, msg string, keysAndValues ...interface{}) {
+func (t *testLogger) Info(level int, msg string, keysAndValues ...any) {
t.doLog(msg)
}
-func (t *testLogger) Error(err error, msg string, keysAndValues ...interface{}) {
+func (t *testLogger) Error(err error, msg string, keysAndValues ...any) {
t.doLog(msg)
}
-func (t *testLogger) WithValues(keysAndValues ...interface{}) logr.LogSink {
+func (t *testLogger) WithValues(keysAndValues ...any) logr.LogSink {
return t
}
diff --git a/internal/reconcile/event.go b/internal/reconcile/event.go
index 57ebf4eb4..cfb800b27 100644
--- a/internal/reconcile/event.go
+++ b/internal/reconcile/event.go
@@ -39,7 +39,7 @@ import (
// The action identifies the reconcile stage that produced the event and is
// recorded in the event's action field. Callers pass the relevant
// sourcev1.Action for the stage.
-func EventLogf(ctx context.Context, rec events.Recorder, obj runtime.Object, eventType string, reason string, action sourcev1.Action, messageFmt string, args ...interface{}) {
+func EventLogf(ctx context.Context, rec events.Recorder, obj runtime.Object, eventType string, reason string, action sourcev1.Action, messageFmt string, args ...any) {
msg := fmt.Sprintf(messageFmt, args...)
if eventType == corev1.EventTypeWarning {
ctrl.LoggerFrom(ctx).Error(errors.New(reason), msg)
diff --git a/internal/reconcile/reconcile_test.go b/internal/reconcile/reconcile_test.go
index e22f370b5..ef3978d4c 100644
--- a/internal/reconcile/reconcile_test.go
+++ b/internal/reconcile/reconcile_test.go
@@ -174,9 +174,7 @@ func TestComputeReconcileResult(t *testing.T) {
},
recErr: &serror.Generic{
Err: fmt.Errorf("some error"), Reason: "some reason",
- Config: serror.Config{
- Ignore: true,
- },
+ Ignore: true,
},
wantResult: ctrl.Result{RequeueAfter: testSuccessInterval},
afterFunc: func(t *WithT, obj conditions.Setter, patchOpts *patch.HelperOptions) {
diff --git a/internal/reconcile/summarize/matchers_test.go b/internal/reconcile/summarize/matchers_test.go
index b71aa99c8..ea09a82ea 100644
--- a/internal/reconcile/summarize/matchers_test.go
+++ b/internal/reconcile/summarize/matchers_test.go
@@ -39,7 +39,7 @@ type haveStatusObservedGeneration struct {
actual int64
}
-func (m *haveStatusObservedGeneration) Match(actual interface{}) (success bool, err error) {
+func (m *haveStatusObservedGeneration) Match(actual any) (success bool, err error) {
obj, ok := actual.(runtime.Object)
if !ok {
return false, fmt.Errorf("actual should be a runtime object")
@@ -54,11 +54,11 @@ func (m *haveStatusObservedGeneration) Match(actual interface{}) (success bool,
return Equal(m.expected).Match(og)
}
-func (m *haveStatusObservedGeneration) FailureMessage(actual interface{}) (message string) {
+func (m *haveStatusObservedGeneration) FailureMessage(actual any) (message string) {
return fmt.Sprintf("expected\n\t%d\nto match\n\t%d\n", m.actual, m.expected)
}
-func (m *haveStatusObservedGeneration) NegatedFailureMessage(actual interface{}) (message string) {
+func (m *haveStatusObservedGeneration) NegatedFailureMessage(actual any) (message string) {
return fmt.Sprintf("expected\n\t%d\nto not match\n\t%d\n", m.actual, m.expected)
}
@@ -75,7 +75,7 @@ type haveStatusLastHandledReconcileAt struct {
actual string
}
-func (m *haveStatusLastHandledReconcileAt) Match(actual interface{}) (success bool, err error) {
+func (m *haveStatusLastHandledReconcileAt) Match(actual any) (success bool, err error) {
obj, ok := actual.(runtime.Object)
if !ok {
return false, fmt.Errorf("actual should be a runtime object")
@@ -90,10 +90,10 @@ func (m *haveStatusLastHandledReconcileAt) Match(actual interface{}) (success bo
return Equal(m.expected).Match(ra)
}
-func (m *haveStatusLastHandledReconcileAt) FailureMessage(actual interface{}) (message string) {
+func (m *haveStatusLastHandledReconcileAt) FailureMessage(actual any) (message string) {
return fmt.Sprintf("expected\n\t%s\nto match\n\t%s\n", m.actual, m.expected)
}
-func (m *haveStatusLastHandledReconcileAt) NegatedFailureMessage(actual interface{}) (message string) {
+func (m *haveStatusLastHandledReconcileAt) NegatedFailureMessage(actual any) (message string) {
return fmt.Sprintf("expected\n\t%s\nto not match\n\t%s\n", m.actual, m.expected)
}
diff --git a/internal/reconcile/summarize/processor.go b/internal/reconcile/summarize/processor.go
index 2b1fdddb6..4dda3c508 100644
--- a/internal/reconcile/summarize/processor.go
+++ b/internal/reconcile/summarize/processor.go
@@ -72,7 +72,7 @@ func ErrorActionHandler(ctx context.Context, recorder events.Recorder, obj clien
}
// logError logs error based on the passed error configurations.
-func logError(ctx context.Context, eventType string, err error, msg string, keysAndValues ...interface{}) {
+func logError(ctx context.Context, eventType string, err error, msg string, keysAndValues ...any) {
switch eventType {
case corev1.EventTypeNormal, serror.EventTypeNone:
ctrl.LoggerFrom(ctx).Info(msg, keysAndValues...)
diff --git a/internal/reconcile/summarize/processor_test.go b/internal/reconcile/summarize/processor_test.go
index d7af0a00f..652516b14 100644
--- a/internal/reconcile/summarize/processor_test.go
+++ b/internal/reconcile/summarize/processor_test.go
@@ -21,7 +21,6 @@ import (
"testing"
. "github.com/onsi/gomega"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta"
@@ -109,9 +108,7 @@ func TestRecordReconcileReq(t *testing.T) {
g := NewWithT(t)
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-obj",
- },
+ GenerateName: "test-obj",
}
if tt.beforeFunc != nil {
diff --git a/internal/reconcile/summarize/summary_test.go b/internal/reconcile/summarize/summary_test.go
index c9acbca38..afbf9312c 100644
--- a/internal/reconcile/summarize/summary_test.go
+++ b/internal/reconcile/summarize/summary_test.go
@@ -328,10 +328,8 @@ func TestSummarizeAndPatch(t *testing.T) {
g.Expect(sourcev1.AddToScheme(scheme)).To(Succeed())
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- Generation: tt.generation,
- },
+ GenerateName: "test-",
+ Generation: tt.generation,
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: 5 * time.Second},
},
@@ -458,9 +456,7 @@ func TestSummarizeAndPatch_Intermediate(t *testing.T) {
Build()
obj := &sourcev1.GitRepository{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-",
- },
+ GenerateName: "test-",
Spec: sourcev1.GitRepositorySpec{
Interval: metav1.Duration{Duration: interval},
},
diff --git a/internal/util/temp_root.go b/internal/util/temp_root.go
new file mode 100644
index 000000000..4c3df7fef
--- /dev/null
+++ b/internal/util/temp_root.go
@@ -0,0 +1,113 @@
+/*
+Copyright 2026 The Flux authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/go-logr/logr"
+)
+
+// staleSuffix is appended to a temp root that a previous process left behind,
+// when it is moved aside to be purged.
+const staleSuffix = ".stale-"
+
+// PrepareTempRoot gives the process an empty directory at root for its
+// temporary files. Anything a previous process left in root, because it
+// exited without running its deferred cleanup, is moved aside first. It
+// returns the paths that hold leftovers, including those a previous purge
+// did not finish, so that the caller can remove them with PurgeTempRoots.
+// It must be called before the reconcilers start.
+func PrepareTempRoot(root string) ([]string, error) {
+ _, err := os.Lstat(root)
+ switch {
+ case err == nil:
+ stale := fmt.Sprintf("%s%s%d", root, staleSuffix, time.Now().UnixNano())
+ if err := os.Rename(root, stale); err != nil {
+ return nil, fmt.Errorf("failed to move aside %s: %w", root, err)
+ }
+ case !errors.Is(err, fs.ErrNotExist):
+ return nil, fmt.Errorf("failed to stat %s: %w", root, err)
+ }
+
+ if err := os.MkdirAll(root, 0o700); err != nil {
+ return nil, fmt.Errorf("failed to create %s: %w", root, err)
+ }
+
+ parent, base := filepath.Split(root)
+ entries, err := os.ReadDir(parent)
+ if err != nil {
+ return nil, fmt.Errorf("failed to list %s: %w", parent, err)
+ }
+ var stale []string
+ for _, entry := range entries {
+ if strings.HasPrefix(entry.Name(), base+staleSuffix) {
+ stale = append(stale, filepath.Join(parent, entry.Name()))
+ }
+ }
+ return stale, nil
+}
+
+// PurgeTempRoots removes the given paths. A directory is emptied one entry
+// at a time, so that ctx is honoured between entries, and then removed.
+// Every removed path is logged at info level and every failure at error
+// level. It stops as soon as ctx is done and returns the number of paths
+// that were removed. Paths it did not remove are picked up by
+// PrepareTempRoot on the next start.
+func PurgeTempRoots(ctx context.Context, log logr.Logger, paths []string) int {
+ purged := 0
+ for i, path := range paths {
+ if err := purgeTempRoot(ctx, path); err != nil {
+ if ctx.Err() != nil {
+ log.Error(err, "aborted purge of stale tmp dirs",
+ "path", path, "purged", purged, "remaining", len(paths)-i)
+ return purged
+ }
+ log.Error(err, "failed to remove stale tmp dir", "path", path)
+ continue
+ }
+ log.Info("removed stale tmp dir", "path", path)
+ purged++
+ }
+ return purged
+}
+
+// purgeTempRoot removes the entries of path one by one, checking ctx before
+// each, and then path itself.
+func purgeTempRoot(ctx context.Context, path string) error {
+ // If path is not a readable directory, RemoveAll below deals with it.
+ entries, _ := os.ReadDir(path)
+ for _, entry := range entries {
+ if err := ctx.Err(); err != nil {
+ return err
+ }
+ if err := os.RemoveAll(filepath.Join(path, entry.Name())); err != nil {
+ return err
+ }
+ }
+ if err := ctx.Err(); err != nil {
+ return err
+ }
+ return os.RemoveAll(path)
+}
diff --git a/internal/util/temp_root_test.go b/internal/util/temp_root_test.go
new file mode 100644
index 000000000..1711cdcbf
--- /dev/null
+++ b/internal/util/temp_root_test.go
@@ -0,0 +1,126 @@
+/*
+Copyright 2026 The Flux authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/gomega"
+)
+
+func TestPrepareTempRoot(t *testing.T) {
+ t.Run("creates the root when it does not exist", func(t *testing.T) {
+ g := NewWithT(t)
+ root := filepath.Join(t.TempDir(), "source-controller")
+
+ stale, err := PrepareTempRoot(root)
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(stale).To(BeEmpty())
+ g.Expect(root).To(BeADirectory())
+ })
+
+ t.Run("moves a previous process's leftovers out of the root", func(t *testing.T) {
+ g := NewWithT(t)
+ root := filepath.Join(t.TempDir(), "source-controller")
+ leftover := filepath.Join(root, "gitrepository-default-foo-123", "repo")
+ g.Expect(os.MkdirAll(leftover, 0o700)).To(Succeed())
+ g.Expect(os.WriteFile(filepath.Join(root, "chart-index-1.yaml"), []byte("x"), 0o600)).To(Succeed())
+
+ stale, err := PrepareTempRoot(root)
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(stale).To(HaveLen(1))
+ g.Expect(filepath.Join(stale[0], "gitrepository-default-foo-123", "repo")).To(BeADirectory())
+ g.Expect(filepath.Join(stale[0], "chart-index-1.yaml")).To(BeARegularFile())
+
+ entries, err := os.ReadDir(root)
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(entries).To(BeEmpty())
+ })
+
+ t.Run("lists leftovers a previous purge did not finish", func(t *testing.T) {
+ g := NewWithT(t)
+ parent := t.TempDir()
+ root := filepath.Join(parent, "source-controller")
+ unfinished := filepath.Join(parent, "source-controller"+staleSuffix+"1")
+ unrelated := filepath.Join(parent, "other-controller"+staleSuffix+"1")
+ for _, dir := range []string{root, unfinished, unrelated} {
+ g.Expect(os.MkdirAll(dir, 0o700)).To(Succeed())
+ }
+
+ stale, err := PrepareTempRoot(root)
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(stale).To(ContainElement(unfinished))
+ g.Expect(stale).ToNot(ContainElement(unrelated))
+ g.Expect(stale).To(HaveLen(2))
+ })
+}
+
+func TestPurgeTempRoots(t *testing.T) {
+ t.Run("removes every path", func(t *testing.T) {
+ g := NewWithT(t)
+ parent := t.TempDir()
+ a := filepath.Join(parent, "a", "nested")
+ b := filepath.Join(parent, "b")
+ g.Expect(os.MkdirAll(a, 0o700)).To(Succeed())
+ g.Expect(os.MkdirAll(b, 0o700)).To(Succeed())
+
+ purged := PurgeTempRoots(context.Background(), logr.Discard(), []string{filepath.Join(parent, "a"), b})
+ g.Expect(purged).To(Equal(2))
+ g.Expect(filepath.Join(parent, "a")).ToNot(BeADirectory())
+ g.Expect(b).ToNot(BeADirectory())
+ })
+
+ t.Run("stops when the context is done", func(t *testing.T) {
+ g := NewWithT(t)
+ dir := t.TempDir()
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ purged := PurgeTempRoots(ctx, logr.Discard(), []string{dir})
+ g.Expect(purged).To(Equal(0))
+ g.Expect(dir).To(BeADirectory())
+ })
+
+ t.Run("removes a root with many entries", func(t *testing.T) {
+ g := NewWithT(t)
+ root := filepath.Join(t.TempDir(), "source-controller"+staleSuffix+"1")
+ for _, name := range []string{"gitrepository-default-a-1", "helmchart-default-b-2", "chart-build-3"} {
+ g.Expect(os.MkdirAll(filepath.Join(root, name, "nested"), 0o700)).To(Succeed())
+ }
+ g.Expect(os.WriteFile(filepath.Join(root, "chart-index-4.yaml"), []byte("x"), 0o600)).To(Succeed())
+
+ purged := PurgeTempRoots(context.Background(), logr.Discard(), []string{root})
+ g.Expect(purged).To(Equal(1))
+ g.Expect(root).ToNot(BeAnExistingFile())
+ })
+
+ t.Run("removes files and tolerates missing paths", func(t *testing.T) {
+ g := NewWithT(t)
+ parent := t.TempDir()
+ file := filepath.Join(parent, "source-controller"+staleSuffix+"1")
+ missing := filepath.Join(parent, "source-controller"+staleSuffix+"2")
+ g.Expect(os.WriteFile(file, []byte("x"), 0o600)).To(Succeed())
+
+ purged := PurgeTempRoots(context.Background(), logr.Discard(), []string{file, missing})
+ g.Expect(purged).To(Equal(2))
+ g.Expect(file).ToNot(BeAnExistingFile())
+ })
+}
diff --git a/internal/util/temp_test.go b/internal/util/temp_test.go
index 2f98079c6..a5e85fc38 100644
--- a/internal/util/temp_test.go
+++ b/internal/util/temp_test.go
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -75,12 +74,8 @@ func Test_pattern(t *testing.T) {
func mockObj() client.Object {
return &corev1.Secret{
- TypeMeta: metav1.TypeMeta{
- Kind: "Secret",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "foo",
- Namespace: "default",
- },
+ Kind: "Secret",
+ Name: "foo",
+ Namespace: "default",
}
}
diff --git a/main.go b/main.go
index 3fbef9181..7720169f7 100644
--- a/main.go
+++ b/main.go
@@ -17,18 +17,21 @@ limitations under the License.
package main
import (
+ "context"
+ "crypto/tls"
"fmt"
"os"
+ "path/filepath"
"time"
flag "github.com/spf13/pflag"
+ "github.com/spiffe/go-spiffe/v2/workloadapi"
"helm.sh/helm/v4/pkg/getter"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
- "k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime"
ctrlcache "sigs.k8s.io/controller-runtime/pkg/cache"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -53,6 +56,8 @@ import (
"github.com/fluxcd/pkg/runtime/metrics"
"github.com/fluxcd/pkg/runtime/pprof"
"github.com/fluxcd/pkg/runtime/probes"
+ fluxspiffe "github.com/fluxcd/pkg/spiffe"
+ fluxbroker "github.com/fluxcd/pkg/spiffe/broker"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
@@ -63,6 +68,7 @@ import (
"github.com/fluxcd/source-controller/internal/features"
"github.com/fluxcd/source-controller/internal/helm"
scosign "github.com/fluxcd/source-controller/internal/oci/cosign"
+ "github.com/fluxcd/source-controller/internal/util"
)
const controllerName = "source-controller"
@@ -95,27 +101,31 @@ func main() {
)
var (
- metricsAddr string
- eventsAddr string
- healthAddr string
- concurrent int
- requeueDependency time.Duration
- helmIndexLimit int64
- helmChartLimit int64
- helmChartFileLimit int64
- artifactOptions artcfg.Options
- clientOptions client.Options
- logOptions logger.Options
- leaderElectionOptions leaderelection.Options
- rateLimiterOptions helper.RateLimiterOptions
- featureGates feathelper.FeatureGates
- watchOptions helper.WatchOptions
- intervalJitterOptions jitter.IntervalOptions
- helmCacheMaxSize int
- helmCacheTTL string
- helmCachePurgeInterval string
- tokenCacheOptions pkgcache.TokenFlags
- defaultServiceAccount string
+ metricsAddr string
+ eventsAddr string
+ healthAddr string
+ concurrent int
+ requeueDependency time.Duration
+ helmIndexLimit int64
+ helmChartLimit int64
+ helmChartFileLimit int64
+ artifactOptions artcfg.Options
+ clientOptions client.Options
+ logOptions logger.Options
+ leaderElectionOptions leaderelection.Options
+ rateLimiterOptions helper.RateLimiterOptions
+ featureGates feathelper.FeatureGates
+ watchOptions helper.WatchOptions
+ intervalJitterOptions jitter.IntervalOptions
+ helmCacheMaxSize int
+ helmCacheTTL string
+ helmCachePurgeInterval string
+ tokenCacheOptions pkgcache.TokenFlags
+ defaultServiceAccount string
+ authorizedArtifactClients []string
+ authorizedEventServers []string
+ spiffeBrokerEndpoint string
+ spiffeBrokerIDs []string
)
flag.StringVar(&metricsAddr, "metrics-addr", envOrDefault("METRICS_ADDR", ":8080"),
@@ -144,6 +154,14 @@ func main() {
"The list of hostkey algorithms to use for ssh connections, arranged from most preferred to the least.")
flag.StringVar(&defaultServiceAccount, auth.ControllerFlagDefaultServiceAccount,
"", "Default service account to use for workload identity when not specified in resources.")
+ flag.StringArrayVar(&authorizedArtifactClients, fluxspiffe.ControllerFlagAuthorizedArtifactClientSPIFFEID, nil,
+ "SPIFFE ID authorized to fetch artifacts from the artifact server. Can be repeated.")
+ flag.StringArrayVar(&authorizedEventServers, fluxspiffe.ControllerFlagAuthorizedEventServerSPIFFEID, nil,
+ "SPIFFE ID of an event server authorized to receive events. Can be repeated.")
+ flag.StringVar(&spiffeBrokerEndpoint, fluxspiffe.ControllerFlagSPIFFEBrokerEndpoint, "",
+ "The gRPC URL of the SPIFFE Broker endpoint.")
+ flag.StringArrayVar(&spiffeBrokerIDs, fluxspiffe.ControllerFlagSPIFFEBrokerID, nil,
+ "SPIFFE ID of the SPIFFE Broker endpoint. Can be repeated.")
artifactOptions.BindFlags(flag.CommandLine)
clientOptions.BindFlags(flag.CommandLine)
@@ -159,28 +177,15 @@ func main() {
logger.SetLogger(logger.NewLogger(logOptions))
- if defaultServiceAccount != "" {
- auth.SetDefaultServiceAccount(defaultServiceAccount)
- }
+ staleTempDirs := setupTempRoot()
+
+ ctx := ctrl.SetupSignalHandler()
if err := featureGates.WithLogger(setupLog).SupportedFeatures(features.FeatureGates()); err != nil {
setupLog.Error(err, "unable to load feature gates")
os.Exit(1)
}
- switch enabled, err := features.Enabled(auth.FeatureGateObjectLevelWorkloadIdentity); {
- case err != nil:
- setupLog.Error(err, "unable to check feature gate "+auth.FeatureGateObjectLevelWorkloadIdentity)
- os.Exit(1)
- case enabled:
- auth.EnableObjectLevelWorkloadIdentity()
- }
-
- if auth.InconsistentObjectLevelConfiguration() {
- setupLog.Error(auth.ErrInconsistentObjectLevelConfiguration, "invalid configuration")
- os.Exit(1)
- }
-
if err := intervalJitterOptions.SetGlobalJitter(nil); err != nil {
setupLog.Error(err, "unable to set global jitter")
os.Exit(1)
@@ -191,11 +196,69 @@ func main() {
mgr := mustSetupManager(metricsAddr, healthAddr, concurrent, watchOptions, clientOptions, leaderElectionOptions)
probes.SetupChecks(mgr, setupLog)
+ if err := mgr.AddReadyzCheck("leader-election", probes.LeaderElectedReadyz(mgr.Elected())); err != nil {
+ setupLog.Error(err, "unable to create leader election readiness check")
+ os.Exit(1)
+ }
metrics := helper.NewMetrics(mgr, metrics.MustMakeRecorder(), sourcev1.SourceFinalizer)
cacheRecorder := cache.MustMakeMetrics()
- eventRecorder, err := events.NewRecorder(ctrl.Log, eventsAddr, controllerName, events.WithManager(mgr))
+ var eventTLSConfig *tls.Config
+ var spiffeBroker fluxbroker.Client
+ if len(authorizedArtifactClients) > 0 || len(authorizedEventServers) > 0 ||
+ spiffeBrokerEndpoint != "" || len(spiffeBrokerIDs) > 0 {
+ source, err := workloadapi.NewX509Source(ctx)
+ if err != nil {
+ setupLog.Error(err, "unable to create SPIFFE X.509 source")
+ os.Exit(1)
+ }
+ defer func() {
+ if err := source.Close(); err != nil {
+ setupLog.Error(err, "unable to close SPIFFE X.509 source")
+ }
+ }()
+
+ if len(authorizedArtifactClients) > 0 {
+ artifactTLSConfig, err := fluxspiffe.BuildTLSConfig(source, authorizedArtifactClients...)
+ if err != nil {
+ setupLog.Error(err, "unable to configure SPIFFE mTLS for the artifact server")
+ os.Exit(1)
+ }
+ setupLog.Info("artifact server will use inter-controller mTLS via SPIFFE", "spiffeIDs", authorizedArtifactClients)
+ artifactOptions.TLSConfig = artifactTLSConfig
+ }
+
+ if len(authorizedEventServers) > 0 {
+ eventTLSConfig, err = fluxspiffe.BuildTLSConfig(source, authorizedEventServers...)
+ if err != nil {
+ setupLog.Error(err, "unable to configure SPIFFE mTLS for the event server")
+ os.Exit(1)
+ }
+ setupLog.Info("event server will use inter-controller mTLS via SPIFFE", "spiffeIDs", authorizedEventServers)
+ }
+
+ if spiffeBrokerEndpoint != "" || len(spiffeBrokerIDs) > 0 {
+ spiffeBroker, err = fluxbroker.New(spiffeBrokerEndpoint, spiffeBrokerIDs, source)
+ if err != nil {
+ setupLog.Error(err, "unable to create SPIFFE Broker client")
+ os.Exit(1)
+ }
+ defer func() {
+ if err := spiffeBroker.Close(); err != nil {
+ setupLog.Error(err, "unable to close SPIFFE Broker client")
+ }
+ }()
+ setupLog.Info("object-level workload identity will use the SPIFFE Broker API",
+ "endpoint", spiffeBrokerEndpoint, "spiffeIDs", spiffeBrokerIDs)
+ }
+ }
+
+ eventRecorderOpts := []events.RecorderOption{events.WithManager(mgr)}
+ if eventTLSConfig != nil {
+ eventRecorderOpts = append(eventRecorderOpts, events.WithTLSConfig(eventTLSConfig))
+ }
+ eventRecorder, err := events.NewRecorder(ctrl.Log, eventsAddr, controllerName, eventRecorderOpts...)
if err != nil {
setupLog.Error(err, "unable to create event recorder")
os.Exit(1)
@@ -230,15 +293,15 @@ func main() {
}
}
- ctx := ctrl.SetupSignalHandler()
-
if err := (&controller.GitRepositoryReconciler{
- Client: mgr.GetClient(),
- Recorder: eventRecorder,
- Metrics: metrics,
- Storage: storage,
- ControllerName: controllerName,
- TokenCache: tokenCache,
+ Client: mgr.GetClient(),
+ Recorder: eventRecorder,
+ Metrics: metrics,
+ Storage: storage,
+ ControllerName: controllerName,
+ TokenCache: tokenCache,
+ DefaultServiceAccount: defaultServiceAccount,
+ SPIFFEBroker: spiffeBroker,
}).SetupWithManager(mgr, controller.GitRepositoryReconcilerOptions{
DependencyRequeueInterval: requeueDependency,
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
@@ -283,12 +346,14 @@ func main() {
}
if err := (&controller.BucketReconciler{
- Client: mgr.GetClient(),
- Recorder: eventRecorder,
- Metrics: metrics,
- Storage: storage,
- ControllerName: controllerName,
- TokenCache: tokenCache,
+ Client: mgr.GetClient(),
+ Recorder: eventRecorder,
+ Metrics: metrics,
+ Storage: storage,
+ ControllerName: controllerName,
+ TokenCache: tokenCache,
+ DefaultServiceAccount: defaultServiceAccount,
+ SPIFFEBroker: spiffeBroker,
}).SetupWithManager(mgr, controller.BucketReconcilerOptions{
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
}); err != nil {
@@ -304,6 +369,8 @@ func main() {
TokenCache: tokenCache,
CosignVerifierFactory: CosignVerifierFactory,
Metrics: metrics,
+ DefaultServiceAccount: defaultServiceAccount,
+ SPIFFEBroker: spiffeBroker,
}).SetupWithManager(mgr, controller.OCIRepositoryReconcilerOptions{
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
}); err != nil {
@@ -325,6 +392,8 @@ func main() {
}
}()
+ purgeStaleTempDirs(ctx, staleTempDirs)
+
setupLog.Info("starting manager")
if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
@@ -391,7 +460,7 @@ func mustSetupManager(metricsAddr, healthAddr string, maxConcurrent int,
ExtraHandlers: pprof.GetHandlers(),
},
Controller: ctrlcfg.Controller{
- RecoverPanic: ptr.To(true),
+ RecoverPanic: new(true),
MaxConcurrentReconciles: maxConcurrent,
},
}
@@ -445,3 +514,40 @@ func envOrDefault(envName, defaultValue string) string {
return defaultValue
}
+
+// setupTempRoot points TMPDIR at a directory of this controller's own, so
+// that every temporary file and directory it creates, including those of the
+// Helm and Git libraries, lands in one place. Whatever a previous process
+// left there, because it exited without running its deferred cleanup, is
+// moved aside and returned for purgeStaleTempDirs to remove. A failure is
+// logged and leaves TMPDIR unchanged, so that it does not prevent startup.
+func setupTempRoot() []string {
+ root := filepath.Join(os.TempDir(), controllerName)
+ stale, err := util.PrepareTempRoot(root)
+ if err != nil {
+ setupLog.Error(err, "unable to set up tmp dir, stale tmp dirs will not be purged")
+ return nil
+ }
+ if err := os.Setenv("TMPDIR", root); err != nil {
+ setupLog.Error(err, "unable to set TMPDIR, stale tmp dirs will not be purged")
+ return nil
+ }
+ return stale
+}
+
+// purgeStaleTempDirs removes the leftovers found by setupTempRoot in the
+// background, so that the manager startup is not delayed.
+func purgeStaleTempDirs(ctx context.Context, dirs []string) {
+ const purgeTimeout = 2 * time.Minute
+
+ if len(dirs) == 0 {
+ return
+ }
+
+ setupLog.Info("purging stale tmp dirs", "count", len(dirs))
+ go func() {
+ ctx, cancel := context.WithTimeout(ctx, purgeTimeout)
+ defer cancel()
+ util.PurgeTempRoots(ctx, setupLog, dirs)
+ }()
+}
diff --git a/tests/registry/registry.go b/tests/registry/registry.go
index 28b36fd20..b8a550d17 100644
--- a/tests/registry/registry.go
+++ b/tests/registry/registry.go
@@ -51,7 +51,7 @@ func New(t *testing.T) string {
config := &configuration.Configuration{}
config.HTTP.Addr = addr
config.HTTP.DrainTimeout = time.Duration(10) * time.Second
- config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
+ config.Storage = map[string]configuration.Parameters{"inmemory": map[string]any{}}
config.Log.AccessLog.Disabled = true
config.Log.Level = "error"
logrus.SetOutput(io.Discard)