Skip to content

fix(github): support installation tokens across source control workflows - #21184

Closed
rickbassham wants to merge 14 commits into
pingdotgg:mainfrom
rickbassham:fix/github-app-installation-auth
Closed

rickbassham wants to merge 14 commits into
pingdotgg:mainfrom
rickbassham:fix/github-app-installation-auth

Conversation

@rickbassham

@rickbassham rickbassham commented Oct 18, 2026 •

Copy link
Copy Markdown

GitHub App installation tokens fail REST identity verification, and GraphQL Bot slugs can be confused with humans sharing that slug. This completes @rickbassham's original #21184, preserving the contributor commits and merging current main without rewriting the fork branch.

The rebuilt identity reader falls back from REST /user 403 to a typed GraphQL viewer using the captured credential. Actual Bot actors get canonical names at the decoder boundary; same-slug humans keep their identity across listings, activity, reactions and reviewer requests. Clone, create and fork-PR workflows pin credentials, honor explicit destination hosts, infer an App installation owner from paginated repository metadata, and require an explicit owner when inference is inconclusive. App repository creation verifies the owner and sends one mutation, reporting refusal or possible partial success without retrying. App fork PRs disable maintainer modification.

App identities have no automatic new-project publish target. Manual publishing leaves the Bot owner empty. The dialog now uses each provider's existing owner rule, so Bitbucket/Azure prefills also become blank. Existing human Enterprise and self-hosted GitLab publishing targets are preserved. Discovery retains Enterprise-only authentication and prefers a valid public CLI identity over an unrelated saved Enterprise token.

Verification at 3d5dcadb8c:

  • Tests reduced from 34 added cases in seven files to 14 in two existing GitHub files, with existing client/provider cases extended and all 556 baseline cases preserved. Selected suite: 590 cases before, 570/570 passing after across eight files. The human/Bot regression failed before repair; a temporary main API negative control also failed installation identity verification before byte-checked restoration.
  • Scoped GitHub/server/client-runtime/web typechecks, targeted lint, formatting and GitHub export checks pass. One existing array-find lint warning remains.
  • Four fresh whole-PR review rounds with Claude Opus 5.5 and Codex GPT-6-Sol. Confirmed reviewer-identity, creation-error, discovery and Enterprise publishing regressions were repaired; the final round has no blockers.
  • The primary agent ran the actual isolated server through HTTP authentication and WebSocket RPC: 16/16 assertions pass for captured credentials, typed identity fallback, authored listing, and same-slug human/Bot activity and reviewer candidates. External GitHub and gh responses were synthetic. Current-head API proof; before/after details and limits.

No visual or native-client verification is claimed. T3 browser attempts failed with Preview automation snapshot timed out after 15000ms. and Preview automation navigate timed out after 15000ms.; the authorized API/test fallback was used. macOS, Windows, iOS, Android and Electron shell behavior were not exercised.

Before approval, a maintainer should use real installation credentials for listing/detail, reviewer changes, fork PRs, clone and permitted personal/organization creation; check repository-limited token partial-creation recovery and expiry/replacement. Token issuance/renewal and Git HTTPS/SSH authentication remain external. A saved token's identity can still be labeled as a gh login in web Settings. A saved human Enterprise token without GH_HOST can expose the existing failing automatic public-host publish option; use an explicit Enterprise destination. This PR makes no new generic publishing-host guarantee.

Current-head CI is green: lint, build/typecheck, all eight server shards, general tests, web tests and native fingerprint pass. The first run hit an Electron download DNS error and two browser timing failures; both browser suites passed locally (6/6 actual Chromium tests), and one failed-job retry passed. Normal preview/native/release jobs skipped. CodeRabbit status is successful with no review threads; its narrative still describes the contributor head. Four independent whole-PR review rounds cover the current implementation. Authentication scope requires human review and live App verification remains; this is unmerged.

Models/harness: fresh Codex GPT-6-Astra tests, Codex GPT-6.1-Sol implementation, independent Claude Opus 5.5 and Codex GPT-6-Sol reviews through T3 Code; primary integration through the Codex harness.

@github-actions github-actions Bot added vouch:unvouched Author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Oct 18, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This PR substantially broadens GitHub authentication support across discovery, PR operations, cloning, publishing, and repository creation, including new GraphQL mutations and credential-handling paths. The sensitive, cross-cutting runtime and product-default changes warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between c7faef8 and 08db7b4.

Files selected for processing: 17
  • apps/web/src/components/GitActionsControl.tsx
  • docs/user/source-control.md
  • packages/client-runtime/src/operations/projects.test.ts
  • packages/source-control-github/graphql.config.ts
  • packages/source-control-github/src/server/GitHubCredentials.ts
  • packages/source-control-github/src/server/GitHubPullRequestApi.test.ts
  • packages/source-control-github/src/server/GitHubPullRequestApi.ts
  • packages/source-control-github/src/server/GitHubPullRequestProvider.test.ts
  • packages/source-control-github/src/server/GitHubPullRequestProvider.ts
  • packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts
  • packages/source-control-github/src/server/GitHubSourceControlProvider.ts
  • packages/source-control-github/src/server/gitHubDiscovery.test.ts
  • packages/source-control-github/src/server/gitHubPullRequestJson.ts
  • packages/source-control-github/src/server/gitHubViewer.ts
  • packages/source-control-github/src/server/pullRequestListings.graphql
  • packages/source-control-github/src/server/pullRequestListings.graphql.ts
  • packages/source-control-github/src/shared/definition.ts
Files skipped from review as they are similar to previous changes: 1
  • docs/user/source-control.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

Walkthrough

The GitHub provider adds App-token discovery and viewer verification, installation-owner lookup and repository creation, and bot-aware pull request identity handling. Repository publishing and clone operations use host-specific credentials. Documentation and tests cover these changes.

Changes: GitHub App support

Layer / File(s) Summary
Viewer identity and bot-aware actors
packages/source-control-github/src/server/gitHubViewer.ts, packages/source-control-github/src/server/GitHubPullRequestApi.ts, packages/source-control-github/src/server/gitHubPullRequestJson.ts, packages/source-control-github/src/server/pullRequestListings.graphql*, packages/source-control-github/src/server/GitHubPullRequestProvider.ts, packages/source-control-github/src/server/GitHubPullRequestApi.test.ts, packages/source-control-github/src/server/GitHubPullRequestProvider.test.ts
A shared viewer reader falls back to GraphQL after a REST 403. Bot logins are normalized across actor, reviewer, and avatar mapping. Review-thread results no longer include a separate bot-login set.
Credential refresh and host discovery
packages/source-control-github/src/server/GitHubCredentials.ts, packages/source-control-github/src/server/GitHubSourceControlProvider.ts, packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts, packages/source-control-github/src/server/gitHubDiscovery.test.ts
Environment-token variable selection is exposed separately from token reading. Provider discovery checks eligible hosts and prioritizes authentication according to the configured default host and discovery results.
Installation repository lookup and publishing
packages/source-control-github/schema/github.graphql.ts, packages/source-control-github/graphql.config.ts, packages/source-control-github/src/server/sourceControlProvider.graphql*, packages/source-control-github/src/server/GitHubSourceControlProvider.ts, packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts, packages/source-control-github/src/shared/definition.ts, apps/web/src/components/GitActionsControl.tsx, packages/client-runtime/src/operations/projects.test.ts, docs/user/source-control.md
GraphQL operations look up installation owners and create repositories. Bot accounts use installation-owner resolution, and publish-target selection excludes bot accounts as owners. The publish dialog uses the selected provider’s owner result. Documentation describes App-token use and limitations.
Pinned GitHub operations and API coverage
packages/source-control-github/src/server/GitHubSourceControlProvider.ts, packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts, packages/source-control-github/src/server/GitHubPullRequestApi.test.ts
Pull request creation pins credentials and sets fork maintainer-edit permissions based on the viewer. Clone URL lookup selects credentials for the explicit repository host. Tests cover listing fallback, quota handling, and reviewer request endpoints.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant GitHubSourceControlProvider
  participant GitHubCredentials
  participant GitHubREST
  participant GitHubGraphQL
  GitHubSourceControlProvider->>GitHubCredentials: Get credential for selected host
  GitHubSourceControlProvider->>GitHubREST: List installation repositories
  GitHubSourceControlProvider->>GitHubGraphQL: Resolve owner by login
  GitHubGraphQL-->>GitHubSourceControlProvider: Return owner ID
  GitHubSourceControlProvider->>GitHubGraphQL: Create repository with owner ID and visibility
  GitHubGraphQL-->>GitHubSourceControlProvider: Return repository URLs
Loading

Possibly related issues

  • pingdotgg/t3code#14939: The changes select credentials using the explicit repository host during clone URL lookup, matching the issue’s reported host-selection objective.

Suggested reviewers: juliusmarminge

Merge Risk: Minimal · up to 08db7

This change adds GitHub App installation-token support for identity checks, Bot and human actor separation, clone and repository creation, and fork pull requests. No concrete merge-blocking defect was found in the supplied evidence. Maintainers should still smoke-test with real installation credentials, as the author suggests.

Security architecture risk: Low · up to c7fae

Installation tokens gain working access to existing GitHub workflows, but credentials remain bound to a host and repository creation verifies the destination owner. No material security regression was established. Token expiration and interrupted creation still require operational care.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The effective authority is the configured credential's GitHub access, potentially covering all repositories available to an installation and repository creation where granted. This PR makes that authority usable through existing workflows; it does not mint broader credentials. Git clone, fetch, and push retain a separate authentication dependency.

Trust Boundaries and Controls

  • observed — Repository selectors can choose a destination host and owner, but credential lookup is host-keyed and a pinned credential rejects a different host. Saved tokens retain precedence over environment and CLI credentials; enterprise environment tokens remain restricted to GH_HOST. Owner lookup data must match the requested login before creation.

Resilience and Maintainability Implications

  • observed — Credential-pinning regression coverage changes the credential source during creation and verifies that identity, owner lookup, and mutation continue using the captured credential. A separate test verifies that missing creation details do not trigger another mutation. These checks support identity consistency, but do not establish recovery after cancellation or an external commit followed by connection loss.
Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary change: supporting GitHub App installation tokens across source control workflows.
Description check Passed The description is detailed and covers the problem, implementation scope, verification results, limitations, and required maintainer checks. It is substantially complete and directly aligned with the …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and covers the problem, implementation scope, verification results, limitations, and required maintainer checks. It is substantially complete and directly aligned with the pull request objectives.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@juliusmarminge juliusmarminge self-assigned this Oct 19, 2026
@juliusmarminge

Copy link
Copy Markdown
Member

Taking over this one as maintainer for batch pull-request-14. I’ll keep this as a focused fix on the original PR, reduce the tests to the essential installation-token workflows, rebuild against current main, and verify identity fallback and bot/human separation before publishing. Thanks @rickbassham for tracing the App identity, fork-PR and repository-creation behavior.

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

updated the original branch at 08db7b4c4dedccc54e99b7a1301842b79bfb1a97, preserving @rickbassham's commits and merging main (4e42eaf429). thanks for the installation-token implementation. the fix keeps discovery, clone/create and fork-pr support, while canonicalizing actual bot actors before comparing identities so same-slug humans remain distinct.

i reused main's existing viewer query, moved the bot publish-owner rule to the shared provider definition, preserved main's commit statistics and tracing, and removed obsolete duplicate tests. no new test files.

verification:

  • main negative controls reproduce the exact rest 403 on bare-name clone, bot/human reviewer conflation, incorrect fork-edit permission, and the bot publish owner. the fixed cases pass.
  • blacksmith vp run check:changed passes: 268 tests in 11 files, typechecking for ten affected packages, lint, formatting, knip and graphql generation.
  • all 27 current-head checks are green. coderabbit reports no actionable findings.
  • two independent code reviews approve this exact head with no findings.
  • system chrome exercised the real client's github provider selection and publish dialog with the available human account. matching main/branch captures below prove the human prefix is preserved; they do not prove the bot ui state.

unverified: real installation-token operations, expiry/replacement, new-repository permission/partial-creation recovery, and native clients. @rickbassham, real app-token confirmation would help close those external verification gaps. human approval is still required for the authentication scope.

main: human github publish prefix

updated pr: human github publish prefix preserved

@rickbassham

Copy link
Copy Markdown
Author

Tested the updated PR head with a real GitHub App installation token on 2026-10-26.

Version/environment: 08db7b4c4dedccc54e99b7a1301842b79bfb1a97, T3 0.1.2, Linux ARM64, Node 24.22.1. Built the web/server and native runtime from a clean checkout, then verified the deployed revision and server bundle SHA-256 (9a7278679696f93212c468bca50115ca39814b85cf086421ce1a35ac2af86b59). This ran in a disposable instance with its own home/workspace and a separate test credential broker.

Authentication: the dark-dragons-orchestrator[bot] App installation for darkdragonsastro, using T3's dynamic gh auth token credential source; no saved human token or GH_TOKEN override. The host grant was contents/write, pull_requests/write, metadata/read, checks/read, statuses/read, and actions/read. No administration grant was added.

Passed through the running T3 application, using its normal HTTP/WebSocket APIs:

  • Authenticated GitHub discovery and bot routing identity.
  • Bare-name repository lookup and HTTPS clone of t3code-app-workflow-compat-20261018, resolving the organization owner correctly.
  • PR listing, details, reviewer candidates, and an actual successful workflow check from fixture PR #3.
  • T3's push action followed by PR creation: App-authored fixture PR #5. The synthetic commit is also attributed to the App bot.
  • Cross-fork PR creation using an existing public branch on my personal fork: App-authored fixture PR #6. GitHub confirms isCrossRepository: true and maintainerCanModify: false. This required no installation-token write to the personal fork.
  • Revocation/replacement recovery: warmed the running application's credential, revoked only that isolated test token with GitHub's installation-token revocation endpoint, and observed explicit authentication failures in T3. Cleared the separate broker's cache, confirmed a different token was minted, and reran the reads successfully in the same T3 server with zero container restarts. This proves revocation/replacement, not natural-expiry timing.

Headless Chromium web UI passed: paired with the same candidate, revealed the GitHub account as dark-dragons-orchestrator[bot], and opened the Publish repository dialog for a local repository without a remote. The repository field was blank with placeholder owner/repo, with no bot-login owner prefill. Canceled without submitting. No page errors. Backend bare-name owner resolution is covered separately above.

Publish limitation: attempted sourceControl.publishRepository once with a bare repository name and public visibility, targeting darkdragonsastro/t3code-app-compat-pr21184-20261026. T3 returned a permission-related source-control error with its cautious “may already exist / check before retrying” warning. A subsequent independent GitHub lookup could not find the target repository, and the local repository still had no remote. I did not retry the mutation or widen App grants. The initial harness retained error categories rather than the exact API refusal, so I cannot give an HTTP status for that attempt or claim that the missing administration grant alone caused it.

Still unverified: successful repository creation with a suitably permitted installation, failure after successful remote creation / partial-creation recovery, natural token expiry, same-slug human/bot reviewer edge cases with real accounts, and native desktop/mobile clients. These results do not replace maintainer approval for the authentication scope.

@github-actions

Copy link
Copy Markdown
Contributor

This PR conflicts with main. Rebase it or merge main into it. If it still conflicts after 7 days with no activity, it will be closed automatically.

See the conflict window.

@github-actions github-actions Bot added the needs-rebase Conflicts with its base branch. Closes after 7 days with no activity. label Nov 12, 2026
@t3dotgg

t3dotgg commented Nov 12, 2026

Copy link
Copy Markdown
Member

Note

🤖 Claude Opus 5.5 responding on behalf of Theo

Closing. This PR conflicts with main in 7 files, which is more than we will review as a rebase. If the change still matters, open a fresh PR from current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rebase Conflicts with its base branch. Closes after 7 days with no activity. size:XL 500-999 changed lines (additions + deletions). vouch:unvouched Author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants