feat(proxy): context-aware ACLs — sync hero_osis context list + enforce per-route #22

Merged
timur merged 1 commit from feat_21_context_acl into development 2026-04-12 16:32:07 +00:00
Owner

Closes #21 (first pass — UI + admin RPC for per-route context are follow-ups).

Summary

  • contexts SQLite table mirrors hero_osis's context list; context_sync polls base.context_list/base.context_get over $HERO_SOCKET_DIR/hero_osis/rpc.sock every HERO_PROXY_CONTEXT_SYNC_SECS (default 60s)
  • domain_routes.context column (defaults to "0") — each route declares which hero_osis context it forwards to
  • dispatch_domain_route now rejects unknown contexts with 404 and passes the resolved context to resolve_claims_for_user so the existing role.contexts filter actually kicks in
  • Admin context (name="0") is seeded on DB init so requests can be served before the first hero_osis sync
  • Sync uses raw JSON-RPC 2.0 (no hero_osis_sdk dep) — keeps the dep graph small since we only need two methods

Test plan

  • cargo test --workspace — all green, including the 3 previously-failing domain-routing integration tests
  • 6 new unit tests covering seed/upsert/prune invariants + new-route default
  • Manual: run hero_osis_server + hero_proxy_server together, verify first-sync log line, verify context rows in proxy.db, verify unknown-context route returns 404

What's NOT in this PR

  • Exposing context on AddDomainRoute/UpdateDomainRoute + SDK/UI (admin API extension)
  • Push-based sync (event stream from hero_osis — no such thing yet)
  • Per-context rate limiting / quotas
  • Migration of hero_router vs hero_proxy ownership (still open per hero_rpc#13)

See design note on #21 for more.

🤖 Generated with Claude Code

Closes #21 (first pass — UI + admin RPC for per-route context are follow-ups). ## Summary - `contexts` SQLite table mirrors hero_osis's context list; `context_sync` polls `base.context_list`/`base.context_get` over `$HERO_SOCKET_DIR/hero_osis/rpc.sock` every `HERO_PROXY_CONTEXT_SYNC_SECS` (default 60s) - `domain_routes.context` column (defaults to `"0"`) — each route declares which hero_osis context it forwards to - `dispatch_domain_route` now rejects unknown contexts with 404 and passes the resolved context to `resolve_claims_for_user` so the existing role.contexts filter actually kicks in - Admin context (name=`"0"`) is seeded on DB init so requests can be served before the first hero_osis sync - Sync uses raw JSON-RPC 2.0 (no `hero_osis_sdk` dep) — keeps the dep graph small since we only need two methods ## Test plan - [x] `cargo test --workspace` — all green, including the 3 previously-failing domain-routing integration tests - [x] 6 new unit tests covering seed/upsert/prune invariants + new-route default - [ ] Manual: run `hero_osis_server` + `hero_proxy_server` together, verify first-sync log line, verify context rows in `proxy.db`, verify unknown-context route returns 404 ## What's NOT in this PR - Exposing `context` on `AddDomainRoute`/`UpdateDomainRoute` + SDK/UI (admin API extension) - Push-based sync (event stream from hero_osis — no such thing yet) - Per-context rate limiting / quotas - Migration of `hero_router` vs `hero_proxy` ownership (still open per hero_rpc#13) See design note on #21 for more. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(proxy): context-aware ACLs — sync hero_osis context list + validate in request path
Some checks failed
Test / test (push) Failing after 1m36s
Test / test (pull_request) Failing after 1m58s
621311befe
Implements the proxy side of lhumina_code/hero_proxy#21.

- db: new `contexts` table (local mirror of hero_osis context list)
  with upsert/prune/exists/list methods; `domain_routes.context` column
  defaulting to "0" so each route declares its target hero_osis context
- context_sync: background polling loop that calls `base.context_list`
  and `base.context_get` over hero_osis's rpc.sock via raw JSON-RPC 2.0
  (no hero_osis_sdk dep — keeps graph small). Interval via
  HERO_PROXY_CONTEXT_SYNC_SECS (default 60s). Sync failures are
  warnings, never fatal
- proxy: `dispatch_domain_route` now validates `route.context` against
  the local cache (404 if unknown), injects the resolved value as
  `X-Hero-Context`, and passes it to `resolve_claims_for_user` so the
  existing role.contexts filter actually kicks in
- lib: `create_app_state_with_router` seeds the admin context (name="0")
  so both production and tests can serve requests before the first sync
- main: runs one initial sync synchronously at startup and spawns the
  background loop
- tests: 6 new unit tests covering seed/upsert/prune invariants and
  new-route defaults

No changes to the admin RPC surface: new routes still accept the old
AddDomainRoute shape and get `context="0"` via the SQL default. Exposing
context on create/update + UI is a follow-up.

See hero_osis#21 for the schema side.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
timur merged commit 46ab8602b3 into development 2026-04-12 16:32:07 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_proxy!22
No description provided.