Skip to content

fix(tooling): keep GitHub App auth when the agent gh shim delegates - #373

Merged
patroza merged 1 commit into
fork/devfrom
fix/gh-app-auth-in-agent-shim
Aug 7, 2026
Merged

fix(tooling): keep GitHub App auth when the agent gh shim delegates#373
patroza merged 1 commit into
fork/devfrom
fix/gh-app-auth-in-agent-shim

Conversation

@omegent-app

@omegent-app omegent-app Bot commented Aug 7, 2026

Copy link
Copy Markdown

PR badges stopped appearing in sidebar v2 for active threads, while settled rows kept theirs.
Root-caused on the running server, fix verified against the exact failing invocation.

What was happening

The server's VCS shell-outs resolve gh through each repo's .tools/bin — the agent policy shim
installed by scripts/install-git-hooks.mjs. Caught live off the server process:

CMD=node /var/lib/t3/deploy/t3code/scripts/agent-gh.mjs pr list --head release-cut-mako-easylife \
    --state all --limit 20 --json number,title,url,...

That shim resolves the binary to delegate to via findRealGh, which preferred $T3_GITHUB_REAL_GH
above everything else. That variable names the unauthenticated gh — the binary the GitHub App
wrapper execs after minting an installation token. The host exports it (see the server start
script: "still export REAL_GH / token paths so children that reorder PATH cannot lose minting
config"
) as configuration for the wrapper, not as an authenticated entry point.

So the shim skipped minting entirely and ran raw gh:

$ env -i $(server env) .tools/bin/gh pr list --head release-cut-mako-easylife --state all ...
To get started with GitHub CLI, please run:  gh auth login
exit=4

Exit 4 → SourceControlProviderError → the warning that has been filling the journal every 45s:

WARN: PR lookup failed; keeping last known PR state.  operation: lookupStatusPr
      errorTag: SourceControlProviderError   branch: release-cut-mako-easylife

Why settled rows still showed badges

That asymmetry is the tell. Settled worktrees take the durable settle freeze added in #362, which
returns resolveLastKnownPr(...) without calling the provider at all. A frozen row can't fail a
lookup it never makes. Every active row goes down the live path, hits the auth failure, and falls
back to a last-known value that is empty — so the card renders with no badge.

Introduced by 2ef070919 (2026-08-02, "enforce repository-owned agent ship gates"), which added the
T3_GITHUB_REAL_GH branch to findRealGh.

The fix

Resolution order becomes:

  1. AGENT_GH_REAL — this shim's own re-entry override, unchanged.
  2. PATH — where the App-aware gh lives.
  3. T3_GITHUB_REAL_GH — last resort only, so hosts without a wrapper still work.

Verification

The same command that returned exit 4, under the server's exact environment, after the change:

$ .tools/bin/gh pr list --head sync/upstream-48aa875c0 --state all --limit 5 --json number,state
[{"number":372,"state":"MERGED"}]

Regression test added to scripts/agent-pre-push.test.mjs pinning all three tiers of the order; it
fails on the pre-fix implementation and passes after. Full file: 26 tests pass.

The deploy checkout was patched only to prove the fix live and has been restored to its released
state, so the fleet stays consistent with its deployed SHA until this lands.

Co-authored by @patroza

opened by Patrick Roza in chat thread Discord · Discord · T3

`findRealGh` preferred `$T3_GITHUB_REAL_GH` over anything on PATH. That
variable names the *unauthenticated* gh binary the GitHub App wrapper execs
after it mints an installation token; hosts export it so a child that reorders
PATH keeps minting config, not as an authenticated entry point. Delegating
straight to it skipped minting, so every `gh` call the shim fronted failed with
"gh auth login".

Server-side that is invisible: the VCS spawn PATH includes each repo's
`.tools/bin`, so `gh pr list` resolved to this shim, got exit 4, and surfaced as
`SourceControlProviderError` behind "PR lookup failed; keeping last known PR
state." Sidebar rows then render without a PR badge, while settled rows keep
showing one because the settle freeze serves the last known value instead of
looking up.

Resolution order is now: AGENT_GH_REAL (this shim's own re-entry override) →
PATH (the App-aware `gh`) → T3_GITHUB_REAL_GH as a last resort, so hosts without
a wrapper still work.

Verified against the exact failing invocation on the running server:
`gh pr list --head <branch> --state all` under the server's environment goes
from exit 4 to exit 0, returning the PR.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 1e80411 into fork/dev Aug 7, 2026
4 checks passed
patroza added a commit that referenced this pull request Aug 15, 2026
## Summary

The PR panel mapped every unclassified `gh` exit to **GitHub CLI command
failed.**, so the real guest-wrapper reason never reached the UI.

That is what `pingdotgg#6613` (`pingdotgg/t3code`) showed this time. The live
t3vm image already has ops #80 (host-qualified `--repo`). The product
`#373` shim fix is still on `fork/dev`. App-only mint dies with:

```
t3-github-app-token: app is not installed on pingdotgg/t3code (or repo does not exist)
```

The App is installed on `patroza` / `macs-holding` / `effect-app` /
`aaaomega` — not `pingdotgg`.

This change passes through guest wrapper lines (`t3-github-app-token:` /
`gh-app-wrapper:`) as the command-failed detail, and keeps raw provider
stderr off the VCS error message (tokens stay out of logs).

Installing the App on `pingdotgg` (or using a user/SSH token for those
reads) is still required for the panel to actually load that PR.

## Test plan

- [x] `vp test run apps/server/src/vcs/VcsProcess.test.ts
apps/server/src/sourceControl/GitHubCli.test.ts`
- [ ] After deploy: open a PR the App is not installed on and confirm
the panel shows `app is not installed on …` instead of the generic CLI
line
- [ ] Confirm a `patroza/t3code` PR still loads on t3vm

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
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.

1 participant