Changeset 0.28.4 (#190)

This commit is contained in:
2026-03-14 19:36:33 +00:00
parent fa6b04434a
commit 85d5e3cc13
54 changed files with 7355 additions and 102 deletions

View File

@@ -26,7 +26,7 @@ v0.9.xv0.27.5 Foundation → Extensions → Surfaces → Auth ✅
├─ v0.28.1 Surfaces ICD audit ✅
├─ v0.28.2 ICD audit — all domains ✅
├─ v0.28.3 ICD close-out + FE decomp ✅
├─ v0.28.4 Security tier (red team)
├─ v0.28.4 Security tier (red team)
├─ v0.28.5 Infrastructure
│ (virtual scroll, KB auto-inject,
│ Helm chart, provider model prefs,
@@ -189,33 +189,43 @@ decomposition groundwork.
dual-write from `sb.register()`/`sb.ns()`
### v0.28.4 — Security Tier (ICD Runner Red Team)
New `security` tier in ICD test runner. Multi-user fixtures already exist.
New `security` tier in ICD test runner. 58 tests, 529/531 pass.
5 bugs found and fixed. `surfaces/` directory added with build script.
**Auth boundary:**
- [ ] JWT revocation: disable user via admin API, verify existing token is rejected
immediately. **This will likely expose a real bug** — JWT middleware validates
signature + expiry only, does not check `is_active` in DB. Fix: add `is_active`
check in auth middleware (DB lookup, cached with short TTL).
- [ ] Token reuse after `POST /auth/logout` — revoked refresh token must fail
- [ ] Expired token rejection (craft a token with past expiry)
- [ ] Role escalation: modify JWT claims client-side, attempt admin endpoints
- [ ] User ID substitution: swap `user_id` in request bodies for another user's ID
- [x] JWT revocation: disable user existing token rejected immediately.
**Real bug found + fixed**`UserStatusCache` (30 s TTL) added to
auth middleware; `is_active` checked on every request.
- [x] Token reuse after `POST /auth/logout` — revoked refresh token fails
- [x] Expired token rejection (tampered JWT, alg=none — both rejected)
- [x] Role escalation: modified JWT claims → 401. **Real bug found + fixed**
— role now resolved from DB, not JWT claims.
- [x] User ID substitution: `user_id` in request bodies ignored by handlers
**Cross-tenant data access:**
- [ ] User A's token → GET user B's notes, memories, workspaces, BYOK configs, task runs
- [ ] Team member → access other team's providers, personas, tasks
- [ ] Non-participant → read channel messages, files
- [x] User A's token → GET user B's notes, memories, workspaces, BYOK configs, tasks — all 404/403
- [x] Team member → access other team's providers, personas, tasks — all 403
- [x] Non-participant → read channel messages, files — 403/404
**Input validation:**
- [ ] Path traversal in surface install (covered by cs12, verify E2E)
- [ ] SQL injection in search endpoints (notes, users, channels)
- [ ] XSS payloads in channel titles, note content, persona names (round-trip)
- [ ] Oversized request bodies, malformed JSON
- [x] Path traversal in surface install — rejected (400)
- [x] SQL injection in search endpoints (notes, users, channels) — 7 payloads, all parameterized
- [x] XSS payloads in channel titles, note content, persona names — stored safely, frontend sanitizes
- [x] Oversized request bodies, malformed JSON — handled (400)
- [x] Null byte in path params → 500 **fixed**`ValidatePathParams()` middleware (400)
- [x] Oversized path params → 500 **fixed** — same middleware (400)
**Session security:**
- [ ] Visitor session → access channels outside bound workflow
- [ ] Visitor → escalate to authenticated user via crafted headers
- [ ] Cross-visitor isolation: visitor A's cookie cannot read visitor B's messages
- [x] Visitor session → access channels outside bound workflow — 401
- [x] Visitor → escalate to authenticated user via crafted headers — 401
- [ ] Cross-visitor isolation: enforced by `session_auth.go` channel
binding, but no E2E test (requires public_link workflow setup —
defer to visitor E2E milestone)
**Infrastructure:**
- [x] `CORS_ALLOWED_ORIGINS` env var — production restricts, dev allows `*`
- [x] `surfaces/` directory with `build.sh``dist/<n>.surface`
- [x] `hello-dashboard.surface` unpacked into `surfaces/hello-dashboard/`
### v0.28.5 — Infrastructure
- [ ] Virtual scroll for long conversations (prerequisite for heavy task output channels)