Skip to content

feat(ci): add and test supply-chain hardening in release workflows#452

Merged
auxesis merged 2 commits into
mainfrom
ci/ensure-no-caching-on-release-workflows
May 16, 2026
Merged

feat(ci): add and test supply-chain hardening in release workflows#452
auxesis merged 2 commits into
mainfrom
ci/ensure-no-caching-on-release-workflows

Conversation

@auxesis
Copy link
Copy Markdown
Contributor

@auxesis auxesis commented May 16, 2026

GitHub Actions cache poisoning is a known attack1 against credential-bearing workflows. The mechanism is:

  • a lower-privileged run plants a malicious entry under a deterministic cache key
  • a privileged workflow restores a cache from that cache key and executes it
  • secrets are exfiltrated

The release.yml workflow publishes packages to npm using OIDC trusted publishing and an NPM_TOKEN. Before this change, release.yml was vulnerable to this class of attack.

Mitigate this by explicitly disabling all build caching in release.yml:

  • pnpm/action-setup sets cache: false
  • actions/setup-node sets package-manager-cache: false
  • actions/setup-node does not set cache:
  • no actions/cache step is used

Also add a check to the repo (tests-supply-chain.yml) to test that high-risk workflows (release.yml) are not using caching, and it is not added back in.

Summary by CodeRabbit

  • Documentation

    • Added CI/CD supply-chain hardening guidance to security policy, detailing cache poisoning mitigation.
  • Chores

    • Disabled GitHub Actions caching in release and supply-chain verification workflows.
    • Added automated security validation to enforce cache hardening practices.

Review Change Stack

Footnotes

  1. The Monsters in Your Build Cache - GitHub Actions Cache Poisoning

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 16, 2026

⚠️ No Changeset found

Latest commit: 5da89fe

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Warning

Rate limit exceeded

@auxesis has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 24 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a427f3de-daa5-4f70-b8df-95e1e0a00cad

📥 Commits

Reviewing files that changed from the base of the PR and between f2b3d7b and 5da89fe.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • .github/workflows/release.yml
  • .github/workflows/tests-supply-chain.yml
  • SECURITY.md
  • package.json
  • scripts/__tests__/fixtures/lint-no-workflow-caching/actions-cache-restore.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/actions-cache-save.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/actions-cache.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/clean.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/missing-explicit-false.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/no-actions-cache.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/setup-node-cache.yml
  • scripts/__tests__/lint-no-workflow-caching.test.mjs
  • scripts/lint-no-workflow-caching.mjs
📝 Walkthrough

Walkthrough

This PR implements GitHub Actions cache poisoning prevention by adding a lint script that enforces cache disabling in release workflows, creating comprehensive test fixtures to validate the enforcement, updating the release workflow with explicit cache-disabling configuration, and adding a new supply-chain verification workflow that runs the enforcement checks.

Changes

Supply-Chain Cache Poisoning Prevention

Layer / File(s) Summary
Supply-chain security documentation
SECURITY.md
New CI/CD Supply-Chain Hardening section documents the cache poisoning threat model and specifies required configuration to disable caching in release.yml and tests-supply-chain.yml.
Enforcement script and dependency setup
package.json, scripts/lint-no-workflow-caching.mjs
Core lint script reads workflow YAMLs and detects disallowed caching patterns: with.cache truthy, actions/cache usage, and setup actions without explicit false cache flags. npm script lint:workflow-cache and js-yaml dependency added.
Test fixtures and validation suite
scripts/__tests__/fixtures/lint-no-workflow-caching/*.yml, scripts/__tests__/lint-no-workflow-caching.test.mjs
Seven fixture workflows (clean, no-actions-cache passing; actions-cache, actions-cache-restore, actions-cache-save, setup-node-cache, missing-explicit-false failing). Test suite validates linter behavior and ensures release.yml and tests-supply-chain.yml remain cache-free.
Release and supply-chain workflows
.github/workflows/release.yml, .github/workflows/tests-supply-chain.yml
release.yml disables pnpm and package-manager caching with supply-chain hardening comments. New tests-supply-chain.yml verifies hardening by running linter and test scripts on workflows with caching explicitly disabled.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • calvinbrewer
  • freshtonic
  • yujiyokoo

Poem

🐰 Cache poisoning fades into the past,
With locks and flags, the release workflows hold fast,
Lint scripts verify no shortcuts hide,
Seven test fixtures stand side by side,
Supply-chain security—our rabbit's delight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding supply-chain hardening to release workflows with corresponding tests, which matches the core objectives of disabling caching and adding verification.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/ensure-no-caching-on-release-workflows

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@auxesis auxesis force-pushed the ci/ensure-no-caching-on-release-workflows branch 3 times, most recently from d0d8d08 to f2b3d7b Compare May 16, 2026 05:21
@auxesis auxesis changed the title Ci/ensure no caching on release workflows feat(ci): add and test supply-chain hardening in release workflows May 16, 2026
@auxesis auxesis marked this pull request as ready for review May 16, 2026 05:23
@auxesis auxesis requested a review from a team as a code owner May 16, 2026 05:23
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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.

Inline comments:
In @.github/workflows/tests-supply-chain.yml:
- Around line 50-51: The workflow currently checks out PR code using the
actions/checkout step (uses: actions/checkout@v6) before executing the mutable
gate pnpm run lint:workflow-cache, which allows a PR to modify the policy;
change the gate to run from an immutable source instead—either run the policy
check in a pull_request_target trigger or invoke a pinned reusable
workflow/action that cannot be altered by the PR (instead of using the repo
checkout + pnpm run lint:workflow-cache in the PR context); update the steps
referencing actions/checkout@v6 and the pnpm run lint:workflow-cache invocation
(also at the repeated block around lines 79-80) to call the immutable policy
executor so PR changes cannot weaken the check.

In `@SECURITY.md`:
- Around line 149-151: Update the confusing guidance in SECURITY.md so the
policy is explicit: state that `pnpm/action-setup` must be invoked with `cache:
false` and `actions/setup-node` must use `package-manager-cache: false`, and
reword the later sentence to forbid any `actions/cache` steps or any
cache-enabling values (e.g., `cache: true` or omitting the
`cache:`/`package-manager-cache:` inputs), while allowing the explicit `false`
flags required by those actions (`cache: false` and `package-manager-cache:
false`).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b202d52-da73-4f92-8950-8935f9d6f4ed

📥 Commits

Reviewing files that changed from the base of the PR and between c1c863e and f2b3d7b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • .github/workflows/release.yml
  • .github/workflows/tests-supply-chain.yml
  • SECURITY.md
  • package.json
  • scripts/__tests__/fixtures/lint-no-workflow-caching/actions-cache-restore.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/actions-cache-save.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/actions-cache.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/clean.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/missing-explicit-false.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/no-actions-cache.yml
  • scripts/__tests__/fixtures/lint-no-workflow-caching/setup-node-cache.yml
  • scripts/__tests__/lint-no-workflow-caching.test.mjs
  • scripts/lint-no-workflow-caching.mjs

Comment on lines +50 to +51
- name: Checkout Repo
uses: actions/checkout@v6
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Policy enforcement is mutable by the PR under test.

On pull_request, this workflow checks out PR code and then runs pnpm run lint:workflow-cache, so the same PR can weaken the lint script/tests and still pass while reintroducing cache usage. Move this gate to an immutable source (for example: base-branch pull_request_target policy execution, or a pinned reusable workflow/action that is not editable in the same PR).

Also applies to: 79-80

🤖 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/tests-supply-chain.yml around lines 50 - 51, The workflow
currently checks out PR code using the actions/checkout step (uses:
actions/checkout@v6) before executing the mutable gate pnpm run
lint:workflow-cache, which allows a PR to modify the policy; change the gate to
run from an immutable source instead—either run the policy check in a
pull_request_target trigger or invoke a pinned reusable workflow/action that
cannot be altered by the PR (instead of using the repo checkout + pnpm run
lint:workflow-cache in the PR context); update the steps referencing
actions/checkout@v6 and the pnpm run lint:workflow-cache invocation (also at the
repeated block around lines 79-80) to call the immutable policy executor so PR
changes cannot weaken the check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a valid concern, but will be addressed in a follow up PR, by splitting this check out into a re-usable GitHub Action.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@auxesis, understood — splitting it into a reusable GitHub Action is a solid approach since the action can be pinned to a ref that the PR cannot modify. Would you like me to open a GitHub issue to track that follow-up work?


🧠 Learnings used
Learnt from: auxesis
Repo: cipherstash/stack PR: 431
File: .github/workflows/tests-bench.yml:0-0
Timestamp: 2026-05-06T11:35:47.341Z
Learning: Do not use continue-on-error: true in GitHub Actions workflows to mask test failures. Masking failures hides root causes and makes diagnosis harder. Keep failing steps blocking so genuine issues surface. If a test is known to fail or flaky, isolate it in a separate workflow or job (e.g., a dedicated flaky-tests job) or mark it as flaky in the test suite with clear reporting, rather than masking in the main workflow. Apply this rule to all YAML workflow files under .github/workflows, regardless of PR descriptions.

Comment thread SECURITY.md Outdated
@auxesis auxesis force-pushed the ci/ensure-no-caching-on-release-workflows branch from f2b3d7b to 8c41e7c Compare May 16, 2026 05:30
GitHub Actions cache poisoning is a known attack[^1] against
credential-bearing workflows:

- a lower-privileged run plants a malicious entry under a deterministic
  cache key
- a privileged workflow restores a cache from that cache key and executes it
- secrets are exfiltrated

The `release.yml` workflow publishes packages to npm using OIDC trusted
publishing and an `NPM_TOKEN`. Before this change, `release.yml` was
vulnerable to this class of attack.

Mitigate this by explicitly disabling all build caching in `release.yml`:

- `pnpm/action-setup` sets `cache: false`
- `actions/setup-node` sets `package-manager-cache: false`
- `actions/setup-node` does not set `cache:`
- no `actions/cache` step is used

Also add a check to the repo (`tests-supply-chain.yml`) to test that high-risk
workflows (`release.yml`) are not using caching, and it is not added
back in.

[^1]: https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/
@auxesis auxesis force-pushed the ci/ensure-no-caching-on-release-workflows branch from 8c41e7c to 5da89fe Compare May 16, 2026 05:33
Comment on lines +9 to +12
const TARGET_WORKFLOWS = [
'.github/workflows/release.yml',
'.github/workflows/tests-supply-chain.yml',
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be a problem if there is ever a slightly different name used for a release workflow? Possibly not an immediate concern. You may already have a plan for that anyway given the intent to split this out.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this is just the test of the lint, not the lint itself?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, this is the test of the lint.

Copy link
Copy Markdown
Contributor

@coderdan coderdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Took me a moment to fully understand but its a good solution. Thank you!

@auxesis auxesis merged commit 7a6e777 into main May 16, 2026
7 checks passed
@auxesis auxesis deleted the ci/ensure-no-caching-on-release-workflows branch May 16, 2026 06:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants