Repository navigation
Validate PostgreSQL databases owned by a declared role (#121) - #131
Conversation
A PostgreSQL Service database may now name an owner role and its passwordRef instead of an application, so a team can declare only its database. The schema takes exactly one of application or owner, owner needs passwordRef, and remoteAccess declares a listen address and allowed sources. config validate refuses reserved owners and a remoteAccess that serves no owner, has no firewall, finds the port already open, or allows every address. The inventory models the reference, never a value. Configs that validated before render byte-identical. Converging the role is #122: until then the PostgreSQL role's argument spec refuses an owned database or remoteAccess before any task runs. Fixes #121 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The schema refused only the literal 0.0.0.0 and ::, so ::0 or 0:0:0:0:0:0:0:0 passed config validate as a listen address, and a non-canonical IPv6 address passed validate but crashed the inventory render on IpAddress. Validate the address through IpAddress and refuse an unspecified one with service_remote_access_listen_invalid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6144007 to
375f12a
Compare
|
@romamo Decided without waiting: owned-database validation adds two codes the spec doesn't name, Why: S-006-8 and S-006-11 rule out open access; without these, Reply with a comment starting with |
Summary
Schema and
config validatepart of S-006 (standalone PostgreSQL). A PostgreSQLServicedatabase may name anownerrole and itspasswordRef(environment,path,key) instead of anapplication. A project of one Server, its server type, and such a Service, with no Application or Component, now validates.spec.postgresql.remoteAccess(listenAddress,allowedSources) is accepted and checked.config/schemas/v1/service.schema.json: a database entry takes exactly one ofapplicationorowner(oneOf);ownerrequirespasswordRef(dependentRequired);applicationforbidspasswordRef(dependentSchemas).remoteAccesstakes one IPv4 or IPv6 listen address (wildcards refused) and a non-empty list of sourcessdk/src/cloudfall/validation.py:service_database_owner_reservedforpostgres,alloy, or the Linux user of an Application with a database on the same service;service_remote_access_unused,service_remote_access_unfirewalled,service_remote_access_port_open,service_remote_access_open, plusservice_remote_access_source_invalidfor a source that isn't a canonical CIDR. The changes stay inside the service validators (the PostgreSQL part moved into_validate_postgresql_service)sdk/src/cloudfall/inventory.py: newOwnedPostgresDatabase(name, owner,SecretValueReference) andPostgresRemoteAccess. The model holds the reference only, never a password value. An owned database rendersname,owner,passwordRefwith noapplicationkeysdk/src/cloudfall/domain.py: new value objectsPostgresRoleName,SecretKeyName,IpNetworkCidrConverging these declarations is #122. Until it lands, the
cloudfall_postgresqlrole's argument spec refuses an owned database orremoteAccessbefore any task runs. I checked this against the rendered inventory with Ansible'sArgumentSpecValidator: it reports "missing required arguments: application" and unsupportedpasswordRefandremoteAccess.Test plan
sdk/tests/test_owned_postgresql.py: one test per criterion S-006-1, 2, 3, 4 and 11, plus tests for rendering, an owner whose name matches an application user on another server, a non-canonical source, and wildcard listen addressesuv run ruff check .,uv run mypy,uv run cloudfall config validate --project config/examples: all passsdk/tests/test_validation.py,test_inventory.py,test_data_migration.py,test_migrate.py,engine/tests/test_ansible_inventory.py,test_postgresql_templates.py: 68 passedcloudfall-engine inventory render --project config/exampleswrites a byte-identical file on this branch and onorigin/main(cmp). That is the inventory half of S-006-12; its test is Converge owned PostgreSQL databases with their role and password (S-006-5, 6, 7, 12, 13) #122'sFixes #121
Plan
specs.py coverage --spec 006); byte-identical example inventory render🤖 Generated with Claude Code