Skip to content

fix: P2 hardening — GUI apiKey, constant-time auth, pool byte accounting, /x lock, isGenerating refcount#56

Merged
magicnight merged 3 commits into
mainfrom
fix/v0.5.3-p2-hardening
Jul 8, 2026
Merged

fix: P2 hardening — GUI apiKey, constant-time auth, pool byte accounting, /x lock, isGenerating refcount#56
magicnight merged 3 commits into
mainfrom
fix/v0.5.3-p2-hardening

Conversation

@magicnight

Copy link
Copy Markdown
Owner

The P2/backlog hardening cluster from the debug round (follows the P0/P1 wave in #51). Six items:

  • SRV-5 — GUI-launched server now passes settings.serverAPIKey, so BearerAuthMiddleware installs there too (was CLI-only). Plus review follow-up: empty-string key = no-auth (would otherwise install a middleware expecting "Bearer " and brick the server).
  • SRV-6 — bearer token compared constant-time over UTF-8 bytes (XOR-accumulate, no early exit on content; length leak accepted and documented).
  • POOL-4 — in-flight load bytes are reserved before suspension (pendingBytes), so concurrent loads of different models can no longer combine past maxBytes (OOM window closed). Reservation rolls back on failure — no silent budget shrink.
  • POOL-5evict detaches victims synchronously and load() awaits their unload before the new engine allocates — no transient double residency. sweepIdle stays fire-and-forget (documented: TTL reclaim isn't racing an imminent allocation).
  • A2/x/models/load + /x/models/unload now run under the throwing generation-lock discipline (manual swap waits for in-flight generation; exactly-once release, throw-from-acquire = not held).
  • A3isGenerating is a refcount (begin/end, clamped at 0): concurrent GUI + server generations on the same model no longer clear each other's evict/sweep protection.

Review + verification

Adversarially reviewed (APPROVE): six targeted suspicions — constant-time correctness, reservation-leak lifecycle, victim double-unload, lock exactly-once, markInFlight pairing, begin/end stream-lifetime pairing — all REFUTED with file:line evidence; the one MEDIUM finding (empty-key guard) is fixed in this PR. Local: ** TEST SUCCEEDED **, 79 XCTest + 204 swift-testing, 0 failures; 4 new tests (srv6ConstantTimeEqualsRejectsAnyDifference, testConcurrentLoadsOfDifferentModelsRespectCombinedBudget, testGeneratingRefcountProtectsUntilBalanced, testEndGeneratingClampsAtZeroNoUnderflow) + all prior regression tests green. Branch includes the #55 CI gating fix via merge.

… byte accounting, awaited evictions, /x lock, isGenerating refcount

- SRV-5: GUI-launched server now passes settings.serverAPIKey so
  BearerAuthMiddleware installs (was CLI-only)
- SRV-6: bearer token compared constant-time over UTF-8 bytes
  (length leak accepted, content-position leak closed)
- POOL-4: in-flight load bytes reserved before suspension; concurrent
  distinct-model loads can no longer overshoot maxBytes
- POOL-5: evict returns victims and load() awaits their unload before
  the new engine allocates (no transient double residency);
  sweepIdle stays fire-and-forget (documented — TTL reclaim isn't
  racing an imminent allocation)
- A2: /x/models/load + /x/models/unload wrapped in the throwing
  generation-lock discipline (manual swap waits for in-flight
  generation, same as the generation endpoints)
- A3: isGenerating is a refcount (begin/end, clamped at zero) —
  concurrent GUI + server generations on one model can no longer
  clear each other's evict/sweep protection

Tests: constant-time equality; concurrent-load budget with a LoadGate
stub; refcount protect-until-balanced + underflow clamp.
An empty-string key would install BearerAuthMiddleware expecting the
literal header "Bearer " — 401ing every request while providing no
security. Empty now means "no auth", matching the nil default. Flagged
by the P2 review as the one non-blocking finding (pre-existing, but
SRV-5 newly routes the GUI server through this guard).
@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@magicnight magicnight merged commit b81a176 into main Jul 8, 2026
3 checks passed
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