From 9212a32a26a03cf44724af2e7b8db8605e7c677e Mon Sep 17 00:00:00 2001 From: Guanzhou Song Date: Thu, 3 Sep 2026 23:31:07 +0000 Subject: [PATCH 1/5] feat: build DocumentDB Debian packages Build Debian 13 PostgreSQL 18 extension packages from pinned DocumentDB source, publish signed package bundles to GHCR as OCI artifacts, and consume them when building database images. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Guanzhou Song --- .github/dockerfiles/Dockerfile_extension | 17 +- .github/workflows/build_documentdb_images.yml | 439 +++++++++++++++--- .../workflows/release_documentdb_images.yml | 56 ++- RELEASE.md | 19 +- docs/designs/image-management.md | 20 +- .../testing-with-fork-images.md | 37 +- 6 files changed, 484 insertions(+), 104 deletions(-) diff --git a/.github/dockerfiles/Dockerfile_extension b/.github/dockerfiles/Dockerfile_extension index c0317e502..8fdfb9210 100644 --- a/.github/dockerfiles/Dockerfile_extension +++ b/.github/dockerfiles/Dockerfile_extension @@ -12,6 +12,8 @@ # --build-arg DEB_PACKAGE_REL_PATH=packages/documentdb_0.110-0_arm64.deb \ # -t documentdb-extension:latest \ # -f Dockerfile_extension . +# +# If present, upstream LICENSE and NOTICE files in packages/ are preserved. ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie FROM ${BASE} AS builder @@ -31,10 +33,17 @@ RUN set -eux && \ postgresql-${PG_MAJOR}-pgvector \ postgresql-${PG_MAJOR}-postgis-3 -# Install the DocumentDB extension from a pre-built .deb -COPY ${DEB_PACKAGE_REL_PATH} /tmp/documentdb.deb -RUN dpkg -i /tmp/documentdb.deb && \ - rm -f /tmp/documentdb.deb +# Install the DocumentDB extension from a pre-built .deb. Copying the package +# directory also allows release builds to preserve upstream license files while +# remaining compatible with older test workflows that provide only the .deb. +COPY packages/ /tmp/packages/ +RUN set -eux && \ + dpkg -i "/tmp/packages/$(basename "${DEB_PACKAGE_REL_PATH}")" && \ + if [ -f /tmp/packages/LICENSE ] && [ -f /tmp/packages/NOTICE ]; then \ + mkdir -p /licenses/documentdb; \ + cp /tmp/packages/LICENSE /tmp/packages/NOTICE /licenses/documentdb/; \ + fi && \ + rm -rf /tmp/packages # Gather system library dependencies not present in the CNPG base image RUN set -eux && \ diff --git a/.github/workflows/build_documentdb_images.yml b/.github/workflows/build_documentdb_images.yml index 9c780735e..4c76a295d 100644 --- a/.github/workflows/build_documentdb_images.yml +++ b/.github/workflows/build_documentdb_images.yml @@ -1,8 +1,9 @@ name: RELEASE - Build DocumentDB Candidate Images -# Builds documentdb extension and gateway images from public DocumentDB release artifacts. -# - documentdb image: public deb13 PostgreSQL 18 extension package +# Builds DocumentDB extension and gateway images from released DocumentDB sources. +# - documentdb image: self-built Debian 13 PostgreSQL 18 extension package # - gateway image: public documentdb-local image payload +# The extension package is also published as a signed OCI artifact in GHCR. # These images follow the DATABASE version track (documentDbVersion in values.yaml). # For operator/sidecar images, see build_operator_images.yml. @@ -10,13 +11,17 @@ on: workflow_dispatch: inputs: version: - description: 'Released DocumentDB version to package (for example 0.113.0)' + description: 'Released DocumentDB version to package (for example 0.116.0)' required: false - default: '0.113.0' - documentdb_extension_github_repo: - description: 'GitHub owner/repo for DocumentDB extension releases' + default: '0.116.0' + documentdb_source_github_repo: + description: 'GitHub owner/repo containing the DocumentDB source' required: false default: 'documentdb/documentdb' + documentdb_source_ref: + description: 'Optional DocumentDB source tag or branch (defaults to the release tag)' + required: false + default: '' documentdb_gateway_image_repo: description: 'Container image repo for gateway source (without tag)' required: false @@ -26,32 +31,34 @@ on: types: [documentdb-release] permissions: - packages: write contents: read - id-token: write env: - - DEFAULT_DOCUMENTDB_VERSION: '0.113.0' - DOCUMENTDB_EXTENSION_GITHUB_REPO: ${{ github.event.inputs.documentdb_extension_github_repo || 'documentdb/documentdb' }} + DEFAULT_DOCUMENTDB_VERSION: '0.116.0' + DOCUMENTDB_SOURCE_GITHUB_REPO: ${{ github.event.inputs.documentdb_source_github_repo || 'documentdb/documentdb' }} DOCUMENTDB_GATEWAY_IMAGE_REPO: ${{ github.event.inputs.documentdb_gateway_image_repo || 'ghcr.io/documentdb/documentdb/documentdb-local' }} - + DOCUMENTDB_DEB_REPOSITORY: ghcr.io/${{ github.repository }}/documentdb-deb13 jobs: # --------------------------------------------------------------------------- - # Resolve public release artifacts + # Resolve and pin released DocumentDB sources # --------------------------------------------------------------------------- - resolve-public-artifacts: - name: Resolve Public DocumentDB Sources + resolve-sources: + name: Resolve DocumentDB Sources runs-on: ubuntu-22.04 outputs: documentdb_version: ${{ steps.version.outputs.documentdb_version }} documentdb_version_dash: ${{ steps.version.outputs.documentdb_version_dash }} image_tag: ${{ steps.version.outputs.image_tag }} + source_ref: ${{ steps.version.outputs.source_ref }} + source_sha: ${{ steps.source.outputs.source_sha }} gateway_source_image: ${{ steps.version.outputs.gateway_source_image }} steps: - name: Resolve released DocumentDB version id: version + env: + DOCUMENTDB_SOURCE_REF_INPUT: ${{ github.event.inputs.documentdb_source_ref }} + shell: bash run: | set -euo pipefail RAW_VERSION="${{ github.event.inputs.version || github.event.client_payload.version || env.DEFAULT_DOCUMENTDB_VERSION }}" @@ -61,48 +68,291 @@ jobs: VERSION="$RAW_VERSION" fi if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Version must use dotted semver format (for example 0.113.0), got: $RAW_VERSION" >&2 + echo "Version must use dotted semver format (for example 0.116.0), got: $RAW_VERSION" >&2 exit 1 fi + VERSION_DASH=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.([0-9]+)$/\1-\2/') + SOURCE_REF="$DOCUMENTDB_SOURCE_REF_INPUT" + SOURCE_REF="${SOURCE_REF:-v${VERSION_DASH}}" SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) IMAGE_TAG="${VERSION}-build-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${SHORT_SHA}" GATEWAY_SOURCE_IMAGE="${{ env.DOCUMENTDB_GATEWAY_IMAGE_REPO }}:pg17-${VERSION}" + { echo "documentdb_version=$VERSION" echo "documentdb_version_dash=$VERSION_DASH" echo "image_tag=$IMAGE_TAG" + echo "source_ref=$SOURCE_REF" echo "gateway_source_image=$GATEWAY_SOURCE_IMAGE" } >> "$GITHUB_OUTPUT" + echo "DocumentDB version: $VERSION" - echo "Release tag: v$VERSION_DASH" + echo "DocumentDB source: ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@$SOURCE_REF" echo "Candidate image tag: $IMAGE_TAG" echo "Gateway source image: $GATEWAY_SOURCE_IMAGE" - - name: Verify public extension release assets + - name: Resolve source ref to immutable commit + id: source env: - VERSION_DASH: ${{ steps.version.outputs.documentdb_version_dash }} + SOURCE_REF: ${{ steps.version.outputs.source_ref }} + shell: bash run: | set -euo pipefail - for ARCH in amd64 arm64; do - ASSET_URL="https://github.com/${{ env.DOCUMENTDB_EXTENSION_GITHUB_REPO }}/releases/download/v${VERSION_DASH}/deb13-postgresql-18-documentdb_${VERSION_DASH}_${ARCH}.deb" - echo "Checking $ASSET_URL" - curl -fsI -L "$ASSET_URL" >/dev/null - done + REMOTE="https://github.com/${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}.git" + REFS=$(git ls-remote "$REMOTE" \ + "$SOURCE_REF" \ + "refs/heads/$SOURCE_REF" \ + "refs/tags/$SOURCE_REF" \ + "refs/tags/$SOURCE_REF^{}") + PEELED_SHA=$(echo "$REFS" | awk '$2 ~ /\^\{\}$/ { print $1; exit }') + DIRECT_SHA=$(echo "$REFS" | awk 'NR == 1 { print $1 }') + SOURCE_SHA="${PEELED_SHA:-$DIRECT_SHA}" + if [[ ! "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]]; then + echo "Unable to resolve ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@$SOURCE_REF to a commit" >&2 + exit 1 + fi + echo "source_sha=$SOURCE_SHA" >> "$GITHUB_OUTPUT" + echo "Pinned DocumentDB source commit: $SOURCE_SHA" - name: Verify public gateway source image env: SOURCE_IMAGE: ${{ steps.version.outputs.gateway_source_image }} + run: docker manifest inspect "$SOURCE_IMAGE" >/dev/null + + # --------------------------------------------------------------------------- + # Build Debian 13 PG18 extension packages on native runners + # --------------------------------------------------------------------------- + build-extension-packages: + name: Build DocumentDB Debian Package (${{ matrix.arch }}) + needs: [resolve-sources] + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + arch: [amd64, arm64] + include: + - arch: amd64 + runner: ubuntu-22.04 + - arch: arm64 + runner: ubuntu-22.04-arm + runs-on: ${{ matrix.runner }} + permissions: + contents: read + steps: + - name: Checkout pinned DocumentDB source + uses: actions/checkout@v4 + with: + repository: ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }} + ref: ${{ needs.resolve-sources.outputs.source_sha }} + path: documentdb-source + persist-credentials: false + + - name: Build Debian 13 PostgreSQL 18 package + working-directory: documentdb-source + env: + DOCUMENTDB_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version }} + shell: bash + run: | + set -euo pipefail + BUILD_ARGS=( + --os deb13 + --pg 18 + --version "$DOCUMENTDB_VERSION" + --output-dir packages + ) + if grep -q -- '--no-dbgsym' packaging/build_packages.sh; then + BUILD_ARGS+=(--no-dbgsym) + fi + ./packaging/build_packages.sh "${BUILD_ARGS[@]}" + + - name: Validate and stage package bundle + working-directory: documentdb-source + env: + DOCUMENTDB_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version }} + DOCUMENTDB_VERSION_DASH: ${{ needs.resolve-sources.outputs.documentdb_version_dash }} + DOCUMENTDB_SOURCE_REF: ${{ needs.resolve-sources.outputs.source_ref }} + DOCUMENTDB_SOURCE_SHA: ${{ needs.resolve-sources.outputs.source_sha }} + EXPECTED_ARCH: ${{ matrix.arch }} + shell: bash run: | set -euo pipefail - docker manifest inspect "$SOURCE_IMAGE" >/dev/null + DEB_FILE="packages/deb13-postgresql-18-documentdb_${DOCUMENTDB_VERSION_DASH}_${EXPECTED_ARCH}.deb" + if [[ ! -f "$DEB_FILE" ]]; then + echo "Expected package was not produced: $DEB_FILE" >&2 + find packages -maxdepth 1 -type f -printf '%f\n' >&2 + exit 1 + fi + + PACKAGE_NAME=$(dpkg-deb -f "$DEB_FILE" Package) + PACKAGE_VERSION=$(dpkg-deb -f "$DEB_FILE" Version) + PACKAGE_ARCH=$(dpkg-deb -f "$DEB_FILE" Architecture) + [[ "$PACKAGE_NAME" == "postgresql-18-documentdb" ]] || { + echo "Unexpected package name: $PACKAGE_NAME" >&2 + exit 1 + } + [[ "$PACKAGE_VERSION" == "$DOCUMENTDB_VERSION_DASH" ]] || { + echo "Unexpected package version: $PACKAGE_VERSION" >&2 + exit 1 + } + [[ "$PACKAGE_ARCH" == "$EXPECTED_ARCH" ]] || { + echo "Unexpected package architecture: $PACKAGE_ARCH" >&2 + exit 1 + } + + mkdir -p package-output + cp "$DEB_FILE" package-output/ + cp LICENSE NOTICE package-output/ + ( + cd package-output + sha256sum "$(basename "$DEB_FILE")" > SHA256SUMS + ) + jq -n \ + --arg schemaVersion "1" \ + --arg documentdbVersion "$DOCUMENTDB_VERSION" \ + --arg packageVersion "$PACKAGE_VERSION" \ + --arg packageName "$PACKAGE_NAME" \ + --arg os "debian13" \ + --arg postgresMajor "18" \ + --arg architecture "$PACKAGE_ARCH" \ + --arg sourceRepository "${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}" \ + --arg sourceRef "$DOCUMENTDB_SOURCE_REF" \ + --arg sourceCommit "$DOCUMENTDB_SOURCE_SHA" \ + --arg workflowRepository "$GITHUB_REPOSITORY" \ + --arg workflowRunId "$GITHUB_RUN_ID" \ + '{ + schemaVersion: $schemaVersion, + documentdbVersion: $documentdbVersion, + package: { + name: $packageName, + version: $packageVersion, + os: $os, + postgresMajor: $postgresMajor, + architecture: $architecture + }, + source: { + repository: $sourceRepository, + ref: $sourceRef, + commit: $sourceCommit + }, + build: { + repository: $workflowRepository, + runId: $workflowRunId + } + }' > package-output/build-metadata.json + + echo "Validated $DEB_FILE" + cat package-output/SHA256SUMS + cat package-output/build-metadata.json + + - name: Upload package bundle + uses: actions/upload-artifact@v4 + with: + name: documentdb-deb13-pg18-${{ matrix.arch }} + path: documentdb-source/package-output/* + retention-days: 7 + if-no-files-found: error + compression-level: 0 + + # --------------------------------------------------------------------------- + # Publish and sign the package bundles as GHCR OCI artifacts + # --------------------------------------------------------------------------- + publish-extension-packages: + name: Publish DocumentDB Debian Package (${{ matrix.arch }}) + needs: [resolve-sources, build-extension-packages] + strategy: + fail-fast: false + matrix: + arch: [amd64, arm64] + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + id-token: write + env: + PACKAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }}-pg18-${{ matrix.arch }} + steps: + - name: Download package bundle + uses: actions/download-artifact@v4 + with: + name: documentdb-deb13-pg18-${{ matrix.arch }} + path: package-bundle + + - name: Verify package bundle + working-directory: package-bundle + shell: bash + run: | + set -euo pipefail + sha256sum -c SHA256SUMS + DEB_FILE=$(find . -maxdepth 1 -type f -name '*.deb' -printf '%f\n') + [[ $(echo "$DEB_FILE" | wc -l) -eq 1 ]] || { + echo "Expected exactly one Debian package" >&2 + exit 1 + } + [[ $(dpkg-deb -f "$DEB_FILE" Architecture) == "${{ matrix.arch }}" ]] + + - name: Install ORAS + uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 + with: + version: 1.3.4 + + - name: Install cosign + uses: sigstore/cosign-installer@v3.8.2 + + - name: Login to GHCR + shell: bash + run: echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u "${{ github.actor }}" --password-stdin + + - name: Publish package OCI artifact + working-directory: package-bundle + shell: bash + run: | + set -euo pipefail + DEB_FILE=$(find . -maxdepth 1 -type f -name '*.deb' -printf '%f\n') + PACKAGE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${PACKAGE_TAG}" + oras push "$PACKAGE_REF" \ + --artifact-type application/vnd.documentdb.debian-package.v1 \ + "$DEB_FILE:application/vnd.debian.binary-package" \ + "SHA256SUMS:text/plain" \ + "build-metadata.json:application/vnd.documentdb.build-metadata.v1+json" \ + "LICENSE:text/plain" \ + "NOTICE:text/plain" + + PACKAGE_DIGEST=$(oras resolve "$PACKAGE_REF") + echo "PACKAGE_DIGEST=$PACKAGE_DIGEST" >> "$GITHUB_ENV" + echo "Published $PACKAGE_REF@$PACKAGE_DIGEST" + + - name: Sign package OCI artifact + shell: bash + run: cosign sign "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" -y + + - name: Verify package signature and contents + shell: bash + run: | + set -euo pipefail + PACKAGE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" + cosign verify \ + --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }}" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + "$PACKAGE_REF" + + mkdir package-verification + oras pull "$PACKAGE_REF" --output package-verification + ( + cd package-verification + sha256sum -c SHA256SUMS + DEB_FILE=$(find . -maxdepth 1 -type f -name '*.deb' -printf '%f\n') + [[ $(dpkg-deb -f "$DEB_FILE" Package) == "postgresql-18-documentdb" ]] + [[ $(dpkg-deb -f "$DEB_FILE" Version) == "${{ needs.resolve-sources.outputs.documentdb_version_dash }}" ]] + [[ $(dpkg-deb -f "$DEB_FILE" Architecture) == "${{ matrix.arch }}" ]] + ) # --------------------------------------------------------------------------- # Build and push documentdb + gateway images (per-arch) # --------------------------------------------------------------------------- build-and-push: name: Build and Push ${{ matrix.image.name }} (${{ matrix.arch }}) - needs: [resolve-public-artifacts] + needs: [resolve-sources, publish-extension-packages] strategy: matrix: arch: [amd64, arm64] @@ -117,51 +367,84 @@ jobs: - arch: arm64 runner: ubuntu-22.04-arm runs-on: ${{ matrix.runner }} + permissions: + contents: read + packages: write env: - IMAGE_TAG: ${{ needs.resolve-public-artifacts.outputs.image_tag }} + IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} + PACKAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }}-pg18-${{ matrix.arch }} steps: - name: Checkout code uses: actions/checkout@v4 with: persist-credentials: false - - name: Download public extension package + - name: Install ORAS if: matrix.image.name == 'documentdb' - run: | - set -euo pipefail - mkdir -p packages - DEB_FILE="deb13-postgresql-18-documentdb_${{ needs.resolve-public-artifacts.outputs.documentdb_version_dash }}_${{ matrix.arch }}.deb" - ASSET_URL="https://github.com/${{ env.DOCUMENTDB_EXTENSION_GITHUB_REPO }}/releases/download/v${{ needs.resolve-public-artifacts.outputs.documentdb_version_dash }}/${DEB_FILE}" - curl -fsSL -o "packages/${DEB_FILE}" -L "$ASSET_URL" - ls -lh packages/ + uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 + with: + version: 1.3.4 + + - name: Install cosign + if: matrix.image.name == 'documentdb' + uses: sigstore/cosign-installer@v3.8.2 - name: Login to GHCR - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + shell: bash + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin - - name: Build and Push ${{ matrix.image.name }} (${{ matrix.arch }}) + - name: Download extension package from GHCR + if: matrix.image.name == 'documentdb' + shell: bash run: | set -euo pipefail - TAG=${{ env.IMAGE_TAG }}-${{ matrix.arch }} - IMAGE=ghcr.io/${{ github.repository }}/${{ matrix.image.name }}:$TAG + mkdir packages + PACKAGE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${PACKAGE_TAG}" + PACKAGE_DIGEST=$(oras resolve "$PACKAGE_REF") + cosign verify \ + --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }}" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" + oras pull "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" --output packages + ( + cd packages + sha256sum -c SHA256SUMS + DEB_FILE="deb13-postgresql-18-documentdb_${{ needs.resolve-sources.outputs.documentdb_version_dash }}_${{ matrix.arch }}.deb" + [[ -f "$DEB_FILE" ]] + [[ $(dpkg-deb -f "$DEB_FILE" Package) == "postgresql-18-documentdb" ]] + [[ $(dpkg-deb -f "$DEB_FILE" Version) == "${{ needs.resolve-sources.outputs.documentdb_version_dash }}" ]] + [[ $(dpkg-deb -f "$DEB_FILE" Architecture) == "${{ matrix.arch }}" ]] + ) - BUILD_ARGS="" + - name: Build and push ${{ matrix.image.name }} image + shell: bash + run: | + set -euo pipefail + TAG="${IMAGE_TAG}-${{ matrix.arch }}" + IMAGE="ghcr.io/${{ github.repository }}/${{ matrix.image.name }}:$TAG" + BUILD_ARGS=() case "${{ matrix.image.name }}" in documentdb) - DEB_FILE="deb13-postgresql-18-documentdb_${{ needs.resolve-public-artifacts.outputs.documentdb_version_dash }}_${{ matrix.arch }}.deb" - echo "Using deb: $DEB_FILE" - BUILD_ARGS="--build-arg PG_MAJOR=18 --build-arg DEB_PACKAGE_REL_PATH=packages/$DEB_FILE" + DEB_FILE="deb13-postgresql-18-documentdb_${{ needs.resolve-sources.outputs.documentdb_version_dash }}_${{ matrix.arch }}.deb" + echo "Using self-built Debian package: $DEB_FILE" + BUILD_ARGS=( + --build-arg "PG_MAJOR=18" + --build-arg "DEB_PACKAGE_REL_PATH=packages/$DEB_FILE" + ) ;; gateway) - echo "Using public gateway source image: ${{ needs.resolve-public-artifacts.outputs.gateway_source_image }}" - BUILD_ARGS="--build-arg SOURCE_IMAGE=${{ needs.resolve-public-artifacts.outputs.gateway_source_image }}" + echo "Using public gateway source image: ${{ needs.resolve-sources.outputs.gateway_source_image }}" + BUILD_ARGS=( + --build-arg "SOURCE_IMAGE=${{ needs.resolve-sources.outputs.gateway_source_image }}" + ) ;; esac - docker build --pull $BUILD_ARGS \ - -t $IMAGE \ - -f ${{ matrix.image.dockerfile }} . - docker push $IMAGE + docker build --pull "${BUILD_ARGS[@]}" \ + -t "$IMAGE" \ + -f "${{ matrix.image.dockerfile }}" . + docker push "$IMAGE" # --------------------------------------------------------------------------- # Create multi-arch manifests, sign, and verify @@ -172,38 +455,47 @@ jobs: matrix: image: [documentdb, gateway] runs-on: ubuntu-22.04 - needs: [resolve-public-artifacts, build-and-push] + needs: [resolve-sources, build-and-push] + permissions: + contents: read + packages: write + id-token: write env: - IMAGE_TAG: ${{ needs.resolve-public-artifacts.outputs.image_tag }} + IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} steps: - name: Login to GHCR - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin - - name: Create and Push Manifest + - name: Create and push manifest + shell: bash run: | - docker manifest create ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} \ - --amend ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }}-amd64 \ - --amend ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }}-arm64 - docker manifest push ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} + set -euo pipefail + docker manifest create "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" \ + --amend "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}-amd64" \ + --amend "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}-arm64" + docker manifest push "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" - name: Install cosign uses: sigstore/cosign-installer@v3.8.2 - - name: Sign manifest (keyless) + - name: Sign manifest + shell: bash run: | - DIGEST=$(docker buildx imagetools inspect ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} \ + set -euo pipefail + DIGEST=$(docker buildx imagetools inspect "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" \ | awk '/^Digest:/ { print $2 }') - echo "Signing manifest-list@${DIGEST}" - cosign sign ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST} -y + cosign sign "ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST}" -y - - name: Verify manifest signature (keyless) + - name: Verify manifest signature + shell: bash run: | - DIGEST=$(docker buildx imagetools inspect ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} \ + set -euo pipefail + DIGEST=$(docker buildx imagetools inspect "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" \ | awk '/^Digest:/ { print $2 }') cosign verify \ --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }}" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST} + "ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST}" # --------------------------------------------------------------------------- # Summary @@ -211,21 +503,24 @@ jobs: summary: name: Build Summary runs-on: ubuntu-22.04 - needs: [resolve-public-artifacts, create-manifest] + needs: [resolve-sources, publish-extension-packages, create-manifest] if: always() steps: - name: Summary + shell: bash run: | { echo "## DocumentDB Image Build Summary" echo "" - echo "- **DocumentDB Version**: \`${{ needs.resolve-public-artifacts.outputs.documentdb_version }}\`" - echo "- **Candidate Image Tag**: \`${{ needs.resolve-public-artifacts.outputs.image_tag }}\`" - echo "- **Extension Package Source**: \`https://github.com/${{ env.DOCUMENTDB_EXTENSION_GITHUB_REPO }}/releases/download/v${{ needs.resolve-public-artifacts.outputs.documentdb_version_dash }}/deb13-postgresql-18-documentdb_${{ needs.resolve-public-artifacts.outputs.documentdb_version_dash }}_{amd64,arm64}.deb\`" - echo "- **Gateway Source Image**: \`${{ needs.resolve-public-artifacts.outputs.gateway_source_image }}\`" + echo "- **DocumentDB Version**: \`${{ needs.resolve-sources.outputs.documentdb_version }}\`" + echo "- **DocumentDB Source**: \`${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@${{ needs.resolve-sources.outputs.source_ref }}\`" + echo "- **Pinned Source Commit**: \`${{ needs.resolve-sources.outputs.source_sha }}\`" + echo "- **Candidate Image Tag**: \`${{ needs.resolve-sources.outputs.image_tag }}\`" + echo "- **Debian Package Artifacts**: \`${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${{ needs.resolve-sources.outputs.image_tag }}-pg18-{amd64,arm64}\`" + echo "- **Gateway Source Image**: \`${{ needs.resolve-sources.outputs.gateway_source_image }}\`" echo "- **Images**: documentdb, gateway" echo "" - echo "To release these images, run \`release_documentdb_images.yml\` with:" - echo "- candidate_version: \`${{ needs.resolve-public-artifacts.outputs.image_tag }}\`" - echo "- version: \`${{ needs.resolve-public-artifacts.outputs.documentdb_version }}\`" + echo "To release these images and package artifacts, run \`release_documentdb_images.yml\` with:" + echo "- candidate_version: \`${{ needs.resolve-sources.outputs.image_tag }}\`" + echo "- version: \`${{ needs.resolve-sources.outputs.documentdb_version }}\`" } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release_documentdb_images.yml b/.github/workflows/release_documentdb_images.yml index 24d27af22..12de77bae 100644 --- a/.github/workflows/release_documentdb_images.yml +++ b/.github/workflows/release_documentdb_images.yml @@ -27,6 +27,9 @@ permissions: pull-requests: write id-token: write +env: + DOCUMENTDB_DEB_REPOSITORY: ghcr.io/${{ github.repository }}/documentdb-deb13 + jobs: # --------------------------------------------------------------------------- # Promote documentdb and gateway images (retag candidate → release) @@ -57,13 +60,57 @@ jobs: -t ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.TARGET_TAG }} \ ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.SOURCE_TAG }} + # --------------------------------------------------------------------------- + # Promote signed Debian package artifacts (retag candidate -> release) + # --------------------------------------------------------------------------- + promote-extension-packages: + name: Promote DocumentDB Debian Package (${{ matrix.arch }}) + runs-on: ubuntu-latest + strategy: + matrix: + arch: [amd64, arm64] + env: + SOURCE_TAG: ${{ inputs.candidate_version }}-pg18-${{ matrix.arch }} + TARGET_TAG: ${{ inputs.version }}-pg18-${{ matrix.arch }} + steps: + - name: Install ORAS + uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 + with: + version: 1.3.4 + + - name: Install cosign + uses: sigstore/cosign-installer@v3.8.2 + + - name: Login to GHCR + run: echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u "${{ github.actor }}" --password-stdin + + - name: Verify and retag package artifact + shell: bash + run: | + set -euo pipefail + SOURCE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${SOURCE_TAG}" + SOURCE_DIGEST=$(oras resolve "$SOURCE_REF") + + cosign verify \ + --certificate-identity-regexp "^https://github\\.com/${{ github.repository }}/\\.github/workflows/build_documentdb_images\\.yml@refs/(heads|tags)/[-A-Za-z0-9_./]+$" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${SOURCE_DIGEST}" + + oras tag "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${SOURCE_DIGEST}" "$TARGET_TAG" + TARGET_DIGEST=$(oras resolve "${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${TARGET_TAG}") + if [[ "$TARGET_DIGEST" != "$SOURCE_DIGEST" ]]; then + echo "Promoted package digest mismatch: source=$SOURCE_DIGEST target=$TARGET_DIGEST" >&2 + exit 1 + fi + echo "Promoted $SOURCE_REF to ${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${TARGET_TAG} at $TARGET_DIGEST" + # --------------------------------------------------------------------------- # Update default versions in code and create PR # --------------------------------------------------------------------------- update-defaults: name: Update Default Versions runs-on: ubuntu-latest - needs: promote-database-images + needs: [promote-database-images, promote-extension-packages] if: ${{ inputs.update_defaults == true }} steps: - name: Checkout code @@ -81,7 +128,7 @@ jobs: echo "Failed to extract current default version from operator/src/internal/utils/constants.go" >&2 exit 1 fi - echo "current_version=$CURRENT" >> $GITHUB_OUTPUT + echo "current_version=$CURRENT" >> "$GITHUB_OUTPUT" echo "Current default version: $CURRENT" - name: Update version references @@ -174,6 +221,10 @@ jobs: - `ghcr.io/${{ github.repository }}/documentdb:${{ inputs.version }}` - `ghcr.io/${{ github.repository }}/gateway:${{ inputs.version }}` + ### Debian Package Artifacts + - `ghcr.io/${{ github.repository }}/documentdb-deb13:${{ inputs.version }}-pg18-amd64` + - `ghcr.io/${{ github.repository }}/documentdb-deb13:${{ inputs.version }}-pg18-arm64` + --- *Auto-generated by `release_documentdb_images.yml`* branch: auto/documentdb-${{ inputs.version }} @@ -189,6 +240,7 @@ jobs: echo "" echo "- **Database Version**: \`${{ inputs.version }}\`" echo "- **Images Promoted**: documentdb, gateway" + echo "- **Debian Packages Promoted**: debian13, PostgreSQL 18, amd64 + arm64" echo "- **Source Tag**: \`${{ inputs.candidate_version }}\` → \`${{ inputs.version }}\`" echo "" } >> "$GITHUB_STEP_SUMMARY" diff --git a/RELEASE.md b/RELEASE.md index 9638fdeed..47ab83f89 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -78,8 +78,23 @@ After the PR is approved and merged: Database images follow an **independent release cycle** from the operator: -1. Run **"RELEASE - Build DocumentDB Candidate Images"** (`build_documentdb_images.yml`) with the released DocumentDB `version` -2. Run **"RELEASE - Promote DocumentDB Images"** (`release_documentdb_images.yml`) to promote and auto-create a PR that bumps default image versions across the codebase +1. Run **"RELEASE - Build DocumentDB Candidate Images"** (`build_documentdb_images.yml`) with the released DocumentDB `version`. The workflow builds Debian 13 / PostgreSQL 18 extension packages from the pinned upstream source tag, publishes the signed package bundles to GHCR, and builds the extension and gateway candidate images. +2. Run **"RELEASE - Promote DocumentDB Images"** (`release_documentdb_images.yml`) to promote the package artifacts and images, then auto-create a PR that bumps default image versions across the codebase. + +The extension packages are stored as OCI artifacts rather than as an APT +repository: + +```text +ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18- +``` + +Candidate package tags include the workflow run identifier and are consumed by +the image build in the same workflow. The promotion workflow adds stable +version tags without changing the signed artifact digest. + +Only candidates created by `build_documentdb_images.yml` after package-artifact +publication was introduced can be promoted by `release_documentdb_images.yml`; +older image-only candidate tags do not have the required package artifacts. > **Note:** The deprecated combined workflows (`build_images.yml`, `release_images.yml`) are still available but will be removed in a future release. diff --git a/docs/designs/image-management.md b/docs/designs/image-management.md index 492303ca0..102b3c9c6 100644 --- a/docs/designs/image-management.md +++ b/docs/designs/image-management.md @@ -199,7 +199,7 @@ Builds operator and sidecar images from this repo's Go source. ### Database Image Build (`build_documentdb_images.yml`) -Builds documentdb extension and gateway images from public DocumentDB release artifacts. +Builds documentdb extension and gateway images from released DocumentDB source. | Aspect | Details | |--------|---------| @@ -207,17 +207,19 @@ Builds documentdb extension and gateway images from public DocumentDB release ar | **Images** | documentdb, gateway | | **Dockerfiles** | `.github/dockerfiles/Dockerfile_extension`, `.github/dockerfiles/Dockerfile_gateway_public_image` | | **Tag pattern** | `{documentdb_version}-build-{run_id}-{attempt}-{sha}` (candidate) | -| **Build time** | ~5 minutes (public artifact download + image build) | +| **Build time** | ~15 minutes (native package builds + image builds) | | **Multi-arch** | amd64 + arm64 → multi-arch manifest | -| **Signing** | cosign keyless (OIDC) | -| **Version detection** | Workflow input / repository dispatch payload (defaults to released `0.113.0`) | +| **Signing** | cosign keyless (package OCI artifacts and image manifests) | +| **Version detection** | Workflow input / repository dispatch payload (defaults to released `0.116.0`) | The build process: -1. Resolves the released DocumentDB version to package -2. Downloads the public `deb13` PostgreSQL 18 extension package from `documentdb/documentdb` release assets -3. Verifies the public multi-arch `documentdb-local:pg17-` image exists -4. Builds `Dockerfile_extension` using the public extension `.deb` (installs pg_cron, pgvector, postgis alongside) -5. Builds `Dockerfile_gateway_public_image` by copying the gateway binary and runtime files from the public upstream image +1. Resolves the released DocumentDB version and source ref to an immutable commit +2. Builds Debian 13 PostgreSQL 18 extension packages on native amd64 and arm64 runners +3. Validates the package name, version, architecture, and checksum +4. Publishes the package, checksum, build metadata, LICENSE, and NOTICE as signed OCI artifacts under `documentdb-deb13` +5. Verifies and pulls those exact GHCR artifacts to build `Dockerfile_extension` (which also installs pg_cron, pgvector, and postgis) +6. Verifies the public multi-arch `documentdb-local:pg17-` image and builds `Dockerfile_gateway_public_image` from its gateway payload +7. Creates and signs the multi-architecture extension and gateway image manifests ### Dockerfile Details diff --git a/docs/developer-guides/testing-with-fork-images.md b/docs/developer-guides/testing-with-fork-images.md index f88071599..85851bc54 100644 --- a/docs/developer-guides/testing-with-fork-images.md +++ b/docs/developer-guides/testing-with-fork-images.md @@ -7,7 +7,7 @@ It covers two independent image tracks — pick whichever you actually changed: | Track | What it ships | Repo to fork & build from | Workflow to run | |---|---|---|---| | **Operator track** | `operator`, `sidecar` | This repo (`documentdb/documentdb-kubernetes-operator`) | [`RELEASE - Build Operator Candidate Images`](../../.github/workflows/build_operator_images.yml) | -| **Database track** | `documentdb` (extension), `gateway` | Upstream [`documentdb/documentdb`](https://github.com/documentdb/documentdb) **then** this repo | DocumentDB release pipeline → [`RELEASE - Build DocumentDB Candidate Images`](../../.github/workflows/build_documentdb_images.yml) | +| **Database track** | `documentdb` (extension), `gateway` | Upstream [`documentdb/documentdb`](https://github.com/documentdb/documentdb) source **then** this repo | [`RELEASE - Build DocumentDB Candidate Images`](../../.github/workflows/build_documentdb_images.yml) | If your change is purely Go controller code, skip Step 1 entirely and use the upstream `0.110.0` (or any released) database images. @@ -24,31 +24,38 @@ If your change is purely Go controller code, skip Step 1 entirely and use the up --- -## Step 1 — (Database track only) Build extension + gateway from a documentdb fork +## Step 1 — (Database track only) Build extension + gateway from DocumentDB source Skip this step if you don't need to change the DocumentDB extension or gateway. -1. **Fork** [`documentdb/documentdb`](https://github.com/documentdb/documentdb) and push your changes. -2. **Run the DocumentDB release pipeline** on your fork (typically `Release` workflow). This must publish: - - A GitHub release named `v.-` (note the dash before patch — for example `v0.110-0`). - - Per-arch `.deb` assets attached to that release: `deb13-postgresql-18-documentdb_.-_amd64.deb` and `_arm64.deb`. - - A `documentdb-local` GHCR image: `ghcr.io//documentdb/documentdb-local:pg17-..`. - - The operator-side workflow probes for these exact paths in [its verify steps](../../.github/workflows/build_documentdb_images.yml) (`Verify public extension release assets` and `Verify public gateway source image`). - -3. **In your operator fork**, run **Actions → `RELEASE - Build DocumentDB Candidate Images` → Run workflow**. Provide these inputs: - - `version`: `0.110.0` (or whatever you released in step 2) - - `documentdb_extension_github_repo`: `/documentdb` +1. For a released upstream version, no DocumentDB fork is required. For unreleased database changes, fork [`documentdb/documentdb`](https://github.com/documentdb/documentdb) and push the source branch you want to test. +2. **In your operator fork**, run **Actions → `RELEASE - Build DocumentDB Candidate Images` → Run workflow**. Provide these inputs: + - `version`: `0.116.0` (or the version declared by your source) + - `documentdb_source_github_repo`: `documentdb/documentdb`, or `/documentdb` for custom source + - `documentdb_source_ref`: leave empty to use the release tag derived from `version`, or provide your custom source branch/tag - `documentdb_gateway_image_repo`: `ghcr.io//documentdb/documentdb-local` -4. After the run finishes, your fork has the candidate tag (and per-arch variants): + The workflow resolves the source ref to an immutable commit, builds the + Debian 13 / PostgreSQL 18 extension packages on native amd64 and arm64 + runners, signs and stores them as OCI artifacts in your fork's GHCR, then + uses those exact artifacts to build the extension images. The gateway still + uses the selected `documentdb-local` source image. + +3. After the run finishes, your fork has the candidate image tag (and per-arch variants): ```text ghcr.io//documentdb-kubernetes-operator/documentdb:-build--- ghcr.io//documentdb-kubernetes-operator/gateway:-build--- ``` - The workflow only publishes this computed `image_tag` (printed at the top of the run summary as `candidate_version`); it does **not** retag to the bare ``. The bare-version retag is performed by [`release_documentdb_images.yml`](../../.github/workflows/release_documentdb_images.yml), which is the GA promotion path and should not be run for fork testing. Use the candidate tag from the run summary directly in Step 3. + It also publishes: + + ```text + ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18-amd64 + ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18-arm64 + ``` + + The workflow only publishes the computed candidate tag (printed in the run summary); it does **not** retag to the bare ``. The stable image and package tags are created by [`release_documentdb_images.yml`](../../.github/workflows/release_documentdb_images.yml), which is the GA promotion path and should not be run for fork testing. Use the candidate image tag from the run summary directly in Step 3. --- From ab91002483c60e13716c8a86fb1b36fd98880b1d Mon Sep 17 00:00:00 2001 From: Guanzhou Song Date: Thu, 3 Sep 2026 23:36:26 +0000 Subject: [PATCH 2/5] fix: use supported ORAS CLI version Pin the latest ORAS CLI version recognized by setup-oras v2.0.1 so package publication jobs can install the client. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Guanzhou Song --- .github/workflows/build_documentdb_images.yml | 4 ++-- .github/workflows/release_documentdb_images.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_documentdb_images.yml b/.github/workflows/build_documentdb_images.yml index 4c76a295d..ca090ff84 100644 --- a/.github/workflows/build_documentdb_images.yml +++ b/.github/workflows/build_documentdb_images.yml @@ -294,7 +294,7 @@ jobs: - name: Install ORAS uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 with: - version: 1.3.4 + version: 1.3.1 - name: Install cosign uses: sigstore/cosign-installer@v3.8.2 @@ -383,7 +383,7 @@ jobs: if: matrix.image.name == 'documentdb' uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 with: - version: 1.3.4 + version: 1.3.1 - name: Install cosign if: matrix.image.name == 'documentdb' diff --git a/.github/workflows/release_documentdb_images.yml b/.github/workflows/release_documentdb_images.yml index 12de77bae..9b5f8a2d7 100644 --- a/.github/workflows/release_documentdb_images.yml +++ b/.github/workflows/release_documentdb_images.yml @@ -76,7 +76,7 @@ jobs: - name: Install ORAS uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 with: - version: 1.3.4 + version: 1.3.1 - name: Install cosign uses: sigstore/cosign-installer@v3.8.2 From 64c6c0d930844b49c515bf1cac5da4f915c81658 Mon Sep 17 00:00:00 2001 From: Guanzhou Song Date: Fri, 4 Sep 2026 15:03:12 +0000 Subject: [PATCH 3/5] fix: harden DocumentDB package releases Validate source versions before packaging, verify complete signed candidates before promotion, prevent stable tag replacement, and keep default version updates as separate reviewed changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Guanzhou Song --- .github/workflows/build_documentdb_images.yml | 94 +++-- .../workflows/release_documentdb_images.yml | 341 +++++++----------- CHANGELOG.md | 1 + RELEASE.md | 14 +- docs/designs/image-management.md | 41 ++- .../testing-with-fork-images.md | 2 +- 6 files changed, 248 insertions(+), 245 deletions(-) diff --git a/.github/workflows/build_documentdb_images.yml b/.github/workflows/build_documentdb_images.yml index ca090ff84..3c27d2017 100644 --- a/.github/workflows/build_documentdb_images.yml +++ b/.github/workflows/build_documentdb_images.yml @@ -12,8 +12,7 @@ on: inputs: version: description: 'Released DocumentDB version to package (for example 0.116.0)' - required: false - default: '0.116.0' + required: true documentdb_source_github_repo: description: 'GitHub owner/repo containing the DocumentDB source' required: false @@ -34,7 +33,6 @@ permissions: contents: read env: - DEFAULT_DOCUMENTDB_VERSION: '0.116.0' DOCUMENTDB_SOURCE_GITHUB_REPO: ${{ github.event.inputs.documentdb_source_github_repo || 'documentdb/documentdb' }} DOCUMENTDB_GATEWAY_IMAGE_REPO: ${{ github.event.inputs.documentdb_gateway_image_repo || 'ghcr.io/documentdb/documentdb/documentdb-local' }} DOCUMENTDB_DEB_REPOSITORY: ghcr.io/${{ github.repository }}/documentdb-deb13 @@ -57,11 +55,16 @@ jobs: - name: Resolve released DocumentDB version id: version env: + DOCUMENTDB_VERSION_INPUT: ${{ github.event.inputs.version || github.event.client_payload.version }} DOCUMENTDB_SOURCE_REF_INPUT: ${{ github.event.inputs.documentdb_source_ref }} shell: bash run: | set -euo pipefail - RAW_VERSION="${{ github.event.inputs.version || github.event.client_payload.version || env.DEFAULT_DOCUMENTDB_VERSION }}" + RAW_VERSION="$DOCUMENTDB_VERSION_INPUT" + if [[ -z "$RAW_VERSION" ]]; then + echo "DocumentDB version is required" >&2 + exit 1 + fi if [[ "$RAW_VERSION" =~ ^[0-9]+\.[0-9]+-[0-9]+$ ]]; then VERSION="${RAW_VERSION/-/.}" else @@ -71,13 +74,17 @@ jobs: echo "Version must use dotted semver format (for example 0.116.0), got: $RAW_VERSION" >&2 exit 1 fi + if [[ ! "$DOCUMENTDB_SOURCE_GITHUB_REPO" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then + echo "DocumentDB source repository must use owner/repo format, got: $DOCUMENTDB_SOURCE_GITHUB_REPO" >&2 + exit 1 + fi VERSION_DASH=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.([0-9]+)$/\1-\2/') SOURCE_REF="$DOCUMENTDB_SOURCE_REF_INPUT" SOURCE_REF="${SOURCE_REF:-v${VERSION_DASH}}" SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) IMAGE_TAG="${VERSION}-build-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${SHORT_SHA}" - GATEWAY_SOURCE_IMAGE="${{ env.DOCUMENTDB_GATEWAY_IMAGE_REPO }}:pg17-${VERSION}" + GATEWAY_SOURCE_IMAGE="${DOCUMENTDB_GATEWAY_IMAGE_REPO}:pg17-${VERSION}" { echo "documentdb_version=$VERSION" @@ -88,7 +95,7 @@ jobs: } >> "$GITHUB_OUTPUT" echo "DocumentDB version: $VERSION" - echo "DocumentDB source: ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@$SOURCE_REF" + echo "DocumentDB source: $DOCUMENTDB_SOURCE_GITHUB_REPO@$SOURCE_REF" echo "Candidate image tag: $IMAGE_TAG" echo "Gateway source image: $GATEWAY_SOURCE_IMAGE" @@ -99,7 +106,7 @@ jobs: shell: bash run: | set -euo pipefail - REMOTE="https://github.com/${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}.git" + REMOTE="https://github.com/${DOCUMENTDB_SOURCE_GITHUB_REPO}.git" REFS=$(git ls-remote "$REMOTE" \ "$SOURCE_REF" \ "refs/heads/$SOURCE_REF" \ @@ -109,7 +116,7 @@ jobs: DIRECT_SHA=$(echo "$REFS" | awk 'NR == 1 { print $1 }') SOURCE_SHA="${PEELED_SHA:-$DIRECT_SHA}" if [[ ! "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]]; then - echo "Unable to resolve ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@$SOURCE_REF to a commit" >&2 + echo "Unable to resolve $DOCUMENTDB_SOURCE_GITHUB_REPO@$SOURCE_REF to a commit" >&2 exit 1 fi echo "source_sha=$SOURCE_SHA" >> "$GITHUB_OUTPUT" @@ -148,6 +155,20 @@ jobs: path: documentdb-source persist-credentials: false + - name: Verify source version + working-directory: documentdb-source + env: + EXPECTED_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version_dash }} + shell: bash + run: | + set -euo pipefail + CONTROL_FILE="pg_documentdb_core/documentdb_core.control" + SOURCE_VERSION=$(sed -nE "s/^default_version[[:space:]]*=[[:space:]]*'([^']+)'.*/\1/p" "$CONTROL_FILE") + if [[ "$SOURCE_VERSION" != "$EXPECTED_VERSION" ]]; then + echo "DocumentDB source declares version '$SOURCE_VERSION', expected '$EXPECTED_VERSION'" >&2 + exit 1 + fi + - name: Build Debian 13 PostgreSQL 18 package working-directory: documentdb-source env: @@ -202,6 +223,12 @@ jobs: mkdir -p package-output cp "$DEB_FILE" package-output/ + for LEGAL_FILE in LICENSE NOTICE; do + if [[ ! -f "$LEGAL_FILE" ]]; then + echo "DocumentDB source is missing required legal file: $LEGAL_FILE" >&2 + exit 1 + fi + done cp LICENSE NOTICE package-output/ ( cd package-output @@ -215,11 +242,12 @@ jobs: --arg os "debian13" \ --arg postgresMajor "18" \ --arg architecture "$PACKAGE_ARCH" \ - --arg sourceRepository "${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}" \ + --arg sourceRepository "$DOCUMENTDB_SOURCE_GITHUB_REPO" \ --arg sourceRef "$DOCUMENTDB_SOURCE_REF" \ --arg sourceCommit "$DOCUMENTDB_SOURCE_SHA" \ --arg workflowRepository "$GITHUB_REPOSITORY" \ --arg workflowRunId "$GITHUB_RUN_ID" \ + --arg workflowRunAttempt "$GITHUB_RUN_ATTEMPT" \ '{ schemaVersion: $schemaVersion, documentdbVersion: $documentdbVersion, @@ -237,7 +265,8 @@ jobs: }, build: { repository: $workflowRepository, - runId: $workflowRunId + runId: $workflowRunId, + runAttempt: $workflowRunAttempt } }' > package-output/build-metadata.json @@ -297,7 +326,9 @@ jobs: version: 1.3.1 - name: Install cosign - uses: sigstore/cosign-installer@v3.8.2 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + with: + cosign-release: v2.6.5 - name: Login to GHCR shell: bash @@ -354,6 +385,7 @@ jobs: name: Build and Push ${{ matrix.image.name }} (${{ matrix.arch }}) needs: [resolve-sources, publish-extension-packages] strategy: + fail-fast: false matrix: arch: [amd64, arm64] image: @@ -387,7 +419,9 @@ jobs: - name: Install cosign if: matrix.image.name == 'documentdb' - uses: sigstore/cosign-installer@v3.8.2 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + with: + cosign-release: v2.6.5 - name: Login to GHCR shell: bash @@ -476,7 +510,9 @@ jobs: docker manifest push "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" - name: Install cosign - uses: sigstore/cosign-installer@v3.8.2 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + with: + cosign-release: v2.6.5 - name: Sign manifest shell: bash @@ -507,20 +543,34 @@ jobs: if: always() steps: - name: Summary + env: + PACKAGE_RESULT: ${{ needs.publish-extension-packages.result }} + IMAGE_RESULT: ${{ needs.create-manifest.result }} + DOCUMENTDB_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version }} + DOCUMENTDB_SOURCE_REF: ${{ needs.resolve-sources.outputs.source_ref }} + DOCUMENTDB_SOURCE_SHA: ${{ needs.resolve-sources.outputs.source_sha }} + IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} + GATEWAY_SOURCE_IMAGE: ${{ needs.resolve-sources.outputs.gateway_source_image }} shell: bash run: | { echo "## DocumentDB Image Build Summary" echo "" - echo "- **DocumentDB Version**: \`${{ needs.resolve-sources.outputs.documentdb_version }}\`" - echo "- **DocumentDB Source**: \`${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@${{ needs.resolve-sources.outputs.source_ref }}\`" - echo "- **Pinned Source Commit**: \`${{ needs.resolve-sources.outputs.source_sha }}\`" - echo "- **Candidate Image Tag**: \`${{ needs.resolve-sources.outputs.image_tag }}\`" - echo "- **Debian Package Artifacts**: \`${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${{ needs.resolve-sources.outputs.image_tag }}-pg18-{amd64,arm64}\`" - echo "- **Gateway Source Image**: \`${{ needs.resolve-sources.outputs.gateway_source_image }}\`" + echo "- **Package Publication**: \`$PACKAGE_RESULT\`" + echo "- **Image Publication**: \`$IMAGE_RESULT\`" + echo "- **DocumentDB Version**: \`$DOCUMENTDB_VERSION\`" + echo "- **DocumentDB Source**: \`${DOCUMENTDB_SOURCE_GITHUB_REPO}@${DOCUMENTDB_SOURCE_REF}\`" + echo "- **Pinned Source Commit**: \`$DOCUMENTDB_SOURCE_SHA\`" + echo "- **Candidate Image Tag**: \`$IMAGE_TAG\`" + echo "- **Debian Package Artifacts**: \`${DOCUMENTDB_DEB_REPOSITORY}:${IMAGE_TAG}-pg18-{amd64,arm64}\`" + echo "- **Gateway Source Image**: \`$GATEWAY_SOURCE_IMAGE\`" echo "- **Images**: documentdb, gateway" echo "" - echo "To release these images and package artifacts, run \`release_documentdb_images.yml\` with:" - echo "- candidate_version: \`${{ needs.resolve-sources.outputs.image_tag }}\`" - echo "- version: \`${{ needs.resolve-sources.outputs.documentdb_version }}\`" + if [[ "$PACKAGE_RESULT" == "success" && "$IMAGE_RESULT" == "success" ]]; then + echo "To release these images and package artifacts, run \`release_documentdb_images.yml\` with:" + echo "- candidate_version: \`$IMAGE_TAG\`" + echo "- version: \`$DOCUMENTDB_VERSION\`" + else + echo "The candidate build did not complete successfully and must not be promoted." + fi } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release_documentdb_images.yml b/.github/workflows/release_documentdb_images.yml index 9b5f8a2d7..1a62c6855 100644 --- a/.github/workflows/release_documentdb_images.yml +++ b/.github/workflows/release_documentdb_images.yml @@ -1,77 +1,36 @@ name: RELEASE - Promote DocumentDB Images -# Promotes documentdb extension and gateway candidate images to release tags, -# then creates a PR to update default versions across the codebase. -# This workflow handles only the DATABASE version track (documentDbVersion). -# For operator/sidecar releases, see release_operator.yml. +# Verifies and promotes DocumentDB extension packages and database images. +# Updating the operator's default DocumentDB version is a separate reviewed change. on: workflow_dispatch: inputs: candidate_version: - description: 'Database candidate tag to promote (e.g., 0.111.0-build-123456789-1-deadbee)' + description: 'Database candidate tag to promote (e.g., 0.116.0-build-123456789-1-deadbee)' required: true version: - description: 'Database image release version (e.g., 0.111.0)' + description: 'Database image release version (e.g., 0.116.0)' required: true - default: '0.113.0' - update_defaults: - description: 'Create PR to update default image versions in code' - required: false - default: true - type: boolean permissions: - contents: write - packages: write - pull-requests: write - id-token: write + contents: read + +concurrency: + group: release-documentdb-${{ inputs.version }} + cancel-in-progress: false env: DOCUMENTDB_DEB_REPOSITORY: ghcr.io/${{ github.repository }}/documentdb-deb13 + BUILD_WORKFLOW_IDENTITY: https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }} jobs: - # --------------------------------------------------------------------------- - # Promote documentdb and gateway images (retag candidate → release) - # --------------------------------------------------------------------------- - promote-database-images: - name: Promote ${{ matrix.image }} - runs-on: ubuntu-latest - strategy: - matrix: - image: [documentdb, gateway] - steps: - - name: Login to GHCR - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Verify candidate exists - run: | - echo "Verifying ${{ matrix.image }}:${{ inputs.candidate_version }} exists..." - docker buildx imagetools inspect \ - ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ inputs.candidate_version }} - - - name: Retag existing manifest - env: - SOURCE_TAG: ${{ inputs.candidate_version }} - TARGET_TAG: ${{ inputs.version }} - run: | - echo "Promoting ${{ matrix.image }} from $SOURCE_TAG to $TARGET_TAG" - docker buildx imagetools create \ - -t ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.TARGET_TAG }} \ - ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.SOURCE_TAG }} - - # --------------------------------------------------------------------------- - # Promote signed Debian package artifacts (retag candidate -> release) - # --------------------------------------------------------------------------- - promote-extension-packages: - name: Promote DocumentDB Debian Package (${{ matrix.arch }}) - runs-on: ubuntu-latest - strategy: - matrix: - arch: [amd64, arm64] - env: - SOURCE_TAG: ${{ inputs.candidate_version }}-pg18-${{ matrix.arch }} - TARGET_TAG: ${{ inputs.version }}-pg18-${{ matrix.arch }} + promote: + name: Verify and Promote Candidate + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write steps: - name: Install ORAS uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 @@ -79,159 +38,141 @@ jobs: version: 1.3.1 - name: Install cosign - uses: sigstore/cosign-installer@v3.8.2 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + with: + cosign-release: v2.6.5 - name: Login to GHCR - run: echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u "${{ github.actor }}" --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin - - name: Verify and retag package artifact + - name: Validate release inputs + env: + CANDIDATE_VERSION: ${{ inputs.candidate_version }} + VERSION: ${{ inputs.version }} shell: bash run: | set -euo pipefail - SOURCE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${SOURCE_TAG}" - SOURCE_DIGEST=$(oras resolve "$SOURCE_REF") - - cosign verify \ - --certificate-identity-regexp "^https://github\\.com/${{ github.repository }}/\\.github/workflows/build_documentdb_images\\.yml@refs/(heads|tags)/[-A-Za-z0-9_./]+$" \ - --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${SOURCE_DIGEST}" - - oras tag "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${SOURCE_DIGEST}" "$TARGET_TAG" - TARGET_DIGEST=$(oras resolve "${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${TARGET_TAG}") - if [[ "$TARGET_DIGEST" != "$SOURCE_DIGEST" ]]; then - echo "Promoted package digest mismatch: source=$SOURCE_DIGEST target=$TARGET_DIGEST" >&2 + if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Version must use dotted semver format, got: $VERSION" >&2 exit 1 fi - echo "Promoted $SOURCE_REF to ${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${TARGET_TAG} at $TARGET_DIGEST" - - # --------------------------------------------------------------------------- - # Update default versions in code and create PR - # --------------------------------------------------------------------------- - update-defaults: - name: Update Default Versions - runs-on: ubuntu-latest - needs: [promote-database-images, promote-extension-packages] - if: ${{ inputs.update_defaults == true }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Detect current default version - id: current - run: | - # Extract the assigned DEFAULT_DOCUMENTDB_IMAGE value from constants.go. - CURRENT=$(sed -nE 's|^[[:space:]]*DEFAULT_DOCUMENTDB_IMAGE[[:space:]]*=.*:([0-9]+\.[0-9]+\.[0-9]+)".*|\1|p' \ - operator/src/internal/utils/constants.go | head -1) - if [[ -z "$CURRENT" ]]; then - echo "Failed to extract current default version from operator/src/internal/utils/constants.go" >&2 + if [[ "$CANDIDATE_VERSION" != "${VERSION}-build-"* || + ! "$CANDIDATE_VERSION" =~ -build-[0-9]+-[0-9]+-[0-9a-f]{7}$ ]]; then + echo "Candidate '$CANDIDATE_VERSION' was not built for version '$VERSION'" >&2 exit 1 fi - echo "current_version=$CURRENT" >> "$GITHUB_OUTPUT" - echo "Current default version: $CURRENT" - - name: Update version references + - name: Verify complete candidate env: - OLD_VERSION: ${{ steps.current.outputs.current_version }} - NEW_VERSION: ${{ inputs.version }} + CANDIDATE_VERSION: ${{ inputs.candidate_version }} + VERSION: ${{ inputs.version }} + shell: bash + run: | + set -euo pipefail + VERSION_DASH=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.([0-9]+)$/\1-\2/') + + for IMAGE in documentdb gateway; do + REPOSITORY="ghcr.io/${GITHUB_REPOSITORY}/${IMAGE}" + SOURCE_REF="${REPOSITORY}:${CANDIDATE_VERSION}" + SOURCE_DIGEST=$(docker buildx imagetools inspect "$SOURCE_REF" \ + --format '{{json .Manifest.Digest}}' | tr -d '"') + PLATFORMS=$(docker buildx imagetools inspect "$SOURCE_REF" --raw | + jq -r '[.manifests[].platform.architecture] | sort | join(",")') + + if [[ ! "$SOURCE_DIGEST" =~ ^sha256:[0-9a-f]{64}$ || + "$PLATFORMS" != "amd64,arm64" ]]; then + echo "$SOURCE_REF is not a valid amd64/arm64 image candidate" >&2 + exit 1 + fi + + cosign verify \ + --certificate-identity "$BUILD_WORKFLOW_IDENTITY" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + "${REPOSITORY}@${SOURCE_DIGEST}" + + TARGET_REF="${REPOSITORY}:${VERSION}" + if TARGET_DIGEST=$(docker buildx imagetools inspect "$TARGET_REF" \ + --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"'); then + if [[ "$TARGET_DIGEST" != "$SOURCE_DIGEST" ]]; then + echo "$TARGET_REF already exists at $TARGET_DIGEST, not $SOURCE_DIGEST" >&2 + exit 1 + fi + fi + done + + for ARCH in amd64 arm64; do + SOURCE_REF="${DOCUMENTDB_DEB_REPOSITORY}:${CANDIDATE_VERSION}-pg18-${ARCH}" + SOURCE_DIGEST=$(oras resolve "$SOURCE_REF") + + cosign verify \ + --certificate-identity "$BUILD_WORKFLOW_IDENTITY" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + "${DOCUMENTDB_DEB_REPOSITORY}@${SOURCE_DIGEST}" + + VERIFY_DIR=$(mktemp -d) + oras pull "${DOCUMENTDB_DEB_REPOSITORY}@${SOURCE_DIGEST}" --output "$VERIFY_DIR" + jq -e \ + --arg version "$VERSION" \ + --arg packageVersion "$VERSION_DASH" \ + --arg arch "$ARCH" \ + '.documentdbVersion == $version and + .package.name == "postgresql-18-documentdb" and + .package.version == $packageVersion and + .package.os == "debian13" and + .package.postgresMajor == "18" and + .package.architecture == $arch' \ + "$VERIFY_DIR/build-metadata.json" >/dev/null + rm -rf "$VERIFY_DIR" + + TARGET_REF="${DOCUMENTDB_DEB_REPOSITORY}:${VERSION}-pg18-${ARCH}" + if TARGET_DIGEST=$(oras resolve "$TARGET_REF" 2>/dev/null); then + if [[ "$TARGET_DIGEST" != "$SOURCE_DIGEST" ]]; then + echo "$TARGET_REF already exists at $TARGET_DIGEST, not $SOURCE_DIGEST" >&2 + exit 1 + fi + fi + done + + - name: Promote verified candidate + env: + CANDIDATE_VERSION: ${{ inputs.candidate_version }} + VERSION: ${{ inputs.version }} + shell: bash run: | set -euo pipefail - if [[ "$OLD_VERSION" == "$NEW_VERSION" ]]; then - echo "Version $NEW_VERSION is already the default. No changes needed." - exit 0 - fi - - echo "Updating default versions: $OLD_VERSION → $NEW_VERSION" - - # 1. Update operator constants.go - sed -i "s|:${OLD_VERSION}\"|:${NEW_VERSION}\"|g" \ - operator/src/internal/utils/constants.go - - # 2. Update sidecar plugin config.go - sed -i "s|:${OLD_VERSION}\"|:${NEW_VERSION}\"|g" \ - operator/cnpg-plugins/sidecar-injector/internal/config/config.go - - # 3. Update Helm chart values.yaml - sed -i "s|documentDbVersion: \"${OLD_VERSION}\"|documentDbVersion: \"${NEW_VERSION}\"|" \ - operator/documentdb-helm-chart/values.yaml - - # 4. (Removed) Test workflow fallback images — the legacy - # test-backup-and-restore.yml and test-upgrade-and-rollback.yml - # workflows have been consolidated into test-e2e.yml. Database - # image versions for e2e are resolved from the operator's - # built-in defaults (constants.go) rather than per-workflow - # fallback tags, so no sed is required here. - - # 5. Update sidecar plugin config test (hardcoded expected gateway image) - sed -i "s|:${OLD_VERSION}\"|:${NEW_VERSION}\"|g" \ - operator/cnpg-plugins/sidecar-injector/internal/config/config_test.go - - # 6. Update build workflow defaults - sed -i "s|DEFAULT_DOCUMENTDB_VERSION: '${OLD_VERSION}'|DEFAULT_DOCUMENTDB_VERSION: '${NEW_VERSION}'|" \ - .github/workflows/build_documentdb_images.yml - sed -i "s|default: '${OLD_VERSION}'|default: '${NEW_VERSION}'|g" \ - .github/workflows/build_documentdb_images.yml - - # 7. Update release workflow default version - sed -i "s|default: '${OLD_VERSION}'|default: '${NEW_VERSION}'|g" \ - .github/workflows/release_documentdb_images.yml - - # 8. Update gateway Dockerfile default source image ARG - sed -i "s|pg17-${OLD_VERSION}|pg17-${NEW_VERSION}|" \ - .github/dockerfiles/Dockerfile_gateway_public_image - - # 9. Update e2e schema-upgrade default version pair. This is the - # single source of truth for the two-phase migration spec's CI - # default (test-e2e.yml passes only an optional override), so the - # released pair advances with each DB release: old <- previous - # default (OLD_VERSION), new <- released version (NEW_VERSION). - sed -i -E "s|(defaultOldDocumentDBVersion = )\"[0-9]+\.[0-9]+\.[0-9]+\"|\1\"${OLD_VERSION}\"|" \ - test/e2e/tests/upgrade/helpers_test.go - sed -i -E "s|(defaultNewDocumentDBVersion = )\"[0-9]+\.[0-9]+\.[0-9]+\"|\1\"${NEW_VERSION}\"|" \ - test/e2e/tests/upgrade/helpers_test.go - - echo "=== Files modified ===" - git diff --name-only - echo "" - echo "=== Diff ===" - git diff - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "chore: bump DocumentDB default images to ${{ inputs.version }}" - title: "chore: bump DocumentDB default images to ${{ inputs.version }}" - body: | - ## Automated DocumentDB Version Bump - - Promoted images `documentdb` and `gateway` from candidate `${{ inputs.candidate_version }}` to release `${{ inputs.version }}`. - - ### Changes - - Updated `DEFAULT_DOCUMENTDB_IMAGE` and `DEFAULT_GATEWAY_IMAGE` in `constants.go` - - Updated sidecar plugin default gateway image in `config.go` and `config_test.go` - - Updated `documentDbVersion` in Helm chart `values.yaml` - - Updated build/release workflow defaults in `build_documentdb_images.yml` and `release_documentdb_images.yml` - - Updated gateway Dockerfile default source image in `Dockerfile_gateway_public_image` - - Updated e2e schema-upgrade default version pair in `test/e2e/tests/upgrade/helpers_test.go` (old `${{ steps.current.outputs.current_version }}` → new `${{ inputs.version }}`) - - ### Image References - - `ghcr.io/${{ github.repository }}/documentdb:${{ inputs.version }}` - - `ghcr.io/${{ github.repository }}/gateway:${{ inputs.version }}` - - ### Debian Package Artifacts - - `ghcr.io/${{ github.repository }}/documentdb-deb13:${{ inputs.version }}-pg18-amd64` - - `ghcr.io/${{ github.repository }}/documentdb-deb13:${{ inputs.version }}-pg18-arm64` - - --- - *Auto-generated by `release_documentdb_images.yml`* - branch: auto/documentdb-${{ inputs.version }} - delete-branch: true - labels: | - automated - version-bump + for IMAGE in documentdb gateway; do + REPOSITORY="ghcr.io/${GITHUB_REPOSITORY}/${IMAGE}" + SOURCE_DIGEST=$(docker buildx imagetools inspect "${REPOSITORY}:${CANDIDATE_VERSION}" \ + --format '{{json .Manifest.Digest}}' | tr -d '"') + TARGET_REF="${REPOSITORY}:${VERSION}" + + if TARGET_DIGEST=$(docker buildx imagetools inspect "$TARGET_REF" \ + --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"'); then + echo "$TARGET_REF already points to verified digest $TARGET_DIGEST" + else + docker buildx imagetools create -t "$TARGET_REF" "${REPOSITORY}@${SOURCE_DIGEST}" + fi + + TARGET_DIGEST=$(docker buildx imagetools inspect "$TARGET_REF" \ + --format '{{json .Manifest.Digest}}' | tr -d '"') + [[ "$TARGET_DIGEST" == "$SOURCE_DIGEST" ]] + done + + for ARCH in amd64 arm64; do + SOURCE_REF="${DOCUMENTDB_DEB_REPOSITORY}:${CANDIDATE_VERSION}-pg18-${ARCH}" + SOURCE_DIGEST=$(oras resolve "$SOURCE_REF") + TARGET_REF="${DOCUMENTDB_DEB_REPOSITORY}:${VERSION}-pg18-${ARCH}" + + if TARGET_DIGEST=$(oras resolve "$TARGET_REF" 2>/dev/null); then + echo "$TARGET_REF already points to verified digest $TARGET_DIGEST" + else + oras tag "${DOCUMENTDB_DEB_REPOSITORY}@${SOURCE_DIGEST}" "${VERSION}-pg18-${ARCH}" + fi + + TARGET_DIGEST=$(oras resolve "$TARGET_REF") + [[ "$TARGET_DIGEST" == "$SOURCE_DIGEST" ]] + done - name: Release summary run: | @@ -239,13 +180,9 @@ jobs: echo "## DocumentDB Image Release Summary" echo "" echo "- **Database Version**: \`${{ inputs.version }}\`" + echo "- **Source Candidate**: \`${{ inputs.candidate_version }}\`" echo "- **Images Promoted**: documentdb, gateway" - echo "- **Debian Packages Promoted**: debian13, PostgreSQL 18, amd64 + arm64" - echo "- **Source Tag**: \`${{ inputs.candidate_version }}\` → \`${{ inputs.version }}\`" + echo "- **Packages Promoted**: Debian 13, PostgreSQL 18, amd64 + arm64" echo "" + echo "Default operator image versions are updated separately through a reviewed pull request." } >> "$GITHUB_STEP_SUMMARY" - if [[ "${{ steps.current.outputs.current_version }}" != "${{ inputs.version }}" ]]; then - echo "- **PR Created**: Updates default versions from \`${{ steps.current.outputs.current_version }}\` to \`${{ inputs.version }}\`" >> "$GITHUB_STEP_SUMMARY" - else - echo "- **No PR needed**: Version \`${{ inputs.version }}\` is already the default" >> "$GITHUB_STEP_SUMMARY" - fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 424044906..088308498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Major Features - **Fail-fast ImageVolume capability check**: The operator now depends on the Kubernetes [ImageVolume](https://kubernetes.io/docs/concepts/storage/volumes/#image) feature to mount the DocumentDB extension into PostgreSQL pods. Instead of gating on a Kubernetes version number, the validating webhook performs a capability probe (a server-side dry-run) when a `DocumentDB` is created and **rejects the resource with an actionable error if ImageVolume is unavailable**, so you find out immediately instead of waiting for pods that never become ready. ImageVolume is GA (on by default) in Kubernetes **1.35+**; on **1.33/1.34** it is beta and must be enabled via the `ImageVolume` feature gate on a containerd/CRI-O runtime. The Helm chart's `kubeVersion` floor is relaxed to `>= 1.33.0-0` accordingly. See [Before you start](docs/operator-public-documentation/preview/getting-started/before-you-start.md). +- **Source-built Debian 13 extension packages**: Database image releases now build the PostgreSQL 18 DocumentDB extension package from a pinned upstream source tag on native amd64 and arm64 runners, publish signed package bundles as GHCR OCI artifacts, and verify them before building and promoting the extension image. ## [0.3.0] - 2026-07-15 diff --git a/RELEASE.md b/RELEASE.md index 47ab83f89..dff06b4f6 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -79,7 +79,8 @@ After the PR is approved and merged: Database images follow an **independent release cycle** from the operator: 1. Run **"RELEASE - Build DocumentDB Candidate Images"** (`build_documentdb_images.yml`) with the released DocumentDB `version`. The workflow builds Debian 13 / PostgreSQL 18 extension packages from the pinned upstream source tag, publishes the signed package bundles to GHCR, and builds the extension and gateway candidate images. -2. Run **"RELEASE - Promote DocumentDB Images"** (`release_documentdb_images.yml`) to promote the package artifacts and images, then auto-create a PR that bumps default image versions across the codebase. +2. Run **"RELEASE - Promote DocumentDB Images"** (`release_documentdb_images.yml`) to verify and promote the package artifacts and images. +3. Create a separate PR to bump the default DocumentDB version in the operator, Helm chart, sidecar configuration, gateway Dockerfile, and upgrade tests. Keeping this as a normal PR ensures the version change receives review and CI before users adopt it. The extension packages are stored as OCI artifacts rather than as an APT repository: @@ -90,11 +91,18 @@ ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18-< Candidate package tags include the workflow run identifier and are consumed by the image build in the same workflow. The promotion workflow adds stable -version tags without changing the signed artifact digest. +version tags without changing the signed artifact digest. Existing stable tags +are accepted only when they already point to the same digest; changed artifacts +must use a new release version. Only candidates created by `build_documentdb_images.yml` after package-artifact publication was introduced can be promoted by `release_documentdb_images.yml`; -older image-only candidate tags do not have the required package artifacts. +older image-only candidate tags do not have the required package artifacts and +fail candidate verification before any stable tag is changed. + +GHCR package visibility is managed separately from repository visibility. +Confirm that the `documentdb`, `gateway`, and `documentdb-deb13` packages are +public before publishing a public release. > **Note:** The deprecated combined workflows (`build_images.yml`, `release_images.yml`) are still available but will be removed in a future release. diff --git a/docs/designs/image-management.md b/docs/designs/image-management.md index 102b3c9c6..72a75d331 100644 --- a/docs/designs/image-management.md +++ b/docs/designs/image-management.md @@ -44,9 +44,13 @@ All images are published to **GitHub Container Registry (GHCR)** under `ghcr.io/ | Image | GHCR Path | Source | Dockerfile | Purpose | |-------|-----------|--------|------------|---------| -| **documentdb** | `.../documentdb` | Public `deb13` PostgreSQL 18 package from `documentdb/documentdb` releases | `.github/dockerfiles/Dockerfile_extension` | DocumentDB PostgreSQL extension files for CNPG ImageVolume mode | +| **documentdb** | `.../documentdb` | Debian 13 / PostgreSQL 18 package built from a pinned `documentdb/documentdb` source commit | `.github/dockerfiles/Dockerfile_extension` | DocumentDB PostgreSQL extension files for CNPG ImageVolume mode | | **gateway** | `.../gateway` | Public gateway payload copied from `ghcr.io/documentdb/documentdb/documentdb-local:pg17-` | `.github/dockerfiles/Dockerfile_gateway_public_image` | MongoDB wire-protocol gateway binary (Rust) | +The source-built extension packages are retained as signed OCI artifacts at +`.../documentdb-deb13:-pg18-` and promoted to +`.../documentdb-deb13:-pg18-`. + ### External Image (Not Built Here) | Image | Full Reference | Source | Purpose | @@ -210,7 +214,7 @@ Builds documentdb extension and gateway images from released DocumentDB source. | **Build time** | ~15 minutes (native package builds + image builds) | | **Multi-arch** | amd64 + arm64 → multi-arch manifest | | **Signing** | cosign keyless (package OCI artifacts and image manifests) | -| **Version detection** | Workflow input / repository dispatch payload (defaults to released `0.116.0`) | +| **Version detection** | Required workflow input or repository dispatch payload | The build process: 1. Resolves the released DocumentDB version and source ref to an immutable commit @@ -282,26 +286,31 @@ Flow: ### Database Image Release (`release_documentdb_images.yml`) -Promotes documentdb/gateway candidate images and auto-creates a PR to update defaults. +Verifies and promotes the documentdb/gateway images and their corresponding +Debian package artifacts. ``` Inputs: candidate_version: "0.111.0-build-123456789-1-deadbee" ← source tag version: "0.111.0" ← target release tag - update_defaults: true ← create PR to bump versions Flow: - 1. Promote Images + 1. Verify Complete Candidate + ├── Validate candidate and target versions + ├── Verify image and package signatures + ├── Validate package metadata and architectures + └── Reject conflicting existing stable tags + + 2. Promote Images └── docker buildx imagetools create -t .../documentdb:0.111.0 .../documentdb:0.111.0-test -t .../gateway:0.111.0 .../gateway:0.111.0-test - - 2. Update Defaults (auto-PR) - ├── constants.go: DEFAULT_DOCUMENTDB_IMAGE, DEFAULT_GATEWAY_IMAGE - ├── config.go: sidecar plugin default gateway image - ├── values.yaml: documentDbVersion - ├── test-backup-and-restore.yml: fallback images - └── Opens PR: "chore: bump DocumentDB images to 0.111.0" + + 3. Promote Package Artifacts + └── oras tag + .../documentdb-deb13:0.111.0-pg18-{amd64,arm64} + + 4. Create a normal reviewed PR to update operator defaults ``` --- @@ -366,7 +375,8 @@ The script uses `kind_with_registry.sh` to set up a `registry:2` container on `l ## Version Synchronization Points -When bumping database image versions, the following locations must be updated (automated by `release_documentdb_images.yml`): +After promoting database images, update the following locations in a separate +reviewed pull request: | File | Field | Example | |------|-------|---------| @@ -375,11 +385,8 @@ When bumping database image versions, the following locations must be updated (a | `operator/cnpg-plugins/sidecar-injector/internal/config/config.go` | Default gateway image | `...gateway:0.113.0` | | `operator/cnpg-plugins/sidecar-injector/internal/config/config_test.go` | Expected gateway image | `...gateway:0.113.0` | | `operator/documentdb-helm-chart/values.yaml` | `documentDbVersion` | `"0.113.0"` | -| `.github/workflows/test-backup-and-restore.yml` | `DOCUMENTDB_IMAGE`, `GATEWAY_IMAGE` env | `...documentdb:0.113.0` | -| `.github/workflows/test-upgrade-and-rollback.yml` | `RELEASED_DATABASE_VERSION` | `0.113.0` | -| `.github/workflows/build_documentdb_images.yml` | `DEFAULT_DOCUMENTDB_VERSION`, input default | `0.113.0` | -| `.github/workflows/release_documentdb_images.yml` | Input default | `0.113.0` | | `.github/dockerfiles/Dockerfile_gateway_public_image` | `SOURCE_IMAGE` ARG default | `...pg17-0.113.0` | +| `test/e2e/tests/upgrade/helpers_test.go` | Old/new schema-upgrade defaults | `0.110.0` / `0.113.0` | When bumping operator versions, update: diff --git a/docs/developer-guides/testing-with-fork-images.md b/docs/developer-guides/testing-with-fork-images.md index 85851bc54..fce1cea1b 100644 --- a/docs/developer-guides/testing-with-fork-images.md +++ b/docs/developer-guides/testing-with-fork-images.md @@ -33,7 +33,7 @@ Skip this step if you don't need to change the DocumentDB extension or gateway. - `version`: `0.116.0` (or the version declared by your source) - `documentdb_source_github_repo`: `documentdb/documentdb`, or `/documentdb` for custom source - `documentdb_source_ref`: leave empty to use the release tag derived from `version`, or provide your custom source branch/tag - - `documentdb_gateway_image_repo`: `ghcr.io//documentdb/documentdb-local` + - `documentdb_gateway_image_repo`: leave the default `ghcr.io/documentdb/documentdb/documentdb-local` for released versions, or use your own public image repository when testing custom gateway changes The workflow resolves the source ref to an immutable commit, builds the Debian 13 / PostgreSQL 18 extension packages on native amd64 and arm64 From c398eda2b6aad372a1f622b784ccc7b619efa252 Mon Sep 17 00:00:00 2001 From: Guanzhou Song Date: Fri, 4 Sep 2026 13:05:56 -0400 Subject: [PATCH 4/5] feat: build Debian 13 package from source Build DocumentDB 0.116.0 and later Debian 13 PostgreSQL 18 packages from a pinned source commit on native architecture runners. Preserve the legacy package download path for older releases and leave image promotion behavior unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: faca2436-03f6-47f3-be13-f266ab71a7e9 Signed-off-by: Guanzhou Song --- .github/dockerfiles/Dockerfile_extension | 17 +- .github/workflows/build_documentdb_images.yml | 436 ++++-------------- .../workflows/release_documentdb_images.yml | 315 +++++++------ CHANGELOG.md | 2 +- RELEASE.md | 27 +- docs/designs/image-management.md | 54 +-- .../testing-with-fork-images.md | 16 +- 7 files changed, 290 insertions(+), 577 deletions(-) diff --git a/.github/dockerfiles/Dockerfile_extension b/.github/dockerfiles/Dockerfile_extension index 8fdfb9210..c0317e502 100644 --- a/.github/dockerfiles/Dockerfile_extension +++ b/.github/dockerfiles/Dockerfile_extension @@ -12,8 +12,6 @@ # --build-arg DEB_PACKAGE_REL_PATH=packages/documentdb_0.110-0_arm64.deb \ # -t documentdb-extension:latest \ # -f Dockerfile_extension . -# -# If present, upstream LICENSE and NOTICE files in packages/ are preserved. ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie FROM ${BASE} AS builder @@ -33,17 +31,10 @@ RUN set -eux && \ postgresql-${PG_MAJOR}-pgvector \ postgresql-${PG_MAJOR}-postgis-3 -# Install the DocumentDB extension from a pre-built .deb. Copying the package -# directory also allows release builds to preserve upstream license files while -# remaining compatible with older test workflows that provide only the .deb. -COPY packages/ /tmp/packages/ -RUN set -eux && \ - dpkg -i "/tmp/packages/$(basename "${DEB_PACKAGE_REL_PATH}")" && \ - if [ -f /tmp/packages/LICENSE ] && [ -f /tmp/packages/NOTICE ]; then \ - mkdir -p /licenses/documentdb; \ - cp /tmp/packages/LICENSE /tmp/packages/NOTICE /licenses/documentdb/; \ - fi && \ - rm -rf /tmp/packages +# Install the DocumentDB extension from a pre-built .deb +COPY ${DEB_PACKAGE_REL_PATH} /tmp/documentdb.deb +RUN dpkg -i /tmp/documentdb.deb && \ + rm -f /tmp/documentdb.deb # Gather system library dependencies not present in the CNPG base image RUN set -eux && \ diff --git a/.github/workflows/build_documentdb_images.yml b/.github/workflows/build_documentdb_images.yml index 3c27d2017..d4fe5ca62 100644 --- a/.github/workflows/build_documentdb_images.yml +++ b/.github/workflows/build_documentdb_images.yml @@ -1,9 +1,9 @@ name: RELEASE - Build DocumentDB Candidate Images # Builds DocumentDB extension and gateway images from released DocumentDB sources. -# - documentdb image: self-built Debian 13 PostgreSQL 18 extension package +# - documentdb image: Debian 13 PostgreSQL 18 package built from source for 0.116+ +# (older releases use their published package) # - gateway image: public documentdb-local image payload -# The extension package is also published as a signed OCI artifact in GHCR. # These images follow the DATABASE version track (documentDbVersion in values.yaml). # For operator/sidecar images, see build_operator_images.yml. @@ -11,10 +11,11 @@ on: workflow_dispatch: inputs: version: - description: 'Released DocumentDB version to package (for example 0.116.0)' - required: true - documentdb_source_github_repo: - description: 'GitHub owner/repo containing the DocumentDB source' + description: 'Released DocumentDB version to build (for example 0.116.0)' + required: false + default: '0.113.0' + documentdb_extension_github_repo: + description: 'GitHub owner/repo containing DocumentDB source and releases' required: false default: 'documentdb/documentdb' documentdb_source_ref: @@ -30,12 +31,14 @@ on: types: [documentdb-release] permissions: + packages: write contents: read + id-token: write env: - DOCUMENTDB_SOURCE_GITHUB_REPO: ${{ github.event.inputs.documentdb_source_github_repo || 'documentdb/documentdb' }} + DEFAULT_DOCUMENTDB_VERSION: '0.113.0' + DOCUMENTDB_SOURCE_GITHUB_REPO: ${{ github.event.inputs.documentdb_extension_github_repo || 'documentdb/documentdb' }} DOCUMENTDB_GATEWAY_IMAGE_REPO: ${{ github.event.inputs.documentdb_gateway_image_repo || 'ghcr.io/documentdb/documentdb/documentdb-local' }} - DOCUMENTDB_DEB_REPOSITORY: ghcr.io/${{ github.repository }}/documentdb-deb13 jobs: # --------------------------------------------------------------------------- @@ -55,16 +58,10 @@ jobs: - name: Resolve released DocumentDB version id: version env: - DOCUMENTDB_VERSION_INPUT: ${{ github.event.inputs.version || github.event.client_payload.version }} DOCUMENTDB_SOURCE_REF_INPUT: ${{ github.event.inputs.documentdb_source_ref }} - shell: bash run: | set -euo pipefail - RAW_VERSION="$DOCUMENTDB_VERSION_INPUT" - if [[ -z "$RAW_VERSION" ]]; then - echo "DocumentDB version is required" >&2 - exit 1 - fi + RAW_VERSION="${{ github.event.inputs.version || github.event.client_payload.version || env.DEFAULT_DOCUMENTDB_VERSION }}" if [[ "$RAW_VERSION" =~ ^[0-9]+\.[0-9]+-[0-9]+$ ]]; then VERSION="${RAW_VERSION/-/.}" else @@ -74,17 +71,12 @@ jobs: echo "Version must use dotted semver format (for example 0.116.0), got: $RAW_VERSION" >&2 exit 1 fi - if [[ ! "$DOCUMENTDB_SOURCE_GITHUB_REPO" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then - echo "DocumentDB source repository must use owner/repo format, got: $DOCUMENTDB_SOURCE_GITHUB_REPO" >&2 - exit 1 - fi - VERSION_DASH=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.([0-9]+)$/\1-\2/') SOURCE_REF="$DOCUMENTDB_SOURCE_REF_INPUT" SOURCE_REF="${SOURCE_REF:-v${VERSION_DASH}}" SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) IMAGE_TAG="${VERSION}-build-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${SHORT_SHA}" - GATEWAY_SOURCE_IMAGE="${DOCUMENTDB_GATEWAY_IMAGE_REPO}:pg17-${VERSION}" + GATEWAY_SOURCE_IMAGE="${{ env.DOCUMENTDB_GATEWAY_IMAGE_REPO }}:pg17-${VERSION}" { echo "documentdb_version=$VERSION" @@ -95,7 +87,7 @@ jobs: } >> "$GITHUB_OUTPUT" echo "DocumentDB version: $VERSION" - echo "DocumentDB source: $DOCUMENTDB_SOURCE_GITHUB_REPO@$SOURCE_REF" + echo "DocumentDB source: ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@$SOURCE_REF" echo "Candidate image tag: $IMAGE_TAG" echo "Gateway source image: $GATEWAY_SOURCE_IMAGE" @@ -106,7 +98,7 @@ jobs: shell: bash run: | set -euo pipefail - REMOTE="https://github.com/${DOCUMENTDB_SOURCE_GITHUB_REPO}.git" + REMOTE="https://github.com/${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}.git" REFS=$(git ls-remote "$REMOTE" \ "$SOURCE_REF" \ "refs/heads/$SOURCE_REF" \ @@ -116,7 +108,7 @@ jobs: DIRECT_SHA=$(echo "$REFS" | awk 'NR == 1 { print $1 }') SOURCE_SHA="${PEELED_SHA:-$DIRECT_SHA}" if [[ ! "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]]; then - echo "Unable to resolve $DOCUMENTDB_SOURCE_GITHUB_REPO@$SOURCE_REF to a commit" >&2 + echo "Unable to resolve ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@$SOURCE_REF to a commit" >&2 exit 1 fi echo "source_sha=$SOURCE_SHA" >> "$GITHUB_OUTPUT" @@ -128,26 +120,35 @@ jobs: run: docker manifest inspect "$SOURCE_IMAGE" >/dev/null # --------------------------------------------------------------------------- - # Build Debian 13 PG18 extension packages on native runners + # Build source packages and images on native runners # --------------------------------------------------------------------------- - build-extension-packages: - name: Build DocumentDB Debian Package (${{ matrix.arch }}) + build-and-push: + name: Build and Push ${{ matrix.image.name }} (${{ matrix.arch }}) needs: [resolve-sources] - timeout-minutes: 60 strategy: - fail-fast: false matrix: arch: [amd64, arm64] + image: + - name: documentdb + dockerfile: .github/dockerfiles/Dockerfile_extension + - name: gateway + dockerfile: .github/dockerfiles/Dockerfile_gateway_public_image include: - arch: amd64 runner: ubuntu-22.04 - arch: arm64 runner: ubuntu-22.04-arm runs-on: ${{ matrix.runner }} - permissions: - contents: read + env: + IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Checkout pinned DocumentDB source + if: matrix.image.name == 'documentdb' uses: actions/checkout@v4 with: repository: ${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }} @@ -156,6 +157,7 @@ jobs: persist-credentials: false - name: Verify source version + if: matrix.image.name == 'documentdb' working-directory: documentdb-source env: EXPECTED_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version_dash }} @@ -169,35 +171,35 @@ jobs: exit 1 fi - - name: Build Debian 13 PostgreSQL 18 package - working-directory: documentdb-source - env: - DOCUMENTDB_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version }} - shell: bash - run: | - set -euo pipefail - BUILD_ARGS=( - --os deb13 - --pg 18 - --version "$DOCUMENTDB_VERSION" - --output-dir packages - ) - if grep -q -- '--no-dbgsym' packaging/build_packages.sh; then - BUILD_ARGS+=(--no-dbgsym) - fi - ./packaging/build_packages.sh "${BUILD_ARGS[@]}" - - - name: Validate and stage package bundle + - name: Prepare and validate Debian 13 PostgreSQL 18 package + if: matrix.image.name == 'documentdb' working-directory: documentdb-source env: DOCUMENTDB_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version }} DOCUMENTDB_VERSION_DASH: ${{ needs.resolve-sources.outputs.documentdb_version_dash }} - DOCUMENTDB_SOURCE_REF: ${{ needs.resolve-sources.outputs.source_ref }} - DOCUMENTDB_SOURCE_SHA: ${{ needs.resolve-sources.outputs.source_sha }} EXPECTED_ARCH: ${{ matrix.arch }} shell: bash run: | set -euo pipefail + if dpkg --compare-versions "$DOCUMENTDB_VERSION" ge "0.116.0"; then + BUILD_ARGS=( + --os deb13 + --pg 18 + --version "$DOCUMENTDB_VERSION" + --output-dir packages + ) + if grep -q -- '--no-dbgsym' packaging/build_packages.sh; then + BUILD_ARGS+=(--no-dbgsym) + fi + ./packaging/build_packages.sh "${BUILD_ARGS[@]}" + else + mkdir -p packages + DEB_FILE="deb13-postgresql-18-documentdb_${DOCUMENTDB_VERSION_DASH}_${EXPECTED_ARCH}.deb" + ASSET_URL="https://github.com/${DOCUMENTDB_SOURCE_GITHUB_REPO}/releases/download/v${DOCUMENTDB_VERSION_DASH}/${DEB_FILE}" + echo "Source does not support Debian 13 builds; downloading $ASSET_URL" + curl -fsSL -o "packages/${DEB_FILE}" -L "$ASSET_URL" + fi + DEB_FILE="packages/deb13-postgresql-18-documentdb_${DOCUMENTDB_VERSION_DASH}_${EXPECTED_ARCH}.deb" if [[ ! -f "$DEB_FILE" ]]; then echo "Expected package was not produced: $DEB_FILE" >&2 @@ -221,264 +223,39 @@ jobs: exit 1 } - mkdir -p package-output - cp "$DEB_FILE" package-output/ - for LEGAL_FILE in LICENSE NOTICE; do - if [[ ! -f "$LEGAL_FILE" ]]; then - echo "DocumentDB source is missing required legal file: $LEGAL_FILE" >&2 - exit 1 - fi - done - cp LICENSE NOTICE package-output/ - ( - cd package-output - sha256sum "$(basename "$DEB_FILE")" > SHA256SUMS - ) - jq -n \ - --arg schemaVersion "1" \ - --arg documentdbVersion "$DOCUMENTDB_VERSION" \ - --arg packageVersion "$PACKAGE_VERSION" \ - --arg packageName "$PACKAGE_NAME" \ - --arg os "debian13" \ - --arg postgresMajor "18" \ - --arg architecture "$PACKAGE_ARCH" \ - --arg sourceRepository "$DOCUMENTDB_SOURCE_GITHUB_REPO" \ - --arg sourceRef "$DOCUMENTDB_SOURCE_REF" \ - --arg sourceCommit "$DOCUMENTDB_SOURCE_SHA" \ - --arg workflowRepository "$GITHUB_REPOSITORY" \ - --arg workflowRunId "$GITHUB_RUN_ID" \ - --arg workflowRunAttempt "$GITHUB_RUN_ATTEMPT" \ - '{ - schemaVersion: $schemaVersion, - documentdbVersion: $documentdbVersion, - package: { - name: $packageName, - version: $packageVersion, - os: $os, - postgresMajor: $postgresMajor, - architecture: $architecture - }, - source: { - repository: $sourceRepository, - ref: $sourceRef, - commit: $sourceCommit - }, - build: { - repository: $workflowRepository, - runId: $workflowRunId, - runAttempt: $workflowRunAttempt - } - }' > package-output/build-metadata.json + mkdir -p "$GITHUB_WORKSPACE/packages" + cp "$DEB_FILE" "$GITHUB_WORKSPACE/packages/" - echo "Validated $DEB_FILE" - cat package-output/SHA256SUMS - cat package-output/build-metadata.json - - - name: Upload package bundle - uses: actions/upload-artifact@v4 - with: - name: documentdb-deb13-pg18-${{ matrix.arch }} - path: documentdb-source/package-output/* - retention-days: 7 - if-no-files-found: error - compression-level: 0 - - # --------------------------------------------------------------------------- - # Publish and sign the package bundles as GHCR OCI artifacts - # --------------------------------------------------------------------------- - publish-extension-packages: - name: Publish DocumentDB Debian Package (${{ matrix.arch }}) - needs: [resolve-sources, build-extension-packages] - strategy: - fail-fast: false - matrix: - arch: [amd64, arm64] - runs-on: ubuntu-22.04 - permissions: - contents: read - packages: write - id-token: write - env: - PACKAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }}-pg18-${{ matrix.arch }} - steps: - - name: Download package bundle - uses: actions/download-artifact@v4 - with: - name: documentdb-deb13-pg18-${{ matrix.arch }} - path: package-bundle - - - name: Verify package bundle - working-directory: package-bundle - shell: bash - run: | - set -euo pipefail - sha256sum -c SHA256SUMS - DEB_FILE=$(find . -maxdepth 1 -type f -name '*.deb' -printf '%f\n') - [[ $(echo "$DEB_FILE" | wc -l) -eq 1 ]] || { - echo "Expected exactly one Debian package" >&2 - exit 1 - } - [[ $(dpkg-deb -f "$DEB_FILE" Architecture) == "${{ matrix.arch }}" ]] - - - name: Install ORAS - uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 - with: - version: 1.3.1 - - - name: Install cosign - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - with: - cosign-release: v2.6.5 + cd "$GITHUB_WORKSPACE" + rm -rf documentdb-source - name: Login to GHCR - shell: bash - run: echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u "${{ github.actor }}" --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - name: Publish package OCI artifact - working-directory: package-bundle - shell: bash + - name: Build and Push ${{ matrix.image.name }} (${{ matrix.arch }}) run: | set -euo pipefail - DEB_FILE=$(find . -maxdepth 1 -type f -name '*.deb' -printf '%f\n') - PACKAGE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${PACKAGE_TAG}" - oras push "$PACKAGE_REF" \ - --artifact-type application/vnd.documentdb.debian-package.v1 \ - "$DEB_FILE:application/vnd.debian.binary-package" \ - "SHA256SUMS:text/plain" \ - "build-metadata.json:application/vnd.documentdb.build-metadata.v1+json" \ - "LICENSE:text/plain" \ - "NOTICE:text/plain" + TAG=${{ env.IMAGE_TAG }}-${{ matrix.arch }} + IMAGE=ghcr.io/${{ github.repository }}/${{ matrix.image.name }}:$TAG - PACKAGE_DIGEST=$(oras resolve "$PACKAGE_REF") - echo "PACKAGE_DIGEST=$PACKAGE_DIGEST" >> "$GITHUB_ENV" - echo "Published $PACKAGE_REF@$PACKAGE_DIGEST" - - - name: Sign package OCI artifact - shell: bash - run: cosign sign "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" -y - - - name: Verify package signature and contents - shell: bash - run: | - set -euo pipefail - PACKAGE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" - cosign verify \ - --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }}" \ - --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - "$PACKAGE_REF" - - mkdir package-verification - oras pull "$PACKAGE_REF" --output package-verification - ( - cd package-verification - sha256sum -c SHA256SUMS - DEB_FILE=$(find . -maxdepth 1 -type f -name '*.deb' -printf '%f\n') - [[ $(dpkg-deb -f "$DEB_FILE" Package) == "postgresql-18-documentdb" ]] - [[ $(dpkg-deb -f "$DEB_FILE" Version) == "${{ needs.resolve-sources.outputs.documentdb_version_dash }}" ]] - [[ $(dpkg-deb -f "$DEB_FILE" Architecture) == "${{ matrix.arch }}" ]] - ) - - # --------------------------------------------------------------------------- - # Build and push documentdb + gateway images (per-arch) - # --------------------------------------------------------------------------- - build-and-push: - name: Build and Push ${{ matrix.image.name }} (${{ matrix.arch }}) - needs: [resolve-sources, publish-extension-packages] - strategy: - fail-fast: false - matrix: - arch: [amd64, arm64] - image: - - name: documentdb - dockerfile: .github/dockerfiles/Dockerfile_extension - - name: gateway - dockerfile: .github/dockerfiles/Dockerfile_gateway_public_image - include: - - arch: amd64 - runner: ubuntu-22.04 - - arch: arm64 - runner: ubuntu-22.04-arm - runs-on: ${{ matrix.runner }} - permissions: - contents: read - packages: write - env: - IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} - PACKAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }}-pg18-${{ matrix.arch }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Install ORAS - if: matrix.image.name == 'documentdb' - uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 - with: - version: 1.3.1 - - - name: Install cosign - if: matrix.image.name == 'documentdb' - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - with: - cosign-release: v2.6.5 - - - name: Login to GHCR - shell: bash - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin - - - name: Download extension package from GHCR - if: matrix.image.name == 'documentdb' - shell: bash - run: | - set -euo pipefail - mkdir packages - PACKAGE_REF="${{ env.DOCUMENTDB_DEB_REPOSITORY }}:${PACKAGE_TAG}" - PACKAGE_DIGEST=$(oras resolve "$PACKAGE_REF") - cosign verify \ - --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }}" \ - --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" - oras pull "${{ env.DOCUMENTDB_DEB_REPOSITORY }}@${PACKAGE_DIGEST}" --output packages - ( - cd packages - sha256sum -c SHA256SUMS - DEB_FILE="deb13-postgresql-18-documentdb_${{ needs.resolve-sources.outputs.documentdb_version_dash }}_${{ matrix.arch }}.deb" - [[ -f "$DEB_FILE" ]] - [[ $(dpkg-deb -f "$DEB_FILE" Package) == "postgresql-18-documentdb" ]] - [[ $(dpkg-deb -f "$DEB_FILE" Version) == "${{ needs.resolve-sources.outputs.documentdb_version_dash }}" ]] - [[ $(dpkg-deb -f "$DEB_FILE" Architecture) == "${{ matrix.arch }}" ]] - ) - - - name: Build and push ${{ matrix.image.name }} image - shell: bash - run: | - set -euo pipefail - TAG="${IMAGE_TAG}-${{ matrix.arch }}" - IMAGE="ghcr.io/${{ github.repository }}/${{ matrix.image.name }}:$TAG" - BUILD_ARGS=() + BUILD_ARGS="" case "${{ matrix.image.name }}" in documentdb) DEB_FILE="deb13-postgresql-18-documentdb_${{ needs.resolve-sources.outputs.documentdb_version_dash }}_${{ matrix.arch }}.deb" - echo "Using self-built Debian package: $DEB_FILE" - BUILD_ARGS=( - --build-arg "PG_MAJOR=18" - --build-arg "DEB_PACKAGE_REL_PATH=packages/$DEB_FILE" - ) + echo "Using deb: $DEB_FILE" + BUILD_ARGS="--build-arg PG_MAJOR=18 --build-arg DEB_PACKAGE_REL_PATH=packages/$DEB_FILE" ;; gateway) echo "Using public gateway source image: ${{ needs.resolve-sources.outputs.gateway_source_image }}" - BUILD_ARGS=( - --build-arg "SOURCE_IMAGE=${{ needs.resolve-sources.outputs.gateway_source_image }}" - ) + BUILD_ARGS="--build-arg SOURCE_IMAGE=${{ needs.resolve-sources.outputs.gateway_source_image }}" ;; esac - docker build --pull "${BUILD_ARGS[@]}" \ - -t "$IMAGE" \ - -f "${{ matrix.image.dockerfile }}" . - docker push "$IMAGE" + docker build --pull $BUILD_ARGS \ + -t $IMAGE \ + -f ${{ matrix.image.dockerfile }} . + docker push $IMAGE # --------------------------------------------------------------------------- # Create multi-arch manifests, sign, and verify @@ -490,48 +267,37 @@ jobs: image: [documentdb, gateway] runs-on: ubuntu-22.04 needs: [resolve-sources, build-and-push] - permissions: - contents: read - packages: write - id-token: write env: IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} steps: - name: Login to GHCR - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - name: Create and push manifest - shell: bash + - name: Create and Push Manifest run: | - set -euo pipefail - docker manifest create "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" \ - --amend "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}-amd64" \ - --amend "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}-arm64" - docker manifest push "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" + docker manifest create ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} \ + --amend ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }}-amd64 \ + --amend ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }}-arm64 + docker manifest push ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} - name: Install cosign - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - with: - cosign-release: v2.6.5 + uses: sigstore/cosign-installer@v3.8.2 - - name: Sign manifest - shell: bash + - name: Sign manifest (keyless) run: | - set -euo pipefail - DIGEST=$(docker buildx imagetools inspect "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" \ + DIGEST=$(docker buildx imagetools inspect ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} \ | awk '/^Digest:/ { print $2 }') - cosign sign "ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST}" -y + echo "Signing manifest-list@${DIGEST}" + cosign sign ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST} -y - - name: Verify manifest signature - shell: bash + - name: Verify manifest signature (keyless) run: | - set -euo pipefail - DIGEST=$(docker buildx imagetools inspect "ghcr.io/${{ github.repository }}/${{ matrix.image }}:${IMAGE_TAG}" \ + DIGEST=$(docker buildx imagetools inspect ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.IMAGE_TAG }} \ | awk '/^Digest:/ { print $2 }') cosign verify \ --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }}" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - "ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST}" + ghcr.io/${{ github.repository }}/${{ matrix.image }}@${DIGEST} # --------------------------------------------------------------------------- # Summary @@ -539,38 +305,22 @@ jobs: summary: name: Build Summary runs-on: ubuntu-22.04 - needs: [resolve-sources, publish-extension-packages, create-manifest] + needs: [resolve-sources, create-manifest] if: always() steps: - name: Summary - env: - PACKAGE_RESULT: ${{ needs.publish-extension-packages.result }} - IMAGE_RESULT: ${{ needs.create-manifest.result }} - DOCUMENTDB_VERSION: ${{ needs.resolve-sources.outputs.documentdb_version }} - DOCUMENTDB_SOURCE_REF: ${{ needs.resolve-sources.outputs.source_ref }} - DOCUMENTDB_SOURCE_SHA: ${{ needs.resolve-sources.outputs.source_sha }} - IMAGE_TAG: ${{ needs.resolve-sources.outputs.image_tag }} - GATEWAY_SOURCE_IMAGE: ${{ needs.resolve-sources.outputs.gateway_source_image }} - shell: bash run: | { echo "## DocumentDB Image Build Summary" echo "" - echo "- **Package Publication**: \`$PACKAGE_RESULT\`" - echo "- **Image Publication**: \`$IMAGE_RESULT\`" - echo "- **DocumentDB Version**: \`$DOCUMENTDB_VERSION\`" - echo "- **DocumentDB Source**: \`${DOCUMENTDB_SOURCE_GITHUB_REPO}@${DOCUMENTDB_SOURCE_REF}\`" - echo "- **Pinned Source Commit**: \`$DOCUMENTDB_SOURCE_SHA\`" - echo "- **Candidate Image Tag**: \`$IMAGE_TAG\`" - echo "- **Debian Package Artifacts**: \`${DOCUMENTDB_DEB_REPOSITORY}:${IMAGE_TAG}-pg18-{amd64,arm64}\`" - echo "- **Gateway Source Image**: \`$GATEWAY_SOURCE_IMAGE\`" + echo "- **DocumentDB Version**: \`${{ needs.resolve-sources.outputs.documentdb_version }}\`" + echo "- **DocumentDB Source**: \`${{ env.DOCUMENTDB_SOURCE_GITHUB_REPO }}@${{ needs.resolve-sources.outputs.source_ref }}\`" + echo "- **Pinned Source Commit**: \`${{ needs.resolve-sources.outputs.source_sha }}\`" + echo "- **Candidate Image Tag**: \`${{ needs.resolve-sources.outputs.image_tag }}\`" + echo "- **Gateway Source Image**: \`${{ needs.resolve-sources.outputs.gateway_source_image }}\`" echo "- **Images**: documentdb, gateway" echo "" - if [[ "$PACKAGE_RESULT" == "success" && "$IMAGE_RESULT" == "success" ]]; then - echo "To release these images and package artifacts, run \`release_documentdb_images.yml\` with:" - echo "- candidate_version: \`$IMAGE_TAG\`" - echo "- version: \`$DOCUMENTDB_VERSION\`" - else - echo "The candidate build did not complete successfully and must not be promoted." - fi + echo "To release these images, run \`release_documentdb_images.yml\` with:" + echo "- candidate_version: \`${{ needs.resolve-sources.outputs.image_tag }}\`" + echo "- version: \`${{ needs.resolve-sources.outputs.documentdb_version }}\`" } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release_documentdb_images.yml b/.github/workflows/release_documentdb_images.yml index 1a62c6855..24d27af22 100644 --- a/.github/workflows/release_documentdb_images.yml +++ b/.github/workflows/release_documentdb_images.yml @@ -1,178 +1,186 @@ name: RELEASE - Promote DocumentDB Images -# Verifies and promotes DocumentDB extension packages and database images. -# Updating the operator's default DocumentDB version is a separate reviewed change. +# Promotes documentdb extension and gateway candidate images to release tags, +# then creates a PR to update default versions across the codebase. +# This workflow handles only the DATABASE version track (documentDbVersion). +# For operator/sidecar releases, see release_operator.yml. on: workflow_dispatch: inputs: candidate_version: - description: 'Database candidate tag to promote (e.g., 0.116.0-build-123456789-1-deadbee)' + description: 'Database candidate tag to promote (e.g., 0.111.0-build-123456789-1-deadbee)' required: true version: - description: 'Database image release version (e.g., 0.116.0)' + description: 'Database image release version (e.g., 0.111.0)' required: true + default: '0.113.0' + update_defaults: + description: 'Create PR to update default image versions in code' + required: false + default: true + type: boolean permissions: - contents: read - -concurrency: - group: release-documentdb-${{ inputs.version }} - cancel-in-progress: false - -env: - DOCUMENTDB_DEB_REPOSITORY: ghcr.io/${{ github.repository }}/documentdb-deb13 - BUILD_WORKFLOW_IDENTITY: https://github.com/${{ github.repository }}/.github/workflows/build_documentdb_images.yml@${{ github.ref }} + contents: write + packages: write + pull-requests: write + id-token: write jobs: - promote: - name: Verify and Promote Candidate - runs-on: ubuntu-22.04 - permissions: - contents: read - packages: write + # --------------------------------------------------------------------------- + # Promote documentdb and gateway images (retag candidate → release) + # --------------------------------------------------------------------------- + promote-database-images: + name: Promote ${{ matrix.image }} + runs-on: ubuntu-latest + strategy: + matrix: + image: [documentdb, gateway] steps: - - name: Install ORAS - uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 - with: - version: 1.3.1 - - - name: Install cosign - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - with: - cosign-release: v2.6.5 - - name: Login to GHCR - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - name: Validate release inputs + - name: Verify candidate exists + run: | + echo "Verifying ${{ matrix.image }}:${{ inputs.candidate_version }} exists..." + docker buildx imagetools inspect \ + ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ inputs.candidate_version }} + + - name: Retag existing manifest env: - CANDIDATE_VERSION: ${{ inputs.candidate_version }} - VERSION: ${{ inputs.version }} - shell: bash + SOURCE_TAG: ${{ inputs.candidate_version }} + TARGET_TAG: ${{ inputs.version }} run: | - set -euo pipefail - if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Version must use dotted semver format, got: $VERSION" >&2 - exit 1 - fi - if [[ "$CANDIDATE_VERSION" != "${VERSION}-build-"* || - ! "$CANDIDATE_VERSION" =~ -build-[0-9]+-[0-9]+-[0-9a-f]{7}$ ]]; then - echo "Candidate '$CANDIDATE_VERSION' was not built for version '$VERSION'" >&2 + echo "Promoting ${{ matrix.image }} from $SOURCE_TAG to $TARGET_TAG" + docker buildx imagetools create \ + -t ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.TARGET_TAG }} \ + ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ env.SOURCE_TAG }} + + # --------------------------------------------------------------------------- + # Update default versions in code and create PR + # --------------------------------------------------------------------------- + update-defaults: + name: Update Default Versions + runs-on: ubuntu-latest + needs: promote-database-images + if: ${{ inputs.update_defaults == true }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Detect current default version + id: current + run: | + # Extract the assigned DEFAULT_DOCUMENTDB_IMAGE value from constants.go. + CURRENT=$(sed -nE 's|^[[:space:]]*DEFAULT_DOCUMENTDB_IMAGE[[:space:]]*=.*:([0-9]+\.[0-9]+\.[0-9]+)".*|\1|p' \ + operator/src/internal/utils/constants.go | head -1) + if [[ -z "$CURRENT" ]]; then + echo "Failed to extract current default version from operator/src/internal/utils/constants.go" >&2 exit 1 fi + echo "current_version=$CURRENT" >> $GITHUB_OUTPUT + echo "Current default version: $CURRENT" - - name: Verify complete candidate + - name: Update version references env: - CANDIDATE_VERSION: ${{ inputs.candidate_version }} - VERSION: ${{ inputs.version }} - shell: bash - run: | - set -euo pipefail - VERSION_DASH=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.([0-9]+)$/\1-\2/') - - for IMAGE in documentdb gateway; do - REPOSITORY="ghcr.io/${GITHUB_REPOSITORY}/${IMAGE}" - SOURCE_REF="${REPOSITORY}:${CANDIDATE_VERSION}" - SOURCE_DIGEST=$(docker buildx imagetools inspect "$SOURCE_REF" \ - --format '{{json .Manifest.Digest}}' | tr -d '"') - PLATFORMS=$(docker buildx imagetools inspect "$SOURCE_REF" --raw | - jq -r '[.manifests[].platform.architecture] | sort | join(",")') - - if [[ ! "$SOURCE_DIGEST" =~ ^sha256:[0-9a-f]{64}$ || - "$PLATFORMS" != "amd64,arm64" ]]; then - echo "$SOURCE_REF is not a valid amd64/arm64 image candidate" >&2 - exit 1 - fi - - cosign verify \ - --certificate-identity "$BUILD_WORKFLOW_IDENTITY" \ - --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - "${REPOSITORY}@${SOURCE_DIGEST}" - - TARGET_REF="${REPOSITORY}:${VERSION}" - if TARGET_DIGEST=$(docker buildx imagetools inspect "$TARGET_REF" \ - --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"'); then - if [[ "$TARGET_DIGEST" != "$SOURCE_DIGEST" ]]; then - echo "$TARGET_REF already exists at $TARGET_DIGEST, not $SOURCE_DIGEST" >&2 - exit 1 - fi - fi - done - - for ARCH in amd64 arm64; do - SOURCE_REF="${DOCUMENTDB_DEB_REPOSITORY}:${CANDIDATE_VERSION}-pg18-${ARCH}" - SOURCE_DIGEST=$(oras resolve "$SOURCE_REF") - - cosign verify \ - --certificate-identity "$BUILD_WORKFLOW_IDENTITY" \ - --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ - "${DOCUMENTDB_DEB_REPOSITORY}@${SOURCE_DIGEST}" - - VERIFY_DIR=$(mktemp -d) - oras pull "${DOCUMENTDB_DEB_REPOSITORY}@${SOURCE_DIGEST}" --output "$VERIFY_DIR" - jq -e \ - --arg version "$VERSION" \ - --arg packageVersion "$VERSION_DASH" \ - --arg arch "$ARCH" \ - '.documentdbVersion == $version and - .package.name == "postgresql-18-documentdb" and - .package.version == $packageVersion and - .package.os == "debian13" and - .package.postgresMajor == "18" and - .package.architecture == $arch' \ - "$VERIFY_DIR/build-metadata.json" >/dev/null - rm -rf "$VERIFY_DIR" - - TARGET_REF="${DOCUMENTDB_DEB_REPOSITORY}:${VERSION}-pg18-${ARCH}" - if TARGET_DIGEST=$(oras resolve "$TARGET_REF" 2>/dev/null); then - if [[ "$TARGET_DIGEST" != "$SOURCE_DIGEST" ]]; then - echo "$TARGET_REF already exists at $TARGET_DIGEST, not $SOURCE_DIGEST" >&2 - exit 1 - fi - fi - done - - - name: Promote verified candidate - env: - CANDIDATE_VERSION: ${{ inputs.candidate_version }} - VERSION: ${{ inputs.version }} - shell: bash + OLD_VERSION: ${{ steps.current.outputs.current_version }} + NEW_VERSION: ${{ inputs.version }} run: | set -euo pipefail - for IMAGE in documentdb gateway; do - REPOSITORY="ghcr.io/${GITHUB_REPOSITORY}/${IMAGE}" - SOURCE_DIGEST=$(docker buildx imagetools inspect "${REPOSITORY}:${CANDIDATE_VERSION}" \ - --format '{{json .Manifest.Digest}}' | tr -d '"') - TARGET_REF="${REPOSITORY}:${VERSION}" - - if TARGET_DIGEST=$(docker buildx imagetools inspect "$TARGET_REF" \ - --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"'); then - echo "$TARGET_REF already points to verified digest $TARGET_DIGEST" - else - docker buildx imagetools create -t "$TARGET_REF" "${REPOSITORY}@${SOURCE_DIGEST}" - fi - - TARGET_DIGEST=$(docker buildx imagetools inspect "$TARGET_REF" \ - --format '{{json .Manifest.Digest}}' | tr -d '"') - [[ "$TARGET_DIGEST" == "$SOURCE_DIGEST" ]] - done - - for ARCH in amd64 arm64; do - SOURCE_REF="${DOCUMENTDB_DEB_REPOSITORY}:${CANDIDATE_VERSION}-pg18-${ARCH}" - SOURCE_DIGEST=$(oras resolve "$SOURCE_REF") - TARGET_REF="${DOCUMENTDB_DEB_REPOSITORY}:${VERSION}-pg18-${ARCH}" - - if TARGET_DIGEST=$(oras resolve "$TARGET_REF" 2>/dev/null); then - echo "$TARGET_REF already points to verified digest $TARGET_DIGEST" - else - oras tag "${DOCUMENTDB_DEB_REPOSITORY}@${SOURCE_DIGEST}" "${VERSION}-pg18-${ARCH}" - fi - - TARGET_DIGEST=$(oras resolve "$TARGET_REF") - [[ "$TARGET_DIGEST" == "$SOURCE_DIGEST" ]] - done + if [[ "$OLD_VERSION" == "$NEW_VERSION" ]]; then + echo "Version $NEW_VERSION is already the default. No changes needed." + exit 0 + fi + + echo "Updating default versions: $OLD_VERSION → $NEW_VERSION" + + # 1. Update operator constants.go + sed -i "s|:${OLD_VERSION}\"|:${NEW_VERSION}\"|g" \ + operator/src/internal/utils/constants.go + + # 2. Update sidecar plugin config.go + sed -i "s|:${OLD_VERSION}\"|:${NEW_VERSION}\"|g" \ + operator/cnpg-plugins/sidecar-injector/internal/config/config.go + + # 3. Update Helm chart values.yaml + sed -i "s|documentDbVersion: \"${OLD_VERSION}\"|documentDbVersion: \"${NEW_VERSION}\"|" \ + operator/documentdb-helm-chart/values.yaml + + # 4. (Removed) Test workflow fallback images — the legacy + # test-backup-and-restore.yml and test-upgrade-and-rollback.yml + # workflows have been consolidated into test-e2e.yml. Database + # image versions for e2e are resolved from the operator's + # built-in defaults (constants.go) rather than per-workflow + # fallback tags, so no sed is required here. + + # 5. Update sidecar plugin config test (hardcoded expected gateway image) + sed -i "s|:${OLD_VERSION}\"|:${NEW_VERSION}\"|g" \ + operator/cnpg-plugins/sidecar-injector/internal/config/config_test.go + + # 6. Update build workflow defaults + sed -i "s|DEFAULT_DOCUMENTDB_VERSION: '${OLD_VERSION}'|DEFAULT_DOCUMENTDB_VERSION: '${NEW_VERSION}'|" \ + .github/workflows/build_documentdb_images.yml + sed -i "s|default: '${OLD_VERSION}'|default: '${NEW_VERSION}'|g" \ + .github/workflows/build_documentdb_images.yml + + # 7. Update release workflow default version + sed -i "s|default: '${OLD_VERSION}'|default: '${NEW_VERSION}'|g" \ + .github/workflows/release_documentdb_images.yml + + # 8. Update gateway Dockerfile default source image ARG + sed -i "s|pg17-${OLD_VERSION}|pg17-${NEW_VERSION}|" \ + .github/dockerfiles/Dockerfile_gateway_public_image + + # 9. Update e2e schema-upgrade default version pair. This is the + # single source of truth for the two-phase migration spec's CI + # default (test-e2e.yml passes only an optional override), so the + # released pair advances with each DB release: old <- previous + # default (OLD_VERSION), new <- released version (NEW_VERSION). + sed -i -E "s|(defaultOldDocumentDBVersion = )\"[0-9]+\.[0-9]+\.[0-9]+\"|\1\"${OLD_VERSION}\"|" \ + test/e2e/tests/upgrade/helpers_test.go + sed -i -E "s|(defaultNewDocumentDBVersion = )\"[0-9]+\.[0-9]+\.[0-9]+\"|\1\"${NEW_VERSION}\"|" \ + test/e2e/tests/upgrade/helpers_test.go + + echo "=== Files modified ===" + git diff --name-only + echo "" + echo "=== Diff ===" + git diff + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: bump DocumentDB default images to ${{ inputs.version }}" + title: "chore: bump DocumentDB default images to ${{ inputs.version }}" + body: | + ## Automated DocumentDB Version Bump + + Promoted images `documentdb` and `gateway` from candidate `${{ inputs.candidate_version }}` to release `${{ inputs.version }}`. + + ### Changes + - Updated `DEFAULT_DOCUMENTDB_IMAGE` and `DEFAULT_GATEWAY_IMAGE` in `constants.go` + - Updated sidecar plugin default gateway image in `config.go` and `config_test.go` + - Updated `documentDbVersion` in Helm chart `values.yaml` + - Updated build/release workflow defaults in `build_documentdb_images.yml` and `release_documentdb_images.yml` + - Updated gateway Dockerfile default source image in `Dockerfile_gateway_public_image` + - Updated e2e schema-upgrade default version pair in `test/e2e/tests/upgrade/helpers_test.go` (old `${{ steps.current.outputs.current_version }}` → new `${{ inputs.version }}`) + + ### Image References + - `ghcr.io/${{ github.repository }}/documentdb:${{ inputs.version }}` + - `ghcr.io/${{ github.repository }}/gateway:${{ inputs.version }}` + + --- + *Auto-generated by `release_documentdb_images.yml`* + branch: auto/documentdb-${{ inputs.version }} + delete-branch: true + labels: | + automated + version-bump - name: Release summary run: | @@ -180,9 +188,12 @@ jobs: echo "## DocumentDB Image Release Summary" echo "" echo "- **Database Version**: \`${{ inputs.version }}\`" - echo "- **Source Candidate**: \`${{ inputs.candidate_version }}\`" echo "- **Images Promoted**: documentdb, gateway" - echo "- **Packages Promoted**: Debian 13, PostgreSQL 18, amd64 + arm64" + echo "- **Source Tag**: \`${{ inputs.candidate_version }}\` → \`${{ inputs.version }}\`" echo "" - echo "Default operator image versions are updated separately through a reviewed pull request." } >> "$GITHUB_STEP_SUMMARY" + if [[ "${{ steps.current.outputs.current_version }}" != "${{ inputs.version }}" ]]; then + echo "- **PR Created**: Updates default versions from \`${{ steps.current.outputs.current_version }}\` to \`${{ inputs.version }}\`" >> "$GITHUB_STEP_SUMMARY" + else + echo "- **No PR needed**: Version \`${{ inputs.version }}\` is already the default" >> "$GITHUB_STEP_SUMMARY" + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 088308498..e72977cc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Major Features - **Fail-fast ImageVolume capability check**: The operator now depends on the Kubernetes [ImageVolume](https://kubernetes.io/docs/concepts/storage/volumes/#image) feature to mount the DocumentDB extension into PostgreSQL pods. Instead of gating on a Kubernetes version number, the validating webhook performs a capability probe (a server-side dry-run) when a `DocumentDB` is created and **rejects the resource with an actionable error if ImageVolume is unavailable**, so you find out immediately instead of waiting for pods that never become ready. ImageVolume is GA (on by default) in Kubernetes **1.35+**; on **1.33/1.34** it is beta and must be enabled via the `ImageVolume` feature gate on a containerd/CRI-O runtime. The Helm chart's `kubeVersion` floor is relaxed to `>= 1.33.0-0` accordingly. See [Before you start](docs/operator-public-documentation/preview/getting-started/before-you-start.md). -- **Source-built Debian 13 extension packages**: Database image releases now build the PostgreSQL 18 DocumentDB extension package from a pinned upstream source tag on native amd64 and arm64 runners, publish signed package bundles as GHCR OCI artifacts, and verify them before building and promoting the extension image. +- **Source-built Debian 13 extension images**: Database image releases now build and validate the PostgreSQL 18 DocumentDB extension package from a pinned upstream source tag on native amd64 and arm64 runners, then use it directly to build the signed multi-architecture extension image. ## [0.3.0] - 2026-07-15 diff --git a/RELEASE.md b/RELEASE.md index dff06b4f6..a49ec3706 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -78,31 +78,8 @@ After the PR is approved and merged: Database images follow an **independent release cycle** from the operator: -1. Run **"RELEASE - Build DocumentDB Candidate Images"** (`build_documentdb_images.yml`) with the released DocumentDB `version`. The workflow builds Debian 13 / PostgreSQL 18 extension packages from the pinned upstream source tag, publishes the signed package bundles to GHCR, and builds the extension and gateway candidate images. -2. Run **"RELEASE - Promote DocumentDB Images"** (`release_documentdb_images.yml`) to verify and promote the package artifacts and images. -3. Create a separate PR to bump the default DocumentDB version in the operator, Helm chart, sidecar configuration, gateway Dockerfile, and upgrade tests. Keeping this as a normal PR ensures the version change receives review and CI before users adopt it. - -The extension packages are stored as OCI artifacts rather than as an APT -repository: - -```text -ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18- -``` - -Candidate package tags include the workflow run identifier and are consumed by -the image build in the same workflow. The promotion workflow adds stable -version tags without changing the signed artifact digest. Existing stable tags -are accepted only when they already point to the same digest; changed artifacts -must use a new release version. - -Only candidates created by `build_documentdb_images.yml` after package-artifact -publication was introduced can be promoted by `release_documentdb_images.yml`; -older image-only candidate tags do not have the required package artifacts and -fail candidate verification before any stable tag is changed. - -GHCR package visibility is managed separately from repository visibility. -Confirm that the `documentdb`, `gateway`, and `documentdb-deb13` packages are -public before publishing a public release. +1. Run **"RELEASE - Build DocumentDB Candidate Images"** (`build_documentdb_images.yml`) with the released DocumentDB `version`. For version 0.116.0 and later, the workflow builds the Debian 13 / PostgreSQL 18 extension package from pinned source before building the images. +2. Run **"RELEASE - Promote DocumentDB Images"** (`release_documentdb_images.yml`) to promote and auto-create a PR that bumps default image versions across the codebase > **Note:** The deprecated combined workflows (`build_images.yml`, `release_images.yml`) are still available but will be removed in a future release. diff --git a/docs/designs/image-management.md b/docs/designs/image-management.md index 72a75d331..51d31afce 100644 --- a/docs/designs/image-management.md +++ b/docs/designs/image-management.md @@ -44,13 +44,9 @@ All images are published to **GitHub Container Registry (GHCR)** under `ghcr.io/ | Image | GHCR Path | Source | Dockerfile | Purpose | |-------|-----------|--------|------------|---------| -| **documentdb** | `.../documentdb` | Debian 13 / PostgreSQL 18 package built from a pinned `documentdb/documentdb` source commit | `.github/dockerfiles/Dockerfile_extension` | DocumentDB PostgreSQL extension files for CNPG ImageVolume mode | +| **documentdb** | `.../documentdb` | Debian 13 / PostgreSQL 18 package built from pinned `documentdb/documentdb` source (releases before 0.116 use published assets) | `.github/dockerfiles/Dockerfile_extension` | DocumentDB PostgreSQL extension files for CNPG ImageVolume mode | | **gateway** | `.../gateway` | Public gateway payload copied from `ghcr.io/documentdb/documentdb/documentdb-local:pg17-` | `.github/dockerfiles/Dockerfile_gateway_public_image` | MongoDB wire-protocol gateway binary (Rust) | -The source-built extension packages are retained as signed OCI artifacts at -`.../documentdb-deb13:-pg18-` and promoted to -`.../documentdb-deb13:-pg18-`. - ### External Image (Not Built Here) | Image | Full Reference | Source | Purpose | @@ -213,17 +209,16 @@ Builds documentdb extension and gateway images from released DocumentDB source. | **Tag pattern** | `{documentdb_version}-build-{run_id}-{attempt}-{sha}` (candidate) | | **Build time** | ~15 minutes (native package builds + image builds) | | **Multi-arch** | amd64 + arm64 → multi-arch manifest | -| **Signing** | cosign keyless (package OCI artifacts and image manifests) | -| **Version detection** | Required workflow input or repository dispatch payload | +| **Signing** | cosign keyless (OIDC) | +| **Version detection** | Workflow input / repository dispatch payload (defaults to released `0.113.0`) | The build process: 1. Resolves the released DocumentDB version and source ref to an immutable commit -2. Builds Debian 13 PostgreSQL 18 extension packages on native amd64 and arm64 runners -3. Validates the package name, version, architecture, and checksum -4. Publishes the package, checksum, build metadata, LICENSE, and NOTICE as signed OCI artifacts under `documentdb-deb13` -5. Verifies and pulls those exact GHCR artifacts to build `Dockerfile_extension` (which also installs pg_cron, pgvector, and postgis) -6. Verifies the public multi-arch `documentdb-local:pg17-` image and builds `Dockerfile_gateway_public_image` from its gateway payload -7. Creates and signs the multi-architecture extension and gateway image manifests +2. Builds Debian 13 PostgreSQL 18 extension packages on native amd64 and arm64 runners; releases before 0.116 use their published packages +3. Validates each package's name, version, and architecture +4. Uses each package directly to build `Dockerfile_extension` (installs pg_cron, pgvector, and postgis alongside) +5. Verifies the public multi-arch `documentdb-local:pg17-` image and builds `Dockerfile_gateway_public_image` from its gateway payload +6. Creates and signs the multi-architecture extension and gateway image manifests ### Dockerfile Details @@ -286,31 +281,26 @@ Flow: ### Database Image Release (`release_documentdb_images.yml`) -Verifies and promotes the documentdb/gateway images and their corresponding -Debian package artifacts. +Promotes documentdb/gateway candidate images and auto-creates a PR to update defaults. ``` Inputs: candidate_version: "0.111.0-build-123456789-1-deadbee" ← source tag version: "0.111.0" ← target release tag + update_defaults: true ← create PR to bump versions Flow: - 1. Verify Complete Candidate - ├── Validate candidate and target versions - ├── Verify image and package signatures - ├── Validate package metadata and architectures - └── Reject conflicting existing stable tags - - 2. Promote Images + 1. Promote Images └── docker buildx imagetools create -t .../documentdb:0.111.0 .../documentdb:0.111.0-test -t .../gateway:0.111.0 .../gateway:0.111.0-test - - 3. Promote Package Artifacts - └── oras tag - .../documentdb-deb13:0.111.0-pg18-{amd64,arm64} - - 4. Create a normal reviewed PR to update operator defaults + + 2. Update Defaults (auto-PR) + ├── constants.go: DEFAULT_DOCUMENTDB_IMAGE, DEFAULT_GATEWAY_IMAGE + ├── config.go: sidecar plugin default gateway image + ├── values.yaml: documentDbVersion + ├── test-backup-and-restore.yml: fallback images + └── Opens PR: "chore: bump DocumentDB images to 0.111.0" ``` --- @@ -375,8 +365,7 @@ The script uses `kind_with_registry.sh` to set up a `registry:2` container on `l ## Version Synchronization Points -After promoting database images, update the following locations in a separate -reviewed pull request: +When bumping database image versions, the following locations must be updated (automated by `release_documentdb_images.yml`): | File | Field | Example | |------|-------|---------| @@ -385,8 +374,11 @@ reviewed pull request: | `operator/cnpg-plugins/sidecar-injector/internal/config/config.go` | Default gateway image | `...gateway:0.113.0` | | `operator/cnpg-plugins/sidecar-injector/internal/config/config_test.go` | Expected gateway image | `...gateway:0.113.0` | | `operator/documentdb-helm-chart/values.yaml` | `documentDbVersion` | `"0.113.0"` | +| `.github/workflows/test-backup-and-restore.yml` | `DOCUMENTDB_IMAGE`, `GATEWAY_IMAGE` env | `...documentdb:0.113.0` | +| `.github/workflows/test-upgrade-and-rollback.yml` | `RELEASED_DATABASE_VERSION` | `0.113.0` | +| `.github/workflows/build_documentdb_images.yml` | `DEFAULT_DOCUMENTDB_VERSION`, input default | `0.113.0` | +| `.github/workflows/release_documentdb_images.yml` | Input default | `0.113.0` | | `.github/dockerfiles/Dockerfile_gateway_public_image` | `SOURCE_IMAGE` ARG default | `...pg17-0.113.0` | -| `test/e2e/tests/upgrade/helpers_test.go` | Old/new schema-upgrade defaults | `0.110.0` / `0.113.0` | When bumping operator versions, update: diff --git a/docs/developer-guides/testing-with-fork-images.md b/docs/developer-guides/testing-with-fork-images.md index fce1cea1b..0fdd40456 100644 --- a/docs/developer-guides/testing-with-fork-images.md +++ b/docs/developer-guides/testing-with-fork-images.md @@ -31,15 +31,14 @@ Skip this step if you don't need to change the DocumentDB extension or gateway. 1. For a released upstream version, no DocumentDB fork is required. For unreleased database changes, fork [`documentdb/documentdb`](https://github.com/documentdb/documentdb) and push the source branch you want to test. 2. **In your operator fork**, run **Actions → `RELEASE - Build DocumentDB Candidate Images` → Run workflow**. Provide these inputs: - `version`: `0.116.0` (or the version declared by your source) - - `documentdb_source_github_repo`: `documentdb/documentdb`, or `/documentdb` for custom source + - `documentdb_extension_github_repo`: `documentdb/documentdb`, or `/documentdb` for custom source - `documentdb_source_ref`: leave empty to use the release tag derived from `version`, or provide your custom source branch/tag - `documentdb_gateway_image_repo`: leave the default `ghcr.io/documentdb/documentdb/documentdb-local` for released versions, or use your own public image repository when testing custom gateway changes The workflow resolves the source ref to an immutable commit, builds the Debian 13 / PostgreSQL 18 extension packages on native amd64 and arm64 - runners, signs and stores them as OCI artifacts in your fork's GHCR, then - uses those exact artifacts to build the extension images. The gateway still - uses the selected `documentdb-local` source image. + runners, validates them, and uses them directly to build the extension + images. The gateway still uses the selected `documentdb-local` source image. 3. After the run finishes, your fork has the candidate image tag (and per-arch variants): @@ -48,14 +47,7 @@ Skip this step if you don't need to change the DocumentDB extension or gateway. ghcr.io//documentdb-kubernetes-operator/gateway:-build--- ``` - It also publishes: - - ```text - ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18-amd64 - ghcr.io//documentdb-kubernetes-operator/documentdb-deb13:-pg18-arm64 - ``` - - The workflow only publishes the computed candidate tag (printed in the run summary); it does **not** retag to the bare ``. The stable image and package tags are created by [`release_documentdb_images.yml`](../../.github/workflows/release_documentdb_images.yml), which is the GA promotion path and should not be run for fork testing. Use the candidate image tag from the run summary directly in Step 3. + The workflow only publishes the computed candidate tag (printed in the run summary); it does **not** retag to the bare ``. Stable image tags are created by [`release_documentdb_images.yml`](../../.github/workflows/release_documentdb_images.yml), which is the GA promotion path and should not be run for fork testing. Use the candidate image tag from the run summary directly in Step 3. --- From 3ab2a0b51a62a8dcad0635d5774130e149e43091 Mon Sep 17 00:00:00 2001 From: Guanzhou Song Date: Fri, 4 Sep 2026 14:18:46 -0400 Subject: [PATCH 5/5] refactor: simplify DocumentDB source selection Derive the upstream release tag directly from the requested version and remove the unused source-ref override. Align the workflow input example and documentation with the preserved defaults and observed build time. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: faca2436-03f6-47f3-be13-f266ab71a7e9 Signed-off-by: Guanzhou Song --- .github/workflows/build_documentdb_images.yml | 11 ++--------- docs/designs/image-management.md | 2 +- docs/developer-guides/testing-with-fork-images.md | 5 ++--- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build_documentdb_images.yml b/.github/workflows/build_documentdb_images.yml index d4fe5ca62..807f1e56e 100644 --- a/.github/workflows/build_documentdb_images.yml +++ b/.github/workflows/build_documentdb_images.yml @@ -11,17 +11,13 @@ on: workflow_dispatch: inputs: version: - description: 'Released DocumentDB version to build (for example 0.116.0)' + description: 'Released DocumentDB version to build (for example 0.113.0)' required: false default: '0.113.0' documentdb_extension_github_repo: description: 'GitHub owner/repo containing DocumentDB source and releases' required: false default: 'documentdb/documentdb' - documentdb_source_ref: - description: 'Optional DocumentDB source tag or branch (defaults to the release tag)' - required: false - default: '' documentdb_gateway_image_repo: description: 'Container image repo for gateway source (without tag)' required: false @@ -57,8 +53,6 @@ jobs: steps: - name: Resolve released DocumentDB version id: version - env: - DOCUMENTDB_SOURCE_REF_INPUT: ${{ github.event.inputs.documentdb_source_ref }} run: | set -euo pipefail RAW_VERSION="${{ github.event.inputs.version || github.event.client_payload.version || env.DEFAULT_DOCUMENTDB_VERSION }}" @@ -72,8 +66,7 @@ jobs: exit 1 fi VERSION_DASH=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.([0-9]+)$/\1-\2/') - SOURCE_REF="$DOCUMENTDB_SOURCE_REF_INPUT" - SOURCE_REF="${SOURCE_REF:-v${VERSION_DASH}}" + SOURCE_REF="v${VERSION_DASH}" SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) IMAGE_TAG="${VERSION}-build-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${SHORT_SHA}" GATEWAY_SOURCE_IMAGE="${{ env.DOCUMENTDB_GATEWAY_IMAGE_REPO }}:pg17-${VERSION}" diff --git a/docs/designs/image-management.md b/docs/designs/image-management.md index 51d31afce..79b60a344 100644 --- a/docs/designs/image-management.md +++ b/docs/designs/image-management.md @@ -207,7 +207,7 @@ Builds documentdb extension and gateway images from released DocumentDB source. | **Images** | documentdb, gateway | | **Dockerfiles** | `.github/dockerfiles/Dockerfile_extension`, `.github/dockerfiles/Dockerfile_gateway_public_image` | | **Tag pattern** | `{documentdb_version}-build-{run_id}-{attempt}-{sha}` (candidate) | -| **Build time** | ~15 minutes (native package builds + image builds) | +| **Build time** | ~5 minutes (native package builds + image builds) | | **Multi-arch** | amd64 + arm64 → multi-arch manifest | | **Signing** | cosign keyless (OIDC) | | **Version detection** | Workflow input / repository dispatch payload (defaults to released `0.113.0`) | diff --git a/docs/developer-guides/testing-with-fork-images.md b/docs/developer-guides/testing-with-fork-images.md index 0fdd40456..27da9e283 100644 --- a/docs/developer-guides/testing-with-fork-images.md +++ b/docs/developer-guides/testing-with-fork-images.md @@ -28,11 +28,10 @@ If your change is purely Go controller code, skip Step 1 entirely and use the up Skip this step if you don't need to change the DocumentDB extension or gateway. -1. For a released upstream version, no DocumentDB fork is required. For unreleased database changes, fork [`documentdb/documentdb`](https://github.com/documentdb/documentdb) and push the source branch you want to test. +1. For a released upstream version, no DocumentDB fork is required. For unreleased database changes, fork [`documentdb/documentdb`](https://github.com/documentdb/documentdb), push your changes, and tag them as `v.-` (for example, `v0.116-0`). 2. **In your operator fork**, run **Actions → `RELEASE - Build DocumentDB Candidate Images` → Run workflow**. Provide these inputs: - - `version`: `0.116.0` (or the version declared by your source) + - `version`: `0.116.0` (or the dotted version matching your source tag) - `documentdb_extension_github_repo`: `documentdb/documentdb`, or `/documentdb` for custom source - - `documentdb_source_ref`: leave empty to use the release tag derived from `version`, or provide your custom source branch/tag - `documentdb_gateway_image_repo`: leave the default `ghcr.io/documentdb/documentdb/documentdb-local` for released versions, or use your own public image repository when testing custom gateway changes The workflow resolves the source ref to an immutable commit, builds the