From 3347db9481715bbfc53116deea9767ad6ec4e4d1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:37:33 +0800 Subject: [PATCH 1/6] Update Go dependencies to latest versions (#165) * Initial plan * Update Go dependencies: go 1.25, k8s.io v0.35.2, controller-runtime v0.23.3 Co-authored-by: RichardChen820 <99175581+RichardChen820@users.noreply.github.com> * Update Dockerfile base image to go 1.25 Co-authored-by: RichardChen820 <99175581+RichardChen820@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RichardChen820 <99175581+RichardChen820@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- .github/workflows/golangci-lint.yml | 2 +- Dockerfile | 2 +- go.mod | 77 ++++++------ go.sum | 181 +++++++++++++--------------- 5 files changed, 123 insertions(+), 141 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8a9d997..190eb18 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -19,7 +19,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.24' + go-version: '1.25' - name: Run Build run: go build -o ./out/manager ./cmd/main.go - name: Run Test diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 6326665..6c126fc 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: 1.24.0 + go-version: 1.25.0 - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: diff --git a/Dockerfile b/Dockerfile index 37fbe6c..4186541 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.24-cbl-mariner2.0 AS builder +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.25-cbl-mariner2.0 AS builder ARG MODULE_VERSION WORKDIR /workspace diff --git a/go.mod b/go.mod index 60e75fb..7ba8592 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module azappconfig/provider -go 1.24.0 +go 1.25.0 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 @@ -8,35 +8,35 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0 github.com/golang/mock v1.6.0 github.com/onsi/gomega v1.39.1 - golang.org/x/crypto v0.48.0 - golang.org/x/sync v0.19.0 - k8s.io/apimachinery v0.34.3 - k8s.io/client-go v0.34.3 - sigs.k8s.io/controller-runtime v0.22.5 + golang.org/x/crypto v0.49.0 + golang.org/x/sync v0.20.0 + k8s.io/apimachinery v0.35.2 + k8s.io/client-go v0.35.2 + sigs.k8s.io/controller-runtime v0.23.3 ) require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/go-openapi/jsonpointer v0.22.4 // indirect - github.com/go-openapi/jsonreference v0.21.4 // indirect - github.com/go-openapi/swag v0.25.4 // indirect - github.com/go-openapi/swag/cmdutils v0.25.4 // indirect - github.com/go-openapi/swag/conv v0.25.4 // indirect - github.com/go-openapi/swag/fileutils v0.25.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/go-openapi/swag/jsonutils v0.25.4 // indirect - github.com/go-openapi/swag/loading v0.25.4 // indirect - github.com/go-openapi/swag/mangling v0.25.4 // indirect - github.com/go-openapi/swag/netutils v0.25.4 // indirect - github.com/go-openapi/swag/stringutils v0.25.4 // indirect - github.com/go-openapi/swag/typeutils v0.25.4 // indirect - github.com/go-openapi/swag/yamlutils v0.25.4 // indirect + github.com/go-openapi/jsonpointer v0.22.5 // indirect + github.com/go-openapi/jsonreference v0.21.5 // indirect + github.com/go-openapi/swag v0.25.5 // indirect + github.com/go-openapi/swag/cmdutils v0.25.5 // indirect + github.com/go-openapi/swag/conv v0.25.5 // indirect + github.com/go-openapi/swag/fileutils v0.25.5 // indirect + github.com/go-openapi/swag/jsonname v0.25.5 // indirect + github.com/go-openapi/swag/jsonutils v0.25.5 // indirect + github.com/go-openapi/swag/loading v0.25.5 // indirect + github.com/go-openapi/swag/mangling v0.25.5 // indirect + github.com/go-openapi/swag/netutils v0.25.5 // indirect + github.com/go-openapi/swag/stringutils v0.25.5 // indirect + github.com/go-openapi/swag/typeutils v0.25.5 // indirect + github.com/go-openapi/swag/yamlutils v0.25.5 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/google/btree v1.1.3 // indirect @@ -47,13 +47,13 @@ require ( github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/x448/float16 v0.8.4 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/tools v0.42.0 // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/tools v0.43.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect ) require ( @@ -65,7 +65,6 @@ require ( github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 github.com/json-iterator/go v1.1.12 // indirect @@ -75,28 +74,28 @@ require ( github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect - github.com/prometheus/procfs v0.19.2 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/testify v1.11.1 go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 - golang.org/x/net v0.50.0 // indirect - golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/term v0.40.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect + golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 + golang.org/x/net v0.52.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/term v0.41.0 // indirect + golang.org/x/text v0.35.0 // indirect + golang.org/x/time v0.15.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.34.3 - k8s.io/apiextensions-apiserver v0.34.3 // indirect - k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect - k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8 // indirect + k8s.io/api v0.35.2 + k8s.io/apiextensions-apiserver v0.35.2 // indirect + k8s.io/klog/v2 v2.140.0 + k8s.io/kube-openapi v0.0.0-20260319004828-5883c5ee87b9 // indirect + k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/yaml v1.6.0 // indirect software.sslmate.com/src/go-pkcs12 v0.7.0 diff --git a/go.sum b/go.sum index aaf4d04..5040d0d 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfg github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= 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.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= -github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0 h1:4iB+IesclUXdP0ICgAabvq2FYLXrJWKx1fJQ+GxSo3Y= +github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -46,46 +46,44 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= -github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= -github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= -github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= -github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= -github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= -github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= -github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= -github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= -github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= -github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= -github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= -github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= -github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= -github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= -github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= -github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= -github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= -github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= -github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= -github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= -github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= -github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= -github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= -github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= +github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= +github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= +github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= +github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c= +github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= +github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= +github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk= +github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= +github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= +github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= +github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw= +github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY= +github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU= +github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14= +github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= +github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= +github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= +github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= +github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= +github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= +github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= +github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= @@ -109,8 +107,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -148,10 +144,10 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= -github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= -github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +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/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -170,8 +166,6 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -179,65 +173,54 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +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= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0= -golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= -golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= @@ -254,28 +237,28 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= -k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= -k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= -k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= -k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= -k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= -k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY= -k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= -k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8 h1:oV4uULAC2QPIdMQwjMaNIwykyhWhnhBwX40yd5h9u3U= -k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -sigs.k8s.io/controller-runtime v0.22.5 h1:v3nfSUMowX/2WMp27J9slwGFyAt7IV0YwBxAkrUr0GE= -sigs.k8s.io/controller-runtime v0.22.5/go.mod h1:pc5SoYWnWI6I+cBHYYdZ7B6YHZVY5xNfll88JB+vniI= +k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw= +k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60= +k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0= +k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU= +k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8= +k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o= +k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-openapi v0.0.0-20260319004828-5883c5ee87b9 h1:Sztf7ESG9tAXRW/ACJZjrj5jhdOUqS2KFRQT+CTvu78= +k8s.io/kube-openapi v0.0.0-20260319004828-5883c5ee87b9/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80= +sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= 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/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= -sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= +sigs.k8s.io/structured-merge-diff/v6 v6.3.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.7.0 h1:Db8W44cB54TWD7stUFFSWxdfpdn6fZVcDl0w3R4RVM0= From 2f134e89f5f1aed4e1c78a70da96c28f1f54bab9 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 07:44:52 +0800 Subject: [PATCH 2/6] Update CGO_ENABLED to 1 in Dockerfile builder stage (#167) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RichardChen820 <99175581+RichardChen820@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4186541..e290bf5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ COPY internal/properties/ internal/properties/ ARG TARGETARCH # Build -RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -ldflags "-X azappconfig/provider/internal/properties.ModuleVersion=$MODULE_VERSION" -a -o manager cmd/main.go +RUN CGO_ENABLED=1 GOOS=linux GOARCH=$TARGETARCH go build -ldflags "-X azappconfig/provider/internal/properties.ModuleVersion=$MODULE_VERSION" -a -o manager cmd/main.go # Use distroless as minimal base image to package the manager binary FROM --platform=$BUILDPLATFORM mcr.microsoft.com/cbl-mariner/distroless/minimal:2.0-nonroot From 98c45db9ab9c0baadb6bf1053b65b76360780338 Mon Sep 17 00:00:00 2001 From: linglingye001 <143174321+linglingye001@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:43:36 +0800 Subject: [PATCH 3/6] Snapshot reference support (#166) * snapshot reference support * update * update --- .../configuraiton_setting_loader_test.go | 220 ++++++++++++++++++ .../loader/configuration_setting_loader.go | 167 ++++++++++--- internal/loader/request_tracing.go | 6 + internal/loader/request_tracing_test.go | 29 +++ internal/loader/settings_client.go | 46 ++-- 5 files changed, 421 insertions(+), 47 deletions(-) diff --git a/internal/loader/configuraiton_setting_loader_test.go b/internal/loader/configuraiton_setting_loader_test.go index de0e908..9b00ace 100644 --- a/internal/loader/configuraiton_setting_loader_test.go +++ b/internal/loader/configuraiton_setting_loader_test.go @@ -2215,3 +2215,223 @@ func newSelectorWithTagFilters(key string, label *string, tagFilters []string) a } return acpv1.MakeComparable(selector) } + +// --- Snapshot Reference Tests --- + +func TestParseSnapshotReference(t *testing.T) { + t.Run("valid reference", func(t *testing.T) { + name, err := parseSnapshotReference(`{"snapshot_name":"my-snapshot"}`) + assert.NoError(t, err) + assert.Equal(t, "my-snapshot", name) + }) + + t.Run("empty snapshot name", func(t *testing.T) { + _, err := parseSnapshotReference(`{"snapshot_name":""}`) + assert.Error(t, err) + assert.Contains(t, err.Error(), "snapshot_name is empty") + }) + + t.Run("invalid JSON", func(t *testing.T) { + _, err := parseSnapshotReference(`invalid json`) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse snapshot reference") + }) + + t.Run("missing snapshot_name field", func(t *testing.T) { + _, err := parseSnapshotReference(`{"other_field":"value"}`) + assert.Error(t, err) + assert.Contains(t, err.Error(), "snapshot_name is empty") + }) +} + +func newSnapshotReferenceSettings(key string, snapshotName string, label string) azappconfig.Setting { + snapshotRefContentType := SnapshotReferenceContentType + value := fmt.Sprintf(`{"snapshot_name":"%s"}`, snapshotName) + return azappconfig.Setting{ + Key: &key, + Value: &value, + Label: &label, + ContentType: &snapshotRefContentType, + } +} + +func TestSnapshotReferenceInCreateKeyValueSettings(t *testing.T) { + t.Run("Snapshot reference setting should be collected and traced", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mockSettingsClient := NewMockSettingsClient(mockCtrl) + mockClientManager := NewMockClientManager(mockCtrl) + + EndpointName := "https://fake-endpoint" + testSpec := acpv1.AzureAppConfigurationProviderSpec{ + Endpoint: &EndpointName, + ReplicaDiscoveryEnabled: false, + Target: acpv1.ConfigurationGenerationParameters{ + ConfigMapName: "test-configmap", + }, + } + testProvider := acpv1.AzureAppConfigurationProvider{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "azconfig.io/v1", + Kind: "AppConfigurationProvider", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "testName", + Namespace: "testNamespace", + }, + Spec: testSpec, + } + + // Settings returned: 1 regular kv, 1 snapshot reference + settingsToReturn := []azappconfig.Setting{ + newCommonKeyValueSettings("key1", "value1", "label1"), + newSnapshotReferenceSettings("snapshotRef1", "my-snapshot", "label1"), + } + + keyValueEtags := make(map[acpv1.ComparableSelector][]*azcore.ETag) + keyValueEtags[newKeyValueSelector("*", nil)] = []*azcore.ETag{} + settingsResponse := &SettingsResponse{ + Settings: settingsToReturn, + Etags: keyValueEtags, + } + + mockSettingsClient.EXPECT().GetSettings(gomock.Any(), gomock.Any()).Return(settingsResponse, nil) + + // First GetClients call: for ExecuteFailoverPolicy (initial key-value loading) - returns valid wrapper + // Second GetClients call: for resolveSnapshotReferences - returns empty to trigger error + gomock.InOrder( + mockClientManager.EXPECT().GetClients(gomock.Any()).Return([]*ConfigurationClientWrapper{&fakeClientWrapper}, nil), + mockClientManager.EXPECT().GetClients(gomock.Any()).Return([]*ConfigurationClientWrapper{}, nil), + ) + + configurationProvider, _ := NewConfigurationSettingLoader(testProvider, mockClientManager, mockSettingsClient) + + // Resolution will fail because no clients available for snapshot resolution + _, err := configurationProvider.CreateKeyValueSettings(context.Background(), nil) + + // Expect an error because no clients available for snapshot resolution + assert.Error(t, err) + assert.Contains(t, err.Error(), "no client is available to resolve snapshot references") + + // Verify the tracing feature was set during the collection phase (before resolution) + assert.True(t, configurationProvider.TracingFeatures.UseSnapshotReference, "UseSnapshotReference flag should be set when snapshot reference settings are found") + }) + + t.Run("Settings without snapshot references should not set tracing flag", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mockSettingsClient := NewMockSettingsClient(mockCtrl) + mockClientManager := NewMockClientManager(mockCtrl) + + EndpointName := "https://fake-endpoint" + testSpec := acpv1.AzureAppConfigurationProviderSpec{ + Endpoint: &EndpointName, + ReplicaDiscoveryEnabled: false, + Target: acpv1.ConfigurationGenerationParameters{ + ConfigMapName: "test-configmap", + }, + } + testProvider := acpv1.AzureAppConfigurationProvider{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "azconfig.io/v1", + Kind: "AppConfigurationProvider", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "testName", + Namespace: "testNamespace", + }, + Spec: testSpec, + } + + settingsToReturn := mockConfigurationSettings() + keyValueEtags := make(map[acpv1.ComparableSelector][]*azcore.ETag) + keyValueEtags[newKeyValueSelector("*", nil)] = []*azcore.ETag{} + settingsResponse := &SettingsResponse{ + Settings: settingsToReturn, + Etags: keyValueEtags, + } + + mockSettingsClient.EXPECT().GetSettings(gomock.Any(), gomock.Any()).Return(settingsResponse, nil) + mockClientManager.EXPECT().GetClients(gomock.Any()).Return([]*ConfigurationClientWrapper{&fakeClientWrapper}, nil).AnyTimes() + + configurationProvider, _ := NewConfigurationSettingLoader(testProvider, mockClientManager, mockSettingsClient) + rawSettings, err := configurationProvider.CreateKeyValueSettings(context.Background(), nil) + + assert.NoError(t, err) + assert.NotNil(t, rawSettings) + assert.False(t, configurationProvider.TracingFeatures.UseSnapshotReference, "UseSnapshotReference flag should not be set when no snapshot references exist") + }) + + t.Run("Invalid snapshot reference format should return error", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mockSettingsClient := NewMockSettingsClient(mockCtrl) + mockClientManager := NewMockClientManager(mockCtrl) + + EndpointName := "https://fake-endpoint" + testSpec := acpv1.AzureAppConfigurationProviderSpec{ + Endpoint: &EndpointName, + ReplicaDiscoveryEnabled: false, + Target: acpv1.ConfigurationGenerationParameters{ + ConfigMapName: "test-configmap", + }, + } + testProvider := acpv1.AzureAppConfigurationProvider{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "azconfig.io/v1", + Kind: "AppConfigurationProvider", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "testName", + Namespace: "testNamespace", + }, + Spec: testSpec, + } + + // Create a snapshot reference setting with invalid JSON value + invalidRefContentType := SnapshotReferenceContentType + invalidRefValue := "invalid json" + invalidRefKey := "badRef" + invalidRefLabel := "label1" + settingsToReturn := []azappconfig.Setting{ + { + Key: &invalidRefKey, + Value: &invalidRefValue, + Label: &invalidRefLabel, + ContentType: &invalidRefContentType, + }, + } + + keyValueEtags := make(map[acpv1.ComparableSelector][]*azcore.ETag) + keyValueEtags[newKeyValueSelector("*", nil)] = []*azcore.ETag{} + settingsResponse := &SettingsResponse{ + Settings: settingsToReturn, + Etags: keyValueEtags, + } + + mockSettingsClient.EXPECT().GetSettings(gomock.Any(), gomock.Any()).Return(settingsResponse, nil) + fakeClient := &ConfigurationClientWrapper{ + Client: nil, + Endpoint: EndpointName, + } + mockClientManager.EXPECT().GetClients(gomock.Any()).Return([]*ConfigurationClientWrapper{fakeClient}, nil).AnyTimes() + + configurationProvider, _ := NewConfigurationSettingLoader(testProvider, mockClientManager, mockSettingsClient) + _, err := configurationProvider.CreateKeyValueSettings(context.Background(), nil) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid format for snapshot reference setting") + }) + + t.Run("Snapshot reference with KV ref should require spec.secret", func(t *testing.T) { + // This verifies that if a snapshot ref contains Key Vault references but spec.secret is not configured, + // the parseSnapshotReference itself works but the resolution flow would error. + // For unit test purposes, we validate the parsing side. + name, err := parseSnapshotReference(`{"snapshot_name":"vault-ref-snapshot"}`) + assert.NoError(t, err) + assert.Equal(t, "vault-ref-snapshot", name) + }) +} diff --git a/internal/loader/configuration_setting_loader.go b/internal/loader/configuration_setting_loader.go index 78d1639..7c48e43 100644 --- a/internal/loader/configuration_setting_loader.go +++ b/internal/loader/configuration_setting_loader.go @@ -87,6 +87,7 @@ type ServicePrincipleAuthenticationParameters struct { const ( SecretReferenceContentType string = "application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8" + SnapshotReferenceContentType string = "application/json; profile=\"https://azconfig.io/mime-profiles/snapshot-ref\"; charset=utf-8" FeatureFlagContentType string = "application/vnd.microsoft.appconfig.ff+json;charset=utf-8" AzureClientId string = "azure_client_id" AzureClientSecret string = "azure_client_secret" @@ -204,6 +205,15 @@ func (csl *ConfigurationSettingLoader) RefreshFeatureFlagSettings(ctx context.Co }, nil } +// settingProcessContext holds the mutable state used during setting classification. +type settingProcessContext struct { + rawSettings *RawSettings + resolver *SecretReferenceResolver + snapshotRefs map[string]string // nil to skip snapshot reference collection (e.g. inside snapshot resolution) + useAIConfiguration bool + useAIChatCompletionConfiguration bool +} + func (csl *ConfigurationSettingLoader) CreateKeyValueSettings(ctx context.Context, secretReferenceResolver SecretReferenceResolver) (*RawSettings, error) { keyValueFilters := GetKeyValueFilters(csl.Spec) settingsClient := csl.SettingsClient @@ -233,9 +243,51 @@ func (csl *ConfigurationSettingLoader) CreateKeyValueSettings(ctx context.Contex } resolver := secretReferenceResolver - useAIConfiguration := false - useAIChatCompletionConfiguration := false - for _, setting := range settingsResponse.Settings { + processCtx := &settingProcessContext{ + rawSettings: rawSettings, + resolver: &resolver, + snapshotRefs: make(map[string]string), // collect snapshot references + } + + if err := csl.processSettings(ctx, settingsResponse.Settings, processCtx); err != nil { + return nil, err + } + + csl.TracingFeatures.UseAIConfiguration = processCtx.useAIConfiguration + csl.TracingFeatures.UseAIChatCompletionConfiguration = processCtx.useAIChatCompletionConfiguration + + // Resolve snapshot references + if len(processCtx.snapshotRefs) > 0 { + if err := csl.resolveSnapshotReferences(ctx, processCtx.snapshotRefs, processCtx); err != nil { + return nil, err + } + csl.TracingFeatures.UseAIConfiguration = csl.TracingFeatures.UseAIConfiguration || processCtx.useAIConfiguration + csl.TracingFeatures.UseAIChatCompletionConfiguration = csl.TracingFeatures.UseAIChatCompletionConfiguration || processCtx.useAIChatCompletionConfiguration + } + + // resolve the secret reference settings + if resolvedSecret, err := csl.ResolveSecretReferences(ctx, rawSettings.K8sSecrets, resolver); err != nil { + return nil, err + } else { + rawSettings.K8sSecrets = resolvedSecret.K8sSecrets + err = MergeSecret(rawSettings.SecretSettings, resolvedSecret.SecretSettings) + if err != nil { + return nil, err + } + } + + return rawSettings, nil +} + +// processSettings classifies each setting by content type and populates the process context accordingly. +// Feature flags are skipped, secret references are collected into K8sSecrets, snapshot references +// are collected when processCtx.snapshotRefs is non-nil, and all other settings go into KeyValueSettings. +func (csl *ConfigurationSettingLoader) processSettings(ctx context.Context, settings []azappconfig.Setting, processCtx *settingProcessContext) error { + for _, setting := range settings { + if setting.Key == nil { + continue + } + trimmedKey := trimPrefix(*setting.Key, csl.Spec.Configuration.TrimKeyPrefixes) if len(trimmedKey) == 0 { klog.Warningf("key of the setting '%s' is trimmed to the empty string, just ignore it", *setting.Key) @@ -243,47 +295,48 @@ func (csl *ConfigurationSettingLoader) CreateKeyValueSettings(ctx context.Contex } if setting.ContentType == nil { - rawSettings.KeyValueSettings[trimmedKey] = setting.Value - rawSettings.IsJsonContentTypeMap[trimmedKey] = false + processCtx.rawSettings.KeyValueSettings[trimmedKey] = setting.Value + processCtx.rawSettings.IsJsonContentTypeMap[trimmedKey] = false continue } + switch strings.TrimSpace(strings.ToLower(*setting.ContentType)) { case FeatureFlagContentType: continue // ignore feature flag while getting key value settings case SecretReferenceContentType: if setting.Value == nil { - return nil, fmt.Errorf("the value of Key Vault reference '%s' is null", *setting.Key) + return fmt.Errorf("the value of Key Vault reference '%s' is null", *setting.Key) } if csl.Spec.Secret == nil { - return nil, fmt.Errorf("a Key Vault reference is found in App Configuration, but 'spec.secret' was not configured in the Azure App Configuration provider '%s' in namespace '%s'", csl.Name, csl.Namespace) + return fmt.Errorf("a Key Vault reference is found in App Configuration, but 'spec.secret' was not configured in the Azure App Configuration provider '%s' in namespace '%s'", csl.Name, csl.Namespace) } var secretType corev1.SecretType = corev1.SecretTypeOpaque var err error if secretTypeTag, ok := setting.Tags[PreservedSecretTypeTag]; ok { if secretTypeTag == nil { - return nil, fmt.Errorf("the secret type tag '%s' for setting '%s' is invalid", PreservedSecretTypeTag, *setting.Key) + return fmt.Errorf("the secret type tag '%s' for setting '%s' is invalid", PreservedSecretTypeTag, *setting.Key) } secretType, err = parseSecretType(*secretTypeTag) if err != nil { - return nil, err + return err } } - if resolver == nil { + if *processCtx.resolver == nil { if newResolver, err := csl.createSecretReferenceResolver(ctx); err != nil { - return nil, err + return err } else { - resolver = newResolver + *processCtx.resolver = newResolver } } currentUrl := *setting.Value secretMetadata, err := parse(currentUrl) if err != nil { - return nil, err + return err } secretName := trimmedKey @@ -292,43 +345,95 @@ func (csl *ConfigurationSettingLoader) CreateKeyValueSettings(ctx context.Contex secretName = csl.Spec.Secret.Target.SecretName } - if _, ok := rawSettings.K8sSecrets[secretName]; !ok { - rawSettings.K8sSecrets[secretName] = &TargetK8sSecretMetadata{ + if _, ok := processCtx.rawSettings.K8sSecrets[secretName]; !ok { + processCtx.rawSettings.K8sSecrets[secretName] = &TargetK8sSecretMetadata{ Type: secretType, SecretsKeyVaultMetadata: make(map[string]KeyVaultSecretMetadata), } } - rawSettings.K8sSecrets[secretName].SecretsKeyVaultMetadata[trimmedKey] = *secretMetadata + processCtx.rawSettings.K8sSecrets[secretName].SecretsKeyVaultMetadata[trimmedKey] = *secretMetadata + case SnapshotReferenceContentType: + // Only collect snapshot references when snapshotRefs is non-nil (top-level loading). + // During snapshot reference resolution, snapshotRefs is nil to prevent nested resolution. + if processCtx.snapshotRefs != nil && setting.Value != nil { + processCtx.snapshotRefs[trimmedKey] = *setting.Value + csl.TracingFeatures.UseSnapshotReference = true + } default: - rawSettings.KeyValueSettings[trimmedKey] = setting.Value - rawSettings.IsJsonContentTypeMap[trimmedKey] = isJsonContentType(setting.ContentType) - if !rawSettings.IsJsonContentTypeMap[trimmedKey] { + processCtx.rawSettings.KeyValueSettings[trimmedKey] = setting.Value + processCtx.rawSettings.IsJsonContentTypeMap[trimmedKey] = isJsonContentType(setting.ContentType) + if !processCtx.rawSettings.IsJsonContentTypeMap[trimmedKey] { continue } if isAIConfigurationContentType(setting.ContentType) { - useAIConfiguration = true + processCtx.useAIConfiguration = true } if isAIChatCompletionContentType(setting.ContentType) { - useAIChatCompletionConfiguration = true + processCtx.useAIChatCompletionConfiguration = true } } } - csl.TracingFeatures.UseAIConfiguration = useAIConfiguration - csl.TracingFeatures.UseAIChatCompletionConfiguration = useAIChatCompletionConfiguration + return nil +} - // resolve the secret reference settings - if resolvedSecret, err := csl.ResolveSecretReferences(ctx, rawSettings.K8sSecrets, resolver); err != nil { - return nil, err - } else { - rawSettings.K8sSecrets = resolvedSecret.K8sSecrets - err = MergeSecret(rawSettings.SecretSettings, resolvedSecret.SecretSettings) +func (csl *ConfigurationSettingLoader) resolveSnapshotReferences( + ctx context.Context, + snapshotRefs map[string]string, + processCtx *settingProcessContext, +) error { + clients, err := csl.ClientManager.GetClients(ctx) + if err != nil { + return err + } + if len(clients) == 0 { + return fmt.Errorf("no client is available to resolve snapshot references") + } + + for key, snapshotRefValue := range snapshotRefs { + snapshotName, err := parseSnapshotReference(snapshotRefValue) if err != nil { - return nil, err + return fmt.Errorf("invalid format for snapshot reference setting '%s': %s", key, err.Error()) } + + snapshotSettings, err := loadSnapshotSettings(ctx, clients[0].Client, snapshotName) + if err != nil { + return fmt.Errorf("failed to load snapshot settings: key=%s, error=%s", key, err.Error()) + } + + // Process snapshot settings with snapshotRefs=nil to prevent nested snapshot reference resolution + snapshotProcessCtx := &settingProcessContext{ + rawSettings: processCtx.rawSettings, + resolver: processCtx.resolver, + snapshotRefs: nil, // do not collect nested snapshot references + } + if err := csl.processSettings(ctx, snapshotSettings, snapshotProcessCtx); err != nil { + return err + } + + processCtx.useAIConfiguration = processCtx.useAIConfiguration || snapshotProcessCtx.useAIConfiguration + processCtx.useAIChatCompletionConfiguration = processCtx.useAIChatCompletionConfiguration || snapshotProcessCtx.useAIChatCompletionConfiguration } - return rawSettings, nil + return nil +} + +// parseSnapshotReference parses a snapshot reference JSON value and returns the snapshot name. +// The expected format is: {"snapshot_name":""} +func parseSnapshotReference(ref string) (string, error) { + var snapshotRef struct { + SnapshotName string `json:"snapshot_name"` + } + + if err := json.Unmarshal([]byte(ref), &snapshotRef); err != nil { + return "", fmt.Errorf("failed to parse snapshot reference: %s", err.Error()) + } + + if snapshotRef.SnapshotName == "" { + return "", fmt.Errorf("snapshot_name is empty in snapshot reference") + } + + return snapshotRef.SnapshotName, nil } func (csl *ConfigurationSettingLoader) CheckAndRefreshSentinels( diff --git a/internal/loader/request_tracing.go b/internal/loader/request_tracing.go index 1bd5606..710b29e 100644 --- a/internal/loader/request_tracing.go +++ b/internal/loader/request_tracing.go @@ -23,6 +23,7 @@ type TracingFeatures struct { IsFailoverRequest bool UseAIConfiguration bool UseAIChatCompletionConfiguration bool + UseSnapshotReference bool } // Feature flag telemetry @@ -47,6 +48,7 @@ const ( LoadBalancingKey string = "LB" AIConfigurationKey string = "AI" AIChatCompletionKey string = "AICC" + SnapshotReferenceKey string = "SnapshotRef" ) func createCorrelationContextHeader(ctx context.Context, provider acpv1.AzureAppConfigurationProvider, tracingFeatures TracingFeatures) http.Header { @@ -97,6 +99,10 @@ func createCorrelationContextHeader(ctx context.Context, provider acpv1.AzureApp features = append(features, AIChatCompletionKey) } + if tracingFeatures.UseSnapshotReference { + features = append(features, SnapshotReferenceKey) + } + if len(features) > 0 { featureStr := "Features=" + strings.Join(features, TracingFeatureDelimiterKey) output = append(output, featureStr) diff --git a/internal/loader/request_tracing_test.go b/internal/loader/request_tracing_test.go index 6d94c17..34a97ca 100644 --- a/internal/loader/request_tracing_test.go +++ b/internal/loader/request_tracing_test.go @@ -131,6 +131,35 @@ func TestCreateCorrelationContextHeader(t *testing.T) { "InstalledBy=Extension", }, }, + { + name: "with snapshot reference", + provider: acpv1.AzureAppConfigurationProvider{}, + tracingFeatures: TracingFeatures{ + UseSnapshotReference: true, + }, + expected: []string{ + "Host=Kubernetes", + "Features=SnapshotRef", + "InstalledBy=Helm", + }, + }, + { + name: "with snapshot reference and other features", + provider: acpv1.AzureAppConfigurationProvider{ + Spec: acpv1.AzureAppConfigurationProviderSpec{ + LoadBalancingEnabled: true, + }, + }, + tracingFeatures: TracingFeatures{ + UseAIConfiguration: true, + UseSnapshotReference: true, + }, + expected: []string{ + "Host=Kubernetes", + "Features=LB+AI+SnapshotRef", + "InstalledBy=Helm", + }, + }, } for _, tt := range tests { diff --git a/internal/loader/settings_client.go b/internal/loader/settings_client.go index 0089207..adeb575 100644 --- a/internal/loader/settings_client.go +++ b/internal/loader/settings_client.go @@ -148,25 +148,11 @@ func (s *SelectorSettingsClient) GetSettings(ctx context.Context, client *azappc // update the etags for the filter pageEtags[acpv1.MakeComparable(filter)] = latestEtags } else { - snapshot, err := client.GetSnapshot(ctx, *filter.SnapshotName, nil) + snapshotSettings, err := loadSnapshotSettings(ctx, client, *filter.SnapshotName) if err != nil { return nil, err } - - if *snapshot.CompositionType != azappconfig.CompositionTypeKey { - return nil, fmt.Errorf("compositionType for the selected snapshot '%s' must be 'key', found '%s'", *filter.SnapshotName, *snapshot.CompositionType) - } - - pager := client.NewListSettingsForSnapshotPager(*filter.SnapshotName, nil) - - for pager.More() { - page, err := pager.NextPage(ctx) - if err != nil { - return nil, err - } else if page.Settings != nil { - settings = append(settings, page.Settings...) - } - } + settings = append(settings, snapshotSettings...) } } @@ -175,3 +161,31 @@ func (s *SelectorSettingsClient) GetSettings(ctx context.Context, client *azappc Etags: pageEtags, }, nil } + +func loadSnapshotSettings(ctx context.Context, client *azappconfig.Client, snapshotName string) ([]azappconfig.Setting, error) { + settings := make([]azappconfig.Setting, 0) + snapshot, err := client.GetSnapshot(ctx, snapshotName, nil) + if err != nil { + var respErr *azcore.ResponseError + if errors.As(err, &respErr) && respErr.StatusCode == 404 { + return settings, nil // treat non-existing snapshot as empty + } + return nil, err + } + + if snapshot.CompositionType == nil || *snapshot.CompositionType != azappconfig.CompositionTypeKey { + return nil, fmt.Errorf("compositionType for the selected snapshot '%s' must be 'key'", snapshotName) + } + + pager := client.NewListSettingsForSnapshotPager(snapshotName, nil) + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, err + } else if page.Settings != nil { + settings = append(settings, page.Settings...) + } + } + + return settings, nil +} From d12f9a9f2389076949505735141f6ee1f852e4b4 Mon Sep 17 00:00:00 2001 From: linglingye001 <143174321+linglingye001@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:44:54 +0800 Subject: [PATCH 4/6] Audience parameter support (#164) * audience parameter support * fix lint * update --- deploy/parameter/helm-values.yaml | 1 + deploy/templates/deployment.yaml | 4 + .../loader/configuration_client_manager.go | 28 +++-- .../configuration_client_manager_test.go | 108 ++++++++++++++++++ 4 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 internal/loader/configuration_client_manager_test.go diff --git a/deploy/parameter/helm-values.yaml b/deploy/parameter/helm-values.yaml index 5b75f6b..6bbcb97 100644 --- a/deploy/parameter/helm-values.yaml +++ b/deploy/parameter/helm-values.yaml @@ -70,6 +70,7 @@ autoscaling: env: azureClientId: "" azureTenantId: "" + azureAppConfigurationAudience: "" # Pod scheduling preferences # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity diff --git a/deploy/templates/deployment.yaml b/deploy/templates/deployment.yaml index ae79d3f..2eb7942 100644 --- a/deploy/templates/deployment.yaml +++ b/deploy/templates/deployment.yaml @@ -88,6 +88,10 @@ spec: {{- end }} - name: REQUEST_TRACING_ENABLED value: "{{ .Values.requestTracing.enabled }}" + {{- if .Values.env.azureAppConfigurationAudience }} + - name: AZURE_APPCONFIG_AUDIENCE + value: {{ .Values.env.azureAppConfigurationAudience | quote }} + {{- end }} livenessProbe: httpGet: path: /healthz diff --git a/internal/loader/configuration_client_manager.go b/internal/loader/configuration_client_manager.go index 6ffd39e..ddc05f4 100644 --- a/internal/loader/configuration_client_manager.go +++ b/internal/loader/configuration_client_manager.go @@ -19,6 +19,7 @@ import ( acpv1 "azappconfig/provider/api/v1" "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/policy" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" azappconfig "github.com/Azure/azure-sdk-for-go/sdk/data/azappconfig/v2" @@ -80,17 +81,30 @@ const ( ApiTokenExchangeAudience string = "api://AzureADTokenExchange" AnnotationClientID string = "azure.workload.identity/client-id" AnnotationTenantID string = "azure.workload.identity/tenant-id" + AzureAppConfigurationAudience string = "AZURE_APPCONFIGURATION_AUDIENCE" ) -var ( - clientOptionWithModuleInfo *azappconfig.ClientOptions = &azappconfig.ClientOptions{ +func newClientOptions() *azappconfig.ClientOptions { + options := &azappconfig.ClientOptions{ ClientOptions: policy.ClientOptions{ Telemetry: policy.TelemetryOptions{ ApplicationID: fmt.Sprintf("%s/%s", properties.ModuleName, properties.ModuleVersion), }, }, } -) + + if audience, ok := os.LookupEnv(AzureAppConfigurationAudience); ok && audience != "" { + options.ClientOptions.Cloud = cloud.Configuration{ + Services: map[cloud.ServiceName]cloud.ServiceConfiguration{ + azappconfig.ServiceName: { + Audience: audience, + }, + }, + } + } + + return options +} func NewConfigurationClientManager(ctx context.Context, provider acpv1.AzureAppConfigurationProvider) (ClientManager, error) { manager := &ConfigurationClientManager{ @@ -118,14 +132,14 @@ func NewConfigurationClientManager(ctx context.Context, provider acpv1.AzureAppC if manager.id, err = parseConnectionString(connectionString, IdSection); err != nil { return nil, err } - if staticClient, err = azappconfig.NewClientFromConnectionString(connectionString, clientOptionWithModuleInfo); err != nil { + if staticClient, err = azappconfig.NewClientFromConnectionString(connectionString, newClientOptions()); err != nil { return nil, err } } else { if manager.credential, err = CreateTokenCredential(ctx, provider.Spec.Auth, provider.Namespace); err != nil { return nil, err } - if staticClient, err = azappconfig.NewClient(*provider.Spec.Endpoint, manager.credential, clientOptionWithModuleInfo); err != nil { + if staticClient, err = azappconfig.NewClient(*provider.Spec.Endpoint, manager.credential, newClientOptions()); err != nil { return nil, err } manager.endpoint = *provider.Spec.Endpoint @@ -286,7 +300,7 @@ func QuerySrvTargetHost(ctx context.Context, host string) ([]string, error) { func (manager *ConfigurationClientManager) newConfigurationClient(endpoint string) (*azappconfig.Client, error) { if manager.credential != nil { - return azappconfig.NewClient(endpoint, manager.credential, clientOptionWithModuleInfo) + return azappconfig.NewClient(endpoint, manager.credential, newClientOptions()) } connectionStr := buildConnectionString(endpoint, manager.secret, manager.id) @@ -294,7 +308,7 @@ func (manager *ConfigurationClientManager) newConfigurationClient(endpoint strin return nil, fmt.Errorf("failed to build connection string for fallback client") } - return azappconfig.NewClientFromConnectionString(connectionStr, clientOptionWithModuleInfo) + return azappconfig.NewClientFromConnectionString(connectionStr, newClientOptions()) } func isValidEndpoint(host string, validDomain string) bool { diff --git a/internal/loader/configuration_client_manager_test.go b/internal/loader/configuration_client_manager_test.go new file mode 100644 index 0000000..c9c0674 --- /dev/null +++ b/internal/loader/configuration_client_manager_test.go @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package loader + +import ( + "azappconfig/provider/internal/properties" + "fmt" + "os" + "testing" + + azappconfig "github.com/Azure/azure-sdk-for-go/sdk/data/azappconfig/v2" +) + +func TestNewClientOptions(t *testing.T) { + expectedAppID := fmt.Sprintf("%s/%s", properties.ModuleName, properties.ModuleVersion) + + tests := []struct { + name string + envVars map[string]string + expectedAudience string + hasCloudConfig bool + }{ + { + name: "no audience set - default behavior", + envVars: nil, + expectedAudience: "", + hasCloudConfig: false, + }, + { + name: "audience set to Azure Government", + envVars: map[string]string{ + AzureAppConfigurationAudience: "https://appconfig.azure.us", + }, + expectedAudience: "https://appconfig.azure.us", + hasCloudConfig: true, + }, + { + name: "audience set to Azure China", + envVars: map[string]string{ + AzureAppConfigurationAudience: "https://appconfig.azure.cn", + }, + expectedAudience: "https://appconfig.azure.cn", + hasCloudConfig: true, + }, + { + name: "audience set to empty string", + envVars: map[string]string{ + AzureAppConfigurationAudience: "", + }, + expectedAudience: "", + hasCloudConfig: false, + }, + { + name: "audience set to custom value", + envVars: map[string]string{ + AzureAppConfigurationAudience: "https://custom.audience.example", + }, + expectedAudience: "https://custom.audience.example", + hasCloudConfig: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Clean up the env var before each test + if err := os.Unsetenv(AzureAppConfigurationAudience); err != nil { + t.Fatalf("Failed to unset environment variable: %v", err) + } + + // Setup environment variables + if tt.envVars != nil { + for k, v := range tt.envVars { + if err := os.Setenv(k, v); err != nil { + t.Fatalf("Failed to set environment variable: %v", err) + } + defer func(key string) { + if err := os.Unsetenv(key); err != nil { + t.Errorf("Failed to unset environment variable: %v", err) + } + }(k) + } + } + + options := newClientOptions() + + // Verify telemetry ApplicationID is always set + if options.ClientOptions.Telemetry.ApplicationID != expectedAppID { + t.Errorf("Expected ApplicationID %q, got %q", expectedAppID, options.ClientOptions.Telemetry.ApplicationID) + } + + // Verify cloud configuration / audience + if tt.hasCloudConfig { + serviceConfig, exists := options.ClientOptions.Cloud.Services[azappconfig.ServiceName] + if !exists { + t.Fatal("Expected cloud service configuration to be set for azappconfig.ServiceName, but it was not found") + } + if serviceConfig.Audience != tt.expectedAudience { + t.Errorf("Expected audience %q, got %q", tt.expectedAudience, serviceConfig.Audience) + } + } else { + if len(options.ClientOptions.Cloud.Services) != 0 { + t.Errorf("Expected no cloud service configuration, but got %v", options.ClientOptions.Cloud.Services) + } + } + }) + } +} From aad025cf82c9646bd7cf5513cae0484f2ab8a9a6 Mon Sep 17 00:00:00 2001 From: "Lingling Ye (from Dev Box)" Date: Thu, 26 Mar 2026 15:19:25 +0800 Subject: [PATCH 5/6] version bump 2.6.0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 150003f..6d88898 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version":"2.5.3" + "version":"2.6.0" } \ No newline at end of file From 9afd7382d26924714d2c760f4498f72aea65bba0 Mon Sep 17 00:00:00 2001 From: Richard chen <99175581+RichardChen820@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:25:19 +0800 Subject: [PATCH 6/6] Update base image to core 2.0 (#168) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e290bf5..1ae1ec5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ ARG TARGETARCH RUN CGO_ENABLED=1 GOOS=linux GOARCH=$TARGETARCH go build -ldflags "-X azappconfig/provider/internal/properties.ModuleVersion=$MODULE_VERSION" -a -o manager cmd/main.go # Use distroless as minimal base image to package the manager binary -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/cbl-mariner/distroless/minimal:2.0-nonroot +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/cbl-mariner/base/core:2.0-nonroot WORKDIR / COPY --from=builder /workspace/manager . USER 65532:65532