chore: harden release workflow for supply-chain security#1178
chore: harden release workflow for supply-chain security#1178thetutlage wants to merge 5 commits into
Conversation
- Use npm Trusted Publishing (OIDC) instead of NPM_TOKEN - Pin third-party actions and reusable workflows to commit SHAs - Drop default permissions to read-only, elevate per-job - Add --ignore-scripts to release-time install - Add npm audit signatures step - Add Dependabot for github-actions ecosystem - Add concurrency guard Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses CodeQL "Workflow does not contain permissions" finding by declaring contents: read at workflow scope so GITHUB_TOKEN is scoped down on push/pull_request/workflow_call runs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Requires approval from the Core Team before npm publish runs, via the GitHub Environment created in each repo. Pair with an npm Trusted Publisher config that pins the environment to fully close the gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The hardened release workflow uses npm install --ignore-scripts and npm audit signatures, both of which require a lockfile to be effective: - npm audit signatures verifies registry signatures of the exact resolved versions in the lockfile; without one, transitive resolution at release time would re-resolve from the registry and silently accept any new version of a dep, which is the supply-chain hole we are trying to close. - --ignore-scripts is meaningful only when paired with reproducible resolution, otherwise an attacker who controls a future version of a transitive dep can still influence build output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds Dependabot for GitHub Actions, pins checkout/setup-node to exact commit SHAs in checks and release workflows, tightens workflow and job permissions with a release concurrency lock, and changes release install/audit steps to use npm audit signatures and only GITHUB_TOKEN. ChangesGitHub Actions Security and Reproducibility Improvements
🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
.github/workflows/checks.yml (1)
14-14: 💤 Low valueConsider adding
persist-credentials: falsefor additional defense-in-depth.While the workflow-level
contents: readpermission already limits what can be done with the token, explicitly settingpersist-credentials: falseon eachactions/checkoutstep prevents the GITHUB_TOKEN from being persisted to disk in the.git/configfile, providing an additional layer of protection against potential credential exfiltration through artifacts or logs.🔒 Optional hardening for checkout steps
Apply this pattern to all six checkout actions in the workflow:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: falseAlso applies to: 24-24, 48-48, 78-78, 95-95, 119-119
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/checks.yml at line 14, The checkout steps use actions/checkout (e.g., the step with "uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5") but do not explicitly disable credential persistence; update each actions/checkout step (all six occurrences referenced in the review) to include the input persist-credentials: false so the GITHUB_TOKEN is not written to .git/config and cannot be persisted to artifacts/logs..github/workflows/release.yml (1)
25-27: 💤 Low valueConsider adding
persist-credentials: falsefor release workflow.Similar to the checks workflow, explicitly setting
persist-credentials: falseprovides additional defense-in-depth by preventing the GITHUB_TOKEN from being persisted to disk, even though the job already has explicitcontents: writepermissions scoped appropriately.🔒 Optional hardening for checkout step
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 + persist-credentials: falseNote: If the release process requires pushing commits or tags using the checkout action's persisted credentials, then
persist-credentials: falsemay need to remain unset or be set totrue. Verify whether the git operations in the "git config" and "npm run release" steps rely on the persisted token or useGITHUB_TOKENdirectly.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yml around lines 25 - 27, Update the actions/checkout step in the release workflow to explicitly set persist-credentials: false (add the persist-credentials: false key under the existing with: block for the checkout action) to avoid persisting GITHUB_TOKEN to the checked-out repo; confirm whether any downstream steps (e.g., the git config or the npm run release commands) rely on persisted checkout credentials and, if they do, either leave persist-credentials unset or change those steps to use GITHUB_TOKEN directly before enforcing the false setting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/checks.yml:
- Line 14: The checkout steps use actions/checkout (e.g., the step with "uses:
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5") but do not
explicitly disable credential persistence; update each actions/checkout step
(all six occurrences referenced in the review) to include the input
persist-credentials: false so the GITHUB_TOKEN is not written to .git/config and
cannot be persisted to artifacts/logs.
In @.github/workflows/release.yml:
- Around line 25-27: Update the actions/checkout step in the release workflow to
explicitly set persist-credentials: false (add the persist-credentials: false
key under the existing with: block for the checkout action) to avoid persisting
GITHUB_TOKEN to the checked-out repo; confirm whether any downstream steps
(e.g., the git config or the npm run release commands) rely on persisted
checkout credentials and, if they do, either leave persist-credentials unset or
change those steps to use GITHUB_TOKEN directly before enforcing the false
setting.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 48c94e09-1e4d-4b08-978c-7d092e0312f5
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
.github/dependabot.yml.github/workflows/checks.yml.github/workflows/release.yml
Re-adds 'secrets: inherit' to the checks job in release.yml so the reusable checks workflow continues to receive repository secrets when invoked by workflow_call from release. Without this, integration tests in checks that depend on secrets (e.g. RESEND_API_KEY in mail) fail during release runs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
NPM_TOKENfrom the workflow, so transitivepostinstallscripts can no longer exfiltrate it from~/.npmrc.actions/checkout,actions/setup-node, and theadonisjs/.github/adonisjs/corereusable workflows to commit SHAs to defend against tag/branch reflog tampering.permissions:tocontents: read, elevates per-job (contents: write+id-token: writeonly on the release job).npm install --ignore-scriptsso transitive postinstall scripts cannot run during the release job.npm audit signaturesstep before publishing to verify registry signatures.github-actionsecosystem so the pinned SHAs are kept current automatically.concurrencyblock to prevent overlapping release runs.Prerequisites
release.yml, environment: none). Confirmed configured before this PR.NPM_TOKENcan be deleted after the first successful tokenless release.Test plan
releaseworkflow manually with a patch bump.NPM_TOKENbeing available.npm install --ignore-scriptsbreaks the build for this repo (e.g. a transitive dep relies onpostinstallto fetch a native binary), drop the flag in a follow-up.🤖 Generated with Claude Code
Summary by CodeRabbit