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
Proposed work class: work-class: structural
Basis: automated intake triage; the lanes App applied this class.
Size: Large
Complexity: High
Uncertainty: Knowable
Flags: intent
Blocked by: none
Understood: agent sessions should act as their own GitHub App identity, not the owner's login, so a trusted account proves a person wrote the text. The owner's 2026-10-17 revisions are the current design: a new App, a dedicated WSL distro for unattended lanes, and a vault-signed token broker. The work spans dotfiles, this repo (babysit self_logins, a guardrails rule, ratification tests), architecture and github-iac.
One question stays open in the comments and needs an owner answer:
AUTOMATION_LANES_APP_SENDER_ID, so review lanes review the App's pushes? RECOMMENDED: no, because decision 4 keeps agent-session PRs out of unattended merge, and review lanes can be added later. Basis: least privilege and the least change to the lanes' trust set.Also unchecked: commit signing on
requires-signingrepos, and the commit author format. No duplicates found.Automated triage, applied by the lanes App.
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.kyle-sexton commentedon Oct 25, 2026
Released for re-triage under the owner's 2026-10-24 rule: an issue stops for a person only for an intent or vision question, a security call, a host or attended run, or spend outside prepaid credit. The hold label came off and intake triage runs again now; it re-applies a hold, with a numbered question, when one of those applies.
To hold this issue again, add
needs-human(orstatus: needs-decision) and say why in a comment.melodic-automation-lanes commentedon Oct 25, 2026
The triage verdict left this issue at
status: needs-decision:melodic-automation-lanes commentedon Oct 25, 2026
Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.
Intended outcome: Agent sessions act as a new, separate GitHub App through a vault-signed token broker with isolated credentials, and this repo gets the babysit self_logins entry, a guardrails rule and ratification tests.
Dependencies
Related work
Open questions
RECOMMENDED: No. Decision 4 keeps agent-session PRs out of unattended merge, and review lanes can be added later. Basis: judgment
RECOMMENDED: Split the repo-local work into its own issue: the babysit self_logins default, a guardrails rule against gh auth switches and unsetting GH_TOKEN, and ratification tests refusing an App-posted marker. Keep registration, the distro and the live probes as owner or host checks. Basis: judgment
RECOMMENDED: Wait for the App to be registered, then record the login and numeric id in the issue before the lane starts. Basis: judgment
RECOMMENDED: Probe both after the App exists and record the result before the dotfiles helper sets the git author. Basis: judgment
Sources read
Automated refinement by the lanes App. Answer with a comment whose first line is
**Decision recorded.**.