paperclip/doc/BOARD-API-KEY-AUDIT-BOUNDAR...

68 lines
4.0 KiB
Markdown

# Board API Key Audit Boundary
Board API key allow decisions authorize a request only when the matching
security disposition is durable. PostgreSQL mutations and non-database effects
have different atomicity constraints, so this document states the boundary
explicitly.
## PostgreSQL guarantee
`server/src/security/board-key-audit-coupling.ts` stages an allow disposition in
the request context.
- A mutation inside `db.transaction` writes the allow disposition on that
transaction before the first domain mutation. Both commit or both roll back.
- Direct `db.insert`, `db.update`, `db.delete`, and mutating `db.execute` calls
are replayed lazily inside a transaction with the staged disposition. An
audit insert failure therefore rolls back the direct domain mutation.
- Direct mutation-builder operations that cannot be replayed safely fail before
issuing SQL and must be moved into an explicit `db.transaction`.
- There is no successful untransacted fallback. Response settlement persists
only successful no-mutation dispositions; it cannot convert an uncoupled
mutation into success.
This boundary deliberately classifies unknown raw SQL as mutating. Read-only
raw SQL is limited to statements beginning with `SELECT`, `SHOW`, `EXPLAIN`,
`TABLE`, or `VALUES`.
## Non-database side-effect review
The runtime route inventory denies undeclared board-key routes. Explicit denials
also cover the MCP surface, tool calls and sessions, plugin action/bridge/data
and webhook surfaces, skill-test execution, agent instruction-file mutation,
and auth/claim/invite surfaces. Board keys can still reach authorized management
routes whose handlers may combine PostgreSQL state with effects that PostgreSQL
cannot roll back.
| Reachable route family | Effect outside PostgreSQL | Residual failure mode |
| --- | --- | --- |
| Artifacts, attachments, company import/export, skills | Object storage or local filesystem writes/removals | An audit or domain rollback can leave an orphaned object/materialized tree; compensation can also fail. |
| Agents, heartbeat/runtime, workspaces, environments | Process start/cancel, git/worktree changes, or provider calls | A crash can occur between durable intent and execution/acknowledgement, causing a missed action or a retry. |
| Plugin and tool management | Plugin lifecycle, OAuth/provider, or network activity | Remote state cannot join the database transaction and may be applied despite a later local failure. |
| Activity publication, plugin events, assignee wakeups | In-process publication or adapter dispatch | A post-commit crash can miss delivery; retry after an ambiguous acknowledgement can duplicate delivery. |
The database audit coupling does not claim atomic rollback for these effects.
Side-effecting handlers must use the following pattern when the effect matters
to correctness or security:
1. Persist the domain change, board-key allow disposition, and an intent/outbox
row in one transaction.
2. Execute the external effect only from the committed intent.
3. Give the effect a stable idempotency key derived from the intent, not from a
delivery attempt.
4. Persist completion or failure so a worker can retry ambiguous outcomes.
5. Use compensating cleanup for object/file/provider state and treat cleanup as
retryable, not guaranteed rollback.
Existing durable wake requests and idempotency keys reduce duplicate/lost-work
risk where they are used. Live UI/plugin publications remain best effort. A
successful no-mutation request is audited during response settlement; if that
audit write fails there is no PostgreSQL domain commit to roll back. A handler
that performs only an external effect must therefore not rely on no-mutation
settlement: it needs a durable intent/outbox boundary before the effect.
When a route becomes board-key reachable, security review must identify every
filesystem, object-store, process, adapter, plugin, and outbound-network effect
and either prove an existing outbox/idempotency boundary or record the residual
risk and remediation owner.