feat(proxy): source X-Hero-Context from authenticated user, not route #24

Merged
timur merged 1 commit from feat_23_user_context into development 2026-04-12 17:02:16 +00:00
Owner

Closes #21 (via the corrected model in #23).

Why this reverts #22's per-route model

Per hero_skills/hero_os_architecture/context_and_security.md, context is a header dimension tied to identity, injected by the trusted boundary (hero_router in the doc; hero_proxy here) based on who is authenticated — not based on hostname. Services trust the header because they trust the boundary.

#22 put context on domain_routes, which pins context to hostname. That's the wrong shape. This PR corrects it.

What changed

Out: domain_routes.context, contexts cache table, context_sync polling module + env var, request-path 404-on-unknown-context, all associated DB helpers + tests.

In: users.context column (default 0). After each auth branch (none/oauth/signature + path-prefix IP auth) resolves a user, inject X-Hero-Context: <user.context> and pass to resolve_claims_for_user so the existing role.contexts filter applies correctly. Unauthenticated requests get no injection — upstream treats missing header as 0 (admin/internal-trust).

Net: +144 / -492 lines. #22 was mostly deleted.

Test plan

  • cargo test --workspace — all green (26 integration + 13 unit including 3 new for user.context)
  • Manual: create a user with context=5, hit an oauth-protected route as that user, verify hero_osis side receives X-Hero-Context: 5

What's NOT in this PR

  • Admin RPC/UI for setting users.context (the DB column + AddUser.context / UpdateUser.context are there; RPC surface + UI form field is a follow-up)
  • Multi-context users — client-supplied X-Hero-Context validated against user's allowed list
  • Live base.context_get validation at users.context write time

🤖 Generated with Claude Code

Closes #21 (via the corrected model in #23). ## Why this reverts #22's per-route model Per `hero_skills/hero_os_architecture/context_and_security.md`, context is a **header dimension tied to identity**, injected by the trusted boundary (hero_router in the doc; hero_proxy here) based on **who is authenticated** — not based on hostname. Services trust the header because they trust the boundary. #22 put context on `domain_routes`, which pins context to hostname. That's the wrong shape. This PR corrects it. ## What changed **Out:** `domain_routes.context`, `contexts` cache table, `context_sync` polling module + env var, request-path 404-on-unknown-context, all associated DB helpers + tests. **In:** `users.context` column (default 0). After each auth branch (`none`/`oauth`/`signature` + path-prefix IP auth) resolves a user, inject `X-Hero-Context: <user.context>` and pass to `resolve_claims_for_user` so the existing `role.contexts` filter applies correctly. Unauthenticated requests get no injection — upstream treats missing header as 0 (admin/internal-trust). Net: +144 / -492 lines. #22 was mostly deleted. ## Test plan - [x] `cargo test --workspace` — all green (26 integration + 13 unit including 3 new for user.context) - [ ] Manual: create a user with `context=5`, hit an oauth-protected route as that user, verify hero_osis side receives `X-Hero-Context: 5` ## What's NOT in this PR - Admin RPC/UI for setting `users.context` (the DB column + `AddUser.context` / `UpdateUser.context` are there; RPC surface + UI form field is a follow-up) - Multi-context users — client-supplied `X-Hero-Context` validated against user's allowed list - Live `base.context_get` validation at `users.context` write time 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(proxy): source X-Hero-Context from authenticated user, not route
All checks were successful
Build & Test / check (push) Successful in 3m25s
Build & Test / check (pull_request) Successful in 3m12s
5f7bb045ff
Implements hero_proxy#23. Replaces the per-route context model from #22
(wrong shape per hero_skills/hero_os_architecture/context_and_security.md
— context is a header dimension tied to identity, not to hostname).

What changed:
- Revert `domain_routes.context` column + `DomainRoute.context` field
- Revert `contexts` SQLite table, `upsert_context` / `prune_contexts_except`
  / `context_name_exists` / `list_contexts` / `seed_default_context`
- Revert `context_sync` module + polling loop + `HERO_PROXY_CONTEXT_SYNC_SECS`
  env var + initial-sync call in main.rs
- Revert request-path 404-on-unknown-context validation

What's new:
- `users.context INTEGER NOT NULL DEFAULT 0` column + idempotent migration
- `User.context`, `AddUser.context`, `UpdateUser.context` plumbed through
  insert/update/list/get/find-by-ip
- After each auth branch (`none`/`oauth`/`signature` + path-prefix IP auth)
  resolves a user, inject `X-Hero-Context: <user.context>` and pass the
  stringified value to `resolve_claims_for_user` so the existing
  `role.contexts` filter applies correctly
- For unauthenticated requests, no injection — upstream treats missing
  header as 0 (admin/internal-trust) per the hero context skill
- 3 new unit tests covering the default/explicit/update paths

Follow-ups (separate issues when needed):
- Admin RPC/UI for editing users.context
- Multi-context users (let client supply X-Hero-Context validated
  against their allowed list)
- Live `base.context_get` validation at users.context write time

Closes hero_proxy#21 (via the new model in #23).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
timur merged commit 7d3bfa3337 into development 2026-04-12 17:02:16 +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!24
No description provided.