Repository navigation
security: give agent sessions their own GitHub App identity before unattended merge #7711
Description
Parent
Refs #7570 (thread: Merge authority and verifier), #7709 item 10 (decided by the owner on 2026-10-17: agent sessions get their own GitHub identity before report-only flips). Research: .work/poteto-review/design/agent-identity-research.md in the owner's checkout; GitHub docs fetched 2026-10-17.
Problem
The verifier's trusted-spec check and the admission marker rule (D33) trust any issue or comment from an account on trusted-actors.json. Agent sessions run gh with the owner's login (an OAuth gho_ token), so whatever they post reads as the owner's. The marker check (ratification.mjs) accepts a comment from a listed human, not posted through an App, and never edited. An agent posting as the owner passes all three tests. A trusted account therefore proves the account, not that a person wrote or reviewed the text.
Proposal
Agent sessions act as a GitHub App of their own, separate from the lanes App, using one-hour installation tokens minted per session. Reuse the dormant melodic-ai App: it has received zero events, its key is already in the estate's GitHub key vault, and dotfiles user-env.yaml:30 lists it with no local consumer. kyle-sexton stays the only kind: human trusted actor. The App is listed only as kind: bot, and only where a trigger has to accept it.
Why an App, not a machine user:
- Two gates decide "human" by account type: babysit's
is_human(babysit_merge_policy.py:735-760) and the pr-merge labeler rule (pr-pipeline/README.md:432-435). A machine user is aUserand would pass both as human. An App is aBotand already fails both. - A machine user needs an org seat, because an outside collaborator cannot use a fine-grained PAT. The org's one seat is filled. Apps take no seat, and GitHub's PAT docs point organization automation to Apps.
- GitHub's Terms allow one free machine account per person, created by that person, who is responsible for what it does.
What it closes beyond the spec check:
- Sessions can no longer post a valid admission marker. That is intended, and the code needs no change.
- github-iac ADR 0015 accepted risk 2: the App holds no org-admin role, so a session cannot merge with
--admin.
Owner decisions
- App: reuse
melodic-ai(recommended) or register a new one. Either way: no administration permission, installed on selected repositories with azure-iac excluded (ADR 0015 trigger 5: there it could mint lane tokens), a new key generated and the old one retired. - Token isolation: without it, an agent can unset
GH_TOKENand act as the owner again, so the App changes the credit, not the reach. Recommended: unattended lanes run as a separate OS user that cannot read the owner's token. Interactive sessions get a separateGH_CONFIG_DIR, plus a guardrails rule that deniesgh authswitches and unsettingGH_TOKEN. Basis: judgment, since interactive sessions have the owner present. - Key handling: sign the App JWT inside the vault, the azure-iac broker pattern, so the key never reaches a host (recommended). The alternative is
vault-exec, which hands the key to the host process. Basis: GitHub's App key guidance, and the existing broker pattern. - Merge-lane eligibility: PRs from agent sessions stay out of unattended merge (
not-lane-authoredis unchanged); recommended. The lanes App remains the only unattended author. - Required review for agent PRs: github-iac ADR 0007 revisit trigger 3 fires, because an owner approval becomes a real second review. Recommended: record it and defer. The verifier is the gate for lane PRs.
Agent-doable work, as draft PRs after the decisions
- dotfiles: a token mint helper and session launcher (bash and PowerShell) that set
GH_TOKEN,GH_CONFIG_DIRand the git author. - claude-code-plugins: the App login in babysit's
self_loginsdefault; a guardrails rule against identity switches; ratification tests proving an App-posted marker is refused. - architecture: a trust-link entry and an ADR; amendments to github-iac ADR 0015 and ADR 0007.
- Post-cutover probes: a session's issue reads as the App, and its marker does not admit.
- Not yet checked: commit signing on
requires-signingrepos, and the commit author format.
Done when
- The owner settles decisions 1-5.
- An interactive and an unattended session each post an issue that reads as the App, and neither can act as the owner (probe recorded).
- An App-posted admission marker does not admit (test plus live probe).
- source-control: settle the verifier verdict follow-ups before report-only flips #7709 item 10 is closed with a pointer here.
Activity
github-actions commentedon Oct 17, 2026
Thanks for the report. Automated triage handed this issue to a maintainer.
Proposed work class: work-class: structural
Basis: automated intake triage; a maintainer confirms or changes it.
Automated triage. A maintainer reviews it.
kyle-sexton commentedon Oct 17, 2026
Decision 1 (owner, 2026-10-17): reuse
melodic-ai; register no new App. The owner prefers fewer Apps. A machine user would need a second paid seat and would pass the account-type human checks. The lanes App's key must stay in the cloud broker (github-iac ADR 0015). So the existing dormant App is the only identity that separates agents from the owner without adding one. Decisions 2-5 remain open.kyle-sexton commentedon Oct 17, 2026
Decisions 2-5 (owner, 2026-10-17, 'go with recommended'): (2) unattended lanes run as a separate OS user that cannot read the owner's gh token; interactive sessions get their own GH_CONFIG_DIR plus a guardrails rule denying gh auth switches and unsetting GH_TOKEN. (3) The App JWT is signed inside the vault, the azure-iac broker pattern; the private key never reaches a host. (4) PRs from agent sessions stay out of unattended merge; the lanes App remains the only unattended author. (5) ADR 0007 revisit trigger 3 is recorded and deferred; the verifier is the gate for lane PRs.
kyle-sexton commentedon Oct 17, 2026
Decisions revised (owner, 2026-10-17, in the Automation Lanes session, after that session's design research):
melodic-aiis live (a medley workflow mints it from org secrets), so it stays medley's. The new App's key is generated into Key Vault only.The interface stands: a separate function, POST /token narrowing repositories (up to 500) and permissions, a one-hour token, no cache, fail closed. Automation Lanes owns the azure-iac function and the shared signing package. This session owns the dotfiles helper (git author = the new App's bot), the guardrails rule, babysit self_logins and the ratification tests.
kyle-sexton commentedon Oct 20, 2026
github-iac's share of the new agent App, carried here because https://github.com/melodic-software/github-iac/issues/691 was closed as superseded by this issue: once the App is registered, github-iac needs (1) a row in the README installed-apps table (synced with live installations in https://github.com/melodic-software/github-iac/pull/717), (2) its install scope recorded (selected repositories, excluding azure-iac, unless this issue decides otherwise), (3) a trust-links entry in melodic-software/architecture, and (4) a decision on whether its bot id joins
AUTOMATION_LANES_APP_SENDER_ID(open here: should review lanes review the new App's pushes?). #691's permission list (contents: read; pull requests: write; issues: write; actions: write; variables: read) is a starting point, not contradicted by the 2026-10-17 decisions; only its per-host token delivery is.