Problem
The required Layer-1 GitHub Actions workflow currently forces every Bazel job to D2B_BAZEL_PROFILE=local with D2B_BAZEL_UNTRUSTED=1. CI therefore cannot reuse the BuildBuddy cache or remote execution used by developers.
The PR workflow is accepted for both main and v3. Any credential-bearing replacement must always execute workflow and bootstrap code from the default branch (main), regardless of the PR base branch, so an older or PR-modified workflow cannot control the privileged path.
GitHub changed pull_request_target in December 2025 to always source workflow code and the default checkout from the repository default branch: https://github.blog/changelog/2025-11-07-actions-pull_request_target-and-environment-branch-protections-changes/
That trigger alone is not sufficient. GitHub explicitly classifies checking out and executing untrusted PR code in a secret-bearing pull_request_target or workflow_run job as a pwn-request vulnerability: https://docs.github.com/en/actions/reference/security/securely-using-pull_request_target
Scope
- Run every remote-eligible required Layer-1 push and PR gate through BuildBuddy while preserving local-only Nix, fixture, hardware, and tagged actions.
- Source privileged orchestration, pinned actions, remote policy, and credential handling exclusively from
main, including for PRs targeting v3 or any future protected branch.
- Keep PR code execution in an unprivileged, isolated context. Do not implement
pull_request_target plus PR-head checkout plus make in a job that contains repository secrets or a privileged token.
- Capture and verify immutable base, head, and tested merge OIDs. A review approval, rerun, or label must not authorize a later pushed head implicitly.
- Broker BuildBuddy authentication so the long-lived API key never enters PR-controlled environment variables, argv, files, action environments, test environments, credential helpers, Bazel rc files, or executable code.
- The PR must not be able to replace
tests/tools/bazel-check, redirect the remote/BES endpoint, add authentication headers, or read the credential source.
- If GitHub-hosted runners cannot provide this isolation directly, use a dedicated credential proxy or equivalent external boundary. Do not expose the key as a normal Actions secret to executed PR code.
- Isolate cache writes by trust domain and PR/head identity. Untrusted PRs may read an approved seed namespace but must not poison trusted push/developer cache entries; trusted
main/v3 pushes remain the only seed authority.
- Use least-privilege
GITHUB_TOKEN permissions, persist-credentials: false, SHA-pinned actions, ephemeral runners, and no execution of PR-produced artifacts in a privileged follow-up workflow.
- Preserve the Bazel facade's redaction, typed failure classification, exact target sets, and fail-closed behavior. Authentication or broker failure must not become a success-shaped reduced gate.
- Replace the current policy assertions requiring local/untrusted CI with assertions for the new trust split and default-branch workflow ownership.
- Add security-focused Layer-1 policy tests covering malicious edits to workflow files,
.bazelrc, the credential helper, endpoints, and PR metadata.
Acceptance criteria
- Required PR gates targeting both
main and v3 use the workflow definition and trusted bootstrap from main.
- All eligible Bazel actions show BuildBuddy cache/remote-execution activity; explicitly local-only actions remain local.
- A PR that modifies workflows, Make,
.bazelrc, tests/tools/bazel-check, tests, or build scripts cannot obtain the BuildBuddy credential, change the authenticated endpoint, write trusted cache entries, or gain repository write access.
- Fork PRs either use the same brokered, isolated BuildBuddy path safely or remain blocked from the remote path until that boundary exists; no long-lived secret is exposed as a workaround.
- Pushes to
main and v3 can seed the trusted cache under the existing security-digest contract.
- The stable required GitHub
check result and existing fixed Layer-1 target coverage remain unchanged.
- BuildBuddy displays the correct tested revision and PR/run linkage rather than the default-branch workflow SHA.
Depends on: #446
Problem
The required Layer-1 GitHub Actions workflow currently forces every Bazel job to
D2B_BAZEL_PROFILE=localwithD2B_BAZEL_UNTRUSTED=1. CI therefore cannot reuse the BuildBuddy cache or remote execution used by developers.The PR workflow is accepted for both
mainandv3. Any credential-bearing replacement must always execute workflow and bootstrap code from the default branch (main), regardless of the PR base branch, so an older or PR-modified workflow cannot control the privileged path.GitHub changed
pull_request_targetin December 2025 to always source workflow code and the default checkout from the repository default branch: https://github.blog/changelog/2025-11-07-actions-pull_request_target-and-environment-branch-protections-changes/That trigger alone is not sufficient. GitHub explicitly classifies checking out and executing untrusted PR code in a secret-bearing
pull_request_targetorworkflow_runjob as a pwn-request vulnerability: https://docs.github.com/en/actions/reference/security/securely-using-pull_request_targetScope
main, including for PRs targetingv3or any future protected branch.pull_request_targetplus PR-head checkout plusmakein a job that contains repository secrets or a privileged token.tests/tools/bazel-check, redirect the remote/BES endpoint, add authentication headers, or read the credential source.main/v3pushes remain the only seed authority.GITHUB_TOKENpermissions,persist-credentials: false, SHA-pinned actions, ephemeral runners, and no execution of PR-produced artifacts in a privileged follow-up workflow..bazelrc, the credential helper, endpoints, and PR metadata.Acceptance criteria
mainandv3use the workflow definition and trusted bootstrap frommain..bazelrc,tests/tools/bazel-check, tests, or build scripts cannot obtain the BuildBuddy credential, change the authenticated endpoint, write trusted cache entries, or gain repository write access.mainandv3can seed the trusted cache under the existing security-digest contract.checkresult and existing fixed Layer-1 target coverage remain unchanged.Depends on: #446