From 294874ad0faa03305832efed05480727b395990e Mon Sep 17 00:00:00 2001 From: "Ian H. Pittwood" Date: Tue, 11 Aug 2026 08:18:57 -0600 Subject: [PATCH 1/2] ci: add zizmor pre-commit hook --- .github/workflows/issues.yml | 2 ++ .github/workflows/product-release.yml | 2 ++ .github/zizmor.yml | 25 +++++++++++++++++++++++++ .pre-commit-config.yaml | 4 ++++ setup-bakery/action.yml | 4 +++- setup-goss/action.yml | 13 +++++++++---- setup-hadolint/action.yml | 4 +++- 7 files changed, 48 insertions(+), 6 deletions(-) diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml index a54792ba2..5f29237f4 100644 --- a/.github/workflows/issues.yml +++ b/.github/workflows/issues.yml @@ -20,6 +20,8 @@ jobs: with: client-id: ${{ secrets.POSIT_PLATFORM_CLIENT_ID }} private-key: ${{ secrets.POSIT_PLATFORM_PEM }} + permission-issues: write + permission-organization-projects: write - name: Add to Platform Carbon Project uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2.0.0 diff --git a/.github/workflows/product-release.yml b/.github/workflows/product-release.yml index a12ab213d..7cd9aacc1 100644 --- a/.github/workflows/product-release.yml +++ b/.github/workflows/product-release.yml @@ -39,6 +39,8 @@ jobs: with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: diff --git a/.github/zizmor.yml b/.github/zizmor.yml index cac780951..a9a0fb381 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -7,3 +7,28 @@ rules: # defeat the purpose of reusable shared actions. "posit-dev/images-shared/*": ref-pin "*": hash-pin + artipacked: + ignore: + # Existing checkouts precede artifact uploads. Keep the exemptions scoped + # to these exact locations so new instances still require review. + - bakery-build-native.yml:145 + - bakery-build-native.yml:242 + - bakery-build-native.yml:427 + - bakery-build-native.yml:563 + - bakery-build-pr.yml:96 + - bakery-build-pr.yml:208 + - bakery-build.yml:131 + - bakery-build.yml:220 + - bakery-build.yml:386 + - ci.yml:69 + - ci.yml:248 + - clean.yml:95 + - clean.yml:141 + - docs.yml:17 + - hadolint.yml:39 + - product-release.yml:45 + superfluous-actions: + ignore: + # Replacing this established third-party action is outside this hook's + # scope; keep the exemption limited to the existing step. + - issues.yml:33 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 205871e7b..e9ed11fe2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,3 +49,7 @@ repos: rev: v1.7.12 hooks: - id: actionlint +- repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: v1.29.0 + hooks: + - id: zizmor diff --git a/setup-bakery/action.yml b/setup-bakery/action.yml index 8df510c8d..4b998b3d2 100644 --- a/setup-bakery/action.yml +++ b/setup-bakery/action.yml @@ -61,8 +61,10 @@ runs: - name: Install Bakery shell: bash + env: + VERSION: ${{ inputs.version }} run: | - uv tool install "git+https://github.com/posit-dev/images-shared.git@${{ inputs.version }}#subdirectory=posit-bakery&egg=posit-bakery" + uv tool install "git+https://github.com/posit-dev/images-shared.git@${VERSION}#subdirectory=posit-bakery&egg=posit-bakery" - name: Configure dependency version cache TTL shell: bash diff --git a/setup-goss/action.yml b/setup-goss/action.yml index 12d966bfa..0d2a0ee97 100644 --- a/setup-goss/action.yml +++ b/setup-goss/action.yml @@ -21,9 +21,12 @@ runs: run: mkdir -p tools - name: Install goss shell: bash + env: + ARCHITECTURE: ${{ inputs.architecture }} + VERSION: ${{ inputs.version }} run: | # Determine architecture if not provided - arch="${{ inputs.architecture }}" + arch="${ARCHITECTURE}" if [ -z "$arch" ]; then arch=$(uname -m) fi @@ -46,10 +49,10 @@ runs: # v0.4.10+ ships versioned tarballs with a consolidated SHA256SUMS file, so "latest" # must be resolved to a concrete tag up front to build the asset filename. - if [ "${{ inputs.version }}" = "latest" ]; then + if [ "${VERSION}" = "latest" ]; then tag=$(curl -fsSL "https://api.github.com/repos/goss-org/goss/releases/latest" | jq '.tag_name' -r) else - tag="${{ inputs.version }}" + tag="${VERSION}" fi version="${tag#v}" @@ -68,8 +71,10 @@ runs: chmod +rx tools/goss - name: Install dgoss shell: bash + env: + VERSION: ${{ inputs.version }} run: | - release_url="https://github.com/goss-org/goss/releases/${{ inputs.version }}/download" + release_url="https://github.com/goss-org/goss/releases/${VERSION}/download" curl -fsSL "${release_url}/dgoss" -o tools/dgoss diff --git a/setup-hadolint/action.yml b/setup-hadolint/action.yml index 3f95272ea..f2ed048c7 100644 --- a/setup-hadolint/action.yml +++ b/setup-hadolint/action.yml @@ -20,7 +20,9 @@ runs: steps: - name: Make tools directory shell: bash - run: mkdir -p "${{ inputs.base_path }}/tools" + env: + BASE_PATH: ${{ inputs.base_path }} + run: mkdir -p "${BASE_PATH}/tools" - name: Install hadolint shell: bash env: From d992faa822b843e6ca78c7dfa98df0581eef7dfc Mon Sep 17 00:00:00 2001 From: "Benjamin R. J. Schwedler" Date: Mon, 17 Aug 2026 14:58:17 -0500 Subject: [PATCH 2/2] Disable git credential persistence on checkouts Fourteen actions/checkout steps across the shared reusable workflows relied on the default persist-credentials: true, which writes the job token into the workspace .git/config. zizmor's artipacked audit flags this as a credential-exfiltration risk: if a later step uploads the workspace (including .git) as an artifact, the token leaks into a downloadable, retained location. None of these jobs run an authenticated git operation after checkout -- registry logins carry their own credentials, bakery reads the workspace read-only, and gh release / gh pr use the GH_TOKEN env var rather than git config. Setting persist-credentials: false therefore removes the token with no behavior change and resolves the finding at its source instead of suppressing it. The two checkouts that genuinely need the persisted credential -- product-release (git push and PR creation with an App token) and docs (gh-pages publish) -- keep their exemptions, now the only entries in the artipacked ignore list. Neither uploads .git as an artifact, so no leak path remains. This also drops the stale bakery-build-native.yml line-number exemptions, letting the zizmor pre-commit hook report no findings. --- .github/workflows/bakery-build-native.yml | 7 +++++++ .github/workflows/bakery-build-pr.yml | 3 +++ .github/workflows/bakery-build.yml | 5 +++++ .github/workflows/ci.yml | 2 ++ .github/workflows/clean.yml | 4 ++++ .github/workflows/hadolint.yml | 2 ++ .github/zizmor.yml | 21 +++++---------------- 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.github/workflows/bakery-build-native.yml b/.github/workflows/bakery-build-native.yml index e3129fbf8..c4b9fa9a6 100644 --- a/.github/workflows/bakery-build-native.yml +++ b/.github/workflows/bakery-build-native.yml @@ -157,6 +157,7 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 - name: Install @@ -253,6 +254,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" @@ -488,6 +491,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" @@ -624,6 +629,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Restores the shared cache like every other job but never saves it: # bakery ci readme has no --image-name filter and always resolves diff --git a/.github/workflows/bakery-build-pr.yml b/.github/workflows/bakery-build-pr.yml index 04b1ba86f..9cfe31bc2 100644 --- a/.github/workflows/bakery-build-pr.yml +++ b/.github/workflows/bakery-build-pr.yml @@ -96,6 +96,7 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 - name: Install @@ -207,6 +208,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" diff --git a/.github/workflows/bakery-build.yml b/.github/workflows/bakery-build.yml index f3bb2a060..5876af3c7 100644 --- a/.github/workflows/bakery-build.yml +++ b/.github/workflows/bakery-build.yml @@ -131,6 +131,7 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 - name: Install @@ -219,6 +220,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" @@ -385,6 +388,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Restores the shared cache like every other job but never saves it: # bakery ci readme has no --image-name filter and always resolves diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcf614177..22389d3f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,7 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 fetch-tags: true @@ -248,6 +249,7 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 fetch-tags: true diff --git a/.github/workflows/clean.yml b/.github/workflows/clean.yml index 86bd6778b..897d0a74b 100644 --- a/.github/workflows/clean.yml +++ b/.github/workflows/clean.yml @@ -94,6 +94,8 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" @@ -140,6 +142,8 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml index 87f8dd88f..2d9037661 100644 --- a/.github/workflows/hadolint.yml +++ b/.github/workflows/hadolint.yml @@ -38,6 +38,8 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup bakery uses: "posit-dev/images-shared/setup-bakery@main" diff --git a/.github/zizmor.yml b/.github/zizmor.yml index a9a0fb381..72f5413fe 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -9,23 +9,12 @@ rules: "*": hash-pin artipacked: ignore: - # Existing checkouts precede artifact uploads. Keep the exemptions scoped - # to these exact locations so new instances still require review. - - bakery-build-native.yml:145 - - bakery-build-native.yml:242 - - bakery-build-native.yml:427 - - bakery-build-native.yml:563 - - bakery-build-pr.yml:96 - - bakery-build-pr.yml:208 - - bakery-build.yml:131 - - bakery-build.yml:220 - - bakery-build.yml:386 - - ci.yml:69 - - ci.yml:248 - - clean.yml:95 - - clean.yml:141 + # Only these two checkouts persist credentials on purpose, and both need + # to: product-release pushes commits/PRs with its App token, and docs + # publishes to gh-pages. Neither job uploads .git as an artifact, so + # there is no leak path. Every other checkout sets + # persist-credentials: false inline instead of being exempted here. - docs.yml:17 - - hadolint.yml:39 - product-release.yml:45 superfluous-actions: ignore: