Skip to content

feat(server): enforce tenant boundary on all request-scoped lookups (6/7)#185

Draft
abhinav-galileo wants to merge 1 commit intoabhi/rfc-1-1-pr5-python-sdk-targetfrom
abhi/rfc-1-1-pr6-tenant-enforcement
Draft

feat(server): enforce tenant boundary on all request-scoped lookups (6/7)#185
abhinav-galileo wants to merge 1 commit intoabhi/rfc-1-1-pr5-python-sdk-targetfrom
abhi/rfc-1-1-pr6-tenant-enforcement

Conversation

@abhinav-galileo
Copy link
Copy Markdown
Collaborator

Stacked on top of #183. Addresses review feedback that PR1-PR5 record `tenant_id` but do not enforce the tenant boundary on reads/writes, allowing cross-tenant access and cross-tenant data mixing in runtime evaluation.

What this PR enforces

Every request-scoped lookup of a tenant-owned row (`Agent`, `Control`, `Policy`, `Target`) goes through a helper in `services/tenant_scoped_lookups.py` that returns 404 on cross-tenant access. Affected paths:

  • `endpoints/agents.py` - `list_agents`, `get_agent`, `_get_agent_or_404` (used by 11 endpoints), association add/remove for policies and controls, evaluator list/get, `patch_agent`.
  • `endpoints/controls.py` - `get_control`, `get_control_data`, `set_control_data`, `delete_control`, `patch_control`.
  • `endpoints/policies.py` - `add_control_to_policy`, `remove_control_from_policy`, `list_policy_controls`.
  • `endpoints/evaluation.py` - agent lookup in `evaluate`.
  • `endpoints/targets.py` / `services/targets.py` - `control_exists` becomes `control_exists_in_tenant`, so attaching a cross-tenant control to a target returns 404.

initAgent special case

`Agent.name` is still globally unique at the schema level, so a callers in tenant B cannot create an agent with a name tenant A already owns. Before: this would upsert onto tenant A's row. After: 409 `AGENT_NAME_CONFLICT` with a generic "agent name is not available" message that does not disclose which tenant holds the name.

What is still out of scope

  • Tenant-scoped uniqueness on `Agent.name`, `Control.name`, `Policy.name`. Names remain globally reserved until a later schema change relaxes uniqueness. This PR is about enforcement of the access boundary, not tenant independence.
  • Observability tables (`control_execution_events`).

Test plan

  • `make check` clean (579 server tests including 17 new enforcement tests, 503 SDK, 249 evaluators, others).
  • `make sdk-ts-generate-check` zero drift.
  • New `test_tenant_enforcement.py` covers:
    • cross-tenant `initAgent` (409, no tenant disclosure in body)
    • cross-tenant `get_agent`, `list_agents` (empty list), `patch_agent` (404)
    • cross-tenant `add_agent_policy` from either direction (404)
    • cross-tenant `add_agent_control` (404)
    • cross-tenant `get_control`, `set_control_data`, `patch_control`, `delete_control` (404)
    • cross-tenant `add_control_to_policy` from either direction (404)
    • cross-tenant `attach_target_control` where the control is in another tenant (404)
    • cross-tenant `evaluate` (404)
    • same-tenant sanity path still succeeds across all associations
  • Validated on integration branch with PR1-PR6 merged.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@abhinav-galileo abhinav-galileo force-pushed the abhi/rfc-1-1-pr6-tenant-enforcement branch from 7bf2e63 to 11c4a6f Compare April 20, 2026 21:55
Adds services/tenant_scoped_lookups.py with helpers for Agent, Control,
Policy, and Target that return 404 on cross-tenant access. Sweeps every
lookup path in agents, controls, policies, evaluation, and target
endpoints to use these helpers. initAgent now returns 409 with a
non-disclosing message when Agent.name is taken by another tenant,
since Agent.name is still globally unique at the schema level.

New test_tenant_enforcement.py covers cross-tenant access negatives for
every affected path plus a same-tenant sanity test.
@abhinav-galileo abhinav-galileo force-pushed the abhi/rfc-1-1-pr6-tenant-enforcement branch from 11c4a6f to 55574c1 Compare April 21, 2026 13:40
@abhinav-galileo abhinav-galileo changed the title feat(server): enforce tenant boundary on all request-scoped lookups (6/6) feat(server): enforce tenant boundary on all request-scoped lookups (6/7) Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant