fix(install): verify Sigstore build provenance at first install (#61) - #66
Merged
Merged
Conversation
…#61) install.sh and install.ps1 downloaded the archive and its .sha256 from the same release and only compared them to each other, so an attacker able to replace both files was trusted. self-update already verifies build provenance with gh attestation verify; first install did not. Add a provenance check after the checksum passes: download the release's codex-switch-build-provenance.json bundle and run gh attestation verify <archive> --bundle <bundle> --repo xjoker/codex-switch --signer-workflow xjoker/codex-switch/.github/workflows/release.yml --deny-self-hosted-runners which proves the artifact was built by this repo's release workflow on a GitHub-hosted runner and cannot be forged. Offline --bundle mode needs no gh auth login and no GitHub API call, so it works during curl | bash. Graceful by default: without a GitHub CLI that supports attestation the checksum is still enforced and provenance is skipped with a warning; set CS_REQUIRE_PROVENANCE=1 to make that a hard failure. A failed verification (tampered artifact or wrong signer) always aborts the install. Co-authored-by: xJoker <xjoker@users.noreply.github.com>
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.
Fixes #61.
Problem
scripts/install.shandscripts/install.ps1download the archive and its${asset}.sha256from the same GitHub Release and only check that the two match. That trusts anyone who can replace both files together.self-updatealready does more — SHA-256 plusgh attestation verifyagainst this repo and release workflow (src/update.rs) — but first install did not.Fix
After the checksum passes, verify the archive's Sigstore build provenance:
The provenance bundle is already published as a release asset (used by
self-update). This proves the artifact was built by this repository's release workflow on a GitHub-hosted runner and cannot be forged, which the checksum cannot.Key property: offline
--bundlemode needs neithergh auth loginnor any GitHub API call, so it works during a freshcurl … | bash/irm … | iexinstall.Behavior
CS_REQUIRE_PROVENANCE=1to make a missing verifier a hard failure.Applied symmetrically to
install.sh(bash) andinstall.ps1(PowerShell).Verification
Empirically validated
gh attestation verifyagainst the realv20260804.1.0release before writing the scripts, then ran the modifiedinstall.shend-to-end against the live release (sandboxedHOME):Build provenance verified: cs-linux-amd64.tar.gz→ installs, exit 0.skipping build-provenance verification (checksum was still verified)→ installs, exit 0.CS_REQUIRE_PROVENANCE=1: errors → exit 1 (fail closed).--signer-workflow:gh attestation verifyexits 1 → install aborts.GH_CONFIG_DIRempty,GH_TOKEN/GITHUB_TOKENunset), while online mode required auth — hence bundle mode.bash -n scripts/install.shpasses;cargo fmt --check,clippy -D warnings,cargo test --allall pass (no Rust changed).install.ps1mirrors the logic; its syntax is validated by the existing CI PowerShell parse step (no localpwshavailable).Residual
Unlike
self-update, the installer does not additionally pin--source-ref/--source-digest(that needs a tag→commit resolution via the GitHub API and would reintroduce an auth/rate-limit dependency). The--repo+--signer-workflow+--deny-self-hosted-runnerspins already defeat the asset-replacement attack in the issue; tighter source pinning can be a follow-up.Docs
Updated the wiki
Getting-Started.mdinstall section to describe checksum + provenance verification andCS_REQUIRE_PROVENANCE.Note: the CI Format and audit job will be red until #63 (webbrowser RUSTSEC-2026-0257 lockfile bump) merges to
dev; that failure is pre-existing and unrelated to this change.