Skip to content

docs: document the repository settings behind the human gates - #169

Open
alejandro-llanes wants to merge 1 commit into
theam:mainfrom
alejandro-llanes:docs/repository-settings-behind-the-gates
Open

docs: document the repository settings behind the human gates#169
alejandro-llanes wants to merge 1 commit into
theam:mainfrom
alejandro-llanes:docs/repository-settings-behind-the-gates

Conversation

@alejandro-llanes

@alejandro-llanes alejandro-llanes commented Aug 16, 2026

Copy link
Copy Markdown

What changes

apps/docs/docs/reference/security.md gains a Repository settings that back the gates
section, placed immediately after The invariants that never move — the paragraph it
qualifies. For each setting it states the required value, whether Facility or the setting
enforces it
, and which advertised gate a skip breaks.

It covers the four areas the issue asks for — Actions approving pull requests, the default
GITHUB_TOKEN scope, default-branch protection and required checks, and who may merge or
bypass — plus stale-approval dismissal, which matters here specifically because the
address-review agent pushes commits to a pull request branch after a human has reviewed it.

Two subsections follow: which settings are readable through the GitHub API (endpoint and
field), and what facility doctor --github does not check yet, recorded as a follow-up
rather than implemented here.

Three guides link to it before the first agent run:

file where
guides/kickstart.md step 5, and again immediately before the /architect paragraph
guides/existing-repo.md Step 1 — import
reference/cli.md where doctor --run-guards --github is described, to state the boundary of what it checks

Documentation only. No code, no behaviour change.

Why

Closes #48.

The gap is easy to confirm: grepping the repository for approve pull requests,
can_approve, approving_review_count, enforce_admins or restrictions returns nothing.
The setting Allow GitHub Actions to create and approve pull requests is not mentioned
anywhere, and the existing guidance ("protect the default branch, require a human review")
names no setting and assigns no ownership.

That matters because the invariants lean on repository configuration more than the docs
admit:

  • facility-review.yml states it "never approves or merges" — but that is a prompt, and
    the job runs with pull-requests: write. The hard stop is
    can_approve_pull_request_reviews: false.
  • Never push to protected branches is vacuous on an unprotected default branch, and
    facility-address-review.yml and facility-doctor.yml hold contents: write.
  • The GitHub App installation holds Contents: Read and write, so a bypass entry on
    required pull requests converts that into merge authority.

So a repository can run the whole loop, look correct, and still let an automated actor
satisfy a human gate — which is exactly what the issue describes.

Verification

Every API claim in the new section was probed against the live GitHub API rather than
written from memory:

probe result
GET /repos/{owner}/{repo}/actions/permissions/workflow returns both settings in one call: {"default_workflow_permissions":"read","can_approve_pull_request_reviews":false}
GET /orgs/{org}/actions/permissions/workflow 403 without org admin and the admin:org scope
GET /repos/{owner}/{repo}/branches/{branch}/protection 404 "Branch not protected" as an admin on an unprotected branch, but 404 "Not Found" without admin — two different meanings, same status code
GET /repos/{owner}/{repo}/rules/branches/{branch} answers without admin, so it works where the protection endpoint cannot

Those last two are why the doctor follow-up list is specific: the command currently treats
any non-zero exit as a failure, so a branch protected by a ruleset and a caller who simply
lacks admin both report the same way as a genuinely unprotected branch — and the protection
response it already fetches is never parsed.

Commands run:

node guards/run.mjs                  # actions-pinned, markdown-links — 2 passed, 0 failed
pnpm --filter @facility/docs test    # 12 passed, 0 failed (includes the Pages build)
pnpm verify                          # see below

The docs build runs under onBrokenLinks: "throw", so the four new relative links are
verified rather than assumed. Because the guides link to an anchor and onBrokenAnchors
only warns, I checked the built output directly instead of trusting the slug rule:
id="repository-settings-that-back-the-gates" is present in reference/security/index.html,
and guides/kickstart, guides/existing-repo and reference/cli all emit links pointing at
it.

On pnpm verify

It completed Lint, Typecheck, the clean cache-disabled workspace build, isolated Postgres,
both test-database recreations, and the critical integration tests, then exited 1 in the
final stage on a single test:

FAIL runner/test/docker-proxy.test.ts > restricted Docker API
     > forwards a Docker exec upgrade body before waiting for 101
Error: Test timed out in 5000ms.        (then afterEach: Hook timed out in 10000ms)

Test Files  1 failed | 11 passed (12)
     Tests  1 failed | 168 passed (169)

This is pre-existing and unrelated to this pull request. I confirmed it rather than
assuming: checking out unmodified main at ae68401 and running that file alone reproduces
the same failure, same test, same timeout —

× forwards a Docker exec upgrade body before waiting for 101  15011ms
Test Files  1 failed (1)
     Tests  1 failed | 24 passed (25)

It looks environment-dependent (a Unix-socket upgrade handshake that never receives its
101), so it may well be green in CI — flagging it only so the failing run below isn't
mistaken for something this branch introduced. Nothing in this diff is reachable from
runner/; the change is four Markdown files under apps/docs/.

  • pnpm verify passes locally — runs green except the pre-existing
    docker-proxy timeout documented above, which also fails on clean main
  • Behaviour verified beyond the test suite (say how)
  • Documentation updated, or no user-facing change

Facility claims agents never approve, never merge, and never push to
protected branches. Part of that is enforced by the product; the rest is
GitHub repository configuration, and the docs never said which was which.
A repository could run the whole loop, look correct, and still let an
automated actor satisfy a human gate.

Add a section to the security reference, immediately after the invariants
it qualifies, stating per setting what it must be, whether Facility or the
setting enforces it, and which advertised gate a skip breaks. It covers
Actions approving pull requests, the default GITHUB_TOKEN scope,
default-branch protection and required checks, and who may merge or bypass.

Record which settings are readable through the API, and note what
`facility doctor --github` does not check yet: the branch-protection
response it already fetches is never parsed, and a branch protected by a
ruleset is reported as a failure.

Link it from kickstart and the existing-repo guide before the first agent
run, and from the CLI reference where `doctor` is described.

Closes theam#48

@adrian-lorenzo adrian-lorenzo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for putting this together!

The checklist is useful, but the API section cannot currently verify the bypass guarantee it asks operators to enforce. Under classic branch protection, restrictions covers who can push; pull-request bypass actors live in required_pull_request_reviews.bypass_pull_request_allowances. For rulesets, /rules/branches/{branch} returns active rules but not the ruleset’s bypass_actors; those require fetching each ruleset, and GitHub only exposes them when the caller has sufficient access.

Please point readers to the correct fields and endpoints, make the result explicitly unknown when permissions hide bypass actors, and clarify that admin:org is the classic-token requirement—fine-grained and App tokens use the organization Administration permission.

Once those distinctions are reflected in the guidance, this will be ready to approve.

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.

Document the repository settings that back the human gates

2 participants