Skip to content
Company OS
Esc
↑↓navigate↵open⌘Jpreview
On this page

Security

Overview

Company OS enforces security through three core mechanisms:

  1. Tenant isolation via Row-Level Security (RLS) in PostgreSQL
  2. Principal identity resolution across communication channels
  3. 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 os schema and any application schema containing tenant data
  • A mandatory tenant_id column on every table storing tenant-scoped data
  • A TenantContext Effect-service that scopes every database connection via SET LOCAL app.tenant_id = <current_tenant_id>
  • Compile-time enforcement: queries executed without an active TenantContext are 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_id in elke tabel van schema os en van elke app die tenant-data bevat + een verplichte TenantContext-Effect-service die elke databaseverbinding scoped (SET LOCAL app.tenant_id). Een query zonder TenantContext compileert 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: stores id, tenant_id, class (user|agent|factory), and verantwoordelijke_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) en agent_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 factory are only granted capabilities where target: 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 factory krijgt alleen capabilities met target: dev-tooling (Linear, GitHub, CI, deploy). Capabilities met target: tenant-app weigeren een factory-principal in de registry-permissiecheck, niet in een prompt. Acceptatietest: factory-principal roept search_aanvragen aan → denied met 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)
  • [[/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

Was this page helpful?