How deep a connected scan goes: catalog introspection only
The probe proves what the internet can see. A connected scan is the deeper half: authenticated, structural, and built so that the exact SQL it runs is inspectable before you grant anything.
Depth here means thoroughness about structure, not access to contents. The scan reads descriptions of your schema, never the rows inside it.
Six statements, all constants
A capture runs six statements: tables, columns, policies, indexes, buckets and server version. Each is a module-level constant in the scanner package reading only pg_catalog views plus storage.buckets metadata, and the whole set is exported as INTROSPECTION_QUERIES so a deployment can audit precisely what will execute.
The policy query resolves role OIDs to role names inside the SQL itself, so a finding can say "granted to anon, public" without a second round-trip. The index query separates key columns from INCLUDE payload, because payload columns cannot satisfy a predicate. The version statement travels with the snapshot so findings can be interpreted against the Postgres release that produced them.
Nothing is interpolated and no query accepts a bind parameter, because no query needs one. There is consequently no code path that could be steered towards a user table: the executor receives finished strings, and every string names pg_catalog or storage.buckets.
-- Abridged; the full text ships as INTROSPECTION_QUERIES.tables.
SELECT n.nspname AS schema_name,
c.relname AS table_name,
c.relrowsecurity AS rls_enabled,
c.relforcerowsecurity AS rls_forced
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r', 'p')
AND (n.nspname NOT IN ('pg_catalog', 'auth', 'storage', /* ... */)
OR (n.nspname = 'storage' AND c.relname = 'objects'))
ORDER BY n.nspname, c.relname;One snapshot, pure rules
The capture produces a single snapshot and stops talking to your database. Every catalog rule is then a pure function over that snapshot, which is why the number of round-trips is fixed regardless of how many rules exist, and why rules are tested against fixtures with no database present at all.
Purity pays off twice more. A rule improvement can be replayed over snapshots already stored with past scan runs, so history acquires the new judgement without touching your database again. And a finding can cite the snapshot it came from, so evidence and verdict travel together.
storage.objects is the deliberate exception to system-schema exclusion. Its policy state decides whether private buckets stay private, so it stays in scope while the rest of the managed schemas are ignored.
When something cannot be read
Missing privileges degrade the scan instead of breaking it. Without read access to storage.buckets, the bucket rule is skipped and a warning names the exact grant that enables it. An unreadable server version costs one field, not the run.
Warnings surface next to results in the dashboard and in the CLI report, so a scan that quietly checked less than usual never presents itself as a clean bill of health.
What the snapshot holds
Concretely, a snapshot carries: every developer-authored table with its RLS-enabled and RLS-forced flags; every column with its type and nullability; every policy with its command, permissive-or-restrictive flag, target roles, USING expression and WITH CHECK expression; every valid index with its key columns and any partial predicate; bucket metadata including the public flag; and the server version string.
That is the entire world the rules see. It is also why findings can be re-judged when rules improve: the evidence was complete at capture time, so a better rule needs no fresh conversation with your database to reach a sharper verdict about the past.
Auditing it yourself
You do not need to take the zero-data-access claim on faith. Read the INTROSPECTION_QUERIES export in packages/scanner/src/introspect.ts, or ask us at info@getveristria.com and we will walk through it. The same file holds the row interfaces the results are parsed into, so an auditor can check the whole contract in one sitting.
The absence of bind parameters is a property of the executor's type signature, not a promise buried in documentation: it accepts a finished SQL string and returns rows, and nothing in the package constructs SQL from user-shaped input. After capture, evaluation, storage and diffing happen entirely on RowShield's side, so your database sees one short-lived session per scan and nothing between scans.
Related questions
- Can I inspect the queries without reading the source?
- Yes. INTROSPECTION_QUERIES is exported deliberately: import it and print each member, or write to info@getveristria.com and we will send the current text of all six statements.
Did this answer your question? If not, tell us what is missing — article corrections go straight to the person who maintains it.