Skip to content

Collapse the audit roster and add a MySQL/MariaDB archetype seam#15

Open
jeffjensen wants to merge 9 commits into
mainfrom
refactor/collapse-audit-roster
Open

Collapse the audit roster and add a MySQL/MariaDB archetype seam#15
jeffjensen wants to merge 9 commits into
mainfrom
refactor/collapse-audit-roster

Conversation

@jeffjensen

@jeffjensen jeffjensen commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Collapses the spring-boot audit roster behind a single registrar and adds a database-selection seam to the archetype. Two workstreams from the scaling plan (WS2 + WS3); every commit is atomic and the branch builds green — mvnw clean install, archetype Testcontainers self-test included.

WS2 — collapse the audit roster

One new audit used to edit ~4 parallel lists, and a forgotten facade wiring failed silently.

  • AuditAssertionRegistrar (a SmartInitializingSingleton) registers every DatabaseAuditSuite.all() assertion — and the DatabaseAuditAssertions facade — as a bean under its concrete type, replacing the 10 per-assertion @Bean methods in DatabaseAuditTestConfiguration. It registers bean definitions with an instance supplier so setPrimary works, and takes a name-prefix so a by-name peer datasource's beans don't collide with the primary's.
  • The archetype by-name token config (DatabaseAuditDsNameTokenTestConfiguration) shrank from 13 beans to 4 by delegating to the same registrar — no more untested bean-list copy.
  • DatabaseAuditSuite drops its 10 now-dead typed getters; all() (guarded by the roster test) is the single enumeration.

WS3 — archetype database-selection seam

The consumer-facing templates were already platform-neutral; only the demo harness was PostgreSQL-only.

  • New databasePlatform property (postgresql default, mysql, mariadb) drives DemoDatabaseTestConfig (container selected via Velocity; preferQueryMode=simple for PostgreSQL only), the JDBC driver + Testcontainers module in the generated pom, and deletion of the PostgreSQL-only plan ITs for other engines.
  • Added a full-mysql Testcontainers self-test running the catalog, JPA, and unconditional-mutation audits against MySQL.

Notable corrections found during verification

  • Kept RepositoryWorkloadIT for every engine (the plan draft proposed deleting it for non-PostgreSQL): UnconditionalMutationAudit throws on an empty capture, so its priming workload must still run.
  • Changelog: add the FK after its supporting index, so MySQL/MariaDB (which auto-index an unindexed FK) reuse idx_child_parent_id instead of adding a redundant one. End state identical on every engine.
  • MySQL PK audit: named Liquibase's bookkeeping tables lowercase on MySQL/MariaDB, because core's PrimaryKeyPresenceAudit exclusion matches the lowercase databasechangelog case-sensitively but MySQL stores an unquoted DATABASECHANGELOG uppercase. A core follow-up (make that exclusion case-insensitive) is tracked separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_0141skitWw3Cdgkf2kP3vve6

Summary by CodeRabbit

  • New Features
    • Added multi-database demo generation via databasePlatform (defaulting to PostgreSQL) and optional databaseImage override.
    • Audit checks are now organized by family (catalog/JPA/runtime) with a unified, automatic audit registration flow.
  • Bug Fixes
    • Generated projects only include PostgreSQL-specific plan audits when targeting PostgreSQL.
    • Improved cross-engine schema/catalog handling for Liquibase bookkeeping and schema selection.
  • Documentation
    • Updated archetype and site docs to replace the old PostgreSQL-only image flag with databasePlatform/databaseImage, and added guides for adding new databases and audits.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jeffjensen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ac1d18bb-f16d-4bf0-9939-177c704441f8

📥 Commits

Reviewing files that changed from the base of the PR and between f3e1c2b and 2a164ec.

📒 Files selected for processing (26)
  • CLAUDE.md
  • archetype/src/main/resources/META-INF/archetype-post-generate.groovy
  • archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
  • archetype/src/main/resources/archetype-resources/pom.xml
  • archetype/src/main/resources/archetype-resources/src/test/java/AbstractDatabaseAuditIT.java
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoPostgresTestConfig.java
  • archetype/src/main/resources/archetype-resources/src/test/java/runtime/RepositoryWorkloadIT.java
  • archetype/src/main/resources/archetype-resources/src/test/resources/application.properties
  • archetype/src/main/resources/archetype-resources/src/test/resources/db/changelog/db.changelog-master.xml
  • archetype/src/test/java/io/github/databaseaudits/archetype/PostGenerateScriptTest.java
  • archetype/src/test/resources/projects/disabled-tests/archetype.properties
  • archetype/src/test/resources/projects/full-mysql/archetype.properties
  • archetype/src/test/resources/projects/full-mysql/goal.txt
  • archetype/src/test/resources/projects/full/archetype.properties
  • archetype/src/test/resources/projects/targeted-datasource/archetype.properties
  • archetype/src/test/resources/projects/tests-only-targeted/archetype.properties
  • archetype/src/test/resources/projects/tests-only-with-project-dir/archetype.properties
  • archetype/src/test/resources/projects/tests-only/archetype.properties
  • archetype/src/test/resources/projects/with-parent-class/archetype.properties
  • integration/src/site/asciidoc/adding-a-database.adoc
  • integration/src/site/asciidoc/adding-an-audit.adoc
  • integration/src/site/asciidoc/archetype.adoc
  • integration/src/site/asciidoc/audits.adoc
  • integration/src/site/asciidoc/index.adoc
  • integration/src/site/site.xml
📝 Walkthrough

Walkthrough

This PR adds multi-engine database support to the archetype-generated demo project and refactors Spring integration audit wiring around AuditFamily, AuditScope, AuditAssertion, and AuditAssertionRegistrar. It also updates templates, fixtures, tests, and docs to match the new database selection and bean-registration flow.

Changes

Audit Assertion Framework Refactor

Layer / File(s) Summary
Audit contracts
integration/src/main/java/.../AuditFamily.java, AuditScope.java, AuditAssertion.java, AbstractAuditAssertion.java
Adds the family/scope assertion contract and makes the base assertion type implement it.
Assertion scope adapters
integration/src/main/java/.../assertion/*.java, DatabaseAuditExcludes.java
Each concrete assertion now reports its family and accepts AuditScope; DatabaseAuditExcludes adds JPA relation exclusions.
Suite roster and family dispatch
DatabaseAuditSuite.java, DatabaseAuditAssertions.java
The suite builds a unified roster and the facade filters assertions by family before running them.
Registrar wiring, tests, and docs
AuditAssertionRegistrar.java, DatabaseAuditTestConfiguration.java, DatabaseAuditDsNameTokenTestConfiguration.java, DatabaseAuditTestConfigurationIT.java, integration/src/site/asciidoc/*, integration/src/site/site.xml
Dynamic bean registration replaces per-assertion beans, and the related integration tests and documentation are updated to match.
Estimate DatabaseAuditTestConfigurationIT and the new registrar flow add the bulk of the review surface.

Archetype Multi-Engine Database Support

Layer / File(s) Summary
Metadata and post-generate rules
archetype-metadata.xml, archetype-post-generate.groovy
Replaces postgresImage with databasePlatform/databaseImage and gates PostgreSQL-only plan audit templates and console guidance.
Demo container and dependency selection
app/DemoDatabaseTestConfig.java, app/DemoPostgresTestConfig.java (removed), pom.xml, AbstractDatabaseAuditIT.java
Adds the shared multi-engine container config, removes the PostgreSQL-only config, and selects the matching test dependencies per platform.
Schema and Liquibase templates
application.properties, db.changelog-master.xml, RepositoryWorkloadIT.java
Adjusts schema/table handling for non-PostgreSQL engines and moves the child foreign key into its own changeSet.
Fixtures and archetype docs
archetype.properties, goal.txt, CLAUDE.md, archetype.adoc
Updates test project fixtures and generated-project documentation for the new platform/image properties and MySQL example project.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: collapsing audit roster wiring and adding a MySQL/MariaDB archetype seam.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/collapse-audit-roster

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Collapse audit assertion wiring via registrar; add MySQL/MariaDB archetype seam

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Replace per-audit Spring beans with a suite-driven registrar to prevent missing audits.
• Add archetype databasePlatform/databaseImage seam to generate Postgres/MySQL/MariaDB demo
 harnesses.
• Expand docs and self-tests, including a full MySQL Testcontainers archetype verification run.
Diagram

graph TD
  Cfg["Spring test config"] --> Reg["AuditAssertionRegistrar"] --> BF["BeanFactory registry"] --> Beans["*AuditAssertion beans"]
  Suite["DatabaseAuditSuite"] --> Reg --> Facade["DatabaseAuditAssertions"]
  Arch["Maven archetype"] --> Demo["DemoDatabaseTestConfig"] --> TC[("Testcontainers DB")]
  Arch --> Gen["post-generate cleanup"]
  subgraph Legend
    direction LR
    _cfg["Config/module"] ~~~ _svc["Component"] ~~~ _db[("Database")
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. ImportBeanDefinitionRegistrar / BeanDefinitionRegistryPostProcessor
  • ➕ Runs earlier in context refresh; avoids casting BeanFactory to BeanDefinitionRegistry in BeanFactoryAware
  • ➕ More idiomatic for programmatic bean definition registration
  • ➖ Harder to depend on an already-instantiated DatabaseAuditSuite instance (you’d typically register definitions, not instances)
  • ➖ More moving parts for consumers (import selectors, meta-annotations)
2. Expose List + @bean methods only for facade
  • ➕ Keeps all wiring declarative; no programmatic registration
  • ➕ Avoids custom bean naming rules and prefix logic
  • ➖ Doesn’t preserve existing per-assertion bean names/types for direct @Autowired injection without additional qualifiers
  • ➖ Harder to support primary vs peer datasource assertions cleanly without name collisions
3. Component-scan assertions with @component and inject audits
  • ➕ Least Spring-specific plumbing; relies on standard scanning/autowiring
  • ➕ Adds assertions automatically
  • ➖ Core constructors are framework-neutral by design; would leak Spring concerns into integration layer
  • ➖ Still needs an explicit roster/ordering to build audits and map excludes correctly

Recommendation: Keep the current approach: suite-owned roster (DatabaseAuditSuite#all()) + AuditAssertionRegistrar registering concrete assertion beans (with prefix + primary controls) preserves the existing consumer injection story while eliminating parallel bean lists. The main tradeoff (programmatic registration + bean-name rules) is justified by the need to avoid silent omissions and to support multi-datasource collision/primary semantics.

Files changed (40) +704 / -439

Enhancement (7) +279 / -2
archetype-post-generate.groovyDelete plan-based runtime ITs for non-PostgreSQL targets during generation +18/-2

Delete plan-based runtime ITs for non-PostgreSQL targets during generation

• Adds post-generate logic keyed off 'databasePlatform' to remove Join/OrderBy/WhereClause plan ITs for MySQL/MariaDB while retaining RepositoryWorkloadIT. Also gates the printed preferQueryMode guidance to PostgreSQL only.

archetype/src/main/resources/META-INF/archetype-post-generate.groovy

DemoDatabaseTestConfig.javaAdd engine-selectable Testcontainers demo config +70/-0

Add engine-selectable Testcontainers demo config

• Introduces a generated demo configuration that starts PostgreSQL/MySQL/MariaDB Testcontainers based on 'databasePlatform', with per-platform default images and optional 'databaseImage' override. Adds preferQueryMode=simple only for PostgreSQL and registers connection properties via DynamicPropertyRegistrar.

archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java

AuditAssertionRegistrar.javaAdd SmartInitializingSingleton registrar for assertion + facade beans +108/-0

Add SmartInitializingSingleton registrar for assertion + facade beans

• Introduces a programmatic bean registrar that registers each assertion from 'DatabaseAuditSuite#all()' and the 'DatabaseAuditAssertions' facade under concrete types, with configurable name prefixing and primary semantics.

integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java

AuditAssertion.javaIntroduce uniform AuditAssertion contract for generic execution +26/-0

Introduce uniform AuditAssertion contract for generic execution

• Adds an interface that exposes an assertion’s family and a uniform 'assertClean(AuditScope)' method, enabling roster-driven execution and generic Spring registration.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditAssertion.java

AuditFamily.javaAdd AuditFamily enum for catalog/JPA/runtime grouping +18/-0

Add AuditFamily enum for catalog/JPA/runtime grouping

• Introduces an enum used by the facade to select which assertions to run for each family-specific convenience method.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditFamily.java

AuditScope.javaAdd AuditScope record to pass schema + excludes through uniform API +18/-0

Add AuditScope record to pass schema + excludes through uniform API

• Adds a record that carries schema and exclusions so the facade can drive all audits through a single method without per-audit signature knowledge.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditScope.java

DatabaseAuditExcludes.javaAdd JPA excluded-relations slot to exclusions model +21/-0

Add JPA excluded-relations slot to exclusions model

• Introduces 'jpaExcludedRelations' to make JPA exclusions reachable via the facade’s 'assertAllClean' path and exposes a builder method for configuring it.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditExcludes.java

Bug fix (1) +9 / -2
db.changelog-master.xmlReorder Liquibase FK creation to avoid redundant indexes on MySQL/MariaDB +9/-2

Reorder Liquibase FK creation to avoid redundant indexes on MySQL/MariaDB

• Moves FK creation into a dedicated changeset after the supporting index to prevent engines that auto-index FKs from creating an extra redundant index, while keeping equivalent end state across platforms.

archetype/src/main/resources/archetype-resources/src/test/resources/db/changelog/db.changelog-master.xml

Refactor (15) +217 / -367
DatabaseAuditDsNameTokenTestConfiguration.javaUse AuditAssertionRegistrar instead of per-audit @Bean methods +22/-63

Use AuditAssertionRegistrar instead of per-audit @bean methods

• Removes the duplicated per-assertion bean list and replaces it with a registrar that publishes all suite assertions and the facade. Uses a name prefix and non-primary beans to avoid collisions with the primary datasource’s audit beans.

archetype/src/main/resources/archetype-resources/src/test/java/DatabaseAuditDsNameTokenTestConfiguration.java

DatabaseAuditSuite.javaCentralize audit roster into all() and build facade from it +39/-129

Centralize audit roster into all() and build facade from it

• Replaces individual stored assertion fields and typed getters with a single ordered list of 'AuditAssertion's. Updates documentation and construction so 'DatabaseAuditAssertions' is created from the roster and external wiring can iterate 'all()'.

integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java

DatabaseAuditTestConfiguration.javaReplace per-assertion @Bean methods with AuditAssertionRegistrar +16/-85

Replace per-assertion @bean methods with AuditAssertionRegistrar

• Removes the ten explicit assertion beans and the explicit facade bean, replacing them with a single registrar bean that registers all suite assertions and the facade as primary beans with conventional names.

integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfiguration.java

AbstractAuditAssertion.javaMake assertion base class implement AuditAssertion +1/-1

Make assertion base class implement AuditAssertion

• Updates the package-private base assertion class to implement the new 'AuditAssertion' interface so concrete assertions can provide the uniform family/scope entry points.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AbstractAuditAssertion.java

DatabaseAuditAssertions.javaRefactor facade to iterate suite roster by AuditFamily +28/-89

Refactor facade to iterate suite roster by AuditFamily

• Replaces the facade’s per-audit fields with a list of 'AuditAssertion's and uses predicate-based selection to run catalog/JPA/runtime/all. Moves Liquibase PK bookkeeping exclusion logic into the PK assertion’s 'AuditScope' adapter path.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java

ForeignKeyIndexAuditAssertion.javaAdapt FK index assertion to AuditAssertion (family + scoped entrypoint) +11/-0

Adapt FK index assertion to AuditAssertion (family + scoped entrypoint)

• Implements 'family()' and 'assertClean(AuditScope)' and maps scope schema/excludes to the existing typed overload.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyIndexAuditAssertion.java

ForeignKeyNotNullAuditAssertion.javaAdapt FK not-null assertion to AuditAssertion +11/-0

Adapt FK not-null assertion to AuditAssertion

• Implements the new family/scope methods and delegates to the existing typed 'assertClean(schema, excludedColumns)' overload.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyNotNullAuditAssertion.java

ForeignKeyTypeMatchAuditAssertion.javaAdapt FK type-match assertion to AuditAssertion +11/-0

Adapt FK type-match assertion to AuditAssertion

• Adds family identification and a scope-based 'assertClean' adapter that pulls schema and the appropriate exclusion slot.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyTypeMatchAuditAssertion.java

JoinIndexAuditAssertion.javaAdapt join-index runtime assertion to AuditAssertion +11/-0

Adapt join-index runtime assertion to AuditAssertion

• Implements family/scope methods and delegates to existing overload using plan relations and SQL fragment exclusions.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/JoinIndexAuditAssertion.java

OrderByIndexAuditAssertion.javaAdapt order-by runtime assertion to AuditAssertion +11/-0

Adapt order-by runtime assertion to AuditAssertion

• Adds the runtime family and a scope adapter that reads plan exclusion slots from 'DatabaseAuditExcludes'.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/OrderByIndexAuditAssertion.java

PrimaryKeyPresenceAuditAssertion.javaAdapt PK presence assertion to AuditAssertion and centralize bookkeeping exclusion +14/-0

Adapt PK presence assertion to AuditAssertion and centralize bookkeeping exclusion

• Implements family/scope methods and merges Liquibase bookkeeping tables with user exclusions when called via 'AuditScope', keeping the existing typed overload available for direct injection.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/PrimaryKeyPresenceAuditAssertion.java

RedundantIndexAuditAssertion.javaAdapt redundant-index assertion to AuditAssertion +10/-0

Adapt redundant-index assertion to AuditAssertion

• Implements catalog family and scope-based execution and delegates to the typed overload with schema and excluded index names.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/RedundantIndexAuditAssertion.java

SchemaEntityValidationAuditAssertion.javaAdapt JPA schema/entity assertion to AuditAssertion with excludes slot +11/-0

Adapt JPA schema/entity assertion to AuditAssertion with excludes slot

• Implements JPA family and adds scope-based execution that maps the new 'jpaExcludedRelations' exclusion set into the existing varargs overload.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/SchemaEntityValidationAuditAssertion.java

UnconditionalMutationAuditAssertion.javaAdapt unconditional mutation assertion to AuditAssertion +10/-0

Adapt unconditional mutation assertion to AuditAssertion

• Implements runtime family and adds scope-based execution delegating to the existing excluded-statements overload.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/UnconditionalMutationAuditAssertion.java

WhereClauseIndexAuditAssertion.javaAdapt where-clause runtime assertion to AuditAssertion +11/-0

Adapt where-clause runtime assertion to AuditAssertion

• Implements runtime family and scope adapter and delegates to the existing overload using plan exclusions.

integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/WhereClauseIndexAuditAssertion.java

Tests (10) +129 / -50
archetype.propertiesUpdate archetype IT inputs to databasePlatform/databaseImage +2/-1

Update archetype IT inputs to databasePlatform/databaseImage

• Replaces postgresImage with the new platform/image properties to match updated archetype metadata and templates.

archetype/src/test/resources/projects/disabled-tests/archetype.properties

archetype.propertiesAdd full MySQL archetype generation + verify self-test project +21/-0

Add full MySQL archetype generation + verify self-test project

• Adds a new end-to-end archetype IT project targeting MySQL, pinning a MySQL image and validating that non-PostgreSQL generation omits PostgreSQL-only runtime plan ITs while running the remaining audits.

archetype/src/test/resources/projects/full-mysql/archetype.properties

goal.txtRun 'verify' for the full-mysql archetype IT project +1/-0

Run 'verify' for the full-mysql archetype IT project

• Configures the new MySQL archetype self-test to execute Maven verify.

archetype/src/test/resources/projects/full-mysql/goal.txt

archetype.propertiesUpdate full archetype IT inputs to databasePlatform/databaseImage +2/-1

Update full archetype IT inputs to databasePlatform/databaseImage

• Migrates the existing full generation project to use the new properties while keeping PostgreSQL defaults.

archetype/src/test/resources/projects/full/archetype.properties

archetype.propertiesUpdate targeted-datasource archetype IT inputs to new DB properties +2/-1

Update targeted-datasource archetype IT inputs to new DB properties

• Switches from postgresImage to databasePlatform/databaseImage for consistency with the new archetype contract.

archetype/src/test/resources/projects/targeted-datasource/archetype.properties

archetype.propertiesUpdate tests-only-targeted archetype IT inputs to new DB properties +2/-1

Update tests-only-targeted archetype IT inputs to new DB properties

• Replaces postgresImage with databasePlatform/databaseImage so the self-test enumerates all referenced properties.

archetype/src/test/resources/projects/tests-only-targeted/archetype.properties

archetype.propertiesUpdate tests-only-with-project-dir archetype IT inputs to new DB properties +2/-1

Update tests-only-with-project-dir archetype IT inputs to new DB properties

• Replaces postgresImage with databasePlatform/databaseImage to align with updated metadata/templates.

archetype/src/test/resources/projects/tests-only-with-project-dir/archetype.properties

archetype.propertiesUpdate tests-only archetype IT inputs to new DB properties +2/-1

Update tests-only archetype IT inputs to new DB properties

• Replaces postgresImage with databasePlatform/databaseImage for updated archetype metadata compatibility.

archetype/src/test/resources/projects/tests-only/archetype.properties

archetype.propertiesUpdate with-parent-class archetype IT inputs to new DB properties +2/-1

Update with-parent-class archetype IT inputs to new DB properties

• Migrates postgresImage to databasePlatform/databaseImage while keeping PostgreSQL defaults.

archetype/src/test/resources/projects/with-parent-class/archetype.properties

DatabaseAuditTestConfigurationIT.javaAdd tests for registrar registration and suite roster guard +93/-43

Add tests for registrar registration and suite roster guard

• Refactors the wiring test to focus on suite construction, adds a registrar test verifying concrete-type publication + primary flag behavior, and adds a roster guard test that scans core audits to ensure each has a wired assertion in 'suite.all()'.

integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java

Documentation (4) +24 / -11
CLAUDE.mdDocument databasePlatform archetype seam and runtime IT generation rules +10/-4

Document databasePlatform archetype seam and runtime IT generation rules

• Updates the archetype/demo harness documentation to describe the new engine selection property, PostgreSQL-only plan IT handling, and why RepositoryWorkloadIT remains required for all engines.

CLAUDE.md

AbstractDatabaseAuditIT.javaGeneralize docs to container-backed database (not PostgreSQL-only) +1/-1

Generalize docs to container-backed database (not PostgreSQL-only)

• Updates Javadoc wording so the base IT class reads as database-agnostic rather than PostgreSQL-specific.

archetype/src/main/resources/archetype-resources/src/test/java/AbstractDatabaseAuditIT.java

RepositoryWorkloadIT.javaClarify priming workload purpose for all runtime audits +1/-1

Clarify priming workload purpose for all runtime audits

• Updates comments to reflect that the workload primes capture for runtime audits generally, not only plan-based audits.

archetype/src/main/resources/archetype-resources/src/test/java/runtime/RepositoryWorkloadIT.java

archetype.adocUpdate archetype docs for databasePlatform/databaseImage +12/-5

Update archetype docs for databasePlatform/databaseImage

• Replaces postgresImage references with the new platform/image properties in example commands and property documentation, explaining runtime IT differences and per-platform defaults.

integration/src/site/asciidoc/archetype.adoc

Other (3) +46 / -7
archetype-metadata.xmlIntroduce databasePlatform/databaseImage archetype properties +11/-3

Introduce databasePlatform/databaseImage archetype properties

• Replaces the PostgreSQL-only image property with 'databasePlatform' (postgresql/mysql/mariadb) and 'databaseImage' (override/pin container image). Documents how these properties affect generated runtime audits and dependencies.

archetype/src/main/resources/META-INF/maven/archetype-metadata.xml

pom.xmlTemplate engine-specific JDBC + Testcontainers dependencies +26/-1

Template engine-specific JDBC + Testcontainers dependencies

• Adds Velocity branching to include the correct Testcontainers module and JDBC driver based on 'databasePlatform', falling back to PostgreSQL defaults when not specified.

archetype/src/main/resources/archetype-resources/pom.xml

application.propertiesAdjust demo harness properties for MySQL/MariaDB Liquibase tables +9/-3

Adjust demo harness properties for MySQL/MariaDB Liquibase tables

• Renames the referenced demo config class and adds conditional Liquibase table-name settings for MySQL/MariaDB to ensure the PK audit’s bookkeeping exclusion applies consistently.

archetype/src/main/resources/archetype-resources/src/test/resources/application.properties

@qodo-code-review

qodo-code-review Bot commented Jul 3, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (2) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 31 rules

Grey Divider


Action required

1. DemoDatabaseTestConfig uses forbidden imports 📘 Rule violation § Compliance
Description
The archetype template DemoDatabaseTestConfig imports Spring and Testcontainers types, which
violates the restriction that archetype-generated classes may only depend on JUnit and
database-audits (besides the Java standard library). This can pull unwanted third-party dependencies
into generated projects.
Code

archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[R12-22]

+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.DynamicPropertyRegistrar;
+#if($databasePlatform == 'mysql')
+import org.testcontainers.mysql.MySQLContainer;
+#elseif($databasePlatform == 'mariadb')
+import org.testcontainers.mariadb.MariaDBContainer;
+#else
+import org.testcontainers.postgresql.PostgreSQLContainer;
+#end
+import org.testcontainers.utility.DockerImageName;
Evidence
PR Compliance ID 1493006 forbids third-party imports in archetype-generated sources other than JUnit
and database-audits. The added template imports Spring and Testcontainers classes, which are
explicitly disallowed by the rule.

Rule 1493006: Archetype-generated classes restrict dependencies to JUnit and database-audits
archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[12-22]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Archetype-generated classes must restrict imports (beyond `java.*`/`javax.*`) to JUnit and this project's `database-audits` packages. The new archetype template `DemoDatabaseTestConfig.java` imports Spring (`org.springframework.*`) and Testcontainers (`org.testcontainers.*`).

## Issue Context
This file is under `archetype-resources/`, meaning it is emitted into consumer projects.

## Fix Focus Areas
- archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[12-22]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Runtime facade runs PG-only ✓ Resolved 🐞 Bug ≡ Correctness
Description
DatabaseAuditSuite always wires the plan-based runtime assertions (Join/OrderBy/WhereClause) into
all(), and DatabaseAuditAssertions.assertRuntimeClean()/assertAllClean() executes all
assertions with family()==RUNTIME. Since the archetype explicitly treats those plan-based runtime
audits as PostgreSQL-only, calling the runtime/all-family facade methods on MySQL/MariaDB will still
attempt to run those PostgreSQL-only audits and can fail.
Code

integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java[R94-121]

        final QueryPlanExplainer queryPlanExplainer =
                new QueryPlanExplainer(dataSource, platform);

-        this.foreignKeyIndexAuditAssertion =
+        // The one legitimate enumeration of the roster, in family order
+        // (catalog, JPA, runtime); everything else drives it through all().
+        this.all = List.of(
                new ForeignKeyIndexAuditAssertion(new ForeignKeyIndexAudit(
-                        catalogQueries, indexCatalog, platform));
-        this.foreignKeyNotNullAuditAssertion =
+                        catalogQueries, indexCatalog, platform)),
                new ForeignKeyNotNullAuditAssertion(
-                        new ForeignKeyNotNullAudit(catalogQueries, platform));
-        this.foreignKeyTypeMatchAuditAssertion =
+                        new ForeignKeyNotNullAudit(catalogQueries, platform)),
                new ForeignKeyTypeMatchAuditAssertion(
-                        new ForeignKeyTypeMatchAudit(catalogQueries, platform));
-        this.primaryKeyPresenceAuditAssertion =
+                        new ForeignKeyTypeMatchAudit(catalogQueries, platform)),
                new PrimaryKeyPresenceAuditAssertion(
-                        new PrimaryKeyPresenceAudit(catalogQueries, platform));
-        this.redundantIndexAuditAssertion = new RedundantIndexAuditAssertion(
-                new RedundantIndexAudit(indexCatalog));
-        this.schemaEntityValidationAuditAssertion =
+                        new PrimaryKeyPresenceAudit(catalogQueries, platform)),
+                new RedundantIndexAuditAssertion(
+                        new RedundantIndexAudit(indexCatalog)),
                new SchemaEntityValidationAuditAssertion(
                        SchemaEntityValidationAudit.forEntityManagerFactory(
-                                entityManagerFactory, dataSource));
-        this.joinIndexAuditAssertion = new JoinIndexAuditAssertion(
-                new JoinIndexAudit(queryPlanExplainer, sqlCapturer));
-        this.orderByIndexAuditAssertion = new OrderByIndexAuditAssertion(
-                new OrderByIndexAudit(queryPlanExplainer, sqlCapturer));
-        this.whereClauseIndexAuditAssertion =
-                new WhereClauseIndexAuditAssertion(
-                        new WhereClauseIndexAudit(queryPlanExplainer,
-                                sqlCapturer));
-        this.unconditionalMutationAuditAssertion =
+                                entityManagerFactory, dataSource)),
+                new JoinIndexAuditAssertion(
+                        new JoinIndexAudit(queryPlanExplainer, sqlCapturer)),
+                new OrderByIndexAuditAssertion(
+                        new OrderByIndexAudit(queryPlanExplainer, sqlCapturer)),
+                new WhereClauseIndexAuditAssertion(new WhereClauseIndexAudit(
+                        queryPlanExplainer, sqlCapturer)),
                new UnconditionalMutationAuditAssertion(
-                        new UnconditionalMutationAudit(sqlCapturer));
-        this.assertions = new DatabaseAuditAssertions(
-                foreignKeyIndexAuditAssertion, foreignKeyNotNullAuditAssertion,
-                foreignKeyTypeMatchAuditAssertion,
-                primaryKeyPresenceAuditAssertion, redundantIndexAuditAssertion,
-                schemaEntityValidationAuditAssertion, joinIndexAuditAssertion,
-                orderByIndexAuditAssertion, whereClauseIndexAuditAssertion,
-                unconditionalMutationAuditAssertion);
+                        new UnconditionalMutationAudit(sqlCapturer)));
+        this.assertions = new DatabaseAuditAssertions(all);
Evidence
The suite’s roster always includes Join/OrderBy/WhereClause assertions, the facade runs every
RUNTIME assertion, and the archetype itself declares those plan-based audits PostgreSQL-only
(deleting their ITs on other engines). Together, this means the facade runtime/all entry points will
still attempt to run PostgreSQL-only audits on MySQL/MariaDB.

integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java[89-121]
integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java[84-86]
integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java[112-115]
integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/JoinIndexAuditAssertion.java[53-63]
integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/OrderByIndexAuditAssertion.java[52-62]
integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/WhereClauseIndexAuditAssertion.java[52-62]
archetype/src/main/resources/META-INF/archetype-post-generate.groovy[67-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On non-PostgreSQL engines, the facade methods `assertRuntimeClean()` and `assertAllClean()` will still drive Join/OrderBy/WhereClause plan-based audits because:
- `DatabaseAuditSuite#all()` always includes those assertions.
- Those assertions report `AuditFamily.RUNTIME`.
- The facade selects by family only.

But the archetype treats Join/OrderBy/WhereClause plan runtime audits as PostgreSQL-only and deletes their ITs for other platforms, indicating they are not intended to run on MySQL/MariaDB.

## Issue Context
This is a behavioral mismatch introduced/solidified by collapsing the roster behind `all()` + `AuditFamily` selection, combined with adding a MySQL/MariaDB generation path.

## Fix Focus Areas
- integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java[89-121]
- integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java[84-86]
- integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/JoinIndexAuditAssertion.java[53-63]
- integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/OrderByIndexAuditAssertion.java[52-62]
- integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/WhereClauseIndexAuditAssertion.java[52-62]

## Implementation notes
Preferred fix (keeps facade semantics correct cross-platform):
- In `DatabaseAuditSuite`, include Join/OrderBy/WhereClause assertions in `all()` only when the detected `DatabasePlatform` supports the plan-based audits (currently PostgreSQL).
- Keep `UnconditionalMutationAuditAssertion` in `RUNTIME` for all platforms.

Alternative fix:
- Split runtime families (e.g., `RUNTIME_PLAN` vs `RUNTIME_CAPTURE`) and update `assertRuntimeClean()` to run only the portable subset on non-PostgreSQL engines.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Test names missing required underscores 📘 Rule violation ▣ Testability
Description
Several newly added/modified JUnit test methods do not follow the required naming pattern
^test[A-Z][A-Za-z0-9]*_[A-Za-z0-9]+_[A-Za-z0-9]+$. This reduces consistency and may break tooling
that relies on the convention.
Code

integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java[R64-140]

+    void testDatabaseAuditSuiteBean_ConstructsAgainstCoreAuditConstructors()
            throws SQLException {
-        final DataSource dataSource = postgresDataSource();
        final SqlCapturingStatementInspector capturer =
                configuration.sqlCapturingStatementInspector();
+
        final DatabaseAuditSuite suite = configuration.databaseAuditSuite(
-                dataSource, mock(EntityManagerFactory.class), capturer);
-
-        assertThat(suite)
-                .as("The suite bean constructs against core's audit constructors.")
-                .isNotNull();
-        assertThat(configuration.foreignKeyIndexAuditAssertion(suite))
-                .as("The foreignKeyIndexAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.foreignKeyNotNullAuditAssertion(suite))
-                .as("The foreignKeyNotNullAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.foreignKeyTypeMatchAuditAssertion(suite))
-                .as("The foreignKeyTypeMatchAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.primaryKeyPresenceAuditAssertion(suite))
-                .as("The primaryKeyPresenceAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.redundantIndexAuditAssertion(suite))
-                .as("The redundantIndexAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.schemaEntityValidationAuditAssertion(suite))
-                .as("The schemaEntityValidationAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.joinIndexAuditAssertion(suite))
-                .as("The joinIndexAuditAssertion bean constructs.").isNotNull();
-        assertThat(configuration.orderByIndexAuditAssertion(suite))
-                .as("The orderByIndexAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.whereClauseIndexAuditAssertion(suite))
-                .as("The whereClauseIndexAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.unconditionalMutationAuditAssertion(suite))
-                .as("The unconditionalMutationAuditAssertion bean constructs.")
-                .isNotNull();
-        assertThat(configuration.databaseAuditAssertions(suite))
-                .as("The databaseAuditAssertions facade bean constructs.")
-                .isNotNull();
+                postgresDataSource(), mock(EntityManagerFactory.class),
+                capturer);
+
+        assertThat(suite.all())
+                .as("The suite bean wires every audit assertion against core's constructors.")
+                .isNotEmpty();
+    }
+
+    /**
+     * The stock registrar publishes every one of the suite's assertions — and
+     * the {@link DatabaseAuditAssertions} facade — as a primary bean under its
+     * concrete type, so consumers {@code @Autowired} the assertion they need
+     * without a per-audit {@code @Bean} method.
+     */
+    @Test
+    void testAuditAssertionRegistrar_PublishesEveryAssertionAndTheFacadeAsPrimaryBeans()
+            throws SQLException {
+        final DatabaseAuditSuite suite = new DatabaseAuditSuite(
+                postgresDataSource(), mock(EntityManagerFactory.class),
+                new SqlCapturingStatementInspector());
+        final DefaultListableBeanFactory beanFactory =
+                new DefaultListableBeanFactory();
+        final AuditAssertionRegistrar registrar =
+                configuration.auditAssertionRegistrar(suite);
+        registrar.setBeanFactory(beanFactory);
+
+        registrar.afterSingletonsInstantiated();
+
+        for (final AuditAssertion assertion : suite.all()) {
+            assertThat(beanFactory.getBean(assertion.getClass()))
+                    .as("The %s bean is the suite's own assertion instance.",
+                            assertion.getClass().getSimpleName())
+                    .isSameAs(assertion);
+        }
+        assertThat(beanFactory.getBean(DatabaseAuditAssertions.class))
+                .as("The facade bean is the suite's assertions facade.")
+                .isSameAs(suite.assertions());
+        assertThat(beanFactory
+                .getBeanDefinition("foreignKeyIndexAuditAssertion").isPrimary())
+                .as("The stock registrar marks its assertion beans primary.")
+                .isTrue();
+    }
+
+    /**
+     * Guards the roster: every concrete {@code *Audit} in core must have a
+     * wired {@code *AuditAssertion} in the suite, so adding a core audit without
+     * wiring it here fails the build instead of silently never running.
+     */
+    @Test
+    void testSuiteAll_WiresAnAssertionForEveryCoreAudit()
+            throws SQLException {
+        final ClassPathScanningCandidateComponentProvider scanner =
+                new ClassPathScanningCandidateComponentProvider(false);
+        scanner.addIncludeFilter(
+                new RegexPatternTypeFilter(Pattern.compile(".*Audit")));
+        final Set<String> coreAudits = scanner
+                .findCandidateComponents("io.github.databaseaudits.audit")
+                .stream()
+                .map(definition -> simpleName(definition.getBeanClassName()))
+                .collect(Collectors.toSet());
+
+        final DatabaseAuditSuite suite = new DatabaseAuditSuite(
+                postgresDataSource(), mock(EntityManagerFactory.class),
+                new SqlCapturingStatementInspector());
+        final Set<String> wiredAudits = suite.all().stream()
+                .map(DatabaseAuditTestConfigurationIT::auditName)
+                .collect(Collectors.toSet());
+
+        assertThat(wiredAudits).as(
+                "Every core *Audit has a wired *AuditAssertion in the suite.")
+                .isEqualTo(coreAudits);
Evidence
PR Compliance ID 1492971 mandates a specific testX_Y_Z method naming pattern. The added/modified
test methods in DatabaseAuditTestConfigurationIT do not have exactly two underscores and therefore
do not match the required regex.

Rule 1492971: Enforce descriptive test method naming pattern
integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java[64-140]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Test method names must match `^test[A-Z][A-Za-z0-9]*_[A-Za-z0-9]+_[A-Za-z0-9]+$` (three segments separated by exactly two underscores). Newly added/modified tests currently have only one underscore, so they violate the required convention.

## Issue Context
Non-compliant method names include `testDatabaseAuditSuiteBean_ConstructsAgainstCoreAuditConstructors`, `testAuditAssertionRegistrar_PublishesEveryAssertionAndTheFacadeAsPrimaryBeans`, and `testSuiteAll_WiresAnAssertionForEveryCoreAudit`.

## Fix Focus Areas
- integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java[64-140]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. MySQL schemaName mismatch 🐞 Bug ≡ Correctness
Description
For databasePlatform=mysql|mariadb, the generated demo container does not set its database name
based on schemaName, while the archetype default remains schemaName=public and the catalog ITs
pass that schema value into the audits. Generating a MySQL/MariaDB project by only changing
databasePlatform will therefore likely run catalog audits against the wrong/non-existent schema
unless the user also remembers to override schemaName.
Code

archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[R36-47]

+#if($databasePlatform == 'mysql')
+    private static final MySQLContainer DATABASE =
+            new MySQLContainer(DockerImageName.parse("${image}"));
+    static {
+        DATABASE.start();
+    }
+#elseif($databasePlatform == 'mariadb')
+    private static final MariaDBContainer DATABASE =
+            new MariaDBContainer(DockerImageName.parse("${image}"));
+    static {
+        DATABASE.start();
+    }
Evidence
The demo config starts MySQL/MariaDB containers without selecting a database name, while the
archetype default schemaName is public and the generated catalog ITs read that property and pass
it into the audit assertions; the added MySQL self-test has to override schemaName to test,
indicating the mismatch.

archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[36-47]
archetype/src/main/resources/META-INF/maven/archetype-metadata.xml[14-17]
archetype/src/main/resources/archetype-resources/src/test/java/catalog/PrimaryKeyPresenceAuditIT.java[29-38]
archetype/src/test/resources/projects/full-mysql/archetype.properties[9-14]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When generating a MySQL/MariaDB demo harness, the container’s database name is left at its Testcontainers default, but the archetype still defaults `schemaName` to `public` and the catalog ITs use `schemaName` for audit scope. This makes the generated MySQL/MariaDB demo easy to misconfigure (audits run against the wrong schema) unless the user also overrides `schemaName`.

## Issue Context
The PR adds `databasePlatform=mysql|mariadb` generation, so the previous PostgreSQL-centric `schemaName` default becomes a practical footgun for new platforms.

## Fix Focus Areas
- archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[36-47]

## Implementation notes
- For MySQL/MariaDB, configure the container with a database name matching the archetype’s `schemaName` (e.g., `DATABASE.withDatabaseName("${schemaName}")`) so the default `schemaName=public` remains consistent.
- Alternatively (or additionally), adjust documentation / archetype defaults so MySQL/MariaDB generation defaults `schemaName` to the container’s default database.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

5. Unsafe BeanFactory cast ✓ Resolved 🐞 Bug ☼ Reliability
Description
AuditAssertionRegistrar#setBeanFactory unconditionally casts BeanFactory to
BeanDefinitionRegistry, which can throw ClassCastException in Spring setups where the injected
factory isn’t a registry. This would prevent all assertion/facade beans from being registered.
Code

integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java[R73-77]

+    @Override
+    public void setBeanFactory(final BeanFactory beanFactory)
+            throws BeansException {
+        this.registry = (BeanDefinitionRegistry) beanFactory;
+    }
Evidence
The registrar stores a BeanDefinitionRegistry but populates it via an unchecked cast from
BeanFactory, which will crash at runtime if the factory doesn’t implement
BeanDefinitionRegistry.

integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java[73-77]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`AuditAssertionRegistrar#setBeanFactory` blindly casts `BeanFactory` to `BeanDefinitionRegistry`. If the provided BeanFactory implementation is not a registry, this fails with `ClassCastException` and the registrar won’t function.

## Issue Context
This registrar is a public integration seam; adding a defensive check yields clearer failures and avoids surprising runtime crashes in less-common Spring environments.

## Fix Focus Areas
- integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java[73-77]

## Implementation notes
- Replace the cast with an `instanceof` check.
- If not a `BeanDefinitionRegistry`, throw `IllegalStateException` with a clear message (e.g., requires `DefaultListableBeanFactory`/registry-backed context).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +64 to +140
void testDatabaseAuditSuiteBean_ConstructsAgainstCoreAuditConstructors()
throws SQLException {
final DataSource dataSource = postgresDataSource();
final SqlCapturingStatementInspector capturer =
configuration.sqlCapturingStatementInspector();

final DatabaseAuditSuite suite = configuration.databaseAuditSuite(
dataSource, mock(EntityManagerFactory.class), capturer);

assertThat(suite)
.as("The suite bean constructs against core's audit constructors.")
.isNotNull();
assertThat(configuration.foreignKeyIndexAuditAssertion(suite))
.as("The foreignKeyIndexAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.foreignKeyNotNullAuditAssertion(suite))
.as("The foreignKeyNotNullAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.foreignKeyTypeMatchAuditAssertion(suite))
.as("The foreignKeyTypeMatchAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.primaryKeyPresenceAuditAssertion(suite))
.as("The primaryKeyPresenceAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.redundantIndexAuditAssertion(suite))
.as("The redundantIndexAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.schemaEntityValidationAuditAssertion(suite))
.as("The schemaEntityValidationAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.joinIndexAuditAssertion(suite))
.as("The joinIndexAuditAssertion bean constructs.").isNotNull();
assertThat(configuration.orderByIndexAuditAssertion(suite))
.as("The orderByIndexAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.whereClauseIndexAuditAssertion(suite))
.as("The whereClauseIndexAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.unconditionalMutationAuditAssertion(suite))
.as("The unconditionalMutationAuditAssertion bean constructs.")
.isNotNull();
assertThat(configuration.databaseAuditAssertions(suite))
.as("The databaseAuditAssertions facade bean constructs.")
.isNotNull();
postgresDataSource(), mock(EntityManagerFactory.class),
capturer);

assertThat(suite.all())
.as("The suite bean wires every audit assertion against core's constructors.")
.isNotEmpty();
}

/**
* The stock registrar publishes every one of the suite's assertions — and
* the {@link DatabaseAuditAssertions} facade — as a primary bean under its
* concrete type, so consumers {@code @Autowired} the assertion they need
* without a per-audit {@code @Bean} method.
*/
@Test
void testAuditAssertionRegistrar_PublishesEveryAssertionAndTheFacadeAsPrimaryBeans()
throws SQLException {
final DatabaseAuditSuite suite = new DatabaseAuditSuite(
postgresDataSource(), mock(EntityManagerFactory.class),
new SqlCapturingStatementInspector());
final DefaultListableBeanFactory beanFactory =
new DefaultListableBeanFactory();
final AuditAssertionRegistrar registrar =
configuration.auditAssertionRegistrar(suite);
registrar.setBeanFactory(beanFactory);

registrar.afterSingletonsInstantiated();

for (final AuditAssertion assertion : suite.all()) {
assertThat(beanFactory.getBean(assertion.getClass()))
.as("The %s bean is the suite's own assertion instance.",
assertion.getClass().getSimpleName())
.isSameAs(assertion);
}
assertThat(beanFactory.getBean(DatabaseAuditAssertions.class))
.as("The facade bean is the suite's assertions facade.")
.isSameAs(suite.assertions());
assertThat(beanFactory
.getBeanDefinition("foreignKeyIndexAuditAssertion").isPrimary())
.as("The stock registrar marks its assertion beans primary.")
.isTrue();
}

/**
* Guards the roster: every concrete {@code *Audit} in core must have a
* wired {@code *AuditAssertion} in the suite, so adding a core audit without
* wiring it here fails the build instead of silently never running.
*/
@Test
void testSuiteAll_WiresAnAssertionForEveryCoreAudit()
throws SQLException {
final ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(
new RegexPatternTypeFilter(Pattern.compile(".*Audit")));
final Set<String> coreAudits = scanner
.findCandidateComponents("io.github.databaseaudits.audit")
.stream()
.map(definition -> simpleName(definition.getBeanClassName()))
.collect(Collectors.toSet());

final DatabaseAuditSuite suite = new DatabaseAuditSuite(
postgresDataSource(), mock(EntityManagerFactory.class),
new SqlCapturingStatementInspector());
final Set<String> wiredAudits = suite.all().stream()
.map(DatabaseAuditTestConfigurationIT::auditName)
.collect(Collectors.toSet());

assertThat(wiredAudits).as(
"Every core *Audit has a wired *AuditAssertion in the suite.")
.isEqualTo(coreAudits);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Test names missing required underscores 📘 Rule violation ▣ Testability

Several newly added/modified JUnit test methods do not follow the required naming pattern
^test[A-Z][A-Za-z0-9]*_[A-Za-z0-9]+_[A-Za-z0-9]+$. This reduces consistency and may break tooling
that relies on the convention.
Agent Prompt
## Issue description
Test method names must match `^test[A-Z][A-Za-z0-9]*_[A-Za-z0-9]+_[A-Za-z0-9]+$` (three segments separated by exactly two underscores). Newly added/modified tests currently have only one underscore, so they violate the required convention.

## Issue Context
Non-compliant method names include `testDatabaseAuditSuiteBean_ConstructsAgainstCoreAuditConstructors`, `testAuditAssertionRegistrar_PublishesEveryAssertionAndTheFacadeAsPrimaryBeans`, and `testSuiteAll_WiresAnAssertionForEveryCoreAudit`.

## Fix Focus Areas
- integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java[64-140]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +12 to +22
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.DynamicPropertyRegistrar;
#if($databasePlatform == 'mysql')
import org.testcontainers.mysql.MySQLContainer;
#elseif($databasePlatform == 'mariadb')
import org.testcontainers.mariadb.MariaDBContainer;
#else
import org.testcontainers.postgresql.PostgreSQLContainer;
#end
import org.testcontainers.utility.DockerImageName;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Demodatabasetestconfig uses forbidden imports 📘 Rule violation § Compliance

The archetype template DemoDatabaseTestConfig imports Spring and Testcontainers types, which
violates the restriction that archetype-generated classes may only depend on JUnit and
database-audits (besides the Java standard library). This can pull unwanted third-party dependencies
into generated projects.
Agent Prompt
## Issue description
Archetype-generated classes must restrict imports (beyond `java.*`/`javax.*`) to JUnit and this project's `database-audits` packages. The new archetype template `DemoDatabaseTestConfig.java` imports Spring (`org.springframework.*`) and Testcontainers (`org.testcontainers.*`).

## Issue Context
This file is under `archetype-resources/`, meaning it is emitted into consumer projects.

## Fix Focus Areas
- archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[12-22]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +36 to +47
#if($databasePlatform == 'mysql')
private static final MySQLContainer DATABASE =
new MySQLContainer(DockerImageName.parse("${image}"));
static {
DATABASE.start();
}
#elseif($databasePlatform == 'mariadb')
private static final MariaDBContainer DATABASE =
new MariaDBContainer(DockerImageName.parse("${image}"));
static {
DATABASE.start();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Mysql schemaname mismatch 🐞 Bug ≡ Correctness

For databasePlatform=mysql|mariadb, the generated demo container does not set its database name
based on schemaName, while the archetype default remains schemaName=public and the catalog ITs
pass that schema value into the audits. Generating a MySQL/MariaDB project by only changing
databasePlatform will therefore likely run catalog audits against the wrong/non-existent schema
unless the user also remembers to override schemaName.
Agent Prompt
## Issue description
When generating a MySQL/MariaDB demo harness, the container’s database name is left at its Testcontainers default, but the archetype still defaults `schemaName` to `public` and the catalog ITs use `schemaName` for audit scope. This makes the generated MySQL/MariaDB demo easy to misconfigure (audits run against the wrong schema) unless the user also overrides `schemaName`.

## Issue Context
The PR adds `databasePlatform=mysql|mariadb` generation, so the previous PostgreSQL-centric `schemaName` default becomes a practical footgun for new platforms.

## Fix Focus Areas
- archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java[36-47]

## Implementation notes
- For MySQL/MariaDB, configure the container with a database name matching the archetype’s `schemaName` (e.g., `DATABASE.withDatabaseName("${schemaName}")`) so the default `schemaName=public` remains consistent.
- Alternatively (or additionally), adjust documentation / archetype defaults so MySQL/MariaDB generation defaults `schemaName` to the container’s default database.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@jeffjensen jeffjensen force-pushed the refactor/collapse-audit-roster branch from 647409f to 3108543 Compare July 3, 2026 23:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integration/src/site/asciidoc/archetype.adoc`:
- Around line 136-140: Clarify the `databasePlatform` description in
`archetype.adoc` so it reflects that the value is used at generation time and
also by the post-generate script in `tests-only` mode. Update the wording in the
`databasePlatform` entry to remove “project only” and “Not used in tests-only
mode,” and make sure it still explains how `databasePlatform` drives the
generated `pom.xml` and which runtime ITs are included, including the
PostgreSQL-only audits.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ff40ed4-63b1-4495-9711-374e2a7af39b

📥 Commits

Reviewing files that changed from the base of the PR and between fd49d7d and 3108543.

📒 Files selected for processing (41)
  • CLAUDE.md
  • archetype/src/main/resources/META-INF/archetype-post-generate.groovy
  • archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
  • archetype/src/main/resources/archetype-resources/pom.xml
  • archetype/src/main/resources/archetype-resources/src/test/java/AbstractDatabaseAuditIT.java
  • archetype/src/main/resources/archetype-resources/src/test/java/DatabaseAuditDsNameTokenTestConfiguration.java
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoPostgresTestConfig.java
  • archetype/src/main/resources/archetype-resources/src/test/java/runtime/RepositoryWorkloadIT.java
  • archetype/src/main/resources/archetype-resources/src/test/resources/application.properties
  • archetype/src/main/resources/archetype-resources/src/test/resources/db/changelog/db.changelog-master.xml
  • archetype/src/test/resources/projects/disabled-tests/archetype.properties
  • archetype/src/test/resources/projects/full-mysql/archetype.properties
  • archetype/src/test/resources/projects/full-mysql/goal.txt
  • archetype/src/test/resources/projects/full/archetype.properties
  • archetype/src/test/resources/projects/targeted-datasource/archetype.properties
  • archetype/src/test/resources/projects/tests-only-targeted/archetype.properties
  • archetype/src/test/resources/projects/tests-only-with-project-dir/archetype.properties
  • archetype/src/test/resources/projects/tests-only/archetype.properties
  • archetype/src/test/resources/projects/with-parent-class/archetype.properties
  • integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfiguration.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AbstractAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditFamily.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditScope.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditExcludes.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyNotNullAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyTypeMatchAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/JoinIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/OrderByIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/PrimaryKeyPresenceAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/RedundantIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/SchemaEntityValidationAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/UnconditionalMutationAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/WhereClauseIndexAuditAssertion.java
  • integration/src/site/asciidoc/archetype.adoc
  • integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java
💤 Files with no reviewable changes (1)
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoPostgresTestConfig.java

Comment thread integration/src/site/asciidoc/archetype.adoc
@jeffjensen jeffjensen force-pushed the refactor/collapse-audit-roster branch from 3108543 to f882026 Compare July 3, 2026 23:55
jeffjensen and others added 3 commits July 4, 2026 09:09
…on seam

Collapse the parallel per-audit lists behind a family-agnostic AuditAssertion
contract, so the facade iterates the suite's roster instead of enumerating each
audit, and a forgotten audit fails the build instead of silently never running.

* Add AuditAssertion (family() + assertClean(AuditScope)), AuditFamily, and the
  AuditScope value; every *AuditAssertion implements it while keeping its typed
  assertClean(...) overloads for direct injection.
* DatabaseAuditSuite exposes all() and builds the DatabaseAuditAssertions facade
  from it; the facade groups its family runs by AuditFamily rather than holding
  ten fields.
* Add a jpaExcludedRelations slot to DatabaseAuditExcludes so JPA exclusions are
  reachable through assertAllClean (previously unreachable via the facade).
* Add a roster guard test: every concrete core *Audit must have a wired
  *AuditAssertion in suite.all().

This is the first slice of WS2 (collapse the audit roster). The stock config's
per-assertion @bean methods and the suite getters are unchanged for now; the
programmatic bean registrar and the real by-name config come next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C4hrFd9FTwoUZjZT16worW
…gistrar

Replace the ten per-assertion @bean methods (and the facade @bean) in
DatabaseAuditTestConfiguration with a single AuditAssertionRegistrar that
iterates DatabaseAuditSuite.all() and publishes each *AuditAssertion — plus the
DatabaseAuditAssertions facade — as a bean under its concrete type. Adding a core
audit no longer touches the config: once the suite wires its assertion, the
registrar exposes it.

* Add AuditAssertionRegistrar: a SmartInitializingSingleton that, once the suite
  bean exists, registers a bean definition (instance supplier) per assertion.
  Params: a bean-name prefix (so a by-name peer datasource's beans do not collide
  with the primary datasource's) and a primary flag (the primary datasource's
  beans win an unqualified by-type injection).
* DatabaseAuditTestConfiguration registers one with no prefix and primary=true,
  dropping the ten @bean methods and the facade @bean.
* DatabaseAuditSuite drops the ten now-unused typed getters and their fields;
  all() is built directly from the intrinsic construction lines (the one
  legitimate enumeration) and backs both the facade and the registrar.
* Rework DatabaseAuditTestConfigurationIT: the deleted @bean methods give way to
  a registrar test asserting every assertion and the facade register as primary
  beans; the suite-construction and roster-guard tests stay.

Completes WS2 step 4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141skitWw3Cdgkf2kP3vve6
… registrar

Shrink DatabaseAuditDsNameTokenTestConfiguration from thirteen beans to four: the
capturer, the static SqlCapturerRegisteringPostProcessor, the suite, and one
AuditAssertionRegistrar that publishes every *AuditAssertion (and the facade)
under dsNameToken-prefixed bean names. The ten per-assertion @bean methods and
the facade @bean — an untested copy of the stock config's bean list — are gone;
the template now mirrors the stock config's own mechanism, so adding a core audit
no longer touches it.

Completes WS2 step 6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141skitWw3Cdgkf2kP3vve6
@jeffjensen jeffjensen force-pushed the refactor/collapse-audit-roster branch from c98d715 to ec51654 Compare July 4, 2026 14:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
archetype/src/test/java/io/github/databaseaudits/archetype/PostGenerateScriptTest.java (1)

353-358: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: template content still hardcodes the class name.

TOKEN_CONFIG is used for the file name at Line 357 but the file content at Line 358 still hardcodes "class DatabaseAuditDsNameTokenTestConfiguration { ... }". Purely cosmetic since the value matches the constant, but referencing TOKEN_CONFIG there too would keep it single-sourced.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@archetype/src/test/java/io/github/databaseaudits/archetype/PostGenerateScriptTest.java`
around lines 353 - 358, The token template setup still hardcodes the
configuration class name inside setupTokenTemplate even though TOKEN_CONFIG
already defines it. Update the Files.writeString content in
PostGenerateScriptTest.setupTokenTemplate to build the class declaration from
TOKEN_CONFIG as well, so the filename and generated class stay single-sourced
and consistent if the constant changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java`:
- Around line 3-11: The custom database image path in DemoDatabaseTestConfig
needs to be marked as a compatible substitute so Testcontainers accepts mirrors
or forks. Update the logic that derives image names from
$databaseImage/$databasePlatform to apply .asCompatibleSubstituteFor(...) only
when a custom override is used, and keep the standard mysql/mariadb/postgres
defaults unchanged. Use the DemoDatabaseTestConfig image selection block and the
MySQLContainer/MariaDBContainer/PostgreSQLContainer setup to place the
compatibility handling where DockerImageName.parse("${image}") is created.

---

Nitpick comments:
In
`@archetype/src/test/java/io/github/databaseaudits/archetype/PostGenerateScriptTest.java`:
- Around line 353-358: The token template setup still hardcodes the
configuration class name inside setupTokenTemplate even though TOKEN_CONFIG
already defines it. Update the Files.writeString content in
PostGenerateScriptTest.setupTokenTemplate to build the class declaration from
TOKEN_CONFIG as well, so the filename and generated class stay single-sourced
and consistent if the constant changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2dd83e51-81df-40f1-a201-ece36f69e6d8

📥 Commits

Reviewing files that changed from the base of the PR and between 3108543 and f3e1c2b.

📒 Files selected for processing (50)
  • CLAUDE.md
  • archetype/src/main/resources/META-INF/archetype-post-generate.groovy
  • archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
  • archetype/src/main/resources/archetype-resources/pom.xml
  • archetype/src/main/resources/archetype-resources/src/test/java/AbstractDatabaseAuditIT.java
  • archetype/src/main/resources/archetype-resources/src/test/java/DatabaseAuditDsNameTokenTestConfiguration.java
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoDatabaseTestConfig.java
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoPostgresTestConfig.java
  • archetype/src/main/resources/archetype-resources/src/test/java/runtime/RepositoryWorkloadIT.java
  • archetype/src/main/resources/archetype-resources/src/test/resources/application.properties
  • archetype/src/main/resources/archetype-resources/src/test/resources/db/changelog/db.changelog-master.xml
  • archetype/src/test/java/io/github/databaseaudits/archetype/PostGenerateScriptTest.java
  • archetype/src/test/resources/projects/disabled-tests/archetype.properties
  • archetype/src/test/resources/projects/full-mysql/archetype.properties
  • archetype/src/test/resources/projects/full-mysql/goal.txt
  • archetype/src/test/resources/projects/full/archetype.properties
  • archetype/src/test/resources/projects/targeted-datasource/archetype.properties
  • archetype/src/test/resources/projects/tests-only-targeted/archetype.properties
  • archetype/src/test/resources/projects/tests-only-with-project-dir/archetype.properties
  • archetype/src/test/resources/projects/tests-only/archetype.properties
  • archetype/src/test/resources/projects/with-parent-class/archetype.properties
  • integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfiguration.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AbstractAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditFamily.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditScope.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditExcludes.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyNotNullAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyTypeMatchAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/JoinIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/OrderByIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/PrimaryKeyPresenceAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/RedundantIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/SchemaEntityValidationAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/UnconditionalMutationAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/WhereClauseIndexAuditAssertion.java
  • integration/src/site/asciidoc/adding-a-database.adoc
  • integration/src/site/asciidoc/adding-an-audit.adoc
  • integration/src/site/asciidoc/archetype.adoc
  • integration/src/site/asciidoc/architecture.adoc
  • integration/src/site/asciidoc/audits.adoc
  • integration/src/site/asciidoc/exclusions.adoc
  • integration/src/site/asciidoc/index.adoc
  • integration/src/site/asciidoc/usage.adoc
  • integration/src/site/site.xml
  • integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java
💤 Files with no reviewable changes (1)
  • archetype/src/main/resources/archetype-resources/src/test/java/app/DemoPostgresTestConfig.java
✅ Files skipped from review due to trivial changes (15)
  • archetype/src/test/resources/projects/targeted-datasource/archetype.properties
  • integration/src/site/asciidoc/index.adoc
  • archetype/src/test/resources/projects/full-mysql/goal.txt
  • archetype/src/test/resources/projects/disabled-tests/archetype.properties
  • archetype/src/main/resources/archetype-resources/src/test/java/runtime/RepositoryWorkloadIT.java
  • archetype/src/test/resources/projects/tests-only-targeted/archetype.properties
  • integration/src/site/asciidoc/architecture.adoc
  • integration/src/site/asciidoc/audits.adoc
  • archetype/src/main/resources/archetype-resources/src/test/java/AbstractDatabaseAuditIT.java
  • archetype/src/test/resources/projects/full/archetype.properties
  • integration/src/site/asciidoc/adding-a-database.adoc
  • archetype/src/test/resources/projects/tests-only/archetype.properties
  • integration/src/site/asciidoc/exclusions.adoc
  • integration/src/site/asciidoc/adding-an-audit.adoc
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (29)
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditAssertion.java
  • archetype/src/main/resources/archetype-resources/src/test/resources/application.properties
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditScope.java
  • archetype/src/main/resources/META-INF/archetype-post-generate.groovy
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/WhereClauseIndexAuditAssertion.java
  • archetype/src/main/resources/archetype-resources/src/test/resources/db/changelog/db.changelog-master.xml
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/JoinIndexAuditAssertion.java
  • archetype/src/test/resources/projects/tests-only-with-project-dir/archetype.properties
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/RedundantIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/UnconditionalMutationAuditAssertion.java
  • archetype/src/test/resources/projects/with-parent-class/archetype.properties
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyIndexAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/SchemaEntityValidationAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/PrimaryKeyPresenceAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyNotNullAuditAssertion.java
  • archetype/src/main/resources/archetype-resources/pom.xml
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/ForeignKeyTypeMatchAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AuditFamily.java
  • archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditExcludes.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/AuditAssertionRegistrar.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfiguration.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/OrderByIndexAuditAssertion.java
  • archetype/src/test/resources/projects/full-mysql/archetype.properties
  • archetype/src/main/resources/archetype-resources/src/test/java/DatabaseAuditDsNameTokenTestConfiguration.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/DatabaseAuditSuite.java
  • integration/src/test/java/io/github/databaseaudits/spring/boot/DatabaseAuditTestConfigurationIT.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/AbstractAuditAssertion.java
  • integration/src/main/java/io/github/databaseaudits/spring/boot/assertion/DatabaseAuditAssertions.java

jeffjensen and others added 6 commits July 4, 2026 13:40
Generated demo suites can now target MySQL or MariaDB, not only PostgreSQL, via a
new databasePlatform property (default postgresql). The consumer-facing audit ITs
were already platform-neutral; this generalizes the demo harness.

* Add databasePlatform (postgresql | mysql | mariadb) and generalize postgresImage
  to databaseImage (default none, deriving postgres:16 / mysql:8 / mariadb:11) in
  archetype-metadata.xml.
* Rename DemoPostgresTestConfig to DemoDatabaseTestConfig; it selects the
  PostgreSQL/MySQL/MariaDB Testcontainers container by databasePlatform via Velocity
  and applies preferQueryMode=simple for PostgreSQL only. The generated pom gates the
  JDBC driver and Testcontainers module on the platform.
* The plan-based runtime audits (Join/OrderBy/WhereClause index) are PostgreSQL-only,
  so archetype-post-generate.groovy deletes their ITs for other engines.
  RepositoryWorkloadIT and UnconditionalMutationAuditIT stay for every engine — the
  mutation audit throws on an empty capture, so its priming workload must still run
  (the plan draft proposed deleting RepositoryWorkloadIT; that would break the build).
* Add the foreign key after its supporting index in the demo changelog, so MySQL and
  MariaDB (which auto-index an unindexed foreign key) reuse idx_child_parent_id
  instead of adding a redundant one; the end state is identical on every engine.
* Name Liquibase's bookkeeping tables lowercase on MySQL/MariaDB, so the primary-key
  audit's built-in lowercase exclusion matches the otherwise-uppercase DATABASECHANGELOG.
* Add a full-mysql Testcontainers self-test (runs the catalog, JPA, and mutation
  audits against MySQL); update every existing self-test's archetype.properties.

Completes WS3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141skitWw3Cdgkf2kP3vve6
Update the generation guide (site archetype.adoc) property table and command
examples, and the project CLAUDE.md, to describe database-engine selection:
databasePlatform (postgresql/mysql/mariadb), databaseImage's per-platform defaults,
the renamed DemoDatabaseTestConfig, and that the plan-based audits are generated for
PostgreSQL only while the catalog, JPA, and unconditional-mutation audits run on
every engine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141skitWw3Cdgkf2kP3vve6
The page already defers to the core audit reference for the full audit
descriptions; dropping the leading audit-count/platform summary keeps the
count from drifting out of sync with core.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UEuiBscyCyDrtzszMwiAo8
The asciidoctor-parser doxia module drops inline NOTE/TIP/WARNING bodies (it
logs "Fallback behaviour for node: admonition"), so their text never reached
the rendered site. Convert them to bold "*Note:*"/"*Warning:*" lead-in
paragraphs — matching the extending guides — so the content shows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UEuiBscyCyDrtzszMwiAo8
The post-generate script test repeated the artifact id, the src/test/java path
prefix, the audited datasource's name and its derived bean names, and the
generated config class names as string literals across its cases. Hoist them
into private static final constants (alongside the existing PACKAGE_PATH) so the
datasource fixtures read as one set and the structural paths are named once.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UEuiBscyCyDrtzszMwiAo8
@jeffjensen jeffjensen force-pushed the refactor/collapse-audit-roster branch from f3e1c2b to 2a164ec Compare July 4, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant