Skip to content

Auto-merge: close the ci.yml self-edit hole (a required status check, not CODEOWNERS) #344

Description

@agentiknet

Follow-up to #343, which fixed three real problems in the auto-merge job but left one hole that code cannot close.

The hole

For pull_request, GitHub runs the workflow from the PR's merged tree. So a PR that edits .github/workflows/ci.yml runs its own edited version — including the self-modification guard added in #343. A PR can delete the guard and the deleted guard is the one that would have caught it.

Everything else in #343 (base-pinned policy, var-only enable) holds. This is specifically about ci.yml policing itself.

Realistic threat here isn't an attacker. Fork PRs can't reach BOT_APP_PRIVATE_KEY, so agent-setup fails and the job can't act. It's our own agents opening branch PRs — an agent asked to "fix CI" could plausibly rewrite the guard without malice, and the only remaining gate is the agentic reviewer's APPROVED, which is another LLM.

Why CODEOWNERS is the wrong fix here

The obvious answer is CODEOWNERS + "Require review from Code Owners" on .github/**. It does not work for this repo.

agentiknet is the only collaborator, and GitHub does not allow approving your own PR. Requiring code-owner review would mean no .github/** change could ever be merged except by admin bypass — which makes the control theatre, since bypass is exactly what would be used every time.

A two-person control needs two people. Noting this explicitly because it's the first thing anyone (including me) reaches for.

What would actually work: a required status check

Rulesets can require a named status check to pass. A required check that never reports leaves the PR blocked. So:

  1. Split the guard into its own job with a stable name, e.g. policy-guard, that always runs on pull_request.
  2. Mark policy-guard a required check in the ruleset protecting main.
  3. A PR that deletes or renames the job → the required check never reports → merge blocked, no human needed.

The ruleset lives in repo settings, out of a PR's reach. This is the same principle as #343's vars.AGENTFLOW_AUTOMERGE: the thing that enforces must live where the PR cannot edit it.

Caveat to verify when implementing: confirm the blocked-on-missing-check behaviour against admin bypass, and decide whether agentiknet should retain bypass (probably yes for emergencies, but then it's advisory for humans and binding for bots — which is precisely the desired split).

Also worth deciding

vars.AGENTFLOW_AUTOMERGE=true is currently set. After #343 it is the only thing that enables auto-merge. Worth a conscious decision on whether LLM-approval-driven auto-merge is wanted at all, rather than leaving it on because it was on. Turning the var off is a one-click, zero-code kill switch.

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions