Security
Overview
Company OS enforces security through three core mechanisms:
- Tenant isolation via Row-Level Security (RLS) in PostgreSQL
- Principal identity resolution across communication channels
- Factory principal capability restrictions
Tenant Isolation
As specified in ADR-0001 §3.1 (THE-6), tenant isolation is achieved by:
- Row-Level Security (RLS) policies on all tables in the
osschema and any application schema containing tenant data - A mandatory
tenant_idcolumn on every table storing tenant-scoped data - A
TenantContextEffect-service that scopes every database connection viaSET LOCAL app.tenant_id = <current_tenant_id> - Compile-time enforcement: queries executed without an active
TenantContextare rejected
This ensures that application bugs cannot lead to cross-tenant data leaks, as RLS acts as a defense-in-depth mechanism.
Evidence:
- ADR-0001 §3.1: “Row-Level Security in Postgres +
tenant_idin elke tabel van schemaosen van elke app die tenant-data bevat + een verplichteTenantContext-Effect-service die elke databaseverbinding scoped (SET LOCAL app.tenant_id). Een query zonderTenantContextcompileert niet.” - Acceptance test: “principal van tenant A leest een rij van tenant B via een bewust verkeerde app-query → RLS weigert.”
Principal Identity Resolution
As specified in ADR-0001 §3.2 (THE-7), the OS resolves identities from various channels (WhatsApp, Teams, Better Auth, etc.) to a unified principal model:
- Core tables:
principal: storesid,tenant_id,class(user|agent|factory), andverantwoordelijke_principal_id(responsible human)principal_identity: links a principal to external identities via(principal_id, provider, external_id)agent_credential: stores credentials for agent principals
- Identity resolution is explicit: a channel identifier (e.g., WhatsApp number) must be explicitly linked to a principal by a tenant-admin; the OS never auto-creates principals
- The same human user may have multiple channel identities (e.g., WhatsApp and Teams) that resolve to the same principal
Evidence:
- ADR-0001 §3.2: “Voorstel:
principal (id, tenant_id, class: user|agent|factory, verantwoordelijke_principal_id),principal_identity (principal_id, provider, external_id)enagent_credential (principal_id, …)op dag één. Een WhatsApp-nummer, Teams-user en Better Auth-sessie resolven naar dezelfde principal of worden geweigerd; het OS maakt nooit impliciet een principal aan. Alleen een tenant-admin koppelt identiteiten.”
Factory Principal Restrictions
As specified in ADR-0001 §3.4 (THE-9), factory principals are restricted to dev-tooling capabilities:
- Principals of class
factoryare only granted capabilities wheretarget: dev-tooling(e.g., Linear, GitHub, CI, deploy) - The registry permission check rejects any attempt by a factory principal to invoke a capability with
target: tenant-app(which accesses tenant data) - This enforcement occurs at the registry level, not via prompt filtering, ensuring systemic security
Evidence:
- ADR-0001 §3.4: “Voorstel: principal-klasse
factorykrijgt alleen capabilities mettarget: dev-tooling(Linear, GitHub, CI, deploy). Capabilities mettarget: tenant-appweigeren een factory-principal in de registry-permissiecheck, niet in een prompt. Acceptatietest: factory-principal roeptsearch_aanvragenaan →deniedmet Receipt.”
Implementation Status
As of the current codebase:
- The authentication tables (
user,session,account,verification) exist in the public schema (see/packages/db/src/schema/auth.ts) - The OS schema (
principal,principal_identity,agent_credential) and RLS policies are planned for implementation in slice 1 (see ADR-0001 §5)
Related Systems
- [[/openwiki/systems/auth.md|Authentication]]: Better Auth integration for user sessions
- [[/openwiki/systems/database.md|Database]]: PostgreSQL usage and schema design
- [[/openwiki/concepts/one-way-doors.md|One-way Doors]]: THE-6 (tenant isolation) is a one-way door decision