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
- Postgres `getTableColumns` binds the caller schema (#60).
23
+
- Dashboard loading states (#61).
24
+
- SQL editor guard bypasses closed (#63).
25
+
-`COMMENT` / `CALL` table names no longer treated as mutations (#64).
26
+
- ReDoS-safe parsing for chat-access-policy deny/allow regexes (#65).
27
+
- Hermes agent + web UI pinned to release tags (#68).
28
+
29
+
### Changed
30
+
31
+
- Schema API (`/objects`, `/schema`, table indexes/stats) filters by per-user policy.
32
+
-`@deepsql/mcp` remains `0.27.0` for this cut.
33
+
11
34
## [1.1.0] — 2026-08-15
12
35
13
36
### Added
@@ -59,5 +82,6 @@ First public OSS release.
59
82
- Residual high-severity items tracked in `docs/oss-ux/OSS_SECURITY_REVIEW.md` (IDOR sweep, SET preamble allowlist, SSRF hardening, share-password defaults) are deferred past this cut.
60
83
- Primary distribution path remains `docker compose up --build` (no pre-built container registry in this release).
2.**LLM Provider Registry**: Use `LlmProviderRegistry` for all provider-specific LLM behavior. Do NOT add if/else or switch on provider type. Chat and embedding providers are registered and resolved independently — some providers offer only one. Providers are *factories* over credentials, not `ChatModel`s, so credentials stay resolvable per call and key rotation needs no restart.
4.**SQL Rule**: All generated SQL MUST use table-qualified column names (`table.column_name`).
321
-
5.**RAG Caching**: Three-tier cache (memory → Redis → Azure Search). Redis failure is graceful (app continues without caching).
322
-
6.**Virtual Threads**: Enabled for concurrency (JDK 25).
321
+
5.**Chat access policy**: Fail closed. Walk the whole SQL tree (CTEs, set ops, subqueries). Deny unparseable or unhandled statements. Require an actor except `INTERNAL`/`SCHEDULED`. MCP/Editor identity comes from `SecurityContext`, not `QueryActorContextHolder`. Persist `allowed_schemas`. Do not let "how many" override a protected-column mention. Public share is refused when the connection has an active policy.
322
+
6.**RAG Caching**: Three-tier cache (memory → Redis → Azure Search). Redis failure is graceful (app continues without caching).
323
+
7.**Virtual Threads**: Enabled for concurrency (JDK 25).
323
324
324
325
### Frontend Rules
325
326
1.**API Centralization**: ALL API calls through `src/lib/api/client.js`. Never create direct axios instances.
@@ -328,6 +329,15 @@ returns a number).
328
329
4.**Tooltips**: Always use `HelpTooltip` component, never plain `title` attributes.
329
330
5.**Design**: Minimal black/white/grey palette, Inter font, subtle transitions. See UX guidelines in full CLAUDE.md.
330
331
332
+
### Admin profile switch
333
+
Admins can **View as** a sub-user from the top-right of the home layout (`ProfileSwitch`) to verify connection ACLs, chat/editor policies, and role-gated nav.
334
+
335
+
The admin JWT **subject** stays the administrator so logout, refresh, and `/admin/impersonate` still own the real session. Policy identity is the target: an httpOnly `impersonate_user` cookie plus an `impUid` claim on the access token. `JwtAuthenticationFilter` overlays that principal onto the SecurityContext for every request except the impersonation control plane, logout, and session refresh. Chat, Editor, schema listing, and Agent MCP calls then run `AccessControlService` / `ConnectionChatAccessPolicyService` as the target (`actorIsAdmin` is false, so policies apply).
336
+
337
+
The Agent tab must not inherit the admin MCP token. `/api/agent/session` mints an MCP token for the effective user and never falls back to the admin session JWT while View as is active. nginx `auth_request` on `/agent-api` forwards `/api/auth/me`'s `X-Remote-User` (the overlaid username) instead of hardcoding `admin`.
338
+
339
+
`POST|DELETE|GET /api/admin/impersonate` are excluded from the overlay so stop/list still run as the real admin. Cannot target another ADMIN, self, or a non-ACTIVE account. `/auth/me` returns the **effective** user plus `impersonating` / `impersonatorUsername`.
340
+
331
341
### Git Rules
332
342
- Do NOT commit automatically — wait for explicit user instruction.
`/inferred-relationships/*`) had the check; every later "Phase" block did not — so an
510
+
authenticated user could pass someone else's connection id to
511
+
`/brain/health-scores/{id}`, `/brain/data-sensitivity/{id}` (which names the PII
512
+
columns), `/brain/cost-attribution/{id}`, `/brain/ml-overview/{id}` and ~90 more and
513
+
read that user's database intelligence. All 116 are now guarded, and
514
+
`BrainControllerAuthorizationSafetyTest` fails the build if a new one is not. The
515
+
misses clustered by **when a section was written**, not by read/write semantics —
516
+
when adding a controller section, guard it as you write it.
517
+
-**When the path carries some other id** (`simulationId`, `experimentId`, `patternId`,
518
+
`noteId`, `taskId`), resolve the owning connection first via that service's
519
+
`getConnectionId(id)` and assert on the result. Do not skip the check because the
520
+
path has no `connectionId` in it.
521
+
-**An endpoint with no connection scope at all is admin-only.**
522
+
`POST /brain/column-values/embed-all` spans every connection, so it carries
523
+
`@PreAuthorize("hasRole('ADMIN')")` — it cannot be authorized against one
524
+
connection's grants. `@EnableMethodSecurity(prePostEnabled = true)` is on in
525
+
`SecurityConfig`, so `@PreAuthorize` is live.
526
+
-**Assert inside the `try`, and rethrow `ResponseStatusException` before the
527
+
catch-all.** Every handler in `BrainController` ends with a
528
+
`catch (Exception) -> 500`; without the earlier
529
+
`catch (ResponseStatusException e) { throw e; }` a 403 is swallowed and reported as a
530
+
server error, so a client cannot tell "not yours" from "broken". The safety test
531
+
asserts this too.
532
+
394
533
### MCP & CLI Release Rules
395
534
396
535
**Whenever you add, rename, or remove an MCP tool or a CLI subcommand, you MUST update all of these in the same commit — they are agent-facing surfaces and drift silently breaks discoverability:**
0 commit comments