Record default-branch protection as a B2 requirement
B2 specified the service account and its scoped token but never said the project repo's default branch must be protected — which turns out to be the load-bearing part of the PR gate. In Gitea, write access includes merging pull requests, and repository ownership does not restrict merging either. So an agent with the access it needs to push branches can also merge its own PR, and the review gate holds only because the agent's code does not call the merge endpoint. That is the advisory guarantee A4 exists to rule out. Verified rather than assumed: before protection was configured, the agent's own token merged its own PR (HTTP 200). With protection it is refused (405), as is a direct push to the default branch. The amendment says to assert both, so relaxing the protection later fails a test instead of silently removing the gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
914bc26221
commit
846e5494ca
1 file changed
+19
@@ -550,6 +550,25 @@ PR_OPEN
|
|||||||
- *Outbound:* `git` + Gitea API to push branches and open PRs, via a dedicated
|
- *Outbound:* `git` + Gitea API to push branches and open PRs, via a dedicated
|
||||||
Gitea **service account** with a scoped token. Record any runnable test service's
|
Gitea **service account** with a scoped token. Record any runnable test service's
|
||||||
URL/port in the PR description.
|
URL/port in the PR description.
|
||||||
|
- **The project repo's default branch must be protected, and this is what makes
|
||||||
|
the PR gate real.** The service account needs write access to push branches —
|
||||||
|
and in Gitea, *write access includes merging pull requests*. Repository
|
||||||
|
ownership does not help: an account that merely collaborates can still merge,
|
||||||
|
and one that owns the repo can merge and delete it. So without branch
|
||||||
|
protection the agent can merge its own PR, and the review gate holds only
|
||||||
|
because the agent's code does not call the merge endpoint. That is precisely
|
||||||
|
the advisory guarantee A4 exists to rule out.
|
||||||
|
- Required on the default branch: **block direct pushes** by the agent
|
||||||
|
account, and **restrict merging** to the operator (a merge whitelist, or
|
||||||
|
required approvals that the agent's own account cannot satisfy).
|
||||||
|
- Feature-branch pushes are unaffected, so the agent's normal workflow is
|
||||||
|
unchanged.
|
||||||
|
- **Verify it rather than assume it.** The property is observable from
|
||||||
|
outside: the agent's own token must be refused when it attempts to merge
|
||||||
|
its own PR and when it pushes to the default branch. Assert both, so that
|
||||||
|
relaxing the protection later fails a test instead of silently removing
|
||||||
|
the gate. (Discovered the hard way — before protection was configured, the
|
||||||
|
agent's token merged its own PR successfully.)
|
||||||
- *Inbound:* react to PR comments, commits, pushes. **Poll** the Gitea API
|
- *Inbound:* react to PR comments, commits, pushes. **Poll** the Gitea API
|
||||||
(15–30s) rather than take webhooks, to keep the VM outbound-only. Intake is
|
(15–30s) rather than take webhooks, to keep the VM outbound-only. Intake is
|
||||||
structured JSON — never via a chat bridge.
|
structured JSON — never via a chat bridge.
|
||||||
|
|||||||
Reference in new issue
Block a user