Is your feature request related to a problem?
.github/workflows/deploy-native.yml pins some actions to a commit SHA and lets others float on a major tag:
| Action |
Current ref |
Pinned |
actions/checkout |
df4cb1c069e1874edd31b4311f1884172cec0e10 (v6.0.3) |
yes |
docker/setup-buildx-action |
d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 (v4.1.0) |
yes |
actions/setup-node |
@v4 |
no |
actions/upload-artifact |
@v4 |
no |
actions/download-artifact |
@v4 |
no |
A major tag is mutable, so @v4 resolves to whatever the tag points at when the workflow runs. That is the supply-chain exposure pinning exists to remove, and here it is only half-removed.
The blast radius is not incidental. All three unpinned actions run in the build job, which holds the repository checkout and produces build-out/imcp2 — the binary the ship job then installs on the deploy host and starts under systemd. Code executing in build can therefore alter what gets deployed. That is the same exposure actions/checkout already carries, and checkout is pinned.
Surfaced by Copilot review on #84 (#84 (comment)). That review comment noted the in-file comment claimed all third-party actions were pinned, which was not true. #84 fixed the comment to describe what is actually pinned and to name the three that are not; it deliberately did not pin them, because no SHA for those actions is recorded anywhere in this repository and guessing one is worse than an honest comment — a wrong SHA fails at run time, and a fabricated one cannot be reviewed. This issue tracks doing it properly.
Describe the solution you'd like
Replace the three floating refs with full 40-character commit SHAs, each carrying a trailing comment with the human-readable version, matching the existing convention:
uses: actions/setup-node@<sha> # v4.x.y
Resolve each SHA from the upstream repository's release tag and confirm it against that tag before committing it. Then update the comment above the first uses: in the build job — it currently names these three as unpinned, and that sentence should go away once they are not.
Worth checking .github/workflows/ci.yml in the same pass; it uses the same pinned actions/checkout and nothing else today, but the convention should hold repository-wide.
Alternatives considered
- Leave them floating. Rejected: it leaves a mutable-tag path into the job that builds the deployed artifact.
- Pin to a release tag such as
@v4.0.2 instead of a SHA. Better than @v4, but lightweight tags are still movable, so it narrows the window rather than closing it.
- Adopt Dependabot for
github-actions. Complementary rather than an alternative — it keeps pins current once they exist, and would stop pinning from becoming a staleness problem. Reasonable to do alongside.
Additional context
Is your feature request related to a problem?
.github/workflows/deploy-native.ymlpins some actions to a commit SHA and lets others float on a major tag:actions/checkoutdf4cb1c069e1874edd31b4311f1884172cec0e10(v6.0.3)docker/setup-buildx-actiond7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5(v4.1.0)actions/setup-node@v4actions/upload-artifact@v4actions/download-artifact@v4A major tag is mutable, so
@v4resolves to whatever the tag points at when the workflow runs. That is the supply-chain exposure pinning exists to remove, and here it is only half-removed.The blast radius is not incidental. All three unpinned actions run in the
buildjob, which holds the repository checkout and producesbuild-out/imcp2— the binary theshipjob then installs on the deploy host and starts under systemd. Code executing inbuildcan therefore alter what gets deployed. That is the same exposureactions/checkoutalready carries, andcheckoutis pinned.Surfaced by Copilot review on #84 (#84 (comment)). That review comment noted the in-file comment claimed all third-party actions were pinned, which was not true. #84 fixed the comment to describe what is actually pinned and to name the three that are not; it deliberately did not pin them, because no SHA for those actions is recorded anywhere in this repository and guessing one is worse than an honest comment — a wrong SHA fails at run time, and a fabricated one cannot be reviewed. This issue tracks doing it properly.
Describe the solution you'd like
Replace the three floating refs with full 40-character commit SHAs, each carrying a trailing comment with the human-readable version, matching the existing convention:
Resolve each SHA from the upstream repository's release tag and confirm it against that tag before committing it. Then update the comment above the first
uses:in thebuildjob — it currently names these three as unpinned, and that sentence should go away once they are not.Worth checking
.github/workflows/ci.ymlin the same pass; it uses the same pinnedactions/checkoutand nothing else today, but the convention should hold repository-wide.Alternatives considered
@v4.0.2instead of a SHA. Better than@v4, but lightweight tags are still movable, so it narrows the window rather than closing it.github-actions. Complementary rather than an alternative — it keeps pins current once they exist, and would stop pinning from becoming a staleness problem. Reasonable to do alongside.Additional context
deploy-native.ymlis a new file there); Deploy production on release-* tags #81 stacks on it and inherits the same reusable workflow for production deploys, so the exposure applies to both staging and production rollouts.