Skip to content

fix(copilot): keep rotated credentials on account endpoint - #61757

Open
nullptr0807 wants to merge 1 commit into
NousResearch:mainfrom
nullptr0807:fix/61746-copilot-enterprise-endpoint
Open

fix(copilot): keep rotated credentials on account endpoint#61757
nullptr0807 wants to merge 1 commit into
NousResearch:mainfrom
nullptr0807:fix/61746-copilot-enterprise-endpoint

Conversation

@nullptr0807

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes Copilot credential rotation for Enterprise/proxied accounts by keeping the runtime API token and account-specific endpoint together.

When a pool entry contains a raw GitHub token, _swap_credential() exchanges it and applies the returned short-lived Copilot token plus base_url as one runtime pair. When the pool already contains an exchanged semicolon metadata token, Hermes avoids an invalid re-exchange and derives the Enterprise endpoint from proxy-ep instead. Exchange failures remain fail-soft and preserve the selected pool values.

The PR also categorizes GitHub's exact endpoint-forbidden HTTP 403 envelope as an authentication/endpoint-access failure on chat gateways rather than the misleading generic “failed after retries” message.

This builds on the core fix in #61754, while covering the already-exchanged token path and the gateway diagnostic reported in the issue.

Related Issue

Fixes #61746

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✅ Tests (adding or improving test coverage)

Changes Made

  • run_agent.py
    • exchange raw Copilot pool credentials during rotation
    • derive account-specific endpoints from already-exchanged Copilot tokens without re-exchanging them
    • preserve existing token/endpoint values when resolution fails
  • gateway/run.py
    • recognize GitHub's endpoint-forbidden 403 envelope, including its Markdown Terms-of-Service link
    • return an authentication/endpoint-access diagnostic without broadening every HTTP 403 into an auth error
  • tests/agent/test_restore_primary_pool_reselect.py
    • cover raw-token exchange, exchanged-token endpoint repair, and fail-soft behavior
  • tests/gateway/test_telegram_noise_filter.py
    • cover the real wrapped GitHub 403 and a negative unrelated-403 case

How to Test

  1. Run focused Copilot, credential-pool, Responses transport, and gateway tests:

    python -m pytest \
      tests/run_agent/test_run_agent_codex_responses.py \
      tests/agent/test_restore_primary_pool_reselect.py \
      tests/agent/test_credential_pool_routing.py \
      tests/gateway/test_telegram_noise_filter.py \
      tests/hermes_cli/test_copilot_token_exchange.py \
      -o 'addopts=' -q

    Expected: 335 passed.

  2. Run lint and whitespace checks:

    python -m ruff check \
      run_agent.py gateway/run.py \
      tests/agent/test_restore_primary_pool_reselect.py \
      tests/gateway/test_telegram_noise_filter.py
    git diff origin/main...HEAD --check
  3. With a Copilot Enterprise credential whose token advertises proxy-ep=proxy.enterprise.githubcopilot.com, rotate from a stale pool entry whose stored URL is https://api.githubcopilot.com. The rebuilt client should use https://api.enterprise.githubcopilot.com.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing issues and PRs
  • My PR contains only changes related to this fix
  • I've run the entire pytest tests/ -q suite — the hermetic full-suite runner reached 16.1% with no failures before the local 10-minute command timeout; focused affected tests pass
  • I've added regression tests
  • I've tested on Linux 6.17 / Python 3.11.15

Documentation & Housekeeping

  • Documentation update — N/A; no user-facing configuration changed
  • cli-config.yaml.example update — N/A
  • CONTRIBUTING.md / AGENTS.md update — N/A
  • Cross-platform impact considered; implementation is platform-neutral Python
  • Tool descriptions/schemas update — N/A

Test Results

335 passed in 28.27s
240 passed in 5.41s
All checks passed!  # ruff
git diff --check: clean

@nullptr0807
nullptr0807 force-pushed the fix/61746-copilot-enterprise-endpoint branch from cc83e5d to 4b118f8 Compare July 10, 2026 01:39
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery provider/copilot GitHub Copilot (ACP + Chat) area/auth Authentication, OAuth, credential pools P2 Medium — degraded but workaround exists labels Jul 10, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #61746 (the issue) and the complementary core fix #61754 (open). #61754 refreshes the Copilot token + base_url together at rotation time; this PR (#61757) additionally covers the already-exchanged-token endpoint-derivation path and reclassifies GitHub's endpoint-forbidden 403 envelope in gateway/run.py. Two overlapping OPEN PRs for the same issue — maintainer picks which to merge (or merges both, since they cover distinct sub-paths).

@teknium1

Copy link
Copy Markdown
Contributor

Thanks — the reported rotation defect is present on current main, and this is a focused repair.

Current run_agent.py:4505-4506 independently selects the pool entry token and stored base URL before rebuilding the client at run_agent.py:4527-4532. The PR replaces that Copilot-specific pairing with the existing account-aware resolution helpers: hermes_cli/copilot_auth.py:415-434 returns the exchanged token and endpoint, while hermes_cli/copilot_auth.py:383-412 derives the endpoint for an already-exchanged token. This covers both representations without adding configuration or changing tool/prompt state.

The gateway addition also matches the current behavior: gateway/run.py:356-372 otherwise maps this exact 403 envelope to the generic retry-exhausted reply.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 11, 2026
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 comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists provider/copilot GitHub Copilot (ACP + Chat) sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Copilot credential rotation reuses stale public endpoint for Enterprise accounts

3 participants