ACL state per context — consume hero_osis context list for access control #21
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_proxy#21
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Companion to lhumina_code/hero_osis#21.
Context
hero_osis now owns the authoritative list of contexts (namespaces/buckets for data isolation). The
Contextrootobject in thebasedomain has been extended with:description— human-readable purposetags— grouping/filteringdb_path— filesystem path OSIS uses for this context's databaseThe admin context (X-Hero-Context: 0) is the canonical holder of the list; all context CRUD flows through
base.context_*RPC methods in hero_osis.See the referenced comment for the updated routing model (header-based contexts, claims-based auth, hero_router as sole TCP entry): lhumina_code/hero_rpc#13 (comment)
What hero_proxy needs to do
base.context_listagainst context 0 to learn which contexts exist and their metadata.X-Hero-Context: <n>, verify the caller is authorized for that context per local ACL state. Reject with an appropriate error otherwise.Deliverables
base.context_liston hero_osisNotes
X-Hero-Claimsheader = FULL TRUST (internal call). Claims present = restricted. ACL enforcement should only kick in on the restricted path.Design note (per deliverable #1)
Where ACL state lives
Keep it in the existing SQLite DB (
hero_proxy.db). Rationale:roles.contextscolumn (comma-separated) already filters claims by contextauthz::resolve_claims_for_user()already accepts acontextparam and applies the filterSchema additions:
contexts— a cached mirror of hero_osis's context list (not the source of truth, just a lookup for validation + UI display)sid TEXT PRIMARY KEY— hero_osis SIDname TEXT NOT NULL UNIQUE— the integer string used inX-Hero-Context(e.g. "0", "1")description TEXT,tags TEXT(comma-separated),db_path TEXTsynced_at TEXT— timestamp of last sync from hero_osisdomain_routes:context TEXT NOT NULL DEFAULT '0'— declares which context this route forwards to. Overrides the hardcoded"0"at proxy.rs:548.Sync model: pull (polling), not push
hero_osis has no event/pubsub mechanism today. Start with a background task:
CONTEXT_SYNC_INTERVAL_SECS(default 60s): refreshbase.context_list→base.context_getper sid), diff against localcontextstable, upsert new/changed, delete ones that disappearedBaseClient::new("unix://$HERO_SOCKET_DIR/hero_osis/rpc.sock", "0")— always query via context 0 (the admin context, per hero_osis#21)Push model can be added later if/when hero_osis grows an event stream.
Enforcement in the request path
Replace the hardcoded
"0"at proxy.rs:548 with:domain_route.context(new column) as the intended context for this routecontextscache — if not present, reject with 404 Not Found (leaks less than 403; the request simply has nowhere to go)resolve_claims_for_user(..., context=Some(&ctx))— existing code already filters roles by contextX-Hero-Context: <ctx>— already stripped from incoming requests for security, we own the valueTrust model reminder: internal calls without
X-Hero-Claimsstill get FULL TRUST at the service. The proxy's ACL layer only kicks in for authenticated external requests. No change to that.Scope of this issue (Phase 1)
contextstable +domain_routes.contextcolumnhero_osis_sdkdependency withbasefeaturecontext_syncmodule with background refresh taskExplicitly out of scope (follow-up issues)
domain_routes.contextin hero_proxy_uiroles.contextsvalues (those are still honored; no breaking change)Router question — still open
Per hero_rpc#13, hero_router is the sole TCP entry point. Today hero_proxy is still the active ingress on ports 9997/9996. Proceeding with implementation in hero_proxy because it's the current runtime reality. If hero_router absorbs ingress later, this code moves with the proxy logic; the DB schema + sync module are reusable.
First-pass implementation in #22.
Delivered:
Deferred to follow-ups:
contexton AddDomainRoute/UpdateDomainRoute + SDK/UIClosing. The per-route model from #22 was the wrong shape (context is a header dimension tied to identity, not hostname, per hero_skills/hero_os_architecture/context_and_security.md). Corrected in #23/#24: context now sourced from
users.context, injected asX-Hero-Contextafter each auth branch resolves a user. Follow-ups (admin RPC/UI for users.context, multi-context users, live validation at write time) tracked on #23 or separate issues when needed.