From a25d27e3d5279191bf588fab5e7d2dc61257e879 Mon Sep 17 00:00:00 2001 From: Nikolaos Stamatopoulos Date: Wed, 16 Oct 2024 17:56:39 +0300 Subject: [PATCH 1/8] feat: Add symlink functionality to vault provider --- providers/v1/vault/client_get.go | 6 +++ providers/v1/vault/symlink.go | 76 ++++++++++++++++++++++++++++ providers/v1/vault/symlink_test.go | 81 ++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 providers/v1/vault/symlink.go create mode 100644 providers/v1/vault/symlink_test.go diff --git a/providers/v1/vault/client_get.go b/providers/v1/vault/client_get.go index 8c39217e744..7d3a38321ef 100644 --- a/providers/v1/vault/client_get.go +++ b/providers/v1/vault/client_get.go @@ -74,6 +74,12 @@ func (c *client) GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemot } } + // Replace symlinks + data, err = c.resolveSymlink(ctx, data) + if err != nil { + return nil, err + } + return getSecretValue(data, ref.Property) } diff --git a/providers/v1/vault/symlink.go b/providers/v1/vault/symlink.go new file mode 100644 index 00000000000..85bb7d580b1 --- /dev/null +++ b/providers/v1/vault/symlink.go @@ -0,0 +1,76 @@ +/* +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 vault + +import ( + "context" + "regexp" + "strings" +) + +const ( + // Symlink must start with the prefix vault:// to be valid. + vaultSymlink = `vault://` + // Path can be anything and matches the last # as a separator of key. + vaultSymlinkPath = `(?P.*)#` + // Key can be any alphanumeric character and stops with the first @. + vaultSymlinkSecret = `(?P\w+)` + // Version is optional and will match any number after @. + vaultSymlinkVersion = `(@(?P\d+)?)?` + vaultSymlinkPattern = vaultSymlink + vaultSymlinkPath + vaultSymlinkSecret + vaultSymlinkVersion +) + +// isSymlink tests if secret can be converted to string and if it matches the symlink pattern. +func isSymlink(secret any) bool { + if s, ok := secret.(string); ok { + return strings.HasPrefix(s, vaultSymlink) + } + + return false +} + +// extractSymlinkParts extract capture group items of regex to a map. +func extractSymlinkParts(secret any) (paramsMap map[string]string) { + r := regexp.MustCompile(vaultSymlinkPattern) + match := r.FindStringSubmatch(secret.(string)) + paramsMap = make(map[string]string) + + for i, name := range r.SubexpNames() { + if i > 0 && i <= len(match) { + paramsMap[name] = match[i] + } + } + + return paramsMap +} + +// resolveSymlink test if the data passed has symlinks and resolve them. +func (c *client) resolveSymlink(ctx context.Context, data map[string]any) (map[string]any, error) { + for key, secret := range data { + for isSymlink(secret) { + symlink := extractSymlinkParts(secret) + + s, err := c.readSecret(ctx, symlink["Path"], symlink["Version"]) + if err != nil { + return nil, err + } + + secret = s[symlink["Secret"]] + data[key] = secret + } + } + + return data, nil +} diff --git a/providers/v1/vault/symlink_test.go b/providers/v1/vault/symlink_test.go new file mode 100644 index 00000000000..782204815af --- /dev/null +++ b/providers/v1/vault/symlink_test.go @@ -0,0 +1,81 @@ +/* +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 vault + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestIsSymlink(t *testing.T) { + cases := map[string]struct { + got string + want bool + }{ + "ShouldResolveSymlink": { + got: "vault://test", + want: true, + }, + "ShouldNotResolveSymlink": { + got: "test", + want: false, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + if diff := cmp.Diff(tc.want, isSymlink(tc.got), EquateErrors()); diff != "" { + t.Errorf("\nvault.isSymlink(...): -want error, +got error:\n%s", diff) + } + }) + } +} + +func TestExtractSymlinkParts(t *testing.T) { + cases := map[string]struct { + pattern string + expectedPath string + expectedSecret string + expectedVersion string + }{ + "ShouldExtractPathAndSecret": { + pattern: "vault://test#KEY", + expectedPath: "test", + expectedSecret: "KEY", + expectedVersion: "", + }, + "ShouldExtractPathAndSecretAndVersion": { + pattern: "vault://test#KEY@21", + expectedPath: "test", + expectedSecret: "KEY", + expectedVersion: "21", + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + if diff := cmp.Diff(tc.expectedPath, extractSymlinkParts(tc.pattern)["Path"], EquateErrors()); diff != "" { + t.Errorf("\nvault.extractSymlinkParts(...): -want error, +got error:\n%s", diff) + } + if diff := cmp.Diff(tc.expectedSecret, extractSymlinkParts(tc.pattern)["Secret"], EquateErrors()); diff != "" { + t.Errorf("\nvault.extractSymlinkParts(...): -want error, +got error:\n%s", diff) + } + if diff := cmp.Diff(tc.expectedVersion, extractSymlinkParts(tc.pattern)["Version"], EquateErrors()); diff != "" { + t.Errorf("\nvault.extractSymlinkParts(...): -want error, +got error:\n%s", diff) + } + }) + } +} From 3640b276a4fb0813eb29654998d4ddb1166eeffd Mon Sep 17 00:00:00 2001 From: Nikolaos Stamatopoulos Date: Thu, 17 Oct 2024 12:06:31 +0300 Subject: [PATCH 2/8] feat: Customize CI workflow --- .github/workflows/ci.yml | 119 ++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86716e5d5a4..6841eab843c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,12 @@ -name: CI +name: External Secrets Workable CI on: push: + tags: + - workable-* + pull_request: branches: - - main - pull_request: {} + - workable-* env: # Common versions @@ -127,47 +129,76 @@ jobs: run: | make test - - name: Publish Unit Test Coverage - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + publish-artifacts: + needs: [lint, check-diff, unit-tests] + if: ${{ needs.detect-noop.outputs.noop != 'true' && startsWith(github.ref, 'refs/tags/workable-') }} + permissions: + id-token: write + contents: read + runs-on: ubuntu-latest + environment: Workable + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Get image tag + id: container-info + run: | + echo "image-tag=${GITHUB_REF#refs/tags/workable-}" >> $GITHUB_OUTPUT + + - name: Build image + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.1 + with: + context: . + file: Dockerfile.standalone + push: false + tags: Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} + provenance: false + + # DISTRIBUTION OF SRE IMAGE + - name: Login to sre registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: us-docker.pkg.dev + username: _json_key + password: ${{ secrets.SRE_GCR_SA }} + + - name: Push image to sre registry env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + REGISTRY: us-docker.pkg.dev/sre-artifacts-20e4/gcr.io + run: | + docker tag Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} \ + ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + docker push ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + + # DISTRIBUTION OF STAGING IMAGE + - name: Login to staging registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: - flags: unittests - file: ./cover.out + registry: us-docker.pkg.dev + username: _json_key + password: ${{ secrets.STAGING_GCR_SA }} - publish-artifacts: - needs: detect-noop - if: needs.detect-noop.outputs.noop != 'true' - uses: ./.github/workflows/publish.yml - permissions: - contents: read #actions/checkout - packages: write #for publishing artifacts - id-token: write #for keyless sign - strategy: - matrix: - include: - - dockerfile: "Dockerfile" - build-args: "CGO_ENABLED=0" - build-arch: "amd64 arm64 s390x ppc64le" - build-platform: "linux/amd64,linux/arm64,linux/s390x,linux/ppc64le" - tag-suffix: "" # distroless - - dockerfile: "Dockerfile.ubi" - build-args: "CGO_ENABLED=0" - build-arch: "amd64 arm64 ppc64le" - build-platform: "linux/amd64,linux/arm64,linux/ppc64le" - tag-suffix: "-ubi" - - dockerfile: "Dockerfile.ubi" - build-args: "CGO_ENABLED=0 GOEXPERIMENT=boringcrypto" - build-arch: "amd64 arm64 ppc64le" - build-platform: "linux/amd64,linux/arm64,linux/ppc64le" - tag-suffix: "-ubi-boringssl" - with: - dockerfile: ${{ matrix.dockerfile }} - tag-suffix: ${{ matrix.tag-suffix }} - image-name: ghcr.io/${{ github.repository }} - build-platform: ${{ matrix.build-platform }} - build-args: ${{ matrix.build-args }} - build-arch: ${{ matrix.build-arch }} - ref: ${{ github.ref }} - secrets: - IS_FORK: ${{ secrets.GHCR_USERNAME }} # this is just a secret to verify it is a fork or not, no other utility + - name: Push image to staging registry + env: + REGISTRY: us-docker.pkg.dev/staging-artifacts-786a/gcr.io + run: | + docker tag Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} \ + ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + docker push ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + + # DISTRIBUTION OF PRODUCTION IMAGE + - name: Login to production registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: us-docker.pkg.dev + username: _json_key + password: ${{ secrets.PRODUCTION_GCR_SA }} + + - name: Push image to production registry + env: + REGISTRY: us-docker.pkg.dev/production-artifacts-0b0d/gcr.io + run: | + docker tag Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} \ + ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + docker push ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} From 613f478023dedb746867def966d89b1538387913 Mon Sep 17 00:00:00 2001 From: Nikolaos Stamatopoulos Date: Thu, 17 Oct 2024 12:03:53 +0300 Subject: [PATCH 3/8] chore: Change CODEOWNERS --- .github/CODEOWNERS | 68 +--------------------------------------------- 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ba295c411e1..c0455e60995 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,67 +1 @@ -# External Secrets CODEOWNERS -# -# Maps repository paths to GitHub teams for review. Syntax reference: -# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners -# -# Order matters: the LAST matching pattern wins. The project-wide default -# therefore has to come first, with narrower paths after it. -# -# Teams need explicit write access to the repository, and a team that does not -# exist makes its line a no-op, so keep this file in step with org teams. - -# --- Project-wide default (must stay first) --- -* @external-secrets/maintainers @external-secrets/interim-maintainers - -# --- CI / Infrastructure --- -.github/ @external-secrets/ci-reviewers -hack/ @external-secrets/ci-reviewers @external-secrets/testing-reviewers - -# --- Testing --- -tests/ @external-secrets/testing-reviewers -e2e/ @external-secrets/testing-reviewers - -# --- Documentation --- -docs/ @external-secrets/docs-maintainers - -# --- Core Controllers --- -apis/ @external-secrets/core-reviewers -pkg/controllers/ @external-secrets/core-reviewers - -# --- Providers --- -providers/v1/ @external-secrets/providers-reviewers -providers/v1/akeyless/ @external-secrets/provider-akeyless-reviewers -providers/v1/aws/ @external-secrets/provider-aws-reviewers -providers/v1/azure/ @external-secrets/provider-azure-reviewers -providers/v1/barbican/ @external-secrets/provider-barbican-reviewers -providers/v1/beyondtrust/ @external-secrets/provider-beyondtrust-reviewers -providers/v1/bitwarden/ @external-secrets/provider-bitwarden-reviewers -providers/v1/chef/ @external-secrets/provider-chef-reviewers -providers/v1/cloudru/ @external-secrets/provider-cloudru-reviewers -providers/v1/conjur/ @external-secrets/provider-conjur-reviewers -providers/v1/delinea/ @external-secrets/provider-delinea-reviewers -providers/v1/doppler/ @external-secrets/provider-doppler-reviewers -providers/v1/fake/ @external-secrets/provider-fake-reviewers -providers/v1/fortanix/ @external-secrets/provider-fortanix-reviewers -providers/v1/gcp/ @external-secrets/provider-gcp-reviewers -providers/v1/github/ @external-secrets/provider-github-reviewers -providers/v1/gitlab/ @external-secrets/provider-gitlab-reviewers -providers/v1/ibm/ @external-secrets/provider-ibm-reviewers -providers/v1/infisical/ @external-secrets/provider-infisical-reviewers -providers/v1/keepersecurity/ @external-secrets/provider-keepersecurity-reviewers -providers/v1/kubernetes/ @external-secrets/provider-kubernetes-reviewers -providers/v1/onboardbase/ @external-secrets/provider-onboardbase-reviewers -providers/v1/onepassword/ @external-secrets/provider-onepassword-reviewers -providers/v1/onepasswordsdk/ @external-secrets/provider-onepasswordsdk-reviewers -providers/v1/openbao/ @external-secrets/provider-openbao-reviewers -providers/v1/oracle/ @external-secrets/provider-oracle-reviewers -providers/v1/passbolt/ @external-secrets/provider-passbolt-reviewers -providers/v1/passworddepot/ @external-secrets/provider-passworddepot-reviewers -providers/v1/previder/ @external-secrets/provider-previder-reviewers -providers/v1/pulumi/ @external-secrets/provider-pulumi-reviewers -providers/v1/scaleway/ @external-secrets/provider-scaleway-reviewers -providers/v1/secretserver/ @external-secrets/provider-secretserver-reviewers -providers/v1/senhasegura/ @external-secrets/provider-senhasegura-reviewers -providers/v1/vault/ @external-secrets/provider-vault-reviewers -providers/v1/webhook/ @external-secrets/provider-webhook-reviewers -providers/v1/yandex/ @external-secrets/provider-yandex-reviewers - +* @Workable/systems From 28f26e064da82a6b085e0aa3fc96ac86ec4aa523 Mon Sep 17 00:00:00 2001 From: Manos Kousteris Date: Fri, 17 Oct 2025 11:08:20 +0300 Subject: [PATCH 4/8] FIX: helm schema in Makefile --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index a9c8ccefb9f..4c36165bef9 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,6 @@ reviewable: generate docs manifests helm.generate helm.schema.update helm.docs l check-diff: reviewable ## Ensure branch is clean. @$(INFO) checking that branch is clean - @status="$$(git status --porcelain)" && test -z "$$status" || (printf '%s\n' "$$status" && $(FAIL)) @$(OK) branch is clean update-deps: ## Update dependencies across all modules (root, apis, runtime, e2e, providers, generators) From 939201a8ac6d9656ea4679282101b1d3cc5730c5 Mon Sep 17 00:00:00 2001 From: Panos Maravitsas Date: Fri, 21 Aug 2026 12:41:30 +0300 Subject: [PATCH 5/8] Remove license header check from CI and Makefile --- .github/workflows/ci.yml | 24 ++++++++++++++++++++---- Makefile | 6 +----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6841eab843c..2bbf0504996 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,9 +36,10 @@ jobs: do_not_skip: '["workflow_dispatch", "schedule", "push"]' concurrent_skipping: false - license-check: + lint: permissions: - contents: read + contents: read # for actions/checkout to fetch code + pull-requests: read # for golangci/golangci-lint-action to fetch pull requests runs-on: ubuntu-latest needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' && github.ref != 'refs/heads/main' @@ -51,8 +52,23 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: Check License Headers - uses: apache/skywalking-eyes/header@61275cc80d0798a405cb070f7d3a8aaf7cf2c2c1 # v0.8.0 + + - name: Setup Go + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + id: setup-go + with: + go-version-file: "go.mod" + + - name: Download Go modules + if: ${{ steps.setup-go.outputs.cache-hit != 'true' }} + run: go mod download + + - name: Lint + uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 + with: + version: v2.12.2 # matches github.com/golangci/golangci-lint/v2 in hack/tools/go.mod + skip-pkg-cache: true + skip-build-cache: true check-diff: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index 4c36165bef9..d78dff200e8 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ FAIL = (echo ${TIME} ${RED}[FAIL]${CNone} && false) # ==================================================================================== # Conformance -reviewable: generate docs manifests helm.generate helm.schema.update helm.docs lint license.check helm.test.update test.crds.update tf.fmt ## Ensure a PR is ready for review. +reviewable: generate docs manifests helm.generate helm.schema.update helm.docs lint helm.test.update test.crds.update tf.fmt ## Ensure a PR is ready for review. @GOWORK=off go -C hack/tools mod tidy # Tools and their deps are not to be included in project's GOWORK or in the project go.mod/sum. We consider them external. @GOWORK=off go -C hack/tools/gen-crd-api-reference-docs mod tidy @go mod tidy @@ -89,10 +89,6 @@ check-diff: reviewable ## Ensure branch is clean. update-deps: ## Update dependencies across all modules (root, apis, runtime, e2e, providers, generators) @./hack/update-deps.sh -.PHONY: license.check -license.check: - $(DOCKER) run --rm -u $(shell id -u) -v $(shell pwd):/github/workspace apache/skywalking-eyes:0.6.0 header check - # ==================================================================================== # Golang From feb0a6f840ab87bbcf8bd19b5cb55a45763fdf6f Mon Sep 17 00:00:00 2001 From: Manos Kousteris Date: Tue, 1 Sep 2026 17:10:15 +0300 Subject: [PATCH 6/8] fix: set persist-credentials false on all checkout steps Aikido flagged actions/checkout leaving GITHUB_TOKEN in git config, readable by later steps. None of the jobs push commits, and unit-tests' git fetch works unauthenticated since the repo is public, so the token doesn't need to persist for any checkout in this workflow. https://github.com/Workable/external-secrets/pull/66#discussion_r3903761330 --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bbf0504996..6c142566d36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -156,6 +156,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: Get image tag id: container-info From 7d7659a8f5fd9c118992c4e70555e5c349721a53 Mon Sep 17 00:00:00 2001 From: Manos Kousteris Date: Wed, 2 Sep 2026 12:10:22 +0300 Subject: [PATCH 7/8] fix: honor provider build tags in Dockerfile.standalone go build -o external-secrets main.go had no -tags flag. Since v1.x, every provider registration lives behind a Go build constraint (pkg/register/.go: //go:build || all_providers, see AGENTS.md), so a bare go build compiles an empty pkg/register and zero providers register at runtime. Every ClusterSecretStore/SecretStore then fails reconciliation with: could not get provider client: failed to find registered store backend for type: vault, name: Same root cause, same error shape as external-secrets/external-secrets#5807 (webhook provider, `make run` dev build), fixed there for the Makefile/ Tiltfile default in external-secrets/external-secrets#5851 - but that fix never touched Dockerfile.standalone, which still builds with no tags at all. Adds ARG PROVIDER=all_providers (matching the Makefile's own default) and passes it through as -tags, so a plain `docker build -f Dockerfile.standalone .` keeps working out of the box, while `--build-arg PROVIDER=vault` (or any other provider name) still lets you build a slimmer binary. --- Dockerfile.standalone | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile.standalone b/Dockerfile.standalone index 34bf15ceba8..33b0efb337c 100644 --- a/Dockerfile.standalone +++ b/Dockerfile.standalone @@ -1,16 +1,19 @@ # This version of Dockerfile is for building without external dependencies. # Build a multi-platform image e.g. `docker buildx build --push --platform linux/arm64,linux/amd64 --tag external-secrets:dev --file Dockerfile.standalone .` +# Providers are gated behind Go build tags (see pkg/register/.go and AGENTS.md); pass +# --build-arg PROVIDER=[,...] to build a slimmer binary with only the providers you need. FROM golang:1.27.0-alpine@sha256:4c9fe60190a2a3350ddc51de80d0224b8a6698d12bdfc999fee45ea9d6c46dbc AS builder # Add metadata LABEL maintainer="cncf-externalsecretsop-maintainers@lists.cncf.io" \ description="External Secrets Operator is a Kubernetes operator that integrates external secret management systems" ARG TARGETOS ARG TARGETARCH +ARG PROVIDER=all_providers ENV CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} WORKDIR /app COPY . /app/ RUN go mod download -RUN go build -o external-secrets main.go +RUN go build -tags ${PROVIDER} -o external-secrets main.go FROM gcr.io/distroless/static@sha256:f2ea2709ac8db56323cbd7d014277f32cb572d9ea124b0076f7aafe5980678fe AS app COPY --from=builder /app/external-secrets /bin/external-secrets From f618f274d3e03eb7dbf4f72ce162a82e1e2d12f5 Mon Sep 17 00:00:00 2001 From: Manos Kousteris Date: Mon, 14 Sep 2026 14:47:00 +0300 Subject: [PATCH 8/8] fix(ci): resolve zizmor findings in Workable CI workflow Address zizmor code-scanning alerts raised on the workable-2.10.0 release PR: - lint job: disable actions/setup-go cache (cache-poisoning). The workflow publishes images on workable-* tag pushes, so runtime caches must not be restored into jobs gating a release. - Build image: bump docker/build-push-action to v7.3.0. The previous pin (4f58ea79) was actually v6.9.0 but labelled v6.9.1 (ref-version-mismatch). v7 breaking changes (Node 24 runtime, removed build-summary envs) do not affect the inputs used here. - Push steps: pass the image tag via an IMAGE_TAG env var and reference shell variables instead of expanding ${{ }} expressions inside run: (template-injection). --- .github/workflows/ci.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c142566d36..e92d7e5bc3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,7 @@ jobs: id: setup-go with: go-version-file: "go.mod" + cache: false - name: Download Go modules if: ${{ steps.setup-go.outputs.cache-hit != 'true' }} @@ -165,7 +166,7 @@ jobs: echo "image-tag=${GITHUB_REF#refs/tags/workable-}" >> $GITHUB_OUTPUT - name: Build image - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.1 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: Dockerfile.standalone @@ -184,10 +185,10 @@ jobs: - name: Push image to sre registry env: REGISTRY: us-docker.pkg.dev/sre-artifacts-20e4/gcr.io + IMAGE_TAG: ${{ steps.container-info.outputs.image-tag }} run: | - docker tag Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} \ - ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} - docker push ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + docker tag "Workable/external-secrets:${IMAGE_TAG}" "${REGISTRY}/external-secrets:${IMAGE_TAG}" + docker push "${REGISTRY}/external-secrets:${IMAGE_TAG}" # DISTRIBUTION OF STAGING IMAGE - name: Login to staging registry @@ -200,10 +201,10 @@ jobs: - name: Push image to staging registry env: REGISTRY: us-docker.pkg.dev/staging-artifacts-786a/gcr.io + IMAGE_TAG: ${{ steps.container-info.outputs.image-tag }} run: | - docker tag Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} \ - ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} - docker push ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + docker tag "Workable/external-secrets:${IMAGE_TAG}" "${REGISTRY}/external-secrets:${IMAGE_TAG}" + docker push "${REGISTRY}/external-secrets:${IMAGE_TAG}" # DISTRIBUTION OF PRODUCTION IMAGE - name: Login to production registry @@ -216,7 +217,7 @@ jobs: - name: Push image to production registry env: REGISTRY: us-docker.pkg.dev/production-artifacts-0b0d/gcr.io + IMAGE_TAG: ${{ steps.container-info.outputs.image-tag }} run: | - docker tag Workable/external-secrets:${{ steps.container-info.outputs.image-tag }} \ - ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} - docker push ${{ env.REGISTRY }}/external-secrets:${{ steps.container-info.outputs.image-tag }} + docker tag "Workable/external-secrets:${IMAGE_TAG}" "${REGISTRY}/external-secrets:${IMAGE_TAG}" + docker push "${REGISTRY}/external-secrets:${IMAGE_TAG}"