Skip to content

fix(modules): name per-app resources by app and inject usable Postgres credentials - #185

Merged
Alexanderamiri merged 1 commit into
mainfrom
fix/db-per-app-wiring
Oct 31, 2026
Merged

Alexanderamiri merged 1 commit into
mainfrom
fix/db-per-app-wiring

Conversation

@Alexanderamiri

Copy link
Copy Markdown
Member

Problem

  • service-bucket, service-database, service-queue and service-rds named resources {team}-{name}, with no app name in it. Two apps in one team that both declare e.g. databases: [{name: main}] would collide.
  • For Postgres, env got the RDS endpoint as host:port, which is not a usable connection URL. The master password went to SSM but was never injected into the task. The user was hardcoded to postgres and the app was never told what it was.
  • The task role was granted rds-db:connect, but IAM database authentication is not enabled on the instance, so the grant did nothing.
  • docs/app-yaml-reference.md documented the password at /{project}/apps/{name}/db-master-password. The real path is /javabin/apps/<team>/<dbname>/db-master-password.

Change

  • Naming: the modules now name resources {team}-{service}-{name}, where service is the app name. That covers the S3 bucket (…-{account_id}), DynamoDB table, SQS queue and DLQ, and RDS (instance, subnet group, SG, final snapshot). The RDS password moves to /javabin/apps/{team}/{app}/{name}/db-master-password. service-rds gets a new required service variable, and the generator passes it. The new names still match the boundary's DenyBadName {team}-* patterns, the team exec role's /javabin/apps/{team}/* read, and the SSO deny on apps/*/*/db-master-password (IAM * spans /). app-secret-rollout does not match the nested path, so it still ignores the password.

  • Postgres wiring (generator): new keys jdbc_env, user_env and password_env, next to env, host_env and port_env.

    • env → postgresql://host:port/db (libpq URI)
    • jdbc_env → jdbc:postgresql://host:port/db
    • user_env → master user
    • password_env → the SSM password ARN as an ECS secrets entry

    The URLs contain no credentials, because the generated password has characters that would need URL-encoding. New module outputs: url, jdbc_url, username. master_username is now a variable (default postgres).

  • IAM: the rds-db:connect statement is gone. The task role keeps ssm:GetParameter on its own password.

  • Adopted DBs: env, jdbc_env, user_env and password_env are rejected with adopt. The platform does not know the database name or credentials of an adopted DB, so those values stay in secrets:. host_env and port_env work as before.

  • Validation: generation now rejects names that would make an invalid resource:

    • an RDS identifier that is not letters, digits and single hyphens, is over 63 characters, or has a database name that does not start with a letter
    • a bucket name with underscores, or over 63 characters
    • a DLQ name over 80 characters

    It also rejects one variable name used for two database values, and a database variable that another resource already sets.

  • Docs: docs/app-yaml-reference.md (env table, correct password path, naming table), docs/reusable-modules.md, terraform/modules/README.md and CLAUDE.md.

Existing resources: nothing is renamed

On 2026-10-31 I checked live AWS (AWS_PROFILE=javabin, account 553637109631) and every app state in javabin-terraform-state-553637109631: cupcake/cupcake-backend, cupcake/cupcake, javazoneweb/javazone-2027, jzwatch/jz-watch and testteam/platform-test-app. None of them contains a bucket_*, database_*, queue_* or rds_* module. Only secret_* modules exist, and their naming does not change.

  • The only RDS instance, dbmoresleep, is a legacy instance meant for adopt, and the adopted path does not change.
  • The only SQS queue, javazone-talk-events, comes from a separate project (Project=javazone-es-integration), not from this module.
  • No DynamoDB table or S3 bucket follows the module pattern.
  • A GitHub code search for buckets/databases/queues in javaBin app.yaml files finds only commented examples in app-template.

So no compat or moved path is needed. If an app adds one of these resources before this merges, its next plan would replace that resource. Check new app PRs for that until this lands.

Verification

  • python3 -m unittest discover -s scripts/tests: 142 tests OK. New PerAppResourceTest covers app naming in every module, URL/JDBC/user/password injection (password in secrets, not environment), variable-name clashes, and the identifier, bucket and queue name limits. The adopt tests cover the rejected keys.
  • python3 -m unittest discover -s terraform/lambda-src/tests: 219 tests OK.
  • terraform fmt -check -recursive terraform/modules, and terraform validate for service-rds, service-bucket, service-database and service-queue.
  • Generated a full app (bucket, DynamoDB, Postgres with all env keys, queue), pointed its module sources at the local modules, and ran terraform init -backend=false && terraform validate: valid.

🤖 Generated with Claude Code

…s credentials

S3, DynamoDB, SQS and RDS resources are now {team}-{app}-{name}, so two
apps in one team no longer collide. Postgres entries get a credential-free
postgresql:// URL (env), a JDBC URL (jdbc_env), the master user (user_env)
and the password as an ECS secret (password_env). The rds-db:connect grant
is dropped (IAM DB auth was never enabled). Generation rejects names that
would make an invalid RDS identifier, bucket or queue name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Alexanderamiri
Alexanderamiri requested a review from a team as a code owner October 31, 2026 12:09
@github-actions

Copy link
Copy Markdown

Terraform Plan

✅ No changes — infrastructure is up to date.

Plan output
Acquiring state lock. This may take a few moments...
aws_ssm_parameter.atlassian_org_id: Refreshing state... [id=/javabin/platform/atlassian-org-id]
aws_ssm_parameter.atlassian_api_key: Refreshing state... [id=/javabin/platform/atlassian-api-key]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.

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