feat(copilot): Enterprise test kit — doctor + live-proxy harness + outbound capture#1136
feat(copilot): Enterprise test kit — doctor + live-proxy harness + outbound capture#1136chopratejas wants to merge 5 commits into
Conversation
Lets a community member with a Copilot Business/Enterprise seat verify that Headroom routes premium models correctly, and cleanly tell a Headroom bug apart from a GitHub entitlement/policy limit (catalog shows models the seat may not be entitled to RUN; the 400 "model not supported" is upstream, not Headroom). - tools/copilot-test/copilot_doctor.py — read-only diagnostic: where the credential lives, resolved host, the exact outbound request, /models catalog, inference on chat + /responses, and a pass-through contract check. Secret-free output (tokens shown as prefix/kind only). - tools/copilot-test/enterprise_proxy_test.py — starts a real proxy at a given host and runs premium models THROUGH Headroom; prints a PASS/FAIL matrix. - tools/copilot-test/ENTERPRISE-COPILOT-TEST.md — provisioning + run + decision matrix runbook (Copilot Business). - headroom/copilot_auth.py — optional env-gated outbound capture (HEADROOM_COPILOT_DEBUG_OUTBOUND); no-op unless enabled. Logs host + identity headers + token KIND only, never the token.
PR governanceThis PR follows the template and is marked ready for human review. |
- copilot_auth.py: capture hook now records only fixed credential labels
(scheme + type prefix) — no token bytes reach the file or log sink
(CodeQL clear-text storage/logging of sensitive information).
- copilot_doctor.py: redact() emits only the non-secret token type prefix
+ length (never a token slice); host-type check parses the URL hostname
and uses endswith(".ghe.com") instead of a substring match (CodeQL
incomplete URL substring sanitization).
- tests: add capture-never-leaks-token and disabled-by-default coverage.
CodeQL taints the whole headers dict (it holds the auth token), so any header- or token-env-derived value reaching a write/log was flagged even though it was redacted. The capture now records only host + URL + constant credential labels; the doctor's env list shows presence only; integration-id / editor-version are surfaced by the doctor's reconstruction instead.
| head("[1] Environment variables") | ||
| for v in copilot_auth._API_TOKEN_ENV_VARS + copilot_auth._COPILOT_OAUTH_TOKEN_ENV_VARS: | ||
| # presence by KEY only — never read the value of a token env var | ||
| print(f" {v:38s} {'SET' if v in os.environ else 'unset'}") |
Windows Validation Report — PR #1136Status: ✅ COMPLETE & VERIFIED Enterprise Copilot subscription feature is fully tested and production-ready on Windows. Test SummaryAll three validation flows completed successfully:
Model Testing ResultsKey Findings
RecommendationReady for merge and release. Enterprise users can now use Test Environment:
|
JerrettDavis
left a comment
There was a problem hiding this comment.
This PR is not merge-ready because CI is currently red: CodeQL=FAILURE. Please fix or rerun the failing checks after updating from current main.
|
Fantastic @orty - so in essence - this works on your Windows - with your Enterprise Github Copilot License? |
Description
We cannot validate Headroom's GitHub Copilot support beyond
gpt-4owithout an entitled seat (Copilot Business requires 10+ employees). Investigation traced the recurring "only a subset of models" reports to an upstream GitHub entitlement/policy gate, not Headroom: the/modelscatalog and inference are both keyed to the token's entitlement, and premium models return400 "The requested model is not supported"even when hittingapi.githubcopilot.comdirectly with no Headroom in the path (verified locally). Headroom does not filter the catalog — it forwards the token and GitHub decides.This PR adds a self-contained, secret-free test kit so a community member with a Copilot Business/Enterprise seat can run two commands and tell us, unambiguously, whether premium models flow through Headroom — and if not, whether it is a Headroom bug or their org policy.
Related: #488, #635, #644, #972, #1039 — this is a diagnostic kit to confirm the root cause, not a fix for them.
Type of Change
Changes Made
tools/copilot-test/copilot_doctor.py— read-only diagnostic: where the credential lives (keychain/file/env, cross-platform), the resolved API host, the exact outbound request Headroom forwards, the/modelscatalog, inference on/chat/completions+/responses(the [BUG]headroom wrap copilot --subscriptioncannot reach gpt-5.x — forces /chat/completions and blocks --wire-api override #644/fix(copilot): use responses API for subscription reasoning models #647 wire-API split), and a pass-through contract check. Output is secret-free — tokens are reduced to their non-secret type prefix + length only.tools/copilot-test/enterprise_proxy_test.py— starts a real Headroom proxy at a given host and runs premium models through it; prints a PASS/FAIL matrix. Host-agnostic (GITHUB_COPILOT_API_URL).tools/copilot-test/ENTERPRISE-COPILOT-TEST.md— provisioning + run + decision-matrix runbook (Copilot Business).headroom/copilot_auth.py— optional, env-gated outbound capture (HEADROOM_COPILOT_DEBUG_OUTBOUND). No-op unless enabled. Records only host + URL + fixed credential labels (scheme + token type prefix); no token bytes and no request headers are written or logged. (Integration-id / editor-version are surfaced by the doctor's reconstruction.)tests/test_copilot_auth.py— adds two tests: the capture never emits token bytes, and it is a no-op when the env var is unset.Testing
pytest) — touched Copilot pathsruff check)mypy headroom/copilot_auth.py)Test Output
Real Behavior Proof
api.githubcopilot.com..venv/bin/python tools/copilot-test/copilot_doctor.pythen.venv/bin/python tools/copilot-test/enterprise_proxy_test.py(run from repo root).gpt-4oreturns200through the proxy;gpt-5.5andclaude-sonnet-4.6return400 "not supported"on both/chat/completionsand/responses; the same 400s reproduce hittingapi.githubcopilot.comdirectly with no Headroom in the path → upstream entitlement, not a Headroom bug. Outbound capture confirmedhost=api.githubcopilot.com integration-id=vscode-chatand the credential is reduced toBearer / gho_***(no token bytes).Review Readiness
Checklist
Screenshots (if applicable)
N/A — CLI/diagnostic output is shown above.
Additional Notes
gho_/tid_) + length via constant literals — never a token slice — so no clear-text token data reaches any file or log sink. The doctor's host-type check uses parsedurlparse(...).hostname+endswith(".ghe.com")instead of a substring match.✅native but❌through-proxy = Headroom bug;❌in both = org policy/entitlement;403= SSO authorization needed.