name: Continuous Delivery on: push: branches: - main paths-ignore: - Debian/ClusterImageCatalog*.yaml workflow_dispatch: permissions: read-all env: IMAGE_STAGING: "ghcr.io/${{ github.repository_owner }}/postgresql-testing" IMAGE_RELEASE: "ghcr.io/${{ github.repository_owner }}/postgresql" DEFAULT_DISTRO: "bullseye" jobs: generate-jobs: name: Generate Jobs runs-on: ubuntu-24.04 outputs: strategy: ${{ steps.generate-jobs.outputs.strategy }} steps: - name: Checkout Code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Generate Jobs id: generate-jobs shell: bash run: | bash .github/generate-strategy.sh build: needs: generate-jobs strategy: ${{ fromJson(needs.generate-jobs.outputs.strategy) }} name: ${{ matrix.name }} runs-on: ubuntu-24.04 permissions: contents: read packages: write security-events: write steps: - name: Checkout Code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up QEMU uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 with: platforms: ${{ matrix.platforms }} - name: Docker meta env: TAGS: ${{ toJson(matrix.tags) }} run: | RESULT="" for tag in $(jq -r '.[]' <<< "${TAGS}") do RESULT="${RESULT},${IMAGE_STAGING}:${tag}" # If we are running the pipeline in the main branch images are pushed in both -testing and PROD repo if [ "${GITHUB_REF#refs/heads/}" == main ] then RESULT="${RESULT},${IMAGE_RELEASE}:${tag}" fi done echo "TAGS=${RESULT%,}" >> $GITHUB_ENV - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 - name: Log in to the GitHub Container registry uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # When publishing new images from main, we should not overwrite an existing # tag in order to guarantee the tag's SHA digest consistency. - name: Verify primary tag is not overwritten run: | echo "MISSING_TAG=false" >> $GITHUB_ENV # if we are not on the main branch, always push if [ "${GITHUB_REF#refs/heads/}" != main ]; then echo "MISSING_TAG=true" >> $GITHUB_ENV exit 0 fi IMAGE="${IMAGE_RELEASE}:${{ matrix.fullTag }}" # If the primary tag already exists, skip the building phase if skopeo inspect docker://${IMAGE} >/dev/null 2>/dev/null; then echo "Image ${IMAGE} already exists" # We still need to grab the digest to build the imageCatalog echo "OLD_DIGEST=$(skopeo inspect docker://${IMAGE} --format '{{ .Digest }}')" >> $GITHUB_ENV else echo "MISSING_TAG=true" >> $GITHUB_ENV fi - name: Build and load uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 if: ${{ env.MISSING_TAG == 'true' }} with: context: ${{ matrix.dir }} file: ${{ matrix.file }} push: false load: true tags: ${{ env.TAGS }} - name: Dockle scan uses: erzz/dockle-action@69369bc745ee29813f730231a821bcd4f71cd290 # v1 if: ${{ env.MISSING_TAG == 'true' }} with: image: "${{ env.IMAGE_STAGING }}:${{ matrix.tags[0] }}" exit-code: '1' failure-threshold: WARN accept-keywords: key accept-filenames: usr/share/cmake/Templates/Windows/Windows_TemporaryKey.pfx,etc/trusted-key.key,usr/share/doc/perl-IO-Socket-SSL/certs/server_enc.p12,usr/share/doc/perl-IO-Socket-SSL/certs/server.p12,usr/local/lib/python3.9/dist-packages/azure/core/settings.py,usr/local/lib/python3.8/site-packages/azure/core/settings.py,usr/share/postgresql-common/pgdg/apt.postgresql.org.asc,usr/local/lib/python3.7/dist-packages/azure/core/settings.py,etc/ssl/private/ssl-cert-snakeoil.key,usr/lib/python3.9/site-packages/azure/core/settings.py,usr/local/lib/python3.11/dist-packages/azure/core/settings.py - name: Run Snyk to check Docker image for vulnerabilities uses: snyk/actions/docker@master if: ${{ env.MISSING_TAG == 'true' }} continue-on-error: true env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: image: "${{ env.IMAGE_STAGING }}:${{ matrix.tags[0] }}" args: --severity-threshold=high --file=${{ matrix.file }} - name: Upload result to GitHub Code Scanning uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3 if: ${{ env.MISSING_TAG == 'true' }} continue-on-error: true with: sarif_file: snyk.sarif - name: Build and push id: build uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 if: ${{ env.MISSING_TAG == 'true' }} with: context: ${{ matrix.dir }} file: ${{ matrix.file }} platforms: ${{ matrix.platforms }} push: true tags: ${{ env.TAGS }} - name: Create artifact run: | # Set a default image BASE_IMAGE=${IMAGE_STAGING} if [ "${GITHUB_REF#refs/heads/}" == main ]; then BASE_IMAGE=${IMAGE_RELEASE} fi DIGEST="${{ steps.build.outputs.digest }}" if [[ "${{ env.MISSING_TAG }}" == "false" ]]; then DIGEST="${{ env.OLD_DIGEST }}" fi IMAGE=${BASE_IMAGE}:${{ matrix.fullTag }}@${DIGEST} \ MAJOR=${{ matrix.version }} \ yq --null-input '{ "apiVersion": "postgresql.cnpg.io/v1", "kind": "ClusterImageCatalog", "metadata": {"name":"postgresql"}, "spec": { "images": [ { "major": env(MAJOR), "image": env(IMAGE) } ] } }' > ${{ matrix.version }}-${{ matrix.distro }}.yaml - name: Upload artifact uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ matrix.version }}-${{ matrix.distro }}-clusterimagecatalog path: ${{ matrix.version }}-${{ matrix.distro }}.yaml image-catalog: name: Generate ClusterImageCatalog runs-on: ubuntu-24.04 needs: build permissions: contents: write steps: - name: Checkout Code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: token: ${{ secrets.REPO_GHA_PAT }} - name: Download artifacts uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: pattern: '*-clusterimagecatalog' path: clusterimagecatalog merge-multiple: true - name: Update ClusterImageCatalog run: | yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/*-bullseye.yaml > Debian/ClusterImageCatalog-bullseye.yaml yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/*-bookworm.yaml > Debian/ClusterImageCatalog-bookworm.yaml ln -f -s ClusterImageCatalog-${DEFAULT_DISTRO}.yaml Debian/ClusterImageCatalog.yaml cat Debian/ClusterImageCatalog.yaml Debian/ClusterImageCatalog-bullseye.yaml Debian/ClusterImageCatalog-bookworm.yaml - name: Temporarily disable "include administrators" branch protection if: ${{ always() && github.ref == 'refs/heads/main' }} id: disable_include_admins uses: benjefferies/branch-protection-bot@af281f37de86139d1c7a27b91176b5dc1c2c827c # v1.1.2 with: access_token: ${{ secrets.REPO_GHA_PAT }} branch: main enforce_admins: false - name: Push ClusterImageCatalog updates uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9 if: ${{ github.ref == 'refs/heads/main' }} with: author_name: CloudNativePG Automated Updates author_email: noreply@cnpg.com message: 'Automatic ClusterImageCatalog update' add: 'Debian/ClusterImageCatalog*.yaml' - name: Enable "include administrators" branch protection uses: benjefferies/branch-protection-bot@af281f37de86139d1c7a27b91176b5dc1c2c827c # v1.1.2 if: ${{ always() && github.ref == 'refs/heads/main' }} with: access_token: ${{ secrets.REPO_GHA_PAT }} branch: main enforce_admins: ${{ steps.disable_include_admins.outputs.initial_status }}