Skip to content

fix(credential_pool): check copilot suppression before token exchange (salvage #76341) - #77561

Merged
kshitijk4poor merged 3 commits into
NousResearch:mainfrom
kshitijk4poor:salvage-76341-copilot-gate
Aug 3, 2026
Merged

fix(credential_pool): check copilot suppression before token exchange (salvage #76341)#77561
kshitijk4poor merged 3 commits into
NousResearch:mainfrom
kshitijk4poor:salvage-76341-copilot-gate

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Salvages #76341 by @wangyunyou — both commits cherry-picked to preserve authorship, plus one review-fold commit fixing a classification bug the early gate made decisive.

Context — what this fixes, for whom

Anyone with a suppressed copilot source (hermes auth remove copilot gh_cli): every load_pool("copilot") — model picker open, /model, agent startup — ran the full token exchange (3 retries x 10s timeouts + 4.5s backoff, ~35s worst case) and THEN discarded the result at the post-exchange suppression check. The PR moves the gate before the network call and adds an all-sources early exit that skips even the gh auth token subprocess.

Review fold (the salvage's addition)

The per-source gate classifies with "gh" in source.lower() — which classifies GH_TOKEN and GITHUB_TOKEN as gh_cli (substring match). Pre-existing on main, but this PR makes the classification decide whether the exchange runs at all: a user who suppressed env:GH_TOKEN would have the suppression silently bypassed, and one who suppressed gh_cli would silently lose env-sourced tokens. Fixed to match resolve_copilot_token's exact "gh auth token" sentinel, with 3 regression tests (env-var suppression gates the exchange / gh_cli suppression doesn't swallow env tokens / all-sources suppression skips the resolve subprocess). Also corrected the "~13s" worst-case comment (actual: ~35s from copilot_auth's constants).

Verification

Closes #76341 (superseded by this salvage — original author credited via cherry-pick authorship).

wangyunyou and others added 3 commits August 3, 2026 15:52
The copilot branch of _seed_from_singletons ran the suppression gate
_after get_copilot_api_token(), which retries the network exchange 3x
with backoff (~13s worst case). A source the user already suppressed
(hermes auth remove copilot gh_cli) still burned the full exchange dead
time on every pool load — model picker open, /model, agent startup —
only to have the entry discarded afterwards.

Move the _is_suppressed() gate ahead of the network call, matching the
early-gate pattern every other singleton branch uses. Suppressed copilot
sources now skip the exchange entirely. Measured: model.options payload
build drops from ~13s to ~0.2-0.4s for a user with copilot suppressed.

Add regression test test_load_pool_skips_exchange_for_suppressed_copilot
asserting the exchange is never invoked for a suppressed source.
…ppressed

The all-sources suppression gate now runs before resolve_copilot_token(),
which shells out to `gh auth token` (~30ms) on every pool load. A user
who suppressed every copilot source (hermes auth remove copilot gh_cli
suppresses gh_cli + all env variants) still paid the subprocess spawn on
every load — model picker open, /model, agent startup.

Enumerate the same source space credential_sources._remove_copilot_gh
suppresses and bail before any work when all are suppressed. Measured:
model.options payload build drops from ~0.46s to ~0.26s cold for an
all-suppressed user; resolve_copilot_token() is no longer called at all.
Review fold on the NousResearch#76341 salvage: the substring test ('gh' in
source.lower()) classified GH_TOKEN and GITHUB_TOKEN as gh_cli, so a
user's env-var-specific suppression was silently bypassed (and
suppressing gh_cli silently dropped env tokens). Pre-existing bug on
main, but the PR's early gate makes the classification decide whether
the exchange runs at all. Match resolve_copilot_token's exact
'gh auth token' sentinel instead.

Adds 3 regression tests: env-var suppression gates the exchange,
gh_cli suppression doesn't swallow env tokens, all-sources suppression
skips the resolve subprocess entirely. Also corrects the ~13s comment
(actual worst case ~35s: 3x10s timeouts + 4.5s backoff).
@kshitijk4poor
kshitijk4poor enabled auto-merge (rebase) August 3, 2026 10:23
@kshitijk4poor
kshitijk4poor merged commit 536ed6a into NousResearch:main Aug 3, 2026
35 checks passed
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/copilot GitHub Copilot (ACP + Chat) area/auth Authentication, OAuth, credential pools sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 3, 2026
@kshitijk4poor
kshitijk4poor deleted the salvage-76341-copilot-gate branch August 5, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists provider/copilot GitHub Copilot (ACP + Chat) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants