The entire security-coverage pass, unfiltered. It builds a database-wide ownership map and checks whether data can cross a trust boundary through any kind of object. That covers SECURITY DEFINER functions, views, triggers, RLS policies and column grants. Each is classified as leaking, safely contained, or not judgeable. It writes pgTAP tests for the security cases and three reports. The PII audit runs as part of it. Enterprise edition.
unitautogen seccover --schema public --out sec_out
sec_report.html and sec_report.jsonrls_report.html and rls_report.jsoncls-report.html and cls_report.jsonfunctions/, triggers/, views/, rls/ and cls/, plus seed_gate.json<out>/security/<schema>/. Keep the default paths so the links between reports work.A leak is reported into any schema it reaches, whatever --schema names.
--schema a,b and --out DIR--sec-html PATH and --sec-json PATH move the report--sec-gate fails the run on a finding, see CI and CD--no-emit-tests a report-only run--no-pii-audit skips the PII audit--storage also checks Supabase Storage, see hipaaIt needs a licence that includes seccover, which is Enterprise. Startup and trial licences include it too. Without one it reports NOT LICENSED, generates nothing and exits with code 5. On Supabase, unitautogen --supabase seccover --schema public writes to supabase/tests/seccover/security/.
== security: DB-WIDE ownership map (20 RLS table(s) across all schemas, 3 identities) -- a leak is reported into ANY schema regardless of --schema ==
trigger bindings: 31 judged contained 3, leaking 13, no-tenant-axis 1, not-reached 14
[CONTAINED] sz.doc_safe :: trg_audit_safe -- role sz_user -- INSERT: the caller's cross-tenant INSERT is rejected (WITH CHECK or a trigger guard contains it) ...
[LEAKING] sz.docs2 :: trg_docs2 -- role sz_user -- INSERT: the caller's INSERT stamped with the rival's tenant reached the rival's scope in audit2, docs2 ...
CLS security report -> out\security\sz\cls-report.html (9 leaking, 0 enforced/contained, 0 unreliable)
24 (function, role) pair(s) judged over 13 function(s): 24 leaking, 0 too strict, 0 enforced, 0 unproven, 0 unproven cell(s); 0 not covered
security report -> out\security\sz\sec_report.html
A contents index, then numbered chapters, laid out like the HIPAA report. Every table has a row-number column, and every chapter heading has a link anchor.
| Chapter | What it shows |
|---|---|
| 1. Summary | Four totals, leaking, too strict, enforced and unproven, across functions, views, trigger bindings and RLS tables. Then one card per check, RLS policy tests, RLS leaks, trigger bindings, views and PII in errors, saying whether it ran and what it found. |
| 2. What to fix | Every finding ranked, with the object, the finding, the smallest database change that closes it and a link to the evidence. Fix now means another tenant's data is reachable or writable. Review means no leak, but a wrong result for an entitled caller, a policy error, an open policy or a hardening gap. Not evidenced means the path could not be exercised, so the fix is a test fixture. |
| 3. Reports | The other reports of the run, each with the question it answers and a link. Only files that exist are listed. |
| 4. How to read this report | A glossary of every verdict, flag, caller, cell mark, channel and column. |
| 5. Function verdicts | Every client-reachable SECURITY DEFINER function with its verdict, links to its unit test and security tests, its coverage, and one row per table and role with a mark per command. |
| View verdicts | Only when there are views. A view runs as its owner unless it is security_invoker, so the base table's RLS may never be checked for the caller. |
| Trigger bindings | Each trigger on a row-secured table, per role and command, with a Leaks into column naming the exact tables a leak reaches. |
| RLS policies, last | One matrix per table, identities by command, for row level and column level, with holes, too-strict and unreliable cells, policy errors and a pgTAP test link per table. Then the bypass surfaces. |
The marks read as follows. ✗ is a hole, the role can act but shouldn't. ! is too strict, an authorised caller is denied. ✓ is enforced as declared. ? is unproven, the check could not have fired.
Chapters 1 to 5 keep these numbers whenever the run judged functions. After that the numbers depend on what the run found. View verdicts appear only when there are views, then Not covered, What each caller got back and Member of 2 tenants when there is something to show, then Trigger bindings, Who else can read these tables, and the RLS policies last.
--sec-gate