ALive
Guard A
Whose data is this?
Every read from the database is filtered to your company before it runs. If our own code ever forgets to say which company, the read fails instead of returning anything.
A single session-level do_orm_execute listener adds tenant criteria to every tenant-bearing table (24 today, found by mapper introspection, so new tables are covered automatically). An unset scope raises TenantScopeViolation. Fail-closed is the default.
- Held in place by
- Automatic coverage of every table with a tenant column
- Not yet
- A second, database-level layer (Postgres row-level security) under raw SQL
BLive
Guard B
Are you allowed?
Every action checks the person’s role before it runs. A viewer can look but can’t approve or change anything, and another company’s records don’t exist for you at all.
can(principal, permission, resource) is a pure decision. It denies with no principal, with a permission outside the role, or when the resource belongs to another tenant. 104 route declarations use it, and it also gates agent tool calls and the inbound MCP bridge.
- Held in place by
- A test that classifies every route. A route with no declared check fails the suite.
- Not yet
- Nothing structural outstanding
CLive
Guard C
Where is it going?
When a workflow calls a web address you configured, Lyhnis checks where that address really points, and checks again after every redirect. Internal networks and the cloud’s metadata service are refused.
validate_egress_url(): scheme allowlist, an explicit block on the cloud metadata address, and a denylist of loopback, private, link-local and reserved ranges on every resolved IP. It fails closed on resolution errors and re-runs on each redirect hop.
- Held in place by
- Wired into every step that takes a user-supplied URL, including webhooks, MCP servers and OAuth
- Not yet
- Built-in connectors to fixed hosts (Stripe, Google, Microsoft and others) don’t pass through it yet. They can’t be pointed elsewhere, and one universal egress layer is planned.
DLive
Guard D
Who did it?
Every change goes into the audit trail through one front door. It records who acted (a person, an API key or the system) and from where, and strips secrets out before anything is stored.
audit_emit() owns attribution, redaction and de-duplication. Mutating requests are recorded by default, the API key that acted is recorded, and 97 older call sites were moved onto it.
- Held in place by
- A test that pins the audit posture and every reviewed exemption
- Not yet
- For five sensitive action types, the action and its record can be saved as one transaction. That mode is built and is being switched on type by type.