Audits
For a full description of what each audit detects, finding format, and exclusion types, see the core audit reference.
Catalog audits
Catalog audits read database metadata (information schema / system catalogs). No SQL execution is analyzed.
| Audit | Assertion Bean | Exclusion type |
|---|---|---|
PrimaryKeyPresenceAudit |
PrimaryKeyPresenceAuditAssertion |
Table names (Set<String>). Liquibase bookkeeping tables are excluded automatically. |
PrimaryKeyTypeAudit |
PrimaryKeyTypeAuditAssertion |
Column names in table.column format (Set<String>) |
DuplicateForeignKeyAudit |
DuplicateForeignKeyAuditAssertion |
FK constraint names (Set<String>) |
ForeignKeyIndexAudit |
ForeignKeyIndexAuditAssertion |
FK constraint names (Set<String>) |
ForeignKeyNotNullAudit |
ForeignKeyNotNullAuditAssertion |
Column names in table.column format (Set<String>) |
ForeignKeyTypeMatchAudit |
ForeignKeyTypeMatchAuditAssertion |
Column names in table.column format (Set<String>) |
RedundantIndexAudit |
RedundantIndexAuditAssertion |
Index names (Set<String>) |
UniqueIndexNotNullAudit |
UniqueIndexNotNullAuditAssertion |
Index names (Set<String>) |
Catalog audit example
@Autowired
private PrimaryKeyPresenceAuditAssertion primaryKeyPresenceAuditAssertion;
@Autowired
private ForeignKeyIndexAuditAssertion foreignKeyIndexAuditAssertion;
@Test
void assertPrimaryKeysPresent() {
primaryKeyPresenceAuditAssertion.assertClean(schema);
}
@Test
void assertForeignKeysIndexed() {
foreignKeyIndexAuditAssertion.assertClean(schema, Set.of("fk_legacy_unindexed_constraint"));
}JPA audits
| Audit | Assertion Bean | Exclusion type |
|---|---|---|
SchemaEntityValidationAudit |
SchemaEntityValidationAuditAssertion |
None. The audit walks Hibernate’s entity mappings against the live schema and reports every mismatch (missing table, missing column, incompatible column type) in one run. Run under the default ddl-auto=none; do not set ddl-auto=validate, whose fail-fast startup check aborts the context on the first mismatch. |
UnmappedDatabaseObjectAudit |
UnmappedDatabaseObjectAuditAssertion |
Relations — a table or table.column name, optionally schema-qualified (Set<String>). The reverse of SchemaEntityValidationAudit: proves the schema holds only what is mapped. Exclude migration-tool bookkeeping tables (e.g. databasechangelog, databasechangeloglock). |
MissingVersionAttributeAudit |
MissingVersionAttributeAuditAssertion |
Entities — fully-qualified name, simple name, or physical table name (Set<String>) |
EagerCollectionFetchAudit |
EagerCollectionFetchAuditAssertion |
Collection roles, e.g. com.acme.Order.items (Set<String>) |
Runtime audits
Runtime audits intercept SQL statements via Hibernate’s StatementInspector. They split into two groups by
analysis technique.
Plan-based audits (PostgreSQL 16+ only)
WhereClauseIndexAudit, OrderByIndexAudit, and JoinIndexAudit call EXPLAIN (GENERIC_PLAN, FORMAT JSON) on
each captured statement — a PostgreSQL-specific feature, so these audits are PostgreSQL-only and throw
UnsupportedOperationException on any other platform. They also require preferQueryMode=simple on the test
datasource JDBC URL. See Usage — PostgreSQL JDBC requirement.
| Audit | Assertion Bean | Exclusion types |
|---|---|---|
WhereClauseIndexAudit |
WhereClauseIndexAuditAssertion |
Relation names (Set<String>), SQL fragments (List<String>) |
OrderByIndexAudit |
OrderByIndexAuditAssertion |
Relation names (Set<String>), SQL fragments (List<String>) |
JoinIndexAudit |
JoinIndexAuditAssertion |
Relation names (Set<String>), SQL fragments (List<String>) |
UnusedIndexAudit |
UnusedIndexAuditAssertion |
Index names (Set<String>). Advisory and workload-dependent: the capture must hold a representative
workload, and a generic plan can miss an index the planner would pick under production data. Always confirm
against production pg_stat_user_indexes before dropping an index this reports. |
Token-scan audits (all platforms)
These detect via a token scan of the captured SQL — no EXPLAIN needed — so they run on every supported
database platform.
| Audit | Assertion Bean | Exclusion types |
|---|---|---|
UnconditionalMutationAudit |
UnconditionalMutationAuditAssertion |
Exact statement strings (Set<String>) |
OffsetPaginationAudit |
OffsetPaginationAuditAssertion |
SQL fragments (List<String>) |
RepeatedStatementAudit |
RepeatedStatementAuditAssertion |
A threshold (int, minimum 2) plus SQL fragments (List<String>). Counts accumulate for the capturer’s
whole lifetime, so the threshold is a regression tripwire (a generous default like 50), not a precise N+1 count. |
Runtime audit example
// Priming test: must run before runtime audit assertions.
@Order(Integer.MIN_VALUE)
class RepositoryWorkloadIT extends AbstractDatabaseAuditIT {
@Autowired
private ParentRepository parentRepository;
@Test
void primeWorkload() {
parentRepository.findAll();
parentRepository.findById(1L);
}
}
// Runtime audit: runs after priming.
@Order(Integer.MAX_VALUE)
class WhereClauseIndexAuditIT extends AbstractDatabaseAuditIT {
@Autowired
private WhereClauseIndexAuditAssertion whereClauseIndexAuditAssertion;
@Test
void assertWhereClauseIndexClean() {
whereClauseIndexAuditAssertion.assertClean();
}
}Note: @Order across test classes requires ClassOrderer$OrderAnnotation enabled in
junit-platform.properties. See Usage — SQL capture ordering.
Assertion outcomes
A finding is surfaced as an AssertionError (test failure), not an exception, so it appears as a
discrete failing assertion in your test report with the audit’s curated fix-oriented message. An
IllegalStateException (test error) indicates a configuration problem: an unsupported platform, an empty
SQL capture (vacuous run), or a missing preferQueryMode=simple on PostgreSQL (see
Usage — PostgreSQL JDBC requirement).

