mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-08 03:08:13 +00:00
feat(ci): adopt npm Trusted Publishing, GitHub App tokens, explicit secrets
Three best-practice upgrades surfaced by the release-pipeline audit.
npm Trusted Publishing (GA 2025-07-31)
- Drop `env: NODE_AUTH_TOKEN` (empty string would break OIDC fallback;
the var must be unset, not blanked).
- Drop the explicit `--provenance` flag (registry auto-attaches it on
trusted-publisher publishes).
- `id-token: write` permission retained for the OIDC exchange.
- Prerequisite: register the package as a trusted publisher on
npmjs.com bound to this repo + publish.yml. Once configured, the
NPM_TOKEN repo secret can be deleted entirely.
GitHub App token replaces RELEASE_PUSH_TOKEN PAT
- New `actions/create-github-app-token@v3.2.0` step mints a short-lived
(~1h) installation token before the RC checkout.
- Token is consumed by `actions/checkout` (with `persist-credentials:
false`) and by the inline `http.extraheader` at git-push time.
- Same fine-grained permission surface (Contents: write + Workflows:
write), not tied to a user seat, organizationally auditable.
- Prerequisite: create the GitHub App, install on this repo with the
required permissions, and set `vars.RELEASE_APP_ID` (numeric ID,
not sensitive) + `secrets.RELEASE_APP_PRIVATE_KEY` (PEM).
Drop `secrets: inherit` from the ci.yml call
- Verified by grep: ci.yml and its entire reusable-workflow chain
(ci-quality, ci-tests, ci-e2e, ci-scope-parity, ci-report) reference
zero `secrets.*` values. The inherit was passing through nothing.
- GITHUB_TOKEN is implicit and remains available.
Refs the audit at PR #1610.
This commit is contained in:
parent
919acab7fb
commit
34f6f0a941
1 changed files with 56 additions and 19 deletions
75
.github/workflows/publish.yml
vendored
75
.github/workflows/publish.yml
vendored
|
|
@ -275,9 +275,10 @@ jobs:
|
|||
fi
|
||||
|
||||
# ── Phase 3: reusable CI gate ──────────────────────────────────────────────
|
||||
# Runs for both rc (when guard says go) and stable. KTD-9: secrets: inherit
|
||||
# matches release-candidate.yml's prior contract; ci.yml consumes secrets
|
||||
# the current stable publish path was accidentally hiding.
|
||||
# Runs for both rc (when guard says go) and stable. No `secrets:` passed —
|
||||
# ci.yml and its entire reusable-workflow chain (ci-quality, ci-tests,
|
||||
# ci-e2e, ci-scope-parity, ci-report) reference zero `secrets.*` values;
|
||||
# passing any would be unused surface. GITHUB_TOKEN is implicit.
|
||||
ci:
|
||||
needs: [route, rc-guard]
|
||||
if: ${{ always() && (needs.route.outputs.mode == 'stable' || needs.rc-guard.outputs.should_run == 'true') }}
|
||||
|
|
@ -285,7 +286,6 @@ jobs:
|
|||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
secrets: inherit
|
||||
|
||||
# ── Phase 4: publish to npm + push refs (RC path) ──────────────────────────
|
||||
publish:
|
||||
|
|
@ -305,25 +305,46 @@ jobs:
|
|||
# Two distinct step IDs feed this output; exactly one fires per run.
|
||||
vtag: ${{ steps.rc-tags.outputs.vtag || steps.stable-vtag.outputs.vtag }}
|
||||
steps:
|
||||
# ── Mint short-lived GitHub App token (RC only) ──────────────────────
|
||||
# Industry direction (2025-2026): GitHub Apps with
|
||||
# `actions/create-github-app-token` over long-lived PATs for
|
||||
# workflow-touching tag pushes. Same fine-grained permission surface
|
||||
# (Contents: write + Workflows: write), ~1h expiry, not tied to a
|
||||
# user seat, organizationally auditable. Replaces the prior
|
||||
# RELEASE_PUSH_TOKEN PAT (S34132).
|
||||
#
|
||||
# Required secrets/vars (set in repo Settings → Secrets and variables → Actions):
|
||||
# vars.RELEASE_APP_ID — the App's numeric ID (not sensitive)
|
||||
# secrets.RELEASE_APP_PRIVATE_KEY — the App's PEM private key
|
||||
# The App must be installed on this repository with Contents: write
|
||||
# and Workflows: write permissions.
|
||||
- name: Mint GitHub App token (RC)
|
||||
if: needs.route.outputs.mode == 'rc'
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
app-id: ${{ vars.RELEASE_APP_ID }}
|
||||
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
||||
|
||||
# ── Separate checkout steps per mode (KTD-4) ─────────────────────────
|
||||
# Conditional `token:` expressions are footguns: empty string passed to
|
||||
# actions/checkout fails opaquely, and `|| github.token` silently
|
||||
# degrades a missing PAT to GITHUB_TOKEN, masking auth failures until
|
||||
# degrades a missing token to GITHUB_TOKEN, masking auth failures until
|
||||
# the eventual `git push`. Two distinct steps make the auth contract
|
||||
# explicit and fail loudly at checkout when RELEASE_PUSH_TOKEN is
|
||||
# missing on the RC path.
|
||||
# explicit and fail loudly at checkout when the App token mint failed
|
||||
# on the RC path.
|
||||
- name: Checkout (RC)
|
||||
if: needs.route.outputs.mode == 'rc'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
# Fine-grained PAT (Contents: write + Workflows: write) — required
|
||||
# because the v-tag push lands at a SHA whose tree may touch
|
||||
# Short-lived GitHub App installation token. Required because the
|
||||
# v-tag push lands at a SHA whose tree may touch
|
||||
# `.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
|
||||
# author.
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
# Do not persist the token 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.
|
||||
|
|
@ -562,11 +583,12 @@ 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 }}
|
||||
# Short-lived GitHub App token. 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: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VTAG="v${RC_VERSION}"
|
||||
|
|
@ -666,14 +688,29 @@ jobs:
|
|||
echo "vtag verified: ${VTAG} (mode=${MODE})"
|
||||
echo "vtag=${VTAG}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# npm Trusted Publishing (GA'd 2025-07-31). With the package registered
|
||||
# as a trusted publisher on npmjs.com bound to this repo + this
|
||||
# workflow file, npm authenticates via OIDC at publish time —
|
||||
# NODE_AUTH_TOKEN is intentionally NOT set (an empty string would
|
||||
# short-circuit the OIDC fallback; the env var must be unset, not
|
||||
# blanked). Provenance is auto-attached by the registry on
|
||||
# trusted-publisher publishes, so the explicit --provenance flag is
|
||||
# dropped.
|
||||
#
|
||||
# Prerequisite: configure the package as a trusted publisher at
|
||||
# https://www.npmjs.com/package/gitnexus/access (Publishing access →
|
||||
# Trusted Publishers → GitHub Actions) bound to:
|
||||
# Owner: <repo owner>
|
||||
# Repository: GitNexus
|
||||
# Workflow: publish.yml
|
||||
# Environment: (none)
|
||||
- name: Publish to npm
|
||||
if: inputs.dry_run != 'true'
|
||||
shell: bash
|
||||
working-directory: gitnexus
|
||||
env:
|
||||
NPM_TAG: ${{ needs.route.outputs.mode == 'rc' && 'rc' || 'latest' }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: npm publish --provenance --access public --tag "$NPM_TAG"
|
||||
run: npm publish --access public --tag "$NPM_TAG"
|
||||
|
||||
# ── Stable-only: pull CHANGELOG body if present ──────────────────────
|
||||
- name: Extract release notes from CHANGELOG (stable)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue