Skip to content

Design review: GitHub multi-account routing (upstream #11367, #11542, #11672) #966

Description

@rynfar

Maintainer asked (2026-10-01) to consider this as Pylon product work with its own design review.

Upstream: db6e0531e4 (#11367), f26198d799 (#11542), 5e961d3d7f (#11672), plus router parts of f4600d77dd and d612d12b8b: route GitHub operations across several accounts and show connections by environment. Pylon supports one identity per environment today.

Questions: credential storage and secret migration, which account a repo/PR action uses, remote/tunnel environments and pairing scopes, interaction with Forgejo/GitLab/Bitbucket/Azure providers, mobile.

Exit: a recorded decision linked from the upstream review index.

Activity

  1. rynfar commented on Oct 2, 2026

    @rynfar
    CollaboratorAuthor

    Design review

    Recommendation: Decide credential authority before adoption. Prefer an initial GitHub-only, explicitly enabled read-routing phase. Defer routed writes until server authorization and origin-side synchronization semantics are agreed.

    Upstream behavior

    db6e0531e4faac0fc5ac0e12088b01bed6e7b851 (#11367) adds cross-environment routing in packages/client-runtime/src/state/pullRequestRouting.ts. It routes selected PR reads and mutations between connected environments whose active credentials resolve to the same GitHub host and numeric account ID. It does not switch among arbitrary different GitHub accounts.

    Credentials remain server-local. apps/server/src/pullRequest/GitHubPullRequestCli.ts snapshots a token, verifies /user, and pins that token throughout the operation. Host guards live in apps/server/src/sourceControl/GitHubCli.ts. Account identity and credential fingerprint separate server caches; the fingerprint is internal.

    packages/contracts/src/pullRequest.ts adds expectedAccountId, allowStale, routing metadata and host-only identity discovery. rpc.ts, RpcAuthorization.ts, ws.ts and PullRequestService.ts expose and enforce these paths. Identity rejection occurs before dispatch. Reads may fall back; ambiguous mutation failures do not trigger another mutation.

    githubRoutingPermissions.ts provides device-local off/read/read-write preferences. Both endpoints must permit routing. Consent binds to saved connection identity, is revoked on endpoint replacement/removal, and is rechecked after probes. Browser storage prevents stale tabs from restoring revoked consent.

    f26198d799bb81bf754985d457a60f8a851ea895 (#11542) first reorganizes web connections around a selected environment. 5e961d3d7fc07ff1ba998bfd20bb366c2ab8c9a9 (#11672) replaces that arrangement with a flat environment list and folded sharing/load-balancing controls. These layout changes are separable from routing.

    The router portion of f4600d77dd7c2fa9f10e8f4500882e427fcc7e26 removes speculative read racing, prefers local reads and bounds them to 30 seconds. d612d12b8bb278af97b0029f8d48b2403a5f9ee6 canonicalizes host-qualified PR references and cached details across entry points.

    Current Pylon behavior

    Pylon’s PullRequestRef selects an environment/project checkout and optional host; it has no routing identity or expected-account guard. packages/client-runtime/src/state/pullRequests.ts sends operations through their selected environment.

    Provider authority differs:

    • GitHub uses server-local gh authentication. GitHubCli.ts already has pinned credential snapshots, currently used for viewed-file operations; summary batching also respects credential context.
    • Forgejo/Gitea uses ForgejoCli.ts, selecting fj/tea authentication against repository/host context.
    • GitLab uses server-local glab.
    • Bitbucket uses environment settings before server environment-variable fallback. serverSettings.ts stores tokens through auth/ServerSecretStore.ts and redacts client settings.

    ConnectionCredentialStore contains Pylon connection bearer credentials, distinct from source-control credentials. Per-environment connection profiles and settings already exist on web/desktop/mobile.

    The upstream ledger records applicable quota/cache work from f4600d7 and d612d12 as adopted, while excluding routing hooks. Adoption should reuse those changes and Pylon’s existing pinning.

    Options

    Option Scope and impact Risk / rough size
    Don’t adopt Preserve environment-local authority across all providers and clients. No contracts, SQL migrations or orchestration changes. Remote/tunnel behavior remains explicit. Low; under one day for disposition.
    GitHub read routing Add verified identity contracts, capability negotiation, endpoint consent and credential-scoped caching. Integrate shared runtime plus web/desktop/mobile controls. Other providers, mutations, HTTP diffs and viewed-file operations remain origin-bound initially. No inherent SQL migration or decider change. Medium/high; roughly 1–2 weeks.
    Full routed reads/writes Add guarded mutations, destination authorization, invalidation and origin synchronization. Retain same-account matching and server-local secrets. Define typed completion/failure handling where origin orchestration reacts to remote actions. High; roughly 2–3 weeks. Generalizing other providers is additional work.

    Prime credentials, provider homes and agent execution remain separate in every option. Agent/MCP/server operations do not automatically gain a client-side router.

    Credential-authority decision

    Matching account IDs does not imply matching token permissions: a destination token may grant broader access. Device-local sharing preferences control client behavior; they are not server-enforced delegation policy.

    The maintainer must decide whether an explicitly authorized destination session may exercise that broader authority, whether the origin’s authorization constrains routed writes, and whether users should see which environment executes an action. Also decide how an accepted destination mutation refreshes origin linked-PR state when the destination lacks the origin project.

    For adoption: first specify identity, capability and authorization rules; then ship read-only routing with credential-scoped caches; then evaluate writes separately. Preserve origin project metadata and Pylon’s Forgejo capability negotiation. Any durable delegation/receipt storage needs the next available Pylon migration after 067; never import upstream numbering or update projections directly.

    Verification

    Add focused router, registry/resolver, storage, authorization, CLI and PR-service regressions. Cover same account/different permissions, account changes during dispatch, enterprise hosts, endpoint replacement, revocation during probes, offline destinations, old servers, stalled reads and ambiguous writes. Verify origin invalidation, host/cache isolation and local/bearer/SSH/tunnel modes. Keep Forgejo/Gitea, GitLab and Bitbucket origin routing covered.

    Read-only design review (Codex via relay, coordinated by Claude Opus 5.5) against Pylon 00884406f7. Decisions stay with the maintainer.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions