Skip to content

fix(dispatcher): Verify installer attestation before running self-update#1671

Merged
hatayama merged 2 commits into
v3-betafrom
feat/attestation-integrate-update
Jul 10, 2026
Merged

fix(dispatcher): Verify installer attestation before running self-update#1671
hatayama merged 2 commits into
v3-betafrom
feat/attestation-integrate-update

Conversation

@hatayama

@hatayama hatayama commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

The dispatcher self-update flow (uloop update and the scheduled 24h refresh) now requires a valid Sigstore attestation for install.sh / install.ps1 before executing the downloaded installer.

This is Phase B2 of TODO 2 (docs/spec — 2026-07-09 uloop CLIインストールのセキュリティ改善). Phase B1 (verifier package, PR #1670) is already merged; Phase B3 will wire the same verifier into the project runner download path.

User Impact

Before: A compromised GitHub releases origin could serve a malicious install.sh + matching install.sh.sha256, and the dispatcher would happily execute it — sha256 alone cannot prove authenticity when the checksum ships from the same origin as the asset.

After: The installer will not run unless the bundled .sigstore.json cryptographically verifies against Sigstore's public-good trust anchor, the workflow identity matches .github/workflows/dispatcher-publish.yml on an allowed ref (refs/heads/v3-beta or refs/heads/main), and the release tag's commit SHA matches the certificate's Source Repository Digest extension. Fail-closed on bundle-missing, network-failure, digest-mismatch, and identity-mismatch.

Changes

  • update.Command gains a ReleaseTag field so the verifier can resolve the tag to a commit SHA for OID 1.3.6.1.4.1.57264.1.13 binding.
  • attestation_verify.go wires the internal/attestation package into the dispatcher package with a swappable var (verifyReleaseAssetAttestation) so unit tests can isolate download/checksum logic from real Sigstore verification. Exposes both publish-workflow SANs (dispatcher-publish, native-cli-publish) so Phase B3 can reuse the constants.
  • downloadVerifiedUpdateInstaller calls the verifier with attestationDispatcherPublishWorkflowPath after the sha256 check succeeds.
  • Existing tests updated to stub the attestation hook (unchanged behavior). New tests cover fail-closed on attestation error and the exact release-tag / workflow-path passed to the hook.

Verification

  • scripts/check-go-cli.sh — 0 lint issues across all Go modules
  • go test ./... in cli/dispatcher/ — all packages pass, including attestation + dispatcher

Refs: docs/plans/ spec, TODO 2 Phase B2

Review in cubic

The dispatcher self-update flow (uloop update / scheduled 24h refresh) now
requires a valid Sigstore attestation for install.sh / install.ps1 before it
will execute the downloaded installer. Fail-closed on bundle-missing,
network-failure, digest-mismatch, and identity-mismatch — the .sha256 file
ships from the same origin as the asset and cannot certify authenticity if
that origin is compromised, so attestation is the true root of trust.

- update.Command gains a ReleaseTag field so the verifier can resolve the tag
  to a commit SHA and bind it to the certificate's Source Repository Digest
  extension (OID 1.3.6.1.4.1.57264.1.13).
- New attestation_verify.go wires the attestation package into the dispatcher
  package with a swappable var so tests can isolate download/checksum
  behavior from real network + sigstore verification. Also exposes the two
  publish-workflow SANs (dispatcher-publish, native-cli-publish) for Phase
  B3's runner-download reuse.
- downloadVerifiedUpdateInstaller now calls the verifier with
  attestationDispatcherPublishWorkflowPath after checksum verification
  succeeds.
- Tests cover happy path, attestation failure fail-closed, and the workflow
  path / release tag actually passed through to the verifier.
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@hatayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 02125879-cb46-4f7b-b373-0685c41f5075

📥 Commits

Reviewing files that changed from the base of the PR and between 7088d4a and 16d5b78.

📒 Files selected for processing (5)
  • cli/dispatcher/internal/dispatcher/attestation_verify.go
  • cli/dispatcher/internal/dispatcher/attestation_verify_test.go
  • cli/dispatcher/internal/dispatcher/update.go
  • cli/dispatcher/internal/dispatcher/update_test.go
  • cli/dispatcher/internal/update/command.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/attestation-integrate-update

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.

Follow-up to Fable 5 review on PR #1671. The verifier previously relied on
the git-refs endpoint returning 404 for an empty tag, which meant correctness
depended on remote behavior for what should be a local contract violation
(this repo's CLAUDE.md standardizes on contract programming). Fail closed
locally with ErrVerificationFailed and add a test so a future refactor cannot
silently regress the guard.
@hatayama
hatayama merged commit 109bc9f into v3-beta Jul 10, 2026
9 checks passed
@hatayama
hatayama deleted the feat/attestation-integrate-update branch July 10, 2026 04:10
@github-actions github-actions Bot mentioned this pull request Jul 11, 2026
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.

1 participant