From 8bb1aba4f8233dd8fa0b05a7719da97f2eff5af6 Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:07:51 -0300 Subject: [PATCH 1/3] feat: publish worker images for both Aurora services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repository shipped a placeholder Dockerfile (hashicorp/http-echo returning "Hola mundo"), so no worker image was ever published for either service. With tofu-modules >= v7.x the agent runs services from the image their package declares, which leaves Aurora stuck on the legacy exec flow — the only entry in an otherwise worker-orchestrated catalogue — while every other service (services-s-3, services-dynamo-db, services-postgresql-rds) runs from its own image. Mirrors services-postgresql-rds, which has the same shape: one repository, two service paths, two images off the shared gRPC worker bridge. Dockerfile.aurora-postgres-server aws-cli, gomplate, OpenTofu 1.10.10 Dockerfile.aurora-postgres-db the same plus postgresql16-client, which aurora-postgres-db/scripts/aws/reassign_owned drives with psql Both bake the package in at /app/pkg and point the bridge at the service path and its entrypoint. release.yml is replaced with the two-image chain from services-postgresql-rds: release-please cuts one version, the release-publish-oci chain builds, pushes and registers the server image, and a parallel pair of jobs does the same for the db image against the same tag, so both artifacts land in the release notes. Needs the same configuration as the RDS repository before the first release: secrets AWS_ROLE_ARN_ECR_PUSH and ARTIFACT_NP_API_KEY, and variable NP_ARTIFACT_NRN. --- .github/workflows/release.yml | 174 +++++++++++++++++++++++++++++- Dockerfile | 8 -- Dockerfile.aurora-postgres-db | 19 ++++ Dockerfile.aurora-postgres-server | 19 ++++ 4 files changed, 210 insertions(+), 10 deletions(-) delete mode 100644 Dockerfile create mode 100644 Dockerfile.aurora-postgres-db create mode 100644 Dockerfile.aurora-postgres-server diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8a65e73..02c9b55 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,15 +1,185 @@ name: release +# One repo, TWO worker images (aurora-postgres-server + aurora-postgres-db), one +# chained run: release-please cuts the version once, the release-publish-oci +# chain builds/pushes/registers the SERVER image, and a parallel pair of jobs +# does the same for the DB image against the same tag — both artifacts end up +# in the release notes. +# +# Chained on purpose: release-please creates tags with GITHUB_TOKEN, and +# GitHub never triggers workflows from bot-token events. +# +# Recovery / backfill: dispatch with existing_tag to publish + finalize a tag +# that already exists. +# +# Configure: secrets AWS_ROLE_ARN_ECR_PUSH + ARTIFACT_NP_API_KEY, variable +# NP_ARTIFACT_NRN. on: push: branches: - main + workflow_dispatch: + inputs: + existing_tag: + description: 'Publish + finalize an existing tag (recovery/backfill)' + required: true + type: string permissions: contents: write pull-requests: write + id-token: write # OIDC auth against AWS for the ECR pushes jobs: + # Server image rides the full chain: release-please + build + push + + # artifact registration + release finalize. release: - uses: nullplatform/actions-nullplatform/.github/workflows/release.yml@main - secrets: inherit + uses: nullplatform/actions-nullplatform/.github/workflows/release-publish-oci.yml@main + with: + image_name: services/aurora-postgres-server + dockerfile: Dockerfile.aurora-postgres-server + existing_tag: ${{ inputs.existing_tag || '' }} + secrets: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN_ECR_PUSH }} + artifact_np_api_key: ${{ secrets.ARTIFACT_NP_API_KEY }} + + # DB image: same tag, built inline (a second reusable call to the same + # workflow file at a different ref made the run fail at startup; an inline + # buildx job sidesteps it and mirrors what the chain's build does). + publish_db: + name: Build & push aurora-postgres-db + needs: release + if: ${{ !cancelled() && (needs.release.outputs.release_created == 'true' || inputs.existing_tag != '') }} + runs-on: ubuntu-24.04 + outputs: + image_digest: ${{ steps.build.outputs.digest }} + env: + IMAGE: public.ecr.aws/nullplatform/services/aurora-postgres-db + TAG: ${{ inputs.existing_tag || needs.release.outputs.tag_name }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.existing_tag || needs.release.outputs.tag_name }} + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN_ECR_PUSH }} + aws-region: us-east-1 + - name: Login to ECR Public + run: aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws + - name: Build and push + id: build + run: | + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -f Dockerfile.aurora-postgres-db \ + -t "$IMAGE:$TAG" \ + --push . + DIGEST=$(docker buildx imagetools inspect "$IMAGE:$TAG" --format '{{json .Manifest.Digest}}' | tr -d '"') + echo "digest=$DIGEST" >> "$GITHUB_OUTPUT" + echo "pushed $IMAGE:$TAG @ $DIGEST" + + # ...and its own artifact registration + release-notes row (the chain + # registers one image per run; this repo ships two from one version). + finalize_db: + name: Register db artifact & append to release + needs: [release, publish_db] + if: ${{ !cancelled() && needs.publish_db.result == 'success' }} + runs-on: ubuntu-24.04 + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ inputs.existing_tag || needs.release.outputs.tag_name }} + DIGEST: ${{ needs.publish_db.outputs.image_digest }} + ECR_REGISTRY: public.ecr.aws/nullplatform + IMAGE_NAME: services/aurora-postgres-db + steps: + - name: Register oci_image artifact (db) + id: artifact + env: + NULLPLATFORM_API_KEY: ${{ secrets.ARTIFACT_NP_API_KEY }} + NP_ARTIFACT_NRN: ${{ vars.NP_ARTIFACT_NRN }} + run: | + set -o pipefail + if [ -z "$NULLPLATFORM_API_KEY" ]; then + echo "::error::ARTIFACT_NP_API_KEY secret is empty or not set" + exit 1 + fi + if [ -z "$NP_ARTIFACT_NRN" ]; then + echo "::error::NP_ARTIFACT_NRN variable is not set" + exit 1 + fi + curl -fsSL https://cli.nullplatform.com/install.sh | VERSION=alpha sh + export PATH="$HOME/.local/bin:$PATH" + + # Annotations are last-write-wins full replacement on the revision, so + # every run sends the complete set: the release-please notes as the + # curated changelog plus the OCI source/revision/version keys. The + # release body is truncated at its first '## Artifact' section so a + # backfill re-run never feeds the appended artifact tables back in. + EXTRA_ARGS=() + RELEASE_BODY=$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$TAG" --jq '.body // ""' 2>/dev/null || true) + printf '%s' "$RELEASE_BODY" | sed '/^## Artifact/,$d' > changelog.md + if grep -q '[^[:space:]]' changelog.md; then + EXTRA_ARGS+=(--changelog-file changelog.md) + fi + # The image was built from the tag's commit, not the triggering sha + # (they differ on existing_tag backfills). + TAG_COMMIT=$(gh api "repos/$GITHUB_REPOSITORY/commits/$TAG" --jq '.sha' 2>/dev/null || true) + if [ -n "$TAG_COMMIT" ]; then + EXTRA_ARGS+=(--annotation "org.opencontainers.image.revision=$TAG_COMMIT") + fi + + REG_HOST="${ECR_REGISTRY%%/*}" + REPOSITORY="${ECR_REGISTRY#*/}/$IMAGE_NAME" + OUTPUT=$(np artifact create \ + --nrn "$NP_ARTIFACT_NRN" \ + --type oci_image \ + --registry "$REG_HOST" \ + --repository "$REPOSITORY" \ + --digest "$DIGEST" \ + --tag "$TAG" \ + --annotation "org.opencontainers.image.source=${{ github.server_url }}/$GITHUB_REPOSITORY" \ + --annotation "org.opencontainers.image.version=$TAG" \ + "${EXTRA_ARGS[@]}" \ + --visible-to "organization=*" \ + --format json) + echo "$OUTPUT" + ARTIFACT_ID=$(echo "$OUTPUT" | jq -r '.id // empty' || true) + [ -z "$ARTIFACT_ID" ] && ARTIFACT_ID="registered (id unavailable)" + echo "artifact_id=$ARTIFACT_ID" >> "$GITHUB_OUTPUT" + + - name: Append db artifact metadata to the release + if: ${{ !cancelled() }} + env: + ARTIFACT_ID: ${{ steps.artifact.outputs.artifact_id }} + REGISTER_RESULT: ${{ steps.artifact.outcome }} + run: | + IMAGE="$ECR_REGISTRY/$IMAGE_NAME" + case "$REGISTER_RESULT" in + success) ID_ROW="${ARTIFACT_ID}" ;; + *) ID_ROW="registration failed — see run log" ;; + esac + + RELEASE_ID=$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$TAG" --jq '.id' 2>/dev/null || true) + if [ -z "$RELEASE_ID" ]; then + RELEASE_ID=$(gh api "repos/$GITHUB_REPOSITORY/releases" --paginate \ + --jq "[.[] | select(.tag_name==\"$TAG\")][0].id // empty") + fi + if [ -z "$RELEASE_ID" ]; then + echo "::warning::no release found for $TAG; skipping the append" + exit 0 + fi + + # shellcheck disable=SC2016 + SECTION=$(printf '## Artifact (aurora-postgres-db)\n\n| | |\n|---|---|\n| Image | `%s` |\n| Digest | `%s` |\n| Pinned reference | `%s` |\n| Artifact ID | `%s` |' \ + "$IMAGE:$TAG" "$DIGEST" "$IMAGE@$DIGEST" "$ID_ROW") + + BODY=$(gh api "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID" --jq '.body // ""') + if ! printf '%s' "$BODY" | grep -qF "$DIGEST"; then + BODY=$(printf '%s\n\n%s' "$BODY" "$SECTION") + fi + printf '%s' "$BODY" > body.md + gh api -X PATCH "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID" \ + -F draft=false -F "body=@body.md" > /dev/null + echo "db artifact appended to release $TAG" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index bdc864c..0000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM hashicorp/http-echo:1.0.0 - -# Run as a non-root user. -USER 1000:1000 - -CMD ["-text={\"status\":\"ok\",\"msg\":\"Hola mundo\"}", "-listen=:8080", "-status-code=200"] - - diff --git a/Dockerfile.aurora-postgres-db b/Dockerfile.aurora-postgres-db new file mode 100644 index 0000000..40af771 --- /dev/null +++ b/Dockerfile.aurora-postgres-db @@ -0,0 +1,19 @@ +# syntax=docker/dockerfile:1 +# +# aurora-postgres-db service worker image — same base and tooling as the server +# image, plus the postgres client its provisioning scripts drive with psql +# (aurora-postgres-db/scripts/aws/reassign_owned). +FROM public.ecr.aws/nullplatform/scopes/worker-bridge:1.0.0 + +RUN apk add --no-cache aws-cli gomplate postgresql16-client + +ARG TOFU_VERSION=1.10.10 +ARG TARGETARCH +RUN curl -fsSL "https://github.com/opentofu/opentofu/releases/download/v${TOFU_VERSION}/tofu_${TOFU_VERSION}_linux_${TARGETARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin tofu \ + && tofu version + +COPY . /app/pkg +ENV NP_PACKAGE_NAME=aurora-postgres-db \ + NP_SERVICE_PATH=/app/pkg/aurora-postgres-db \ + NP_SCOPE_ENTRYPOINT=/app/pkg/aurora-postgres-db/entrypoint/entrypoint diff --git a/Dockerfile.aurora-postgres-server b/Dockerfile.aurora-postgres-server new file mode 100644 index 0000000..9cb8b8f --- /dev/null +++ b/Dockerfile.aurora-postgres-server @@ -0,0 +1,19 @@ +# syntax=docker/dockerfile:1 +# +# aurora-postgres-server service worker image — built on the lean gRPC worker +# bridge, with the cloud tooling the Aurora server workflows need baked in. +FROM public.ecr.aws/nullplatform/scopes/worker-bridge:1.0.0 + +RUN apk add --no-cache aws-cli gomplate + +# OpenTofu >= 1.10 (S3 backend with use_lockfile); alpine packages 1.7.x. +ARG TOFU_VERSION=1.10.10 +ARG TARGETARCH +RUN curl -fsSL "https://github.com/opentofu/opentofu/releases/download/v${TOFU_VERSION}/tofu_${TOFU_VERSION}_linux_${TARGETARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin tofu \ + && tofu version + +COPY . /app/pkg +ENV NP_PACKAGE_NAME=aurora-postgres-server \ + NP_SERVICE_PATH=/app/pkg/aurora-postgres-server \ + NP_SCOPE_ENTRYPOINT=/app/pkg/aurora-postgres-server/entrypoint/entrypoint From d7abf8624aa23938799d2ddc8dd7222eb5dd5844 Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:15:35 -0300 Subject: [PATCH 2/3] ci: pin the reusable release workflow to a commit actions-nullplatform's newest tag (v1.3.2, May 2026) predates release-publish-oci.yml, which landed in September, so @v1.3.2 does not resolve. Pinned to main's commit instead, which is immutable and does contain the workflow. Move it to a tag once one is cut that includes the file. --- .github/workflows/release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 02c9b55..c0518ea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,11 @@ jobs: # Server image rides the full chain: release-please + build + push + # artifact registration + release finalize. release: - uses: nullplatform/actions-nullplatform/.github/workflows/release-publish-oci.yml@main + # Pinned to a commit, not a tag: release-publish-oci.yml was added to + # actions-nullplatform in September 2026 and the newest tag (v1.3.2) is from + # May, so it does not contain this file — @v1.3.2 fails to resolve. Move this + # to a tag once one is cut that includes the workflow. + uses: nullplatform/actions-nullplatform/.github/workflows/release-publish-oci.yml@3a6b303790f11b1df537bdd792a6c3a5fc8f595c with: image_name: services/aurora-postgres-server dockerfile: Dockerfile.aurora-postgres-server From 75e777a9119358a26a38390c17f66879df11118b Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:18:20 -0300 Subject: [PATCH 3/3] ci: pin the reusable release workflow to v1.4.0 v1.4.0 is the first tag that contains release-publish-oci.yml (the workflow landed in September; v1.3.2 is from May), so the commit pin can become a version. --- .github/workflows/release.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c0518ea..9e59e3e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,11 +34,7 @@ jobs: # Server image rides the full chain: release-please + build + push + # artifact registration + release finalize. release: - # Pinned to a commit, not a tag: release-publish-oci.yml was added to - # actions-nullplatform in September 2026 and the newest tag (v1.3.2) is from - # May, so it does not contain this file — @v1.3.2 fails to resolve. Move this - # to a tag once one is cut that includes the workflow. - uses: nullplatform/actions-nullplatform/.github/workflows/release-publish-oci.yml@3a6b303790f11b1df537bdd792a6c3a5fc8f595c + uses: nullplatform/actions-nullplatform/.github/workflows/release-publish-oci.yml@v1.4.0 with: image_name: services/aurora-postgres-server dockerfile: Dockerfile.aurora-postgres-server