Skip to content

security: fail closed on privileged workflow refs - #1912

Open
lawrencecchen wants to merge 7 commits into
harden-manaflow-cifrom
security/dispatch-trust
Open

security: fail closed on privileged workflow refs#1912
lawrencecchen wants to merge 7 commits into
harden-manaflow-cifrom
security/dispatch-trust

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Remove manual dispatch from secret-bearing Docker, sandbox, Morph, screenshot, and release workflows.
  • Add a fail-closed gate for protected main and trusted generated release commits. It verifies checkout SHA, workflow blob, remote ref, ancestry, and generated release commit metadata.
  • Replace release dispatch with a local reusable workflow call carrying the exact release and protected-main SHAs. Bind newly created release tags to the verified source SHA and reject existing tags at another SHA.
  • Set least-privilege job permissions, pin all actions, disable checkout credential persistence, and add static and behavior contract tests.

Testing

  • scripts/ci/test-verify-privileged-ref.sh
  • ruby scripts/ci/test-privileged-workflow-gates.rb
  • actionlint .github/workflows/*.yml
  • bash -n .github/scripts/verify-privileged-ref.sh scripts/ci/test-verify-privileged-ref.sh
  • shellcheck .github/scripts/verify-privileged-ref.sh scripts/ci/test-verify-privileged-ref.sh
  • git diff --check
  • zizmor --pedantic: 0 low, medium, or high findings; five informational Rust setup notices remain.

Stack and rollout

Stacked on PR 1910. Configure protected main and non-empty required reviewers for the electron environment before merging this stack. No merge was performed by this PR.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Removes workflow_dispatch from secret-bearing workflows and replaces branch-based trust with fail-closed checks for protected refs, workflow revisions, and release metadata. Privileged jobs now run only from protected main pushes, scheduled main runs, or the trusted reusable release call; manual arbitrary-ref runs and post-merge release publishing no longer work.

  • Adds a shared verification gate that checks exact SHAs, workflow files, ancestry, remote refs, and release commit identity; release commits must be single-file Actions-bot commits on the exact base.
  • Runs release publishing from release-pr.yml with exact release, base, and caller SHAs; new tags bind to the verified source, moved tags are rejected, and retries are limited to untouched bot-created draft releases.
  • Finds the latest release tag by fetching tags and sorting by semver, since release tags point at generated commits not reachable from main after a squash merge.
  • Tightens permissions, pins actions, disables checkout credentials, and adds static and behavior contract tests covering the workflows and release script.

Migration

  • Protect main, release/v* branches, and v* tags; configure non-empty required reviewers for the electron environment.
  • Outside the schedule, rerun a recent scheduled release only after confirming its captured main commit remains reachable.

Written for commit 94387db. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cmux-client Canceled Canceled Sep 2, 2026 5:54pm UTC
cmux-www Canceled Canceled Sep 2, 2026 5:54pm UTC

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 10dc44d4-1d95-469a-afbe-8f51e70c259c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown

Greptile Summary

The PR removes manually dispatched privileged workflows and adds fail-closed validation for protected publication refs and generated release commits.

  • Adds a shared verifier for repository, workflow, SHA, ancestry, remote-ref, and generated-commit invariants.
  • Converts desktop release publication to a local reusable-workflow call bound to exact source revisions.
  • Tightens permissions, action pins, checkout behavior, and privileged-workflow contract tests.
  • Introduces a conflicting tag-target invariant between generated-branch and post-merge main builds.

Confidence Score: 4/5

The PR should not merge until the post-merge main release run can reuse the tag created by the generated-branch build; the documentation-policy issue is non-blocking.

The reusable run creates the release tag at the generated commit, while the subsequent main-push run compares that tag against a different merge SHA and fails before any dependent platform artifact job can run.

Files Needing Attention: .github/workflows/release-updates.yml, docs/release-workflow.md

Important Files Changed

Filename Overview
.github/scripts/verify-privileged-ref.sh Adds comprehensive fail-closed validation of event, workflow, checkout, remote-ref, ancestry, and generated-release metadata.
.github/workflows/release-pr.yml Replaces workflow dispatch with an exact-SHA reusable call and captures the generated branch revision.
.github/workflows/release-updates.yml Hardens publication and binds tags to source SHAs, but its existing-tag check rejects the normal post-merge main run.
scripts/ci/test-verify-privileged-ref.sh Adds behavior coverage for verifier success and failure cases using controlled Git repositories and environment contexts.
scripts/ci/test-privileged-workflow-gates.rb Adds static contracts for privileged workflow triggers, permissions, pinned actions, and verifier placement.
docs/release-workflow.md Documents the protected release flow and operational prerequisites, but violates the repository instruction against unsolicited documentation.

Sequence Diagram

sequenceDiagram
  participant Schedule as Scheduled release workflow
  participant Branch as release/vX.Y.Z
  participant Release as GitHub Release
  participant Main as Protected main
  Schedule->>Branch: Create version commit C_release
  Schedule->>Release: Create vX.Y.Z targeting C_release
  Branch->>Main: Merge release PR as C_main
  Main->>Release: Resolve existing vX.Y.Z
  Release-->>Main: Tag points to C_release
  Main->>Main: Compare tag with SOURCE_SHA C_main
  Main-->>Main: Fail before platform artifact jobs
Loading

Reviews (1): Last reviewed commit: "security: gate privileged workflows on t..." | Re-trigger Greptile

Comment thread .github/workflows/release-updates.yml Outdated
Comment on lines +153 to +160
tag_refs="$(GIT_TERMINAL_PROMPT=0 git ls-remote origin \
"refs/tags/$resolved_tag" "refs/tags/$resolved_tag^{}")"
if ! printf '%s\n' "$tag_refs" | awk -v expected="$SOURCE_SHA" '
NF == 2 && $1 == expected { found = 1 }
END { exit(found ? 0 : 1) }
'; then
echo "Release tag $resolved_tag does not point at $SOURCE_SHA" >&2
exit 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Post-merge tag validation fails

When the generated release PR is merged, the main-push run sets SOURCE_SHA to the new main commit, but the existing tag still targets the generated release commit. This comparison rejects the tag, causing prepare-release to fail and all dependent platform artifact jobs to be skipped.

Knowledge Base Used:

Comment thread docs/release-workflow.md Outdated
Comment on lines +1 to +17
# Release workflow

The release workflow runs from the protected `main` branch on its schedule.
It creates a single-file `release/vX.Y.Z` branch, then calls
`.github/workflows/release-updates.yml` as a reusable workflow. The call carries
the exact release commit, its `main` parent, and the protected caller commit.

The publishing workflow has no `workflow_dispatch` trigger. This removes the
manual path that could otherwise select arbitrary branch code while exposing
signing credentials. Outside the schedule, wait for the next scheduled run or
rerun a recent scheduled run after confirming that its protected `main` commit
is still current.

The trust gate rejects stale or moved refs, workflow changes, non-bot release
commits, and release commits that change files other than
`apps/client/package.json`. Keep `main` protected and configure non-empty
required reviewers for the `electron` environment before relying on publication.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unrequested documentation added

This new release document conflicts with the repository instruction not to write documentation unless explicitly requested, adding an unsupported maintenance surface.

Suggested change
# Release workflow
The release workflow runs from the protected `main` branch on its schedule.
It creates a single-file `release/vX.Y.Z` branch, then calls
`.github/workflows/release-updates.yml` as a reusable workflow. The call carries
the exact release commit, its `main` parent, and the protected caller commit.
The publishing workflow has no `workflow_dispatch` trigger. This removes the
manual path that could otherwise select arbitrary branch code while exposing
signing credentials. Outside the schedule, wait for the next scheduled run or
rerun a recent scheduled run after confirming that its protected `main` commit
is still current.
The trust gate rejects stale or moved refs, workflow changes, non-bot release
commits, and release commits that change files other than
`apps/client/package.json`. Keep `main` protected and configure non-empty
required reviewers for the `electron` environment before relying on publication.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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