Skip to content

install.sh: verify release attestation via gh CLI#984

Merged
tw93 merged 1 commit into
tw93:mainfrom
AilfredBitworth:add-attestation-verify
May 26, 2026
Merged

install.sh: verify release attestation via gh CLI#984
tw93 merged 1 commit into
tw93:mainfrom
AilfredBitworth:add-attestation-verify

Conversation

@AilfredBitworth
Copy link
Copy Markdown
Contributor

Summary

Adds optional GitHub Actions build-provenance attestation verification to install.sh. Anchors the downloaded SHA256SUMS file to the attestation already produced by release.yml (via actions/attest-build-provenance@v4) before reading checksums from it.

Motivation

Today the installer trusts SHA256SUMS purely because it was fetched from the release URL. A compromise that gains GitHub release-asset write access can swap the binary and the sums entry together, and the current sha256 gate accepts it. The release workflow already mints Sigstore attestations covering SHA256SUMS and the binaries, but install.sh doesn't consume them. This wires that signal in.

Verifying SHA256SUMS is sufficient: the per-binary sha256 is then anchored to that attested file by the existing verify_release_asset_checksum flow.

Behavior

  • gh CLI available + authenticated → attestation is verified with --owner tw93 --deny-self-hosted-runners. Mismatch is fatal; install aborts.
  • gh unavailable or unauthenticated → falls back to existing sha256-only verification. No behavior change for current users.
  • MOLE_REQUIRE_ATTESTATION=1 → turns the soft check into a hard requirement. Missing gh becomes an install failure. For users who want fail-closed semantics.

Why a soft default

Most macOS users won't have gh installed, and breaking the install path for them would be a worse trade than the current state. The opt-in env var lets security-conscious users (and CI environments) lock it down without forcing a new dependency on everyone.

Test plan

  • bash -n install.sh — clean
  • Local install with gh installed and authenticated → see "Verified (sha256 + attestation)" success line
  • Local install without gh → falls back to existing behavior (silent), install succeeds
  • Local install with MOLE_REQUIRE_ATTESTATION=1 and gh uninstalled → install fails fast with clear error
  • CI shellcheck / shfmt pass

Notes

Drafting because I'd like a maintainer's read on:

  1. Whether --owner tw93 is the right scoping (vs. --repo tw93/Mole, which is stricter but breaks if you ever fork-and-rename).
  2. Whether you'd prefer this opt-in via env (current) vs. opt-out via env (MOLE_SKIP_ATTESTATION=1).
  3. Whether the success log line is too noisy — happy to drop it or gate behind --verbose.

Found while doing an external security audit of Mole. Audit verdict was already ACCEPTABLE / risk LOW — the project is unusually well-hardened for its category. This is one of two minor defense-in-depth items.

Anchors the downloaded SHA256SUMS file to its GitHub Actions
build-provenance attestation (already produced by release.yml via
actions/attest-build-provenance) before reading checksums from it.
This closes a gap where the SHA256SUMS file is trusted purely on the
basis of its GitHub release URL — a release-page-write compromise
could otherwise swap both the binary and its sums entry together.

Behavior:
- If gh CLI is available and authenticated, the attestation is
  verified with --owner tw93 --deny-self-hosted-runners. A mismatch
  is fatal and the install aborts.
- If gh is unavailable or unauthenticated, the installer falls back
  to the existing sha256-only verification (no behavior change for
  current users).
- MOLE_REQUIRE_ATTESTATION=1 turns the soft check into a hard
  requirement: missing gh becomes an install failure.

Verifying SHA256SUMS is sufficient because the binary's sha256 is
then anchored to that attested file by verify_release_asset_checksum
in the line below.
@tw93
Copy link
Copy Markdown
Owner

tw93 commented May 26, 2026

@AilfredBitworth Thanks for this. Decisions on your three open questions:

  1. Keep --owner tw93. The stricter --repo form breaks the install path for forks and the practical risk from "another tw93 repo's workflow forging a colliding attestation" is negligible given Sigstore binds to content hash.
  2. Keep opt-in via MOLE_REQUIRE_ATTESTATION=1. Most macOS users have no gh, so soft default must stay; the env var gives CI / security-minded users the hard mode.
  3. The log_success line is already gated by VERBOSE (install.sh:59), so it follows the same noise rules as the other success lines (Downloaded ${binary_name}, Installed mole to ...). Keep it as-is.

Marking ready and merging.

@tw93 tw93 marked this pull request as ready for review May 26, 2026 23:03
@tw93 tw93 self-requested a review as a code owner May 26, 2026 23:03
@tw93 tw93 closed this May 26, 2026
@tw93 tw93 reopened this May 26, 2026
@tw93 tw93 merged commit 86068b3 into tw93:main May 26, 2026
9 checks passed
@AilfredBitworth
Copy link
Copy Markdown
Contributor Author

Awesome! Glad I could help. I look forward to using this MCP.

tw93 added a commit that referenced this pull request May 29, 2026
…endent

The release attestation gate added this cycle (PR #984) had zero coverage,
so add tests for verify_release_attestation's 2/0/1 return codes (via a PATH
gh stub, since the exec'd binary bypasses function mocks) and for the policy
gate in verify_release_asset_checksum.

The same gate also broke the two happy-path checksum tests on any host with
an authenticated gh: they run `gh attestation verify` against synthetic
fixtures and fail. Stub verify_release_attestation to the gh-unavailable
return so those tests exercise the checksum-only path regardless of host gh
state. CI without gh masked this.
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