You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Today only --verbose console logs exist. Operators debugging Anthropic↔OpenAI translation, model-specific quirks, or upstream errors need full request/response visibility — but storing prompts/responses on disk is the kind of feature that creates GDPR/SOC2 exposure.
⚠️ Reviewer caveats — must be addressed
Privacy posture (devil-advocate, security S7): Storing other users' prompts on the operator's disk creates a data controller relationship. Default retention should arguably be 0 (in-memory only); on-disk persistence should require explicit opt-in beyond just enabling the flag.
Redaction completeness (security S1, backend B12): The original draft regex /gh[opusr]_/ misses:
Strip headers by name (case-insensitive): authorization, x-api-key, cookie, set-cookie, proxy-authorization
Body patterns to mask: gh[oprsu]_[A-Za-z0-9]{20,}, github_pat_[A-Za-z0-9_]{20,}, JWT shape eyJ[A-Za-z0-9_-]+?\.eyJ[A-Za-z0-9_-]+?\.[A-Za-z0-9_-]+, Iv1\.[a-f0-9]{16}
Block trace write if any unmasked match is detected after redaction (defense-in-depth: redaction sanity check before persistence)
Add fuzz tests
JSONL writer: append to ~/.local/share/copilot-api/traces/YYYY-MM-DD.jsonl, mode 0600, line-buffered; rotation by day in filename
Default traces_days = 0 (in-memory only) when first introducing the feature; admin must explicitly set a non-zero value (per devil-advocate privacy posture)
SSE live tail at /admin/traces/stream (admin tier):
Single in-process broadcaster (per backend review Anthropic /v1/messages → Responses API adapter #8) — Set<ReadableStreamController>. Writer pushes each post-redaction line to all subscribers. NOT N file watchers.
Cap concurrent subscribers at 4
Bounded per-subscriber queue (drop-oldest at 1 MB)
Resolve against tracesDir; assert resolved path startsWith tracesDir + sep
Reject anything else with 400
Trace viewer page /admin/traces showing live tail (with banner if any key has debug_enabled per F2.E)
Debug TTL auto-disable hook: works with F2.E debug-ttl-sweeper
Audit log the toggle event (F2.D)
README security notes: document the threat model (anyone with read access to the data dir can read traces); recommend chmod 0700 on the data dir; install script should set this
Tests:
Redaction completeness: fuzz test asserts NO unmasked gho_, ghp_, ghu_, ghs_, ghr_, github_pat_, eyJ…, Iv1\.… in any sample after redaction
Part of #23. Depends on F1.D, F2.A, F2.B, F2.C.
Background
Today only
--verboseconsole logs exist. Operators debugging Anthropic↔OpenAI translation, model-specific quirks, or upstream errors need full request/response visibility — but storing prompts/responses on disk is the kind of feature that creates GDPR/SOC2 exposure.Privacy posture (devil-advocate, security S7): Storing other users' prompts on the operator's disk creates a data controller relationship. Default retention should arguably be
0(in-memory only); on-disk persistence should require explicit opt-in beyond just enabling the flag.Redaction completeness (security S1, backend B12): The original draft regex
/gh[opusr]_/misses:github_pat_…(fine-grained PATs, contain underscores)eyJ…\.eyJ…\.…)Iv1\.b507a08c87ecfe98(insrc/lib/api-config.ts)Without complete redaction, every captured upstream request leaks a working Copilot JWT in plaintext on disk.
Path traversal (security S5):
/admin/traces/:date.jsonlMUST validate input strictly.Goal
Per-key (or admin-header) capture of full request/response to JSONL with mandatory redaction, bounded retention, and live tail.
Tasks
src/middleware/trace.ts: enabled whenkey.debug_enabled === trueORX-Capi-Debug: 1from admin tier (per F2.C){trace_id, ts, key_id, route, req:{method,url,headers,body}, upstream_req:{...}, upstream_res:{status,headers,body|stream_chunks}, res:{...}, latency_ms}authorization,x-api-key,cookie,set-cookie,proxy-authorizationgh[oprsu]_[A-Za-z0-9]{20,},github_pat_[A-Za-z0-9_]{20,}, JWT shapeeyJ[A-Za-z0-9_-]+?\.eyJ[A-Za-z0-9_-]+?\.[A-Za-z0-9_-]+,Iv1\.[a-f0-9]{16}~/.local/share/copilot-api/traces/YYYY-MM-DD.jsonl, mode0600, line-buffered; rotation by day in filenametraces_days = 0(in-memory only) when first introducing the feature; admin must explicitly set a non-zero value (per devil-advocate privacy posture)/admin/traces/stream(admin tier):Set<ReadableStreamController>. Writer pushes each post-redaction line to all subscribers. NOT N file watchers.Last-Event-IDreconnect support/admin/traces/:date.jsonl(admin tier):^\d{4}-\d{2}-\d{2}$strictly (per security S5)/admin/tracesshowing live tail (with banner if any key hasdebug_enabledper F2.E)chmod 0700on the data dir; install script should set thisgho_,ghp_,ghu_,ghs_,ghr_,github_pat_,eyJ…,Iv1\.…in any sample after redaction../, URL-encoded variants) rejectedAcceptance criteria
debug_enabledproduces exactly one redacted JSON line;grep -E 'gho_|ghp_|ghu_|github_pat_|eyJ' filefinds nothingtail -fand/admin/traces/streamshow identical content within 100 mscurl /admin/traces/../../etc/passwdreturns 400File pointers
src/middleware/trace.ts,src/services/trace-writer.ts,src/services/trace-broadcaster.ts,src/services/trace-retention.ts,src/admin/traces/{stream,download,page}.tsx,tests/trace.test.ts,tests/trace-redaction-fuzz.test.tssrc/lib/paths.ts(tracesDir()),src/admin/layout.tsx,README.mdDependencies
Depends on F1.D, F2.A, F2.B, F2.C.