Repository navigation
Self-host releases: only CoderHelm's release workflow can ship an update - #310
Merged
Merged
Conversation
Installs, updates and the Launch Stack now refuse anything that merely looks like a CoderHelm release. - Signature identity is exact: release.yml on refs/tags/<version>, GitHub's OIDC issuer, workflow repository and ref, and a Rekor entry. The installer also reads the certificate itself before cosign runs. No signature, no cosign or gh, or any mismatch: nothing is installed. No skip flag. - No downgrade: updates only go forward; rollbacks only to versions the install ran before (installer and updater). The updater reads releases only from api.github.com for this repo and reports a stale list. - Downloads only from this repo's GitHub release URLs over HTTPS (redirects included); cosign in CodeBuild pinned by SHA-256; VERSION must be a tag. - release.yml: check (signed annotated tag on main), build (read-only, no secrets), publish (release environment with reviewers; signs, verifies, attests; never replaces a release or an S3 template; latest.json only moves forward). The AWS publisher role trusts only that environment. - Every action in every workflow pinned by commit SHA; CI fails otherwise (check_workflows.py), plus actionlint and Dependabot for actions. - scripts/release-protection.sh applies the tag rulesets, main protection, release environment, immutable releases and Actions settings. - docs/self-host/updates-security.md: what is checked and how to verify a release yourself.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR makes the self-host release and update chain refuse anything that only looks like a CoderHelm release. Before anything is installed, the installer, the update build, the Launch Stack installer and
install.shnow require a signature made by exactly this repository'srelease.yml, on that release's own tag, in the Rekor log. The updater never moves an install backwards, except an admin rollback to a version that install already ran. Publishing a release now needs a signed tag onmainand a reviewer's approval. Every action in every workflow is pinned by commit SHA, and CI enforces the pinning.Changes
Verification (identity pinned, fails closed)
installer/lib/release.mjs,installer/lib/sigstore.mjs:--certificate-identity https://github.com/CoderHelm/coderhelm-platform/.github/workflows/release.yml@refs/tags/<tag>--certificate-github-workflow-repositoryand--certificate-github-workflow-refgh attestation verifywith--signer-workflow,--source-ref,--cert-oidc-issuerand--deny-self-hosted-runners, run for every asset.--require-signatureis still accepted, as a no-op.infra/lib/release-verify.tsis a new shared module, used by the update buildspec. The Launch Stack buildspec repeats the same lines, and a test keeps the two identical.$VERSIONmust matchvX.Y.Z.npm install --ignore-scripts.selfhost/install.shresolveslatestto a tag, verifies the signature with cosign or gh, and stops if neither tool is installed.selfhost/launch/bootstrap.mjsrefuses a VERSION that isn't a release tag.No downgrade or replay
rollbackandupdate --rollbackonly go to a version this install ran before.state.versionsis now recorded on every deploy.update_nowonly accepts a strictly newer version.rollbackonly accepts a version in the install'sran_versionsor history.api.github.comfor this repository.releasesfreshness field. It is marked stale when the list stops showing the newest version seen before, or when the list hasn't been read for 3 days.Release workflow (
release.yml)checkjob: the run must be on a tag, the tag must be annotated and signed, GitHub must report it verified, its commit must be signed, and the commit must be an ancestor ofmain.buildjob:contents: read, no secrets, no OIDC, and no rust-cache, so a cached build can't be poisoned. It usescargo --lockedand pinscargo-zigbuild==0.24.0.publishjob:environment: releaseand does no checkout.v2.4.1, the same version the verifiers use.install.shincluded.launch-stack.yamlto S3 with--if-none-match.latest.jsonnow carriestemplateSha256and only ever moves forward.ReleasePublisherRolenow trusts onlyrepo:CoderHelm/coderhelm-platform:environment:release, withStringEquals.permissions: {}, with least privilege set per job.CI
uses:in all 5 workflows is pinned by full SHA with a# vX.Y.Zcomment. Majors are unchanged.Workflow securityCI job:.github/scripts/check_workflows.pyfails on any unpinned action, onpull_request_targetorworkflow_runtriggers, ongithub.event.*,head_reforinputs.*used insiderun:, and on jobs with no permissions.ci.ymlnow haspermissions: contents: read. Thedeploy.ymlbuild job also getscontents: read..github/dependabot.ymlkeeps the pinned actions current.Settings and docs
scripts/release-protection.shapplies the repository settings. It can't be run from CI, so Nam runs it. It sets:mainrulesetreleaseenvironmentdocs/self-host/updates-security.mdcovers who can publish, what installs check, the Launch Stack, how to check a release yourself (cosign verify-blobandgh attestation verify), and what happens when a check fails.updates.mdandsecurity.mdare updated to match.Before the next release
scripts/release-protection.sh.git tag -s.Verification
test/release-security.test.mjs(21 tests) covers:cli/cliprovenance), parsed and refused for the wrong identityNoDowngradetests (no backwards or sidewaysupdate_now; rollback only to ran versions; stale list reported; other repositories refused). The.github/scriptssuite also passes (27 tests, including the workflow checker run against this repository's own workflows).cargo fmt --check,clippy -D warnings, andcargo test --workspace(2123 passed, 0 failed).cfn-lint,actionlint(all workflows),shellcheckoninstall.shandrelease-protection.sh: clean.