Adds scripts/images/rds-mariadb/: the manifest with every mariadb package pinned =~11.8, setup.sh, the rds-datadir and rds-agent services, and the static include drop-in that points MariaDB at the generated configuration on the data volume. The AMI carries engine=mariadb, engine-version=11.8 and the data-volume contract tag, so resolveEngineAMI can select it.
The include is named zz- rather than 00-: MariaDB walks an include directory in byte order and takes the last occurrence of a setting, so a digit prefix would sort ahead of Alpine's packaged mariadb-server.cnf and let a distribution default beat a platform-owned one. setup.sh asserts the resulting order against the real directory at build time. The include target is baked empty as well, because MariaDB treats an includedir it cannot open as a fatal defaults-parsing error and a boot with no data volume would otherwise lose the client alongside the server.
The packaged drop-in also sets skip-networking, which would leave the endpoint resolving and the health probe passing while nothing on the customer ENI could connect. setup.sh disables it at the source and asserts no configuration file still does.
The mariadb service is deliberately not enabled: the packaged service only warns about an empty datadir rather than refusing, so an engine enabled before the bootstrap exists would launch mysqld_safe against an unbootstrapped volume.
rds-datadir moves to scripts/images/common/ rather than being copied. Volume selection, format authorization and mount are already engine-neutral; the mount point and owning user are the only per-engine facts and now come from each preset's own service. The script fails closed when either is unset, so no image can inherit another engine's layout by omission.
Another engine's datadir mounts cleanly and reads as uninitialised to
rds-init, which would initialise beside the customer's data and serve an
empty database that passes every health probe while the real data sits
unreferenced.
rds-init now writes the engine to ${DATA_MOUNT}/.spinifex-rds/engine
before the datadir is inspected, backfills it on attach for volumes
predating it, and refuses a stamp that disagrees.
Define the composite engine interface and a newEngine() factory keyed by a per-engine layout table, so the agent's defaults, health probe and command implementation all come from the engine the image bakes rather than from PostgreSQL-shaped constants. Rename PGBin/PGData/PGUser to EngineBinDir/EngineDataDir/EngineUser, delete PGIsReady, and give engineProbe an injected state function with the pg_isready exit-code mapping moved into the PostgreSQL implementation.
setup.sh now stamps /etc/spinifex-rds/engine and buildAgentUserData emits RDS_ENGINE. The agent compares the two after registering and refuses to run when they disagree, reporting unhealthy before the bootstrap handoff is written so rds-init never unblocks and no datadir is touched.
DBName was passed through unvalidated, so a name such as my-db was accepted
at CreateDBInstance and only quoted into safety by psql inside the guest.
Engine gains a validateDBName rule and ValidateDBName, and rds-init re-checks
the same rule in load_handoff before initdb, where a failure would clear the
datadir and spend the one-shot master password.
PostgreSQL caps the name at NAMEDATALEN-1.