Skip to content

Import rds-postgres-server and rds-postgres-db from nullplatform/services - #2

Merged
sebastiancorrea81 merged 37 commits into
mainfrom
feature/import-rds-postgres-from-services-monorepo
Jul 7, 2026
Merged

Import rds-postgres-server and rds-postgres-db from nullplatform/services#2
sebastiancorrea81 merged 37 commits into
mainfrom
feature/import-rds-postgres-from-services-monorepo

Conversation

@sebastiancorrea81

Copy link
Copy Markdown
Contributor

Summary

  • Extracts databases/rds-postgres-server and databases/rds-postgres-db from the nullplatform/services monorepo into this dedicated repository, preserving their commit history, at the repo root (no databases/ prefix).
  • Adapts module source URLs, service_path, and repository_name defaults to point at this repo instead of nullplatform/services.
  • Completes rds-postgres-server's specs/install/aws with the account-level aws-configuration/aws-networking-configuration/aws-iam-configuration provider registration (toggleable), folding rds-postgres-db's AssumeRole role ARN into the same identity-access-control provider instead of letting each service register its own (which would make assume_role_step's lookup nondeterministic).
  • Reconciles README/comment docs with the already-merged fix that resolves the AssumeRole IAM provider at the account level via --categories (not namespace level, as originally documented).
  • Adds root .gitignore, README.md, and adopts the same CI stack as nullplatform/services-s-3 (branch-validation, conventional-commit, release-please, shellcheck, trivy IaC scan via nullplatform/actions-nullplatform), including a documented .trivyignore suppression for the RDS security group's unrestricted egress (same class of finding services-s-3 suppresses for its own service).
  • Merges main with the ours strategy solely to give this branch a common ancestor with main (required for PR creation) — no content from main's placeholder template was reintroduced.
  • Rewrites two historical commit messages that failed conventional-commit linting (one non-conforming subject, one over-length header) — content/authorship/dates unchanged, only the message text.

Test plan

  • tofu validate + tofu fmt -check on requirements/aws and specs/install/aws for both services
  • trivy config locally: 0 misconfigurations after the .trivyignore suppression
  • shellcheck locally (matching the reusable workflow's discovery logic): clean
  • Full create → delete e2e test of rds-postgres-server run live against a real nullplatform agent/AWS account before this extraction (see commit history) — real RDS instance provisioned and destroyed successfully with this code
  • CI green on this PR (branch-validation, conventional-commit, shellcheck, trivy)

🤖 Generated with Claude Code

sebas_correa and others added 30 commits March 17, 2026 17:40
Adds rds-postgres-db and rds-postgres-server service modules, each with
deployment/permissions Terraform configs, entrypoints, workflow definitions
(create/delete/link/unlink/update), scripts, and service specs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rm provider

Replace hardcoded vpc_id in values.yaml with a runtime lookup from the
nullplatform VPC provider. build_context now derives the account NRN from
the service NRN, queries the provider that stores vpc.id, and reads the
value via np provider read.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…loyed

After writing service attributes, patch the service to set linkable_to: []
so it is not linkable to any scope type once created.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rm account provider

Replace static region from values.yaml with a dynamic lookup using
np provider list/read, reusing the single provider list call already
made for vpc_id resolution. Export REGION from build_context so
subsequent workflow steps receive it via environment output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…absent

Dependency service contexts do not include .service.nrn; use .entity_nrn
as fallback so account NRN resolution works for create/delete/update/link/unlink.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…jq queries

Some providers have null data_source.stored_keys; using (... // []) before
contains() prevents jq from throwing "Cannot iterate over null" when
resolving account.region and vpc.id providers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ebug output

Guard against null .results in np provider list JSON response.
Add temporary debug log to inspect raw provider list output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When running inside a workflow, np provider list sends limit=0 which the
API rejects with 400 (querystring/limit must be >= 1). Pass --limit 100
to ensure a valid paginated request.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ice_outputs

Comments out the `np service patch --body '{"linkable_to": []}'` call
instead of removing it, keeping the toggle easy to re-enable.
…erver

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…k workflows

build_permissions_context was reading tfstate_bucket from values.yaml (which
never defined it), causing an empty bucket name on terraform init during link
and unlink actions. Align with rds-postgres-db pattern: export TFSTATE_BUCKET
from build_context via workflow output and consume it from the environment.
Added an explicit guard in build_permissions_context to fail fast if the var
is missing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ed link

When a link transitions to a failed state before fully materializing,
its .link.attributes never receives the db_name parameter. Subsequent
unlink actions then hit `ERROR: db_name is required to create a link`
and the link gets stuck — user cannot retry nor remove it cleanly.

Mirror the pattern from rds-postgres-db/scripts/aws/build_context (which
sets LINK_NEVER_CREATED=true when .type == "delete" and there is no
server hostname): on a delete action with missing db_name, log a
warning and exit cleanly instead of failing the unlink workflow.

The error is preserved for create/link actions, where missing db_name
is still a user error.

Reproduced on the Galicia POC (CLIEN-759): a second link test with
invalid parameters left the link in failed state; the unlink could
never clean it up. Pairs with #12 (TFSTATE_BUCKET propagation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ate-bucket-link

fix(rds-postgres-server): propagate TFSTATE_BUCKET through link/unlink workflows
…ame-on-unlink

fix(rds-postgres-server): skip db_name check on unlink of never-created link
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d collision

Both modules used the identical name nullplatform-<cluster_name>-rds-secretsmanager-policy
for two different policies. IAM policy names are account-wide unique, so deploying both
modules against the same cluster_name fails with EntityAlreadyExists — caught by an
actual tofu apply against a real AWS account with both modules together.
… just values.yaml

Confirmed via a live test against a real cluster: assume_role_step read an
empty CONTEXT.providers["identity-access-control"] despite the provider being
registered, because values.yaml alone doesn't get the platform to resolve it
into CONTEXT for a given workflow run. scopes-static-files declares
provider_categories per-workflow (via its initial.yaml, included by others) in
addition to values.yaml — ported that here directly since services has no
workflow include: mechanism.
…t CONTEXT.providers

Confirmed via a live end-to-end test against a real agent/cluster (creating
a real RDS instance): CONTEXT.providers["identity-access-control"] is never
populated by this agent version, regardless of provider_categories
declarations in values.yaml or the workflow YAML. build_context already
proves np provider list/read work reliably on this same agent for
account.region/vpc.id — this ports that exact pattern for the
aws-iam-configuration provider (stored key iam_role_arns.arns), looked up at
the service's namespace NRN, where the identity-access-control provider is
registered.

Live-verified end to end: agent assumed
arn:aws:iam::235494813897:role/nullplatform-api-private-rds-postgres-server-role
and successfully created aws_secretsmanager_secret, aws_db_subnet_group,
aws_security_group, and aws_db_instance using that role's permissions (the
agent's own role has no RDS/EC2 policies attached, so this could not have
happened via the old direct-attachment model).
build_context creates its own np-service-<SERVICE_ID> tfstate bucket, same as
rds-postgres-server, but the role only had the Secrets Manager policy.
Confirmed via a live test: assuming this role and running build_context hit
AccessDenied on s3:CreateBucket/PutBucketVersioning. Adds the same np-service-*
scoped S3 policy rds-postgres-server already has.
np service list requires the exact NRN a service is scoped at. Stripping
:application=... to derive a namespace-level NRN made auto-discovery always
return zero results, even with a healthy matching rds-postgres-server —
confirmed live by querying np service list at both levels directly.
…tions, not just primary

Confirmed live: the EKS cluster's VPC has a secondary CIDR (100.17.0.0/16)
for pod networking alongside the primary (10.16.0.0/16). Agent pods get IPs
from the secondary block, but the RDS security group only allowed the
primary CIDR (data.aws_vpc.main.cidr_block), silently blocking
agent-pod-to-RDS connectivity — the postgresql provider hung indefinitely
trying to reach the database during rds-postgres-db's create workflow.
…to-end testing

Documents the 3 required pieces for AssumeRole to actually work (apply
requirements/, grant the agent sts:AssumeRole, register an
identity-access-control provider at the namespace NRN), the fail-open
behavior when any piece is missing, the multi-CIDR VPC networking
requirement, the auto-discovery NRN requirement for rds-postgres-db, and
the orphaned-role edge case from partially-failed creates — all confirmed
against a real cluster during this branch's validation.
… setup guides

Adds the actual module blocks (service_requirements_*, vpc_provider,
aws_cloud_provider) alongside the identity_access_control example already
present, so the setup guide is a complete, copy-pasteable reference
matching the pattern already validated in the services-testing sandbox.
sebas_correa and others added 7 commits July 3, 2026 18:51
- Generalize assume_role_lib to take override/default env var names as
  params (indirect expansion), making it identical and copy-paste
  reusable across rds-postgres-server and rds-postgres-db.
- Pass --dimensions (from .service.dimensions) to the IAM provider
  lookup in assume_role_step, so a future per-dimension AssumeRole
  role at the same namespace NRN resolves the most-specific match
  instead of an arbitrary one.
- Add policies_name_prefix override variable to requirements/ (server
  and db), preserving current default policy names.
- Move requirements/ under specs/requirements/aws/ to match the
  services-s-3 layout convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nullplatform

Mirrors the specs/install convention from nullplatform/scopes-static-files:
requirements/ provisions the AWS AssumeRole IAM role/policies (the agent's
half), install/ registers the service_definition + agent association (the
platform's half) so np service create actually routes to an agent. Modeled
on the module blocks already validated live against PAE/services-testing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ierarchy

The assume_role_step stripped the NRN to namespace level and did a plain
'np provider list' filtered by stored_keys. A plain list does not inherit
providers from ascendant NRN levels, so the identity-access-control provider
(registered at account level) was never found and the step fell back to agent
credentials (assume_role=skipped).

Align with the aws-s3-bucket service: use the full NRN as-is and query with
--categories identity-access-control, which resolves up the hierarchy and
returns the effective provider attributes. Applies to both server and db.
Post-extraction cleanup after splitting rds-postgres-server/rds-postgres-db
out of the nullplatform/services monorepo into their own repository:

- Drop the databases/ path prefix (service_path, cp -r examples, module
  source URLs) now that both services live at the repo root.
- Point requirements/install module source examples and repository_name
  defaults at this repo instead of nullplatform/services.
- Add specs/install/aws support for the account-level aws-configuration,
  aws-networking-configuration and aws-iam-configuration providers
  (vpc_provider, aws_cloud_provider, identity_access_control), toggleable
  via create_account_providers/create_identity_access_control. Only
  rds-postgres-server's install creates identity_access_control — folds in
  rds-postgres-db's role ARN via a variable instead of letting db register
  its own second provider at the same NRN (which would make
  assume_role_step's lookup nondeterministic).
- Fix README/install docs and a stale assume_role_step comment that still
  said the aws-iam-configuration provider is registered at namespace level:
  it's actually account level, per the --categories fix already merged to
  main (0ce7aa7) which walks up the NRN hierarchy from the service's NRN.
- Add root .gitignore (Terraform/IDE artifacts) and README.md, and the
  PR-checks workflow (shellcheck + tofu fmt) that lived at the monorepo
  root and wasn't carried over by the path extraction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…es-s-3

Replace the ad-hoc shellcheck+tofu-fmt workflow carried over from the
services monorepo with the same reusable-workflow stack services-s-3 uses:
branch-validation, conventional-commit, release (release-please), shellcheck,
and trivy IaC scanning — all delegating to nullplatform/actions-nullplatform.

Add .trivyignore suppressing AVD-AWS-0104 (unrestricted RDS security-group
egress) on both services, mirroring services-s-3's own documented-suppression
pattern: standard for an RDS instance's own SG, inbound is already restricted
to 5432 from the VPC's CIDRs. Verified locally with trivy 0.68.2 (0
misconfigurations after the suppression) and shellcheck 0.11.0 (clean) using
the same discovery logic as the reusable workflows.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uses the 'ours' strategy so main's placeholder template (Dockerfile,
README.md) is not reintroduced — this repo's tree is unchanged. Establishes
a common ancestor so GitHub allows opening a PR against main.
@sebastiancorrea81
sebastiancorrea81 merged commit a2b4ea1 into main Jul 7, 2026
4 checks passed
@sebastiancorrea81
sebastiancorrea81 deleted the feature/import-rds-postgres-from-services-monorepo branch July 7, 2026 16:38
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.

3 participants