Skip to content

fix: bug-hunt batch — credential leak, request-path hardening, config validation, papercuts#4

Merged
armenr merged 4 commits into
mainfrom
fix/bug-hunt-batch
Jul 6, 2026
Merged

fix: bug-hunt batch — credential leak, request-path hardening, config validation, papercuts#4
armenr merged 4 commits into
mainfrom
fix/bug-hunt-batch

Conversation

@armenr

@armenr armenr commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Fixes the 13 real issues from the adversarial src/ bug-hunt (1 high, 1 medium, 11 low), in four grouped commits.

🔴 HIGH

  • Fixture recorder credential leakrecord-fixtures.ts wrote inbound authorization/x-api-key verbatim into git-tracked test/fixtures/*.json. Now redacted before write (no real token was ever committed — checked).

🟠 MEDIUM

  • Unvalidated route when — a missing/typo'd when loaded clean then 400'd every request (incl. the main loop) and swapped out the good config via hot-reload. Now validated at load (fail loud).

🟡 LOW (request path + papercuts)

  • Upstream fetch() failure → logged 502 instead of an opaque unlogged 500
  • Propagate client cancellation (req.signal) so aborted requests stop billing
  • Preserve upstream response headers (retry-after / rate-limit / request-id), not just content-type
  • Best-effort logging (a log I/O failure can't crash a request); readDecisions skips a truncated line
  • Missing [models] → clear error; MUX_MODEL_ alias-collision detection
  • Case-insensitive tag matching; check-latest honors MUX_ROUTES; empty-catalog guard

Also de-flaked the fs.watch reload tests (own dir per test + armed watcher).

Verified

  • bun run check green: eslint + tsc + 71 tests (+15), stable across 8 consecutive full-suite runs

armenr added 4 commits July 7, 2026 03:34
The recorder wrote every inbound header verbatim into git-tracked
test/fixtures/*.json, capturing Claude Code's real authorization / x-api-key.
Redact authorization/x-api-key/cookie before writing (extracted as a testable
redactHeaders); guard the server behind import.meta.main so it can be imported.
- Catch upstream fetch() failures -> log + 502 (was an opaque, unlogged 500)
- Propagate client cancellation via req.signal (stop billing aborted requests)
- Preserve upstream response headers (retry-after, rate-limit, request-id),
  not just content-type; strip stale framing headers
- Best-effort log writes so a logging I/O failure can't crash a request
- readDecisions skips a truncated line instead of discarding every record
- Validate each route's when-clause at load (reject missing/empty/multi-key and
  unknown workType) so a bad rule fails loud instead of silently never matching
  and defeating the hot-reload keep-last-good safety net
- Clear error for a missing [models] table (was a raw TypeError)
- Detect two aliases colliding on one MUX_MODEL_ override key
- De-flake the fs.watch reload tests (own dir per test + armed watcher)
- Match route tags case-insensitively against the config when.tag (an uppercase
  config tag no longer silently misroutes a control agent to a paid model)
- check-latest honors MUX_ROUTES like every other command
- Guard an empty/unrecognized OpenRouter catalog instead of flagging every
  configured slug as stale
@armenr armenr merged commit e25fd5e into main Jul 6, 2026
2 checks passed
@armenr armenr deleted the fix/bug-hunt-batch branch July 6, 2026 23:36
@github-actions github-actions Bot mentioned this pull request Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant