[#899][SEC] Split sync-upstream: read-only candidate vs privileged push - #1060
Merged
Merged
Conversation
The daily upstream fork-sync ran as a single job that held a repo-push credential (secrets.SYNC_TOKEN, persisted via actions/checkout without persist-credentials: false) for its entire duration while running code fetched from the untrusted anomalyco/opencode tree (bun install lifecycle scripts, then booting the merged engine for the smoke test). A compromised upstream commit could read that credential out of .git/config. Split into two trust domains: - sync-upstream.yml (candidate): permissions: contents: read, zero references to secrets.SYNC_TOKEN, persist-credentials: false on its checkout. Fetches upstream, merges dev into alpha, runs every existing guard/tripwire and the engine smoke test, and — only on success — packages the resulting dev/alpha commits into an immutable git-bundle artifact. It never pushes anything. - sync-upstream-push.yml (push, new): permissions: contents: write, triggered by workflow_run only when the candidate reports success. Downloads the bundle, verifies it (exact commit-sha match against the candidate's manifest, non-force push), configures the push credential only for the final step, and pushes. It never executes any code from the merged tree, so the push token is never in the same process as code sourced from upstream. Side effect (matches the issue's "push only after guard/smoke pass" requirement): previously the merge step pushed to alpha *before* the frontend anchor tripwire and the engine smoke test ran, so a smoke failure only reported after the fact. Now a failed smoke test blocks artifact production entirely, so nothing reaches the push workflow. Verified locally: YAML parses, every `run:` block passes `bash -n`, scripts/north-star-guard.sh and scripts/assert-no-nul-bytes.py pass, scripts/check-doc-links.py passes on the edited docs, and packages/ui-mac/src/main/frontend-patch-roundtrip.test.ts (which pins the exact `rm -rf packages/app packages/ui` line in this file) still passes 15/15. Also hand-verified the bundle create/fetch/push mechanics end-to-end against a throwaway git repo before writing the workflow YAML. Out of scope per the issue: does not touch alpha-ci.yml's upstream-guard job or its change-type coverage, and does not change sync frequency or upstream selection strategy. Fixes #899 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015BNKogUjFuCri3Ri6BDGkZ
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
Split upstream sync so untrusted upstream code does not share a job with push credentials.
Fixes #899
Test plan
Made with Cursor