verify-db-posture-at-the-targetlisted
Install: claude install-skill damson/hard-won-skills
# Verify database posture at the target
A permission change has at least three surfaces and they disagree. The catalog
says a switch is on. The privilege functions say a role holds a grant. The API
says what a person with a browser key actually receives. Reading one and
reporting the others is how a production endpoint served an empty list to every
anonymous caller for days while `pg_class` looked perfectly healthy: row-level
security was on with no policy behind it, which is catalog-clean, deny-all, and
indistinguishable from a table that is simply empty.
Read every layer separately, and when two disagree, the API is the one users
live in.
## Procedure
1. **Catalog.** Query the objects the change names, never the migration you
just wrote: `pg_class.relrowsecurity`, `pg_policy`, `pg_proc.proacl` and
`proconfig`, `information_schema.role_table_grants`. A migration is a
statement of intent; this is the outcome. Count only the policies that can
admit the command you care about (`polcmd in ('r', '*')` for a read) and only
the permissive ones: a table carrying one `UPDATE` policy reports a
reassuring non-zero while reads are still deny-all. An empty result set is a
third answer, not a clean one, and it means the relation is not there.
2. **Role.** Ask `has_table_privilege` and `has_function_privilege` for each
role that matters, including the service account that actually performs the
work, not only `anon` and `authenticated`. A privilege reaching a