mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-08 03:08:13 +00:00
fix(ci): address zizmor findings on unified publish.yml
Five zizmor alerts on PR #1610; four fixed in code, one resolved structurally by tightening the reusable-workflow contract. artipacked (3 instances) — actions/checkout was persisting credentials in .git/config by default on three checkout steps. The rc-guard and stable-mode checkouts now set `persist-credentials: false` (no pushes happen from those paths). The RC checkout also sets `persist-credentials: false`; the subsequent atomic tag push now supplies auth inline via `http.extraheader` (mirroring the pattern already in pr-autofix-apply.yml). The base64-encoded header is masked alongside the raw token. template-injection — the stable-mode "Set vtag" step interpolated `${{ github.ref_name }}` directly into the shell source. Routed through `env: REF_NAME` instead, eliminating the template-expansion path even though git ref names are constrained by naming rules. secrets-inherit — replaced `secrets: inherit` on the docker.yml call with an explicit secrets passthrough. docker.yml's workflow_call block now declares the two secrets it actually consumes (DOCKERHUB_USERNAME, DOCKERHUB_TOKEN); GITHUB_TOKEN remains implicit. The callee's secret surface is now auditable from the caller without enumeration drift.
This commit is contained in:
parent
36414e0dbc
commit
919acab7fb
2 changed files with 49 additions and 8 deletions
9
.github/workflows/docker.yml
vendored
9
.github/workflows/docker.yml
vendored
|
|
@ -25,6 +25,15 @@ on:
|
|||
a gitnexus/package.json whose version matches the tag.
|
||||
required: true
|
||||
type: string
|
||||
# Explicit secret contract — callers pass these by name. Replaces the
|
||||
# blanket `secrets: inherit` pattern (zizmor `secrets-inherit` audit).
|
||||
# GHCR auth uses the implicit GITHUB_TOKEN; only Docker Hub credentials
|
||||
# need to be passed through.
|
||||
secrets:
|
||||
DOCKERHUB_USERNAME:
|
||||
required: true
|
||||
DOCKERHUB_TOKEN:
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
|
|||
48
.github/workflows/publish.yml
vendored
48
.github/workflows/publish.yml
vendored
|
|
@ -193,6 +193,9 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
# rc-guard reads only — no git pushes from this job. Skip the
|
||||
# default extraheader credential persistence (artipacked audit).
|
||||
persist-credentials: false
|
||||
|
||||
- name: Decide
|
||||
id: decide
|
||||
|
|
@ -320,12 +323,21 @@ jobs:
|
|||
# `.github/workflows/**`, which the default GITHUB_TOKEN cannot
|
||||
# author. See S34132 for the migration history.
|
||||
token: ${{ secrets.RELEASE_PUSH_TOKEN }}
|
||||
# Do not persist the PAT in .git/config (artipacked audit). The
|
||||
# RC tag push uses an inline `http.extraheader` at push time only;
|
||||
# the credential never lands on disk. See the
|
||||
# `Create and push rc tags` step below.
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout (stable)
|
||||
if: needs.route.outputs.mode == 'stable'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
# No `token:` — actions/checkout uses GITHUB_TOKEN by default. Stable
|
||||
# path performs no git pushes; the default scope is sufficient.
|
||||
with:
|
||||
# No git pushes from the stable path either. Skip credential
|
||||
# persistence (artipacked audit).
|
||||
persist-credentials: false
|
||||
|
||||
- name: Working-tree sanity
|
||||
# Defense in depth (mirrors KTD-5 vtag gate, but on the input side):
|
||||
|
|
@ -550,6 +562,11 @@ jobs:
|
|||
env:
|
||||
RC_VERSION: ${{ steps.rc-version.outputs.rc_version }}
|
||||
HEAD_SHA: ${{ needs.rc-guard.outputs.head_sha }}
|
||||
# Auth is supplied inline at push time via `http.extraheader` (per
|
||||
# GitHub's documented x-access-token Basic pattern). It is NOT
|
||||
# persisted in .git/config (artipacked audit) — checkout above
|
||||
# ran with `persist-credentials: false`.
|
||||
PUSH_TOKEN: ${{ secrets.RELEASE_PUSH_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VTAG="v${RC_VERSION}"
|
||||
|
|
@ -568,9 +585,18 @@ jobs:
|
|||
git tag -a "$VTAG" "$RELEASE_SHA" -m "$VTAG"
|
||||
git tag "$MARKER" "$HEAD_SHA"
|
||||
|
||||
# Inline auth header. The base64-encoded form is masked as well
|
||||
# as the raw token, because GitHub's secret-masker only masks the
|
||||
# raw value — any subsequent `set -x` / GIT_TRACE line would
|
||||
# otherwise expose the encoded credential. Pattern mirrors
|
||||
# pr-autofix-apply.yml.
|
||||
auth_header="Authorization: Basic $(printf 'x-access-token:%s' "${PUSH_TOKEN}" | base64 -w0)"
|
||||
echo "::add-mask::${auth_header}"
|
||||
|
||||
# Atomic push of both refs. If either would clobber an existing
|
||||
# remote ref, the push fails and we stop before npm publish.
|
||||
git push --atomic origin "refs/tags/$VTAG" "refs/tags/$MARKER"
|
||||
git -c http.extraheader="${auth_header}" \
|
||||
push --atomic origin "refs/tags/$VTAG" "refs/tags/$MARKER"
|
||||
|
||||
{
|
||||
echo "vtag=$VTAG"
|
||||
|
|
@ -582,8 +608,14 @@ jobs:
|
|||
id: stable-vtag
|
||||
if: needs.route.outputs.mode == 'stable'
|
||||
shell: bash
|
||||
# github.ref_name flows in via env to avoid templating into the
|
||||
# shell source (template-injection audit). Even though refs are
|
||||
# constrained by git naming rules, the env-passthrough pattern
|
||||
# makes injection structurally impossible.
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
echo "vtag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
|
||||
echo "vtag=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# ── KTD-5: vtag integrity gate ───────────────────────────────────────
|
||||
# Fail closed before any artifact-producing step (npm publish, Release,
|
||||
|
|
@ -690,17 +722,17 @@ jobs:
|
|||
) || '' }}
|
||||
|
||||
# ── Phase 5 (RC only): Docker images ───────────────────────────────────────
|
||||
# R6: Docker remains RC-only. Stable Docker builds are explicitly deferred
|
||||
# (see plan Scope Boundaries → Deferred to Follow-Up Work). KTD-8: the
|
||||
# `secrets: inherit` to docker.yml is retained with an explicit security
|
||||
# note in the plan rather than enumerated, because docker.yml's secret
|
||||
# surface is owned and reviewed alongside this caller.
|
||||
# R6: Docker remains RC-only. Stable Docker builds are explicitly deferred.
|
||||
# Secrets are passed explicitly (not via `secrets: inherit`) so the
|
||||
# callee's secret surface is auditable from the caller's source.
|
||||
docker:
|
||||
name: Build & Push RC Docker images
|
||||
needs: [route, publish]
|
||||
if: ${{ needs.route.outputs.mode == 'rc' && needs.publish.outputs.vtag != '' && inputs.dry_run != 'true' }}
|
||||
uses: ./.github/workflows/docker.yml
|
||||
secrets: inherit
|
||||
secrets:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue