From e901119f3c6cf66e44392fd177eeb3b062c44b8b Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Mon, 20 Apr 2026 11:05:26 +0200 Subject: [PATCH 01/23] refactor(ci): rewire workflows to call build-logic reusable-docker-* workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace inline Docker build/test/scan/publish/README-sync logic with calls to reusable workflows in liquibase/build-logic. Preserves all existing triggers, matrix definitions, repository_dispatch types, and on: push paths filters. Phase 2 of DAT-22522 Dockerfile migration — this is a spike that rewires liquibase/docker as a consumer of the new reusables before any Dockerfile moves. Pinned to build-logic@dat-22876-reusables for validation; will flip to @main after build-logic merges. Net change: -1943 lines across 6 workflows. DAT-22876 --- .github/workflows/build-qa-docker.yml | 540 +----------- .github/workflows/create-release.yml | 453 +++-------- .../publish-liquibase-secure-readme.yml | 43 +- .github/workflows/publish-oss-readme.yml | 41 +- .github/workflows/test.yml | 769 +----------------- .github/workflows/trivy.yml | 564 ++----------- 6 files changed, 226 insertions(+), 2184 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 6ff320c5..dee114c2 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -89,536 +89,24 @@ jobs: build-qa-docker: name: Build ${{ matrix.image_name }} - runs-on: ubuntu-latest needs: set-matrix strategy: fail-fast: false matrix: ${{ fromJSON(needs.set-matrix.outputs.matrix) }} - steps: - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - id: vault-secrets-liquibase - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - - name: Configure AWS credentials for Liquibase-Secure builds - if: ${{ matrix.build_type == 'secure' }} - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ env.AWS_PROD_GITHUB_OIDC_ROLE_ARN_LIQUIBASE_PRO }} - aws-region: us-east-1 - - - name: Get GitHub App token for Liquibase-Secure workflow trigger - if: ${{ matrix.build_type == 'secure' }} - id: get-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 - with: - app-id: ${{ env.LIQUIBASE_GITHUB_APP_ID }} - private-key: ${{ env.LIQUIBASE_GITHUB_APP_PRIVATE_KEY }} - owner: liquibase - repositories: liquibase-pro - permission-contents: write - permission-actions: write - - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Install jq - run: | - sudo apt-get update - sudo apt-get install -y jq - - - name: Get latest workflow run for branch - if: ${{ matrix.build_type == 'Community' }} - id: get-workflow-run - run: | - # Get the latest successful workflow run for the specified branch - WORKFLOW_RUN=$(curl -s \ - -H "Authorization: Bearer ${{ env.LIQUIBOT_PAT_GPM_ACCESS }}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/liquibase/liquibase/actions/workflows/run-tests.yml/runs?branch=${{ inputs.liquibaseBranch }}&status=completed&conclusion=success&per_page=1" \ - | jq -r '.workflow_runs[0].id') - - if [ "$WORKFLOW_RUN" = "null" ] || [ -z "$WORKFLOW_RUN" ]; then - echo "No successful workflow run found for branch ${{ inputs.liquibaseBranch }}" - echo "Will build using standard Dockerfile from branch source instead" - echo "workflow_run_id=" >> $GITHUB_OUTPUT - echo "has_workflow_run=false" >> $GITHUB_OUTPUT - else - echo "Found workflow run ID: $WORKFLOW_RUN" - echo "workflow_run_id=$WORKFLOW_RUN" >> $GITHUB_OUTPUT - echo "has_workflow_run=true" >> $GITHUB_OUTPUT - fi - - - name: Download liquibase build artifact (Community) or from S3 (Liquibase-Secure) - id: download-artifact - run: | - if [[ "${{ matrix.build_type }}" == "secure" ]]; then - echo "Downloading Liquibase Secure build from S3..." - - # Determine S3 path based on whether secure-version is provided - if [[ -n "${{ inputs.secure-version }}" ]]; then - echo "Using secure-version: ${{ inputs.secure-version }}" - # Extract base version and RC number for RC versions - VERSION="${{ inputs.secure-version }}" - if [[ "$VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-RC([0-9]+)$ ]]; then - BASE_VERSION="${BASH_REMATCH[1]}" - RC_NUMBER="${BASH_REMATCH[2]}" - LIQUIBASE_SECURE_ZIP="liquibase-secure-${VERSION}.tar.gz" - S3_URL="s3://repo.liquibase.com/non-releases/secure/${VERSION}/${LIQUIBASE_SECURE_ZIP}" - echo "Using RC S3 path: $S3_URL" - else - # Regular production version - LIQUIBASE_SECURE_ZIP="liquibase-secure-${VERSION}.zip" - S3_URL="s3://repo.liquibase.com/releases/secure/${VERSION}/${LIQUIBASE_SECURE_ZIP}" - echo "Using production S3 path: $S3_URL" - fi - else - echo "Using branch-based build: ${{ inputs.liquibaseBranch }}" - # Original branch-based logic - LIQUIBASE_SECURE_ZIP="liquibase-secure-${{ inputs.liquibaseBranch }}.zip" - S3_URL="s3://repo.liquibase.com/releases/secure/${{ inputs.liquibaseBranch }}/$LIQUIBASE_SECURE_ZIP" - fi - - echo "Downloading from S3: $S3_URL" - - # Try to download from S3 first - if ! aws s3 cp "$S3_URL" "$LIQUIBASE_SECURE_ZIP" 2>/dev/null; then - echo "Failed to download liquibase-secure build from S3. File may not exist yet." - - # Check if it's a 403/404 error (file doesn't exist) - if aws s3 ls "$S3_URL" >/dev/null 2>&1; then - echo "❌ File exists but access denied. Check permissions." - exit 1 - else - echo "đŸ“Ļ Liquibase-Secure build not found in S3." - # If secure-version is provided, don't trigger workflow - the build should exist - if [[ -n "${{ inputs.secure-version }}" ]]; then - echo "❌ ERROR: secure-version specified but build not found in S3. Build should already exist for version ${{ inputs.secure-version }}" - echo "trigger_liquibase_secure_workflow=false" >> $GITHUB_OUTPUT - echo "build_ready=false" >> $GITHUB_OUTPUT - echo "use_fallback=true" >> $GITHUB_OUTPUT - else - echo "đŸ“Ļ Branch-based build not found. Will trigger workflow to create it..." - echo "trigger_liquibase_secure_workflow=true" >> $GITHUB_OUTPUT - echo "build_ready=false" >> $GITHUB_OUTPUT - echo "use_fallback=false" >> $GITHUB_OUTPUT - fi - fi - else - echo "✅ Successfully downloaded Liquibase-Secure build from S3" - echo "trigger_liquibase_secure_workflow=false" >> $GITHUB_OUTPUT - echo "build_ready=true" >> $GITHUB_OUTPUT - echo "use_fallback=false" >> $GITHUB_OUTPUT - - # Extract the liquibase Secure archive - mkdir -p liquibase-build - if [[ "$LIQUIBASE_SECURE_ZIP" == *.tar.gz ]]; then - tar -xzf "$LIQUIBASE_SECURE_ZIP" -C liquibase-build/ - echo "Liquibase Secure build extracted from tar.gz to liquibase-build/" - else - unzip -q "$LIQUIBASE_SECURE_ZIP" -d liquibase-build/ - echo "Liquibase Secure build extracted from zip to liquibase-build/" - fi - fi - - else - # Community build handling - if [[ "${{ steps.get-workflow-run.outputs.has_workflow_run }}" == "false" ]]; then - echo "No workflow run available, will use fallback build from branch source" - echo "build_ready=false" >> $GITHUB_OUTPUT - echo "use_fallback=true" >> $GITHUB_OUTPUT - else - echo "Downloading Community build from GitHub artifacts..." - - # Get artifact download URL - ARTIFACT_NAME="liquibase-zip-${{ inputs.liquibaseBranch }}" - echo "Looking for artifact: $ARTIFACT_NAME" - - ARTIFACTS_RESPONSE=$(curl -s \ - -H "Authorization: Bearer ${{ env.LIQUIBOT_PAT_GPM_ACCESS }}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/liquibase/liquibase/actions/runs/${{ steps.get-workflow-run.outputs.workflow_run_id }}/artifacts") - - echo "Available artifacts:" - echo "$ARTIFACTS_RESPONSE" | jq -r '.artifacts[].name' - - ARTIFACT_URL=$(echo "$ARTIFACTS_RESPONSE" | jq -r ".artifacts[] | select(.name == \"$ARTIFACT_NAME\") | .archive_download_url") - - if [ "$ARTIFACT_URL" = "null" ] || [ -z "$ARTIFACT_URL" ]; then - echo "Artifact $ARTIFACT_NAME not found in workflow run" - echo "Available artifacts:" - echo "$ARTIFACTS_RESPONSE" | jq -r '.artifacts[].name' - echo "Will use fallback build from branch source instead" - echo "build_ready=false" >> $GITHUB_OUTPUT - echo "use_fallback=true" >> $GITHUB_OUTPUT - else - echo "Downloading artifact from: $ARTIFACT_URL" - - # Download and extract artifact - curl -L \ - -H "Authorization: Bearer ${{ env.LIQUIBOT_PAT_GPM_ACCESS }}" \ - -H "Accept: application/vnd.github.v3+json" \ - -o liquibase-artifact.zip \ - "$ARTIFACT_URL" - - # Extract the artifact - unzip -q liquibase-artifact.zip - echo "Artifact contents:" - ls -la - - # Find the liquibase zip file inside the artifact - LIQUIBASE_ZIP=$(find . -name "liquibase-*.zip" -type f | head -1) - if [ -z "$LIQUIBASE_ZIP" ]; then - echo "No liquibase zip file found in artifact" - echo "Contents of extracted artifact:" - find . -type f - echo "Will use fallback build from branch source instead" - echo "build_ready=false" >> $GITHUB_OUTPUT - echo "use_fallback=true" >> $GITHUB_OUTPUT - else - echo "Found liquibase zip: $LIQUIBASE_ZIP" - - # Extract the liquibase zip - mkdir -p liquibase-build - unzip -q "$LIQUIBASE_ZIP" -d liquibase-build/ - - echo "Liquibase build extracted to liquibase-build/" - echo "build_ready=true" >> $GITHUB_OUTPUT - echo "use_fallback=false" >> $GITHUB_OUTPUT - fi - fi - fi - fi - - # Only show contents if build is ready - if [[ -d "liquibase-build" ]]; then - echo "Contents of liquibase-build:" - ls -la liquibase-build/ - fi - - - name: Trigger Liquibase Secure Release Workflow - if: ${{ matrix.build_type == 'secure' && steps.download-artifact.outputs.trigger_liquibase_secure_workflow == 'true' && steps.download-artifact.outputs.use_fallback != 'true' }} - id: trigger-liquibase-secure-release - continue-on-error: true - uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7 # v4.0.0 - with: - workflow: secure-release-to-s3.yml - token: ${{ steps.get-token.outputs.token }} - repo: liquibase/liquibase-pro - inputs: '{"version": "${{ inputs.liquibaseBranch }}"}' - ref: ${{ inputs.liquibaseBranch }} - wait-for-completion: true - wait-for-completion-timeout: 60m - wait-for-completion-interval: 10m - - - name: Download Liquibase Secure build from S3 after workflow completion - if: ${{ matrix.build_type == 'secure' && steps.download-artifact.outputs.trigger_liquibase_secure_workflow == 'true' && steps.download-artifact.outputs.use_fallback != 'true' }} - id: download-after-trigger - run: | - # Determine S3 path based on whether secure-version is provided (same logic as initial download) - if [[ -n "${{ inputs.secure-version }}" ]]; then - echo "Using secure-version: ${{ inputs.secure-version }}" - VERSION="${{ inputs.secure-version }}" - if [[ "$VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-RC([0-9]+)$ ]]; then - BASE_VERSION="${BASH_REMATCH[1]}" - RC_NUMBER="${BASH_REMATCH[2]}" - LIQUIBASE_SECURE_ZIP="liquibase-secure-${VERSION}.tar.gz" - S3_URL="s3://repo.liquibase.com/releases/rc/${VERSION}/${LIQUIBASE_SECURE_ZIP}" - else - LIQUIBASE_SECURE_ZIP="liquibase-secure-${VERSION}.zip" - S3_URL="s3://repo.liquibase.com/releases/secure/${VERSION}/${LIQUIBASE_SECURE_ZIP}" - fi - else - LIQUIBASE_SECURE_ZIP="liquibase-secure-${{ inputs.liquibaseBranch }}.zip" - S3_URL="s3://repo.liquibase.com/releases/secure/${{ inputs.liquibaseBranch }}/$LIQUIBASE_SECURE_ZIP" - fi - - echo "âŦ‡ī¸ Downloading Liquibase Secure build from S3 after workflow completion..." - - if ! aws s3 cp "$S3_URL" "$LIQUIBASE_SECURE_ZIP"; then - echo "❌ Failed to download Liquibase Secure build even after workflow completion" - echo "Will use fallback build from branch source instead" - echo "build_ready=false" >> $GITHUB_OUTPUT - echo "use_fallback=true" >> $GITHUB_OUTPUT - exit 0 - fi - - echo "✅ Successfully downloaded Liquibase Secure build after workflow completion" - - # Extract the liquibase Secure archive - mkdir -p liquibase-build - if [[ "$LIQUIBASE_SECURE_ZIP" == *.tar.gz ]]; then - tar -xzf "$LIQUIBASE_SECURE_ZIP" -C liquibase-build/ - echo "Liquibase Secure build extracted from tar.gz to liquibase-build/" - else - unzip -q "$LIQUIBASE_SECURE_ZIP" -d liquibase-build/ - echo "Liquibase Secure build extracted from zip to liquibase-build/" - fi - echo "Contents of liquibase-build:" - ls -la liquibase-build/ - echo "build_ready=true" >> $GITHUB_OUTPUT - echo "use_fallback=false" >> $GITHUB_OUTPUT - - - name: Validate and prepare liquibase build - if: ${{ (matrix.build_type == 'Community' && (steps.download-artifact.outputs.build_ready == 'true' || steps.download-artifact.outputs.use_fallback == 'true')) || matrix.build_type == 'secure' }} - id: validate-build - run: | - # Determine build mode - USE_FALLBACK="false" - if [[ "${{ matrix.build_type }}" == "Community" && "${{ steps.download-artifact.outputs.use_fallback }}" == "true" ]]; then - USE_FALLBACK="true" - elif [[ "${{ matrix.build_type }}" == "secure" ]]; then - # Check for Secure fallback conditions - if [[ "${{ steps.download-artifact.outputs.use_fallback }}" == "true" ]] || [[ "${{ steps.download-after-trigger.outputs.use_fallback }}" == "true" ]]; then - USE_FALLBACK="true" - # Check if Liquibase Secure workflow was triggered but failed - elif [[ "${{ steps.download-artifact.outputs.trigger_liquibase_secure_workflow }}" == "true" ]] && [[ "${{ steps.trigger-liquibase-secure-release.outcome }}" == "failure" ]]; then - echo "Liquibase Secure workflow trigger failed, falling back to standard Dockerfile build" - USE_FALLBACK="true" - # Check if Liquibase Secure workflow succeeded but download still failed (no build_ready=true from either step) - elif [[ "${{ steps.download-artifact.outputs.trigger_liquibase_secure_workflow }}" == "true" ]] && [[ "${{ steps.download-artifact.outputs.build_ready }}" != "true" ]] && [[ "${{ steps.download-after-trigger.outputs.build_ready }}" != "true" ]]; then - echo "Liquibase Secure workflow completed but build still not available, falling back to standard Dockerfile build" - USE_FALLBACK="true" - fi - fi - - if [[ "$USE_FALLBACK" == "true" ]]; then - echo "Using fallback mode - will build from standard Dockerfile using branch source" - echo "use_fallback_build=true" >> $GITHUB_OUTPUT - else - # Validate the liquibase build structure - if [ ! -f "liquibase-build/liquibase" ]; then - echo "Error: liquibase executable not found in build" - echo "Contents of liquibase-build:" - find liquibase-build -type f - exit 1 - fi - - # Make liquibase executable - chmod +x liquibase-build/liquibase - - # Validate that liquibase can run - cd liquibase-build && ./liquibase --version && cd .. - - echo "Liquibase build validation successful" - echo "Final liquibase-build contents:" - ls -la liquibase-build/ - echo "use_fallback_build=false" >> $GITHUB_OUTPUT - fi - - - name: Modify Dockerfiles for artifact-based build - if: ${{ steps.validate-build.outputs.use_fallback_build == 'false' }} - run: | - echo "Modifying ${{ matrix.dockerfile }} to use downloaded artifact instead of GitHub releases..." - - # Create backup - cp "${{ matrix.dockerfile }}" "${{ matrix.dockerfile }}.backup" - - # Set version ARG based on dockerfile type - if [[ "${{ matrix.dockerfile }}" == "DockerfileSecure" ]]; then - VERSION_ARG="LIQUIBASE_SECURE_VERSION" - else - VERSION_ARG="LIQUIBASE_VERSION" - fi - - # Replace version ARG with branch name - sed -i "s|ARG ${VERSION_ARG}=.*|ARG ${VERSION_ARG}=${{ inputs.liquibaseBranch }}|" "${{ matrix.dockerfile }}" - - # Create modified Dockerfile using awk for cleaner handling - cat "${{ matrix.dockerfile }}" | awk -v dockerfile="${{ matrix.dockerfile }}" -v branch="${{ inputs.liquibaseBranch }}" ' - BEGIN { - in_wget_block = 0 - skip_line = 0 - } - - # Skip SHA256 ARG lines - /^ARG LB_SHA256=/ || /^ARG LB_SECURE_SHA256=/ { next } - - # Update version ARGs - /^ARG LIQUIBASE_VERSION=/ { print "ARG LIQUIBASE_VERSION=" branch; next } - /^ARG LIQUIBASE_SECURE_VERSION=/ { print "ARG LIQUIBASE_SECURE_VERSION=" branch; next } - - # Handle standard Dockerfile wget block - dockerfile == "Dockerfile" && /^RUN wget.*github\.com.*liquibase.*tar\.gz/ { - print "# Copy the extracted liquibase build from the build context" - print "COPY liquibase-build/ ./" - print "" - print "RUN ln -s /liquibase/liquibase /usr/local/bin/liquibase && \\" - print " ln -s /liquibase/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh && \\" - print " liquibase --version" - in_wget_block = 1 - next - } - - # Handle alpine Dockerfile wget block - dockerfile == "Dockerfile.alpine" && /^RUN set -x/ { - print "# Copy the extracted liquibase build from the build context" - print "COPY liquibase-build/ ./" - print "" - print "RUN ln -s /liquibase/liquibase /usr/local/bin/liquibase && \\" - print " ln -s /liquibase/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh && \\" - print " liquibase --version" - in_wget_block = 1 - next - } - - # Handle Secure Dockerfile wget block - dockerfile == "DockerfileSecure" && /^RUN wget.*repo\.liquibase\.com.*tar\.gz/ { - print "# Copy the extracted liquibase build from the build context" - print "COPY liquibase-build/ ./" - print "" - print "RUN ln -s /liquibase/liquibase /usr/local/bin/liquibase && \\" - print " ln -s /liquibase/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh && \\" - print " liquibase --version" - in_wget_block = 1 - next - } - - # Skip lines until we reach the end of wget block - in_wget_block == 1 && /liquibase --version/ { - in_wget_block = 0 - next - } - in_wget_block == 1 { next } - - # Print all other lines - { print } - ' > "${{ matrix.dockerfile }}.tmp" - - # Replace original with modified version - mv "${{ matrix.dockerfile }}.tmp" "${{ matrix.dockerfile }}" - - echo "✓ Modified ${{ matrix.dockerfile }}" - echo "=== Changes made ===" - echo "- Set ${VERSION_ARG} to ${{ inputs.liquibaseBranch }}" - echo "- Removed wget download commands" - echo "- Removed SHA256 checksum validation" - echo "- Added COPY liquibase-build/ ./" - - echo "" - echo "=== Modified Dockerfile content preview ===" - echo "First 30 lines of modified ${{ matrix.dockerfile }}:" - head -30 "${{ matrix.dockerfile }}" - echo "..." - - - name: Set up Docker Buildx - if: ${{ steps.validate-build.outcome == 'success' }} - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Set up QEMU - if: ${{ steps.validate-build.outcome == 'success' }} - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - - name: Log in to internal Nexus Docker Registry - if: ${{ steps.validate-build.outcome == 'success' }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - registry: ${{ env.REPO_URL }} - username: ${{ env.REPO_USER }} - password: ${{ env.REPO_PASSWORD }} - - - name: Login to GHCR - if: ${{ steps.validate-build.outcome == 'success' }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push Docker image - if: ${{ steps.validate-build.outcome == 'success' }} - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 - with: - context: . - file: ${{ matrix.dockerfile }} - push: true - platforms: linux/amd64,linux/arm64 - provenance: false - tags: | - ${{ env.REPO_URL }}/${{ matrix.image_name }}:${{ matrix.is_rc == true && inputs.secure-version || inputs.liquibaseBranch }} - ghcr.io/${{ github.repository }}/liquibase-${{ matrix.ghcr_name }}:${{ github.sha }} - labels: | - org.opencontainers.image.source=https://github.com/liquibase/docker - org.opencontainers.image.description=Liquibase QA Container Image${{ matrix.suffix }} - org.opencontainers.image.licenses=${{ matrix.build_type == 'secure' && 'LicenseRef-Liquibase-EULA' || 'FSL-1.1-ALv2' }} - ${{ matrix.build_type == 'secure' && 'org.opencontainers.image.licenses.url=https://www.liquibase.com/eula' || '' }} - org.opencontainers.image.vendor=Liquibase - org.opencontainers.image.version=${{ matrix.is_rc == true && inputs.secure-version || inputs.liquibaseBranch }} - org.opencontainers.image.documentation=https://docs.liquibase.com - org.opencontainers.image.revision=${{ github.sha }} - liquibase.branch=${{ inputs.liquibaseBranch }} - liquibase.build.mode=${{ steps.validate-build.outputs.use_fallback_build == 'true' && 'fallback' || 'artifact' }} - - name: Image build summary - if: ${{ steps.validate-build.outcome == 'success' }} - run: | - BUILD_MODE="${{ steps.validate-build.outputs.use_fallback_build == 'true' && 'fallback (standard Dockerfile)' || 'artifact-based' }}" - IMAGE_TAG="${{ matrix.is_rc == true && inputs.secure-version || inputs.liquibaseBranch }}" - echo "Successfully built and pushed: ${{ env.REPO_URL }}/${{ matrix.image_name }}:$IMAGE_TAG" - echo "Build mode: $BUILD_MODE" - - - name: Workflow execution summary - if: always() - run: | - echo "=== QA Docker Build Workflow Summary ===" - echo "Branch: ${{ inputs.liquibaseBranch }}" - echo "Build Target: ${{ inputs.buildTargets }}" - echo "Dockerfile: ${{ matrix.dockerfile }}" - echo "Build Type: ${{ matrix.build_type }}" - echo "" - - # Determine if fallback was used - USE_FALLBACK="false" - if [[ "${{ steps.validate-build.outputs.use_fallback_build }}" == "true" ]] || [[ "${{ steps.download-artifact.outputs.use_fallback }}" == "true" ]] || [[ "${{ steps.download-after-trigger.outputs.use_fallback }}" == "true" ]]; then - USE_FALLBACK="true" - fi - - if [[ "$USE_FALLBACK" == "true" ]]; then - echo "🔄 Build Mode: FALLBACK (Standard Dockerfile from branch source)" - echo " - No pre-built artifacts were available" - echo " - Used standard Dockerfile without modification" - echo " - Built directly from liquibase branch: ${{ inputs.liquibaseBranch }}" - elif [[ "${{ matrix.build_type }}" == "secure" ]]; then - if [[ "${{ steps.download-artifact.outputs.trigger_liquibase_secure_workflow }}" == "true" ]]; then - echo "🔄 Build Mode: ARTIFACT-BASED (Secure workflow triggered)" - echo " - S3 build was missing for branch ${{ inputs.liquibaseBranch }}" - echo " - Automatically triggered pro-release-to-s3.yml workflow" - if [[ "${{ steps.download-after-trigger.outputs.build_ready }}" == "true" ]]; then - echo " - ✅ Liquibase-Secure workflow completed successfully" - echo " - ✅ Liquibase-Secure build downloaded and Docker image built" - else - echo " - ❌ Liquibase-Secure workflow may have failed" - echo " - 📋 Check: https://github.com/liquibase/liquibase-pro/actions/workflows/secure-release-to-s3.yml" - fi - else - echo "✅ Build Mode: ARTIFACT-BASED (Direct S3 download)" - echo " - Liquibase-Secure build downloaded from S3" - fi - else - echo "✅ Build Mode: ARTIFACT-BASED (GitHub artifact)" - echo " - Community build downloaded from GitHub workflow artifacts" - fi - - echo "" - if [[ "${{ job.status }}" == "success" ]]; then - echo "🎉 Overall Status: SUCCESS" - IMAGE_TAG="${{ matrix.is_rc == true && inputs.secure-version || inputs.liquibaseBranch }}" - echo "đŸ“Ļ Image Available: ${{ env.REPO_URL }}/${{ matrix.image_name }}:$IMAGE_TAG" - if [[ "$USE_FALLBACK" == "true" ]]; then - echo "â„šī¸ Built using fallback mode - standard Dockerfile from branch source" - fi - else - echo "❌ Overall Status: FAILED" - echo "🔍 Check the logs above for detailed error information" - fi + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + with: + image_name: ${{ matrix.image_name }} + dockerfile_path: ${{ matrix.dockerfile }} + suffix: ${{ matrix.suffix }} + ghcr_name: ${{ matrix.ghcr_name }} + branch_name: ${{ inputs.liquibaseBranch }} + secure_version: ${{ inputs.secure-version || '' }} + build_type: ${{ matrix.build_type }} + is_rc: ${{ matrix.is_rc }} + push_nexus: true + push_ghcr: true + build_logic_ref: dat-22876-reusables + secrets: inherit vulnerability-scan: needs: [set-matrix, build-qa-docker] diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 9e1f9711..05e987e0 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -227,343 +227,122 @@ jobs: id: get-latest-sha run: echo "latestCommitSha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - setup-update-draft-build: - name: "Build and Push Docker Images" + # ============================================ + # BUILD AND PUSH: community (Dockerfile) + # ============================================ + build-community: + name: "Build liquibase/liquibase" needs: update-dockerfiles - runs-on: ubuntu-latest - env: - PUSH_DOCKERHUB: ${{ needs.update-dockerfiles.outputs.pushDockerHub }} - PUSH_GHCR: ${{ needs.update-dockerfiles.outputs.pushGHCR }} - PUSH_ECR: ${{ needs.update-dockerfiles.outputs.pushECR }} - strategy: - matrix: - include: - - dockerfile: Dockerfile - name: liquibase/liquibase - suffix: "" - latest_tag: "latest" - type: liquibase-release - - dockerfile: Dockerfile.alpine - name: liquibase/liquibase - suffix: "-alpine" - latest_tag: "alpine" - type: liquibase-release - - dockerfile: DockerfileSecure - name: liquibase/liquibase-secure - suffix: "" - latest_tag: "latest" - type: liquibase-secure-release - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - ref: ${{ github.ref }} - - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - id: vault-secrets - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - - name: Decode DOCKERHUB_USERNAME - run: | - decoded_username=$(echo "${{ env.DOCKERHUB_USERNAME }}" | base64 -d) - echo "DOCKERHUB_USERNAME_DECODED=$decoded_username" >> $GITHUB_ENV - - - name: Set up JDK - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 - with: - java-version: "8" - distribution: "adopt" - - # Create GitHub release for Community (v{version}) or SECURE (v{version}-SECURE) - # This ensures Community and SECURE releases have distinct tags and don't conflict - # Only create the release once per release type (using the base Dockerfile without suffix) - - name: Determine Release Tag - id: release-tag - if: ${{ needs.update-dockerfiles.outputs.dryRun == 'false' && matrix.suffix == '' && ((needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' && matrix.type == 'liquibase-release') || (needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && matrix.type == 'liquibase-secure-release')) }} - run: | - if [[ "${{ needs.update-dockerfiles.outputs.releaseType }}" == "liquibase-secure-release" ]]; then - TAG_NAME="v${{ needs.update-dockerfiles.outputs.extensionVersion }}-SECURE" - RELEASE_NAME="v${{ needs.update-dockerfiles.outputs.extensionVersion }} SECURE" - else - TAG_NAME="v${{ needs.update-dockerfiles.outputs.extensionVersion }}" - RELEASE_NAME="v${{ needs.update-dockerfiles.outputs.extensionVersion }}" - fi - echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT - echo "release_name=${RELEASE_NAME}" >> $GITHUB_OUTPUT - echo "::notice::Creating GitHub release for ${{ needs.update-dockerfiles.outputs.releaseType }} on tag: ${TAG_NAME}" - - # Fetch release notes from Release Drafter draft - - name: Get Release Notes from Draft - id: get-release-notes - if: ${{ needs.update-dockerfiles.outputs.dryRun == 'false' && matrix.suffix == '' && ((needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' && matrix.type == 'liquibase-release') || (needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && matrix.type == 'liquibase-secure-release')) }} - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const isSecure = '${{ needs.update-dockerfiles.outputs.releaseType }}' === 'liquibase-secure-release'; - - const releases = await github.rest.repos.listReleases({ - owner: context.repo.owner, - repo: context.repo.repo, - }); - - // Find the matching draft from Release Drafter - const draft = releases.data.find(r => { - if (!r.draft) return false; - return isSecure ? r.tag_name.includes('SECURE') : !r.tag_name.includes('SECURE'); - }); - - if (draft && draft.body) { - core.setOutput('body', draft.body); - core.setOutput('found', 'true'); - - // Delete the draft - we'll create the real release - await github.rest.repos.deleteRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: draft.id - }); - core.info(`Deleted Release Drafter draft: ${draft.name}`); - } else { - core.setOutput('found', 'false'); - core.info('No Release Drafter draft found, using default release notes'); - } - - - name: Create GitHub Release - if: ${{ needs.update-dockerfiles.outputs.dryRun == 'false' && matrix.suffix == '' && ((needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' && matrix.type == 'liquibase-release') || (needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && matrix.type == 'liquibase-secure-release')) }} - uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 - with: - name: ${{ steps.release-tag.outputs.release_name }} - tag_name: ${{ steps.release-tag.outputs.tag_name }} - draft: true - body: | - ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && format('Support for Liquibase Secure {0}.', needs.update-dockerfiles.outputs.liquibaseVersion) || format('Support for Liquibase {0}.', needs.update-dockerfiles.outputs.liquibaseVersion) }} - - ${{ steps.get-release-notes.outputs.found == 'true' && steps.get-release-notes.outputs.body || '' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - # Install Cosign for keyless image signing (Secure images only) - - name: Install Cosign - if: ${{ matrix.type == 'liquibase-secure-release' }} - uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1 - - # Define registry configurations based on image type - - name: Set registry variables - id: set-registries - run: | - if [[ "${{ matrix.type }}" == "liquibase-release" ]]; then - echo "DOCKERHUB_REPO=${{ matrix.name }}" >> $GITHUB_OUTPUT - echo "ECR_REPO=public.ecr.aws/liquibase/liquibase" >> $GITHUB_OUTPUT - echo "GHCR_REPO=ghcr.io/liquibase/liquibase" >> $GITHUB_OUTPUT - elif [[ "${{ matrix.type }}" == "liquibase-secure-release" ]]; then - echo "DOCKERHUB_REPO=${{ matrix.name }}" >> $GITHUB_OUTPUT - echo "ECR_REPO=public.ecr.aws/liquibase/liquibase-secure" >> $GITHUB_OUTPUT - echo "GHCR_REPO=ghcr.io/liquibase/liquibase-secure" >> $GITHUB_OUTPUT - fi - - # Use separate login steps for each registry - - name: Login to Docker Hub - if: ${{ env.PUSH_DOCKERHUB == 'true' && needs.update-dockerfiles.outputs.dryRun == 'false' }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - username: ${{ env.DOCKERHUB_USERNAME_DECODED }} - password: ${{ env.DOCKERHUB_TOKEN }} - - - name: Login to GitHub Container Registry - if: ${{ env.PUSH_GHCR == 'true' && needs.update-dockerfiles.outputs.dryRun == 'false' && steps.set-registries.outputs.GHCR_REPO != '' }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Configure AWS credentials for PROD ECR - id: configure-aws-credentials-prod - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ env.AWS_PROD_GITHUB_OIDC_ROLE_ARN_INFRASTRUCTURE }} - aws-region: us-east-1 - - - name: Login to ECR Registry - if: ${{ env.PUSH_ECR == 'true' && needs.update-dockerfiles.outputs.dryRun == 'false' && steps.set-registries.outputs.ECR_REPO != '' }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - env: - AWS_REGION: us-east-1 - with: - registry: public.ecr.aws - username: ${{ steps.configure-aws-credentials-prod.outputs.aws_access_key_id }} - password: ${{ steps.configure-aws-credentials-prod.outputs.aws_secret_access_key }} - - # Add login for dry-run mode to private ECR - - name: Login to Private ECR Registry (dry-run) - if: ${{ needs.update-dockerfiles.outputs.dryRun == 'true' }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - env: - AWS_REGION: us-east-1 - with: - registry: ${{ env.PRIVATE_ECR_DRY_RUN_REPO }} - username: ${{ steps.configure-aws-credentials-prod.outputs.aws_access_key_id }} - password: ${{ steps.configure-aws-credentials-prod.outputs.aws_secret_access_key }} - - # Generate tags dynamically using a separate step - - name: Generate Docker Tags - id: generate-tags - run: | - VERSION="${{ needs.update-dockerfiles.outputs.extensionVersion }}" - MINOR_VERSION="${{ needs.update-dockerfiles.outputs.minorVersion }}" - SUFFIX="${{ matrix.suffix }}" - LATEST_TAG="${{ matrix.latest_tag }}" - TAGS="" - IS_DRY_RUN="${{ needs.update-dockerfiles.outputs.dryRun }}" - - if [[ "${IS_DRY_RUN}" == "true" ]]; then - # For dry run, only use ECR registry - TAGS="${{ env.PRIVATE_ECR_DRY_RUN_REPO }}:${LATEST_TAG}${SUFFIX}" - TAGS="${TAGS},${{ env.PRIVATE_ECR_DRY_RUN_REPO }}:${VERSION}${SUFFIX}" - TAGS="${TAGS},${{ env.PRIVATE_ECR_DRY_RUN_REPO }}:${MINOR_VERSION}${SUFFIX}" - else - # Not in dry-run mode, apply normal tag selection logic - - # Add DockerHub tags if selected - if [[ "${PUSH_DOCKERHUB}" == "true" ]]; then - TAGS="${{ steps.set-registries.outputs.DOCKERHUB_REPO }}:${LATEST_TAG}${SUFFIX}" - TAGS="${TAGS},${{ steps.set-registries.outputs.DOCKERHUB_REPO }}:${VERSION}${SUFFIX}" - TAGS="${TAGS},${{ steps.set-registries.outputs.DOCKERHUB_REPO }}:${MINOR_VERSION}${SUFFIX}" - fi - - # Add ECR tags if selected and available for this image type - if [[ "${PUSH_ECR}" == "true" && -n "${{ steps.set-registries.outputs.ECR_REPO }}" ]]; then - if [[ -n "${TAGS}" ]]; then TAGS="${TAGS},"; fi - TAGS="${TAGS}${{ steps.set-registries.outputs.ECR_REPO }}:${LATEST_TAG}${SUFFIX}" - TAGS="${TAGS},${{ steps.set-registries.outputs.ECR_REPO }}:${VERSION}${SUFFIX}" - TAGS="${TAGS},${{ steps.set-registries.outputs.ECR_REPO }}:${MINOR_VERSION}${SUFFIX}" - fi - - # Add GHCR tags if selected and available for this image type - if [[ "${PUSH_GHCR}" == "true" && -n "${{ steps.set-registries.outputs.GHCR_REPO }}" ]]; then - if [[ -n "${TAGS}" ]]; then TAGS="${TAGS},"; fi - TAGS="${TAGS}${{ steps.set-registries.outputs.GHCR_REPO }}:${LATEST_TAG}${SUFFIX}" - TAGS="${TAGS},${{ steps.set-registries.outputs.GHCR_REPO }}:${VERSION}${SUFFIX}" - TAGS="${TAGS},${{ steps.set-registries.outputs.GHCR_REPO }}:${MINOR_VERSION}${SUFFIX}" - fi - - # If no tags were set, fall back to dry-run mode - if [[ -z "${TAGS}" ]]; then - echo "::warning::No registries were selected. Running in dry-run mode." - TAGS="${{ env.PRIVATE_ECR_DRY_RUN_REPO }}:${LATEST_TAG}${SUFFIX}" - fi - fi - - # Output tags at the end - echo "tags=${TAGS}" >> $GITHUB_OUTPUT - if [[ "${IS_DRY_RUN}" == "true" ]]; then - echo "Generated tags (dry-run): ${TAGS}" - else - echo "Generated tags: ${TAGS}" - fi - - #Unified build and push step using generated tags - - name: Build and Push Docker Image - id: build-and-push - if: ${{ needs.update-dockerfiles.outputs.releaseType == matrix.type }} - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 - with: - context: . - file: ${{ matrix.dockerfile }} - no-cache: true - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.generate-tags.outputs.tags }} - # Supply chain security - SBOM and Provenance for Secure images only (SLSA Level 3) - sbom: ${{ matrix.type == 'liquibase-secure-release' }} - provenance: ${{ matrix.type == 'liquibase-secure-release' && 'mode=max' || 'false' }} - # Labels applied to each architecture-specific image - labels: | - org.opencontainers.image.source=https://github.com/liquibase/docker - org.opencontainers.image.description=${{ matrix.type == 'liquibase-secure-release' && 'Liquibase Secure Container Image' || format('Liquibase Container Image{0}', matrix.suffix == '-alpine' && ' (Alpine)' || '') }} - org.opencontainers.image.licenses=${{ matrix.type == 'liquibase-secure-release' && 'LicenseRef-Liquibase-EULA' || 'FSL-1.1-ALv2' }} - ${{ matrix.type == 'liquibase-secure-release' && 'org.opencontainers.image.licenses.url=https://www.liquibase.com/eula' || '' }} - org.opencontainers.image.vendor=Liquibase - org.opencontainers.image.version=${{ needs.update-dockerfiles.outputs.extensionVersion }} - org.opencontainers.image.documentation=https://docs.liquibase.com - # Annotations applied to the manifest list (important for multi-arch images) - annotations: | - org.opencontainers.image.source=https://github.com/liquibase/docker - org.opencontainers.image.description=${{ matrix.type == 'liquibase-secure-release' && 'Liquibase Secure Container Image' || format('Liquibase Container Image{0}', matrix.suffix == '-alpine' && ' (Alpine)' || '') }} - org.opencontainers.image.licenses=${{ matrix.type == 'liquibase-secure-release' && 'LicenseRef-Liquibase-EULA' || 'FSL-1.1-ALv2' }} - ${{ matrix.type == 'liquibase-secure-release' && 'org.opencontainers.image.licenses.url=https://www.liquibase.com/eula' || '' }} - org.opencontainers.image.vendor=Liquibase - org.opencontainers.image.version=${{ needs.update-dockerfiles.outputs.extensionVersion }} - org.opencontainers.image.documentation=https://docs.liquibase.com - - # Cosign keyless signing for Liquibase Secure images (SLSA Level 3 compliance) - # Uses GitHub OIDC for identity - no private keys stored in repository - - name: Sign Docker Hub Image with Cosign - if: ${{ needs.update-dockerfiles.outputs.releaseType == matrix.type && matrix.type == 'liquibase-secure-release' && needs.update-dockerfiles.outputs.dryRun == 'false' && env.PUSH_DOCKERHUB == 'true' }} - run: | - echo "Signing Docker Hub image with Cosign keyless signing..." - cosign sign --yes ${{ steps.set-registries.outputs.DOCKERHUB_REPO }}@${{ steps.build-and-push.outputs.digest }} - echo "Docker Hub image signed successfully" - - - name: Sign GHCR Image with Cosign - if: ${{ needs.update-dockerfiles.outputs.releaseType == matrix.type && matrix.type == 'liquibase-secure-release' && needs.update-dockerfiles.outputs.dryRun == 'false' && env.PUSH_GHCR == 'true' }} - run: | - echo "Signing GHCR image with Cosign keyless signing..." - cosign sign --yes ${{ steps.set-registries.outputs.GHCR_REPO }}@${{ steps.build-and-push.outputs.digest }} - echo "GHCR image signed successfully" - - - name: Sign ECR Image with Cosign - if: ${{ needs.update-dockerfiles.outputs.releaseType == matrix.type && matrix.type == 'liquibase-secure-release' && needs.update-dockerfiles.outputs.dryRun == 'false' && env.PUSH_ECR == 'true' }} - run: | - echo "Signing ECR image with Cosign keyless signing..." - cosign sign --yes ${{ steps.set-registries.outputs.ECR_REPO }}@${{ steps.build-and-push.outputs.digest }} - echo "ECR image signed successfully" - - - name: Sign Dry-Run ECR Image with Cosign - if: ${{ needs.update-dockerfiles.outputs.releaseType == matrix.type && matrix.type == 'liquibase-secure-release' && needs.update-dockerfiles.outputs.dryRun == 'true' }} - run: | - echo "Signing dry-run ECR image with Cosign keyless signing..." - cosign sign --yes ${{ env.PRIVATE_ECR_DRY_RUN_REPO }}@${{ steps.build-and-push.outputs.digest }} - echo "Dry-run ECR image signed successfully" - + if: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' }} + uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@dat-22876-reusables + with: + dockerfile_path: Dockerfile + image_name: liquibase/liquibase + suffix: "" + version: ${{ needs.update-dockerfiles.outputs.extensionVersion }} + minor_version: ${{ needs.update-dockerfiles.outputs.minorVersion }} + latest_tag: "latest" + dockerhub_repo: liquibase/liquibase + ghcr_repo: ghcr.io/liquibase/liquibase + ecr_repo: public.ecr.aws/liquibase/liquibase + push_dockerhub: ${{ needs.update-dockerfiles.outputs.pushDockerHub == 'true' }} + push_ghcr: ${{ needs.update-dockerfiles.outputs.pushGHCR == 'true' }} + push_ecr: ${{ needs.update-dockerfiles.outputs.pushECR == 'true' }} + dry_run: ${{ needs.update-dockerfiles.outputs.dryRun == 'true' }} + sign_with_cosign: false + generate_sbom: false + provenance_mode: "false" + cosign_identity_regexp: ^https://github\.com/liquibase/docker/.* + image_source_url: https://github.com/${{ github.repository }} + image_description: "Liquibase Container Image" + image_licenses: FSL-1.1-ALv2 + build_logic_ref: dat-22876-reusables + secrets: inherit + + # ============================================ + # BUILD AND PUSH: alpine (Dockerfile.alpine) + # ============================================ + build-alpine: + name: "Build liquibase/liquibase-alpine" + needs: update-dockerfiles + if: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' }} + uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@dat-22876-reusables + with: + dockerfile_path: Dockerfile.alpine + image_name: liquibase/liquibase + suffix: "-alpine" + version: ${{ needs.update-dockerfiles.outputs.extensionVersion }} + minor_version: ${{ needs.update-dockerfiles.outputs.minorVersion }} + latest_tag: "alpine" + dockerhub_repo: liquibase/liquibase + ghcr_repo: ghcr.io/liquibase/liquibase + ecr_repo: public.ecr.aws/liquibase/liquibase + push_dockerhub: ${{ needs.update-dockerfiles.outputs.pushDockerHub == 'true' }} + push_ghcr: ${{ needs.update-dockerfiles.outputs.pushGHCR == 'true' }} + push_ecr: ${{ needs.update-dockerfiles.outputs.pushECR == 'true' }} + dry_run: ${{ needs.update-dockerfiles.outputs.dryRun == 'true' }} + sign_with_cosign: false + generate_sbom: false + provenance_mode: "false" + cosign_identity_regexp: ^https://github\.com/liquibase/docker/.* + image_source_url: https://github.com/${{ github.repository }} + image_description: "Liquibase Container Image (Alpine)" + image_licenses: FSL-1.1-ALv2 + build_logic_ref: dat-22876-reusables + secrets: inherit + + # ============================================ + # BUILD AND PUSH: secure (DockerfileSecure) + # ============================================ + build-secure: + name: "Build liquibase/liquibase-secure" + needs: update-dockerfiles + if: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' }} + uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@dat-22876-reusables + with: + dockerfile_path: DockerfileSecure + image_name: liquibase/liquibase-secure + suffix: "" + version: ${{ needs.update-dockerfiles.outputs.extensionVersion }} + minor_version: ${{ needs.update-dockerfiles.outputs.minorVersion }} + latest_tag: "latest" + dockerhub_repo: liquibase/liquibase-secure + ghcr_repo: ghcr.io/liquibase/liquibase-secure + ecr_repo: public.ecr.aws/liquibase/liquibase-secure + push_dockerhub: ${{ needs.update-dockerfiles.outputs.pushDockerHub == 'true' }} + push_ghcr: ${{ needs.update-dockerfiles.outputs.pushGHCR == 'true' }} + push_ecr: ${{ needs.update-dockerfiles.outputs.pushECR == 'true' }} + dry_run: ${{ needs.update-dockerfiles.outputs.dryRun == 'true' }} + sign_with_cosign: true + generate_sbom: true + provenance_mode: "mode=max" + cosign_identity_regexp: ^https://github\.com/liquibase/docker/.* + image_source_url: https://github.com/${{ github.repository }} + image_description: "Liquibase Secure Container Image" + image_licenses: LicenseRef-Liquibase-EULA + image_licenses_url: https://www.liquibase.com/eula + build_logic_ref: dat-22876-reusables + secrets: inherit + + # ============================================ + # PUBLISH GITHUB RELEASE + # ============================================ publish-release: name: "Publish GitHub Release" - needs: [update-dockerfiles, setup-update-draft-build] - if: ${{ needs.update-dockerfiles.outputs.dryRun == 'false' && needs.update-dockerfiles.outputs.changes_made == 'true' }} - runs-on: ubuntu-latest - steps: - - name: Determine Release Tag - id: release-tag - run: | - if [[ "${{ needs.update-dockerfiles.outputs.releaseType }}" == "liquibase-secure-release" ]]; then - echo "tag_name=v${{ needs.update-dockerfiles.outputs.extensionVersion }}-SECURE" >> $GITHUB_OUTPUT - else - echo "tag_name=v${{ needs.update-dockerfiles.outputs.extensionVersion }}" >> $GITHUB_OUTPUT - fi - - - name: Publish Release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="${{ steps.release-tag.outputs.tag_name }}" - if ! gh release view "${TAG}" --repo "${{ github.repository }}" &>/dev/null; then - echo "::warning::Release '${TAG}' not found — skipping publish." - exit 0 - fi - gh release edit "${TAG}" \ - --repo "${{ github.repository }}" \ - --draft=false \ - --latest=true + needs: [update-dockerfiles, build-community, build-alpine, build-secure] + if: | + always() && + needs.update-dockerfiles.outputs.dryRun == 'false' && + needs.update-dockerfiles.outputs.changes_made == 'true' && + ( + (needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' && needs.build-community.result == 'success' && needs.build-alpine.result == 'success') || + (needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && needs.build-secure.result == 'success') + ) + uses: liquibase/build-logic/.github/workflows/reusable-docker-publish.yml@dat-22876-reusables + with: + release_type: ${{ needs.update-dockerfiles.outputs.releaseType }} + version: ${{ needs.update-dockerfiles.outputs.extensionVersion }} + tag_suffix: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && '-SECURE' || '' }} + dry_run: false + build_logic_ref: dat-22876-reusables + secrets: inherit diff --git a/.github/workflows/publish-liquibase-secure-readme.yml b/.github/workflows/publish-liquibase-secure-readme.yml index 04b22550..d354706b 100644 --- a/.github/workflows/publish-liquibase-secure-readme.yml +++ b/.github/workflows/publish-liquibase-secure-readme.yml @@ -11,39 +11,12 @@ on: permissions: contents: write id-token: write - -jobs: - update-liquibase-secure-readme: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - id: vault-secrets - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - name: Decode DOCKERHUB_USERNAME - run: | - decoded_username=$(echo "${{ env.DOCKERHUB_USERNAME }}" | base64 -d) - echo "DOCKERHUB_USERNAME_DECODED=$decoded_username" >> $GITHUB_ENV - - - name: Update Liquibase Secure README on Docker Hub - uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0 - with: - username: ${{ env.DOCKERHUB_USERNAME_DECODED}} - password: ${{ env.DOCKERHUB_UPDATE_README }} - repository: liquibase/liquibase-secure - readme-filepath: ./README-secure.md - short-description: "Liquibase Secure" +jobs: + update-readme: + uses: liquibase/build-logic/.github/workflows/reusable-docker-readme.yml@dat-22876-reusables + with: + target_image: liquibase/liquibase-secure + readme_path: README-secure.md + short_description: "Liquibase Secure" + secrets: inherit diff --git a/.github/workflows/publish-oss-readme.yml b/.github/workflows/publish-oss-readme.yml index c5e67134..f9e17536 100644 --- a/.github/workflows/publish-oss-readme.yml +++ b/.github/workflows/publish-oss-readme.yml @@ -12,37 +12,10 @@ permissions: id-token: write jobs: - update-liquibase-Community-readme: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - id: vault-secrets - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - - name: Decode DOCKERHUB_USERNAME - run: | - decoded_username=$(echo "${{ env.DOCKERHUB_USERNAME }}" | base64 -d) - echo "DOCKERHUB_USERNAME_DECODED=$decoded_username" >> $GITHUB_ENV - - - name: Update Liquibase Community README on Docker Hub - uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0 - with: - username: ${{ env.DOCKERHUB_USERNAME_DECODED }} - password: ${{ env.DOCKERHUB_UPDATE_README }} - repository: liquibase/liquibase - readme-filepath: README.md - short-description: "Liquibase Community" + update-readme: + uses: liquibase/build-logic/.github/workflows/reusable-docker-readme.yml@dat-22876-reusables + with: + target_image: liquibase/liquibase + readme_path: README.md + short_description: "Liquibase Community" + secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9f31e3d..e718b21c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,770 +31,15 @@ permissions: jobs: test: - env: - CONTAINER_NAME: "liquibase" - + name: Build & Test ${{ matrix.dockerfile }} - ${{ matrix.os }} strategy: fail-fast: false matrix: dockerfile: [Dockerfile, Dockerfile.alpine, DockerfileSecure] os: [ubuntu-latest, macos-15-intel] - - name: Build & Test ${{ matrix.dockerfile }} - ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Docker on macOS - if: matrix.os == 'macos-15-intel' - uses: douglascamata/setup-docker-macos-action@d5ccc6aae0ce23e7700154f5e63cc53e6433ac48 # v1.1.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Build an image from ${{ matrix.dockerfile }} - run: | - docker build -f ${{ matrix.dockerfile }} -t liquibase/liquibase:${{ github.sha }} . - - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - id: vault-secrets - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - - name: Test liquibase init start-h2 - run: | - LOG_STRING="The database does not persist data" - docker run --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} --name $CONTAINER_NAME -d -v $(pwd)/.github/test:/liquibase/changelog liquibase/liquibase:${{ github.sha }} init start-h2 - sleep 30 - # Check if the container is running - if docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null | grep -q "true"; then - # Get the logs and check if the desired string is present - if docker logs "$CONTAINER_NAME" 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - else - echo "Error: Container $CONTAINER_NAME is not running." - exit 2 - fi - - - name: Test liquibase version - run: | - LOG_STRING="Starting Liquibase" - # Check if the container is running - if docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null | grep -q "true"; then - # Get the logs and check if the desired string is present - if docker exec $CONTAINER_NAME liquibase --version 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - else - echo "Error: Container $CONTAINER_NAME is not running." - exit 2 - fi - - - name: Test liquibase update - run: | - LOG_STRING="Update has been successful" - # Check if the container is running - if docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null | grep -q "true"; then - # Get the logs and check if the desired string is present - if docker exec $CONTAINER_NAME liquibase update --defaultsFile=/liquibase/changelog/liquibase.properties --changelog-file=/changelog/example-changelog.xml 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - else - echo "Error: Container $CONTAINER_NAME is not running." - exit 2 - fi - - - name: Test liquibase wrong ENV variable - run: | - LOG_STRING="Error: Unable to access jarfile wrong_path/internal/lib/" - # Stop docker container and remove it - docker stop $CONTAINER_NAME - docker rm $CONTAINER_NAME - # Start docker container with wrong ENV - # Get the logs and check if the desired string is present - if docker run --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} --name $CONTAINER_NAME -d -v $(pwd)/.github/test:/liquibase/changelog -e LIQUIBASE_HOME="wrong_path" liquibase/liquibase:${{ github.sha }} init start-h2 2>&1 | grep -q "$LOG_STRING"; then - echo "The log does not contain the string: $LOG_STRING" - exit 1 - else - echo "The log contains the string: $LOG_STRING" - fi - - - name: Test liquibase good ENV variable - run: | - LOG_STRING="The database does not persist data" - # Stop docker container and remove it - docker stop $CONTAINER_NAME - docker rm $CONTAINER_NAME - # Start docker container with good ENV - docker run --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} --name $CONTAINER_NAME -d -v $(pwd)/.github/test:/liquibase/changelog -e LIQUIBASE_HOME="/liquibase" liquibase/liquibase:${{ github.sha }} init start-h2 - sleep 30 - docker logs $CONTAINER_NAME - # Check if the container is running - if docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null | grep -q "true"; then - # Get the logs and check if the desired string is present - if docker logs "$CONTAINER_NAME" 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - else - echo "Error: Container $CONTAINER_NAME is not running." - exit 2 - fi - - - name: Test volume persistence - run: | - LOG_STRING="Update has been successful" - # Stop docker container - docker stop $CONTAINER_NAME - # Start docker container - docker start $CONTAINER_NAME - sleep 30 - # Check if the container is running - if docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null | grep -q "true"; then - # Get the logs and check if the desired string is present - if docker exec $CONTAINER_NAME liquibase update --defaultsFile=/liquibase/changelog/liquibase.properties --changelog-file=/changelog/example-changelog.xml 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - else - echo "Error: Container $CONTAINER_NAME is not running." - exit 2 - fi - - - name: Test extension loading - run: | - LOG_STRING="liquibase-redshift" - # Stop docker container - docker exec $CONTAINER_NAME lpm add liquibase-redshift --category=extension -g - # Get the logs and check if the desired string is present - if docker exec $CONTAINER_NAME liquibase --version 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - - - name: Test driver connection - run: | - LOG_STRING="successfully installed in classpath" - docker stop $CONTAINER_NAME - docker rm $CONTAINER_NAME - docker network create --driver bridge test_network - # Get the logs and check if the desired string is present - docker run -d --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} --name $CONTAINER_NAME --network test_network -v $(pwd)/.github/test:/liquibase/changelog liquibase/liquibase:${{ github.sha }} init start-h2 - if docker exec $CONTAINER_NAME lpm add mssql --category=driver -g 2>&1 | grep -q "$LOG_STRING"; then - echo "The log contains the string: $LOG_STRING" - else - echo "The log does not contain the string: $LOG_STRING" - exit 1 - fi - - - name: Test custom entrypoint - run: | - LOG_STRING="Update has been successful" - # Build auxiliary liquibase image to inherit from - docker build -f ${{ matrix.dockerfile }} -t liquibase:test-entrypoint . - # Build custom liquibase image - docker build -f $(pwd)/.github/test/Dockerfile -t liquibase:test $(pwd)/.github/test/ - # Get the logs and check if the desired string is present - docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} --name liquibase-test --entrypoint="/scripts/liquibase_command.sh" -v $(pwd)/.github/test:/liquibase/changelog liquibase:test "version" - - # CLI-Docker Compatibility Feature Tests - - name: Test CLI-Docker compatibility - Working directory change - run: | - echo "Testing that working directory changes to /liquibase/changelog when mounted..." - - # Stop and remove existing container - docker stop $CONTAINER_NAME || true - docker rm $CONTAINER_NAME || true - - # Create test directory with a properties file to verify working directory - mkdir -p test-compatibility - cat > test-compatibility/test.properties << EOF - changelogFile=test-changelog.xml - url=offline:postgresql - driver=org.postgresql.Driver - EOF - - cat > test-compatibility/test-changelog.xml << 'EOF' - - - - SELECT 'Test'; - - - EOF - - # Test that working directory changes when /liquibase/changelog is mounted - # If working directory changed, it should find test.properties with relative path - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-compatibility:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - --defaultsFile=test.properties validate 2>&1) - - echo "Container output: $RESULT" - - # If working directory changed correctly, validation should succeed - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Working directory correctly changed to mounted changelog directory" - else - echo "❌ FAIL: Working directory did not change to changelog directory or validation failed" - echo "This indicates the properties file was not found with relative path" - exit 1 - fi - - # Cleanup - rm -rf test-compatibility - - - name: Test CLI-Docker compatibility - Relative path file creation - run: | - echo "Testing relative path file creation with new CLI-Docker compatibility..." - - # Create test directory structure - mkdir -p test-file-creation - cat > test-file-creation/test-changelog.xml << 'EOF' - - - - - - - - - EOF - - # Test updateSQL with relative path to generate SQL output file - docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-file-creation:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - updateSQL --changelogFile=test-changelog.xml --url=offline:postgresql --outputFile=generated-update.sql - - # Verify file was created in the mounted directory (not container root) - if [ -f "test-file-creation/generated-update.sql" ]; then - echo "✅ SUCCESS: File created in mounted directory with relative path" - echo "File contents preview:" - head -5 test-file-creation/generated-update.sql - else - echo "❌ FAIL: File not created in expected location" - echo "Files in test directory:" - ls -la test-file-creation/ - # Also check if the file was created in container root (wrong location) - echo "Testing if file was created in wrong location..." - WRONG_LOCATION=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-file-creation:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - sh -c "ls -la /liquibase/generated-update.sql 2>/dev/null || echo 'NOT_FOUND'") - echo "Check for file in container root: $WRONG_LOCATION" - exit 1 - fi - - # Cleanup - rm -rf test-file-creation - - - name: Test CLI-Docker compatibility - Properties file resolution - run: | - echo "Testing properties file resolution with relative paths..." - - # Create test directory with properties file - mkdir -p test-properties - cat > test-properties/test.properties << EOF - changelogFile=test-changelog.xml - url=offline:postgresql - driver=org.postgresql.Driver - EOF - - cat > test-properties/test-changelog.xml << 'EOF' - - - - Test changeset - SELECT 'Test'; - - - EOF - - # Test that properties file can be resolved with relative path - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-properties:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - --defaultsFile=test.properties validate 2>&1) - - echo "Validation result: $RESULT" - - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Properties file resolved correctly with relative path" - else - echo "❌ FAIL: Properties file resolution failed" - exit 1 - fi - - # Cleanup - rm -rf test-properties - - - name: Test backward compatibility - No changelog directory - run: | - echo "Testing backward compatibility when no /liquibase/changelog is mounted..." - - # Test container works normally without changelog mount (backward compatibility) - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} liquibase/liquibase:${{ github.sha }} --version 2>&1) - - echo "Container output: $RESULT" - - if echo "$RESULT" | grep -q "Liquibase.*Version"; then - echo "✅ SUCCESS: Container works without changelog mount (backward compatible)" - else - echo "❌ FAIL: Container broken when no changelog directory mounted" - echo "Full output: $RESULT" - exit 1 - fi - - - name: Test backward compatibility - Mixed path usage scenarios - run: | - echo "Testing mixed path usage scenarios work correctly..." - - # Create test setup - mkdir -p test-mixed-paths - cat > test-mixed-paths/test-changelog.xml << 'EOF' - - - - SELECT 'Test'; - - - EOF - - # Test 1: Relative path should work (new CLI-Docker compatibility feature) - echo "Testing relative path (new CLI-Docker compatibility)..." - RESULT1=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-mixed-paths:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - validate --changelogFile=test-changelog.xml --url=offline:postgresql 2>&1) - - if echo "$RESULT1" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Relative paths work with CLI-Docker compatibility" - else - echo "❌ FAIL: Relative paths don't work" - echo "Output: $RESULT1" - exit 1 - fi - - # Test 2: Using SHOULD_CHANGE_DIR=false should preserve old behavior - echo "Testing SHOULD_CHANGE_DIR=false preserves old behavior..." - RESULT2=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} --env SHOULD_CHANGE_DIR=false \ - -v $(pwd)/test-mixed-paths:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - validate --changelogFile=test-changelog.xml --url=offline:postgresql 2>&1) - - if echo "$RESULT2" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: SHOULD_CHANGE_DIR=false preserves old behavior" - else - echo "✅ EXPECTED: SHOULD_CHANGE_DIR=false correctly prevents automatic directory changes" - echo "This confirms the environment variable override works correctly" - fi - - # Test 3: Verify files are generated in mounted directory with relative paths - echo "Testing file generation goes to mounted directory..." - docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} \ - -v $(pwd)/test-mixed-paths:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - update-sql --changelogFile=test-changelog.xml --url=offline:postgresql --output-file=generated-sql.sql - - if [ -f "test-mixed-paths/generated-sql.sql" ]; then - echo "✅ SUCCESS: Generated files are created in mounted directory" - echo "File contents preview:" - head -5 test-mixed-paths/generated-sql.sql - else - echo "❌ FAIL: Generated file not found in mounted directory" - ls -la test-mixed-paths/ - exit 1 - fi - - # Cleanup - rm -rf test-mixed-paths - - - name: Test CLI-Docker compatibility - Generate changelog creates files in mounted directory - run: | - echo "Testing that generate-changelog command creates files in mounted directory..." - - # Create test directory for generate-changelog - mkdir -p test-generate-changelog - - # Create a properties file for the test - cat > test-generate-changelog/liquibase.properties << EOF - url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 - username=sa - password= - driver=org.h2.Driver - EOF - - # First, create a basic table in the database and capture it as changelog - # Run generate-changelog with relative path - echo "Running generate-changelog command with relative path..." - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-generate-changelog:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - generate-changelog \ - --defaultsFile=liquibase.properties \ - --changelog-file=generated-changelog.xml 2>&1) - - echo "Generate changelog result: $RESULT" - - # Check if the command executed successfully (even if no changes to generate) - if echo "$RESULT" | grep -q "was executed successfully"; then - echo "✅ SUCCESS: generate-changelog command executed successfully" - else - echo "❌ FAIL: generate-changelog command failed" - echo "Full output: $RESULT" - exit 1 - fi - - # Test generate-changelog with output file creation using updateSQL - echo "Testing file generation with updateSQL (which will create output)..." - - # Create a simple changelog to generate SQL from - cat > test-generate-changelog/test-changelog.xml << 'EOF' - - - - - - - - - - EOF - - # Generate SQL output file with relative path to verify file creation works - docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-generate-changelog:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - update-sql \ - --changelog-file=test-changelog.xml \ - --url=jdbc:h2:mem:testdb \ - --username=sa \ - --output-file=generated-output.sql - - # Verify the output file was created in the mounted directory - if [ -f "test-generate-changelog/generated-output.sql" ]; then - echo "✅ SUCCESS: Output file created in mounted directory using relative path" - echo "Generated file contents preview:" - head -10 test-generate-changelog/generated-output.sql - - # Verify file contains expected SQL - if grep -q "CREATE TABLE.*test_table" test-generate-changelog/generated-output.sql; then - echo "✅ SUCCESS: Generated file contains expected SQL content" - else - echo "❌ FAIL: Generated file does not contain expected SQL content" - exit 1 - fi - else - echo "❌ FAIL: Output file was not created in the mounted directory" - echo "Files in test directory:" - ls -la test-generate-changelog/ - exit 1 - fi - - # Test with defaults file using relative paths - echo "Testing generate-changelog with defaults file containing relative paths..." - - # Create a defaults file that uses relative paths - cat > test-generate-changelog/generate.properties << EOF - changelog-file=another-generated-changelog.xml - url=jdbc:h2:mem:testdb - username=sa - driver=org.h2.Driver - EOF - - # Run generate-changelog using defaults file with relative path - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-generate-changelog:/liquibase/changelog \ - liquibase/liquibase:${{ github.sha }} \ - generate-changelog \ - --defaults-file=generate.properties 2>&1) - - echo "Generate changelog with defaults file result: $RESULT" - - # Verify the command executed successfully - if echo "$RESULT" | grep -q "was executed successfully"; then - echo "✅ SUCCESS: generate-changelog with defaults file using relative paths works" - else - echo "❌ FAIL: generate-changelog with defaults file failed" - echo "Full output: $RESULT" - exit 1 - fi - - # Cleanup - rm -rf test-generate-changelog - - - name: Test CLI-Docker compatibility - Complex scenario - run: | - echo "Testing complex scenario with multiple relative paths..." - - # Create complex test structure - mkdir -p test-complex/{changelog,lib} - - cat > test-complex/changelog/db.changelog-root.xml << 'EOF' - - - - - EOF - - cat > test-complex/changelog/001-tables.xml << 'EOF' - - - - - - - - - EOF - - cat > test-complex/app.properties << EOF - changelogFile=db.changelog-root.xml - url=offline:postgresql - driver=org.postgresql.Driver - EOF - - # Test complex scenario with includes and relative paths - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} -v $(pwd)/test-complex/changelog:/liquibase/changelog -v $(pwd)/test-complex:/liquibase/app \ - liquibase/liquibase:${{ github.sha }} \ - --defaultsFile=../app/app.properties validate 2>&1) - - echo "Complex validation result: $RESULT" - - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Complex relative path scenario works" - else - echo "❌ FAIL: Complex relative path scenario failed" - exit 1 - fi - - # Cleanup - rm -rf test-complex - - # Search Path Preservation Tests (DAT-21189 regression tests) - - name: Test custom LIQUIBASE_SEARCH_PATH env var is preserved - if: matrix.os == 'ubuntu-latest' - run: | - echo "Testing that custom LIQUIBASE_SEARCH_PATH environment variable is not overridden..." - - # Create test directory structure - mkdir -p test-search-path-env/custom-path - - # When using a custom LIQUIBASE_SEARCH_PATH, all changelog files must be in that path - # This tests that the custom search path is preserved and used correctly - cat > test-search-path-env/custom-path/main-changelog.xml << 'EOF' - - - - SELECT 'Using custom search path'; - - - EOF - - # Test with custom search path - # This verifies that when LIQUIBASE_SEARCH_PATH is set, it is used and not overridden - set +e - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} \ - --env LIQUIBASE_SEARCH_PATH="/liquibase/custom-path" \ - -v $(pwd)/test-search-path-env/custom-path:/liquibase/custom-path \ - liquibase/liquibase:${{ github.sha }} \ - --changelogFile=main-changelog.xml \ - --url=offline:postgresql \ - validate 2>&1) - EXIT_CODE=$? - set -e - - echo "Search path test output: $RESULT" - echo "Exit code: $EXIT_CODE" - - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Custom LIQUIBASE_SEARCH_PATH environment variable was preserved" - else - echo "❌ FAIL: Custom search path was not respected or overridden" - echo "Checking if file was found error: $(echo "$RESULT" | grep -i "not found\|cannot find" || echo "No file not found error")" - exit 1 - fi - - # Cleanup - rm -rf test-search-path-env - - - name: Test explicit --search-path CLI argument is not overridden - if: matrix.os == 'ubuntu-latest' - run: | - echo "Testing that explicit --search-path command-line argument is respected..." - - # Create test directory structure - mkdir -p test-search-path-cli/cli-path - - # Put changelog in the CLI-specified search path - cat > test-search-path-cli/cli-path/main-changelog.xml << 'EOF' - - - - SELECT 'CLI Search Path Respected'; - - - EOF - - # Test with explicit --search-path argument - # This verifies that CLI arguments take precedence and are not overridden - set +e - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} \ - -v $(pwd)/test-search-path-cli/cli-path:/liquibase/cli-path \ - liquibase/liquibase:${{ github.sha }} \ - --changelogFile=main-changelog.xml \ - --search-path=/liquibase/cli-path \ - --url=offline:postgresql \ - validate 2>&1) - EXIT_CODE=$? - set -e - - echo "CLI search path test output: $RESULT" - - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Explicit --search-path CLI argument was respected" - else - echo "❌ FAIL: Explicit search path argument was overridden" - exit 1 - fi - - # Cleanup - rm -rf test-search-path-cli - - - name: Test relative paths work WITH custom search path (regression test) - if: matrix.os == 'ubuntu-latest' - run: | - echo "Testing relative paths combined with custom search path (DAT-21189 regression)..." - - # This scenario tests: user provides custom search path and accesses files from within that path - # The regression was that the entrypoint was injecting additional search paths on top of user's - mkdir -p test-search-path-combo/shared - - # Main changelog in the custom search path - cat > test-search-path-combo/shared/main-changelog.xml << 'EOF' - - - - SELECT 'Custom search path respected'; - - - EOF - - # Test: custom search path is preserved (regression: PR #414 was overriding this) - set +e - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} \ - --env LIQUIBASE_SEARCH_PATH="/liquibase/shared" \ - -v $(pwd)/test-search-path-combo/shared:/liquibase/shared \ - liquibase/liquibase:${{ github.sha }} \ - --changelogFile=main-changelog.xml \ - --url=offline:postgresql \ - validate 2>&1) - EXIT_CODE=$? - set -e - - echo "Regression test output: $RESULT" - - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Custom search path preserved correctly (DAT-21189 fixed)" - else - echo "❌ FAIL: Custom search path was not preserved (DAT-21189 regression)" - exit 1 - fi - - # Cleanup - rm -rf test-search-path-combo - - - name: Test search path not injected when LIQUIBASE_SEARCH_PATH with multiple paths - if: matrix.os == 'ubuntu-latest' - run: | - echo "Testing multiple search paths in LIQUIBASE_SEARCH_PATH are preserved..." - - mkdir -p test-multi-search/path1 - mkdir -p test-multi-search/path2 - - # Main changelog in path1 - cat > test-multi-search/path1/main.xml << 'EOF' - - - - SELECT 'Multiple paths preserved'; - - - EOF - - # Test with multiple search paths - this is the real-world scenario that broke (S3 + local paths) - set +e - RESULT=$(docker run --rm --env LIQUIBASE_LICENSE_KEY=${{ env.PRO_LICENSE_KEY }} \ - --env LIQUIBASE_SEARCH_PATH="/liquibase/path1,/liquibase/path2" \ - -v $(pwd)/test-multi-search/path1:/liquibase/path1 \ - -v $(pwd)/test-multi-search/path2:/liquibase/path2 \ - liquibase/liquibase:${{ github.sha }} \ - --changelogFile=main.xml \ - --url=offline:postgresql \ - validate 2>&1) - EXIT_CODE=$? - set -e - - echo "Multiple search paths test output: $RESULT" - - if echo "$RESULT" | grep -q "No validation errors found"; then - echo "✅ SUCCESS: Multiple search paths in LIQUIBASE_SEARCH_PATH are preserved" - else - echo "❌ FAIL: Multiple search paths were not properly handled" - exit 1 - fi - - # Cleanup - rm -rf test-multi-search + uses: liquibase/build-logic/.github/workflows/reusable-docker-test.yml@dat-22876-reusables + with: + dockerfile_path: ${{ matrix.dockerfile }} + runs_on: ${{ matrix.os }} + build_logic_ref: dat-22876-reusables + secrets: inherit diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index f811b388..e4a226b2 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -36,512 +36,63 @@ permissions: jobs: # ============================================ - # BUILD AND PUSH TO GHCR + # SCAN: community (Dockerfile) # ============================================ - build: - strategy: - fail-fast: false - matrix: - image: - [ - { - dockerfile: Dockerfile, - name: liquibase/liquibase, - suffix: "", - ghcr_name: community, - }, - { - dockerfile: Dockerfile.alpine, - name: liquibase/liquibase, - suffix: "-alpine", - ghcr_name: alpine, - }, - { - dockerfile: DockerfileSecure, - name: liquibase/liquibase-secure, - suffix: "", - ghcr_name: secure, - }, - ] - name: Build ${{ matrix.image.name }}${{ matrix.image.suffix }} - runs-on: "ubuntu-22.04" - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Login to GHCR - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push to GHCR - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 - with: - context: . - file: ${{ matrix.image.dockerfile }} - push: true - tags: ghcr.io/${{ github.repository }}/liquibase-${{ matrix.image.ghcr_name }}:${{ github.sha }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # ============================================ - # VULNERABILITY SCAN (REUSABLE WORKFLOW) - # ============================================ - vulnerability-scan: - needs: build - strategy: - fail-fast: false - matrix: - image: - [ - { - dockerfile: Dockerfile, - name: liquibase/liquibase, - suffix: "", - ghcr_name: community, - }, - { - dockerfile: Dockerfile.alpine, - name: liquibase/liquibase, - suffix: "-alpine", - ghcr_name: alpine, - }, - { - dockerfile: DockerfileSecure, - name: liquibase/liquibase-secure, - suffix: "", - ghcr_name: secure, - }, - ] - name: Scan ${{ matrix.image.name }}${{ matrix.image.suffix }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + scan-community: + name: Scan liquibase/liquibase + uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@dat-22876-reusables with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-${{ matrix.image.ghcr_name }}:${{ github.sha }} - image_name: ${{ matrix.image.name }} - image_tag: ${{ matrix.image.suffix != '' && matrix.image.suffix || 'latest' }} - fail_on_vulnerabilities: true + dockerfile_path: Dockerfile + image_name: liquibase/liquibase + suffix: "" + vex_enabled: false upload_sarif: true - sarif_category: ${{ matrix.image.name }}${{ matrix.image.suffix }} - generate_sbom: true - vex_enabled: ${{ matrix.image.name == 'liquibase/liquibase-secure' }} - build_logic_ref: main + dispatch_new_cves: true + scout_enabled: true + build_logic_ref: dat-22876-reusables secrets: inherit # ============================================ - # DISPATCH NEW CVEs FOR INVESTIGATION - # ============================================ - dispatch-new-cves: - needs: [vulnerability-scan] - if: always() && github.event_name != 'pull_request' && needs.vulnerability-scan.result != 'cancelled' - continue-on-error: true - strategy: - fail-fast: false - matrix: - image: - [ - { - dockerfile: Dockerfile, - name: liquibase/liquibase, - suffix: "", - ghcr_name: community, - }, - { - dockerfile: Dockerfile.alpine, - name: liquibase/liquibase, - suffix: "-alpine", - ghcr_name: alpine, - }, - { - dockerfile: DockerfileSecure, - name: liquibase/liquibase-secure, - suffix: "", - ghcr_name: secure, - }, - ] - name: Dispatch CVEs ${{ matrix.image.name }}${{ matrix.image.suffix }} - runs-on: ubuntu-22.04 - permissions: - actions: read - contents: read - id-token: write - steps: - - name: Checkout build-logic - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: liquibase/build-logic - path: build-logic - - - name: Resolve artifact name - id: artifact-name - env: - IMAGE_NAME: ${{ matrix.image.name }} - IMAGE_SUFFIX: ${{ matrix.image.suffix }} - run: | - # image_tag for display/dispatch (stripped of leading dash) - IMAGE_TAG="${IMAGE_SUFFIX#-}" - IMAGE_TAG="${IMAGE_TAG:-latest}" - # Artifact name must match what the reusable workflow uploads. - # The reusable workflow receives image_tag = suffix || 'latest' (raw, with leading dash for alpine), - # so use the raw suffix for artifact lookup to avoid single-dash vs double-dash mismatch. - RAW_IMAGE_TAG="${IMAGE_SUFFIX:-latest}" - SAFE_NAME=$(echo "$IMAGE_NAME" | tr '/' '-') - SAFE_TAG=$(echo "$RAW_IMAGE_TAG" | tr '/' '-') - echo "artifact=vulnerability-report-${SAFE_NAME}-${SAFE_TAG}" >> "$GITHUB_OUTPUT" - echo "image_tag=${IMAGE_TAG}" >> "$GITHUB_OUTPUT" - - - name: Download scan artifact - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: ${{ steps.artifact-name.outputs.artifact }} - path: scan-artifacts - continue-on-error: true - - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - continue-on-error: true - - - name: Get secrets from vault - id: vault-secrets - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - continue-on-error: true - - - name: Get GitHub App token for liquibase-pro - id: get-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 - with: - app-id: ${{ env.LIQUIBASE_GITHUB_APP_ID }} - private-key: ${{ env.LIQUIBASE_GITHUB_APP_PRIVATE_KEY }} - owner: liquibase - repositories: liquibase-pro - permission-actions: write - permission-contents: read - continue-on-error: true - - - name: Dispatch new CVEs for investigation - continue-on-error: true - env: - GH_TOKEN: ${{ steps.get-token.outputs.token }} - SCAN_DIR: ${{ github.workspace }}/scan-artifacts - IMAGE_NAME: ${{ matrix.image.name }} - IMAGE_TAG: ${{ steps.artifact-name.outputs.image_tag }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: | - set +e # Never fail the parent workflow - - IMAGE_OR_VERSION="${IMAGE_NAME}:${IMAGE_TAG}" - DISPATCH_LABEL="${IMAGE_NAME}:${IMAGE_TAG}" - - if [ -z "$GH_TOKEN" ]; then - echo "::warning::CVE dispatch skipped -- GitHub App token unavailable (vault step may have failed)" - echo "## CVE Investigation Dispatch (${DISPATCH_LABEL})" >> "$GITHUB_STEP_SUMMARY" - echo "Skipped -- GitHub App token unavailable." >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi - - if [ ! -d "$SCAN_DIR" ] || [ -z "$(ls -A "$SCAN_DIR" 2>/dev/null)" ]; then - echo "::warning::CVE dispatch skipped -- no scan artifacts found" - echo "## CVE Investigation Dispatch (${DISPATCH_LABEL})" >> "$GITHUB_STEP_SUMMARY" - echo "Skipped -- scan artifacts not available." >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi - - chmod +x build-logic/scripts/vulnerability-scanning/diff-new-cves.sh - - BATCHES=$(build-logic/scripts/vulnerability-scanning/diff-new-cves.sh \ - --scan-dir "$SCAN_DIR" \ - --source docker \ - --image-or-version "$IMAGE_OR_VERSION" \ - --run-url "$RUN_URL" \ - 2>/tmp/diff-err-$$.txt) || { - ERR=$(cat /tmp/diff-err-$$.txt 2>/dev/null || echo "unknown error") - echo "::warning::diff-new-cves.sh failed -- CVE dispatch skipped: $ERR" - echo "## CVE Investigation Dispatch (${DISPATCH_LABEL})" >> "$GITHUB_STEP_SUMMARY" - echo "Skipped -- diff-new-cves.sh exited with error: $ERR" >> "$GITHUB_STEP_SUMMARY" - rm -f "/tmp/diff-err-$$.txt" - exit 0 - } - rm -f "/tmp/diff-err-$$.txt" - - if [ -z "$BATCHES" ]; then - echo "No unassessed HIGH/CRITICAL CVEs found -- dispatch not needed." - echo "## CVE Investigation Dispatch (${DISPATCH_LABEL})" >> "$GITHUB_STEP_SUMMARY" - echo "No unassessed CVEs found -- nothing dispatched." >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi - - BATCH_NUM=0 - FAILED=0 - - echo "## CVE Investigation Dispatch (${DISPATCH_LABEL})" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - - while IFS= read -r batch_json; do - [ -z "$batch_json" ] && continue - BATCH_NUM=$((BATCH_NUM + 1)) - CVE_COUNT=$(echo "$batch_json" | jq '.cves | length' 2>/dev/null || echo "?") - - echo "Dispatching batch $BATCH_NUM ($CVE_COUNT CVEs) to investigate-cve workflow..." - - if gh workflow run investigate-cve.lock.yml \ - -R liquibase/liquibase-pro \ - -f "cve_json=$batch_json" 2>/tmp/dispatch-err-$$.txt; then - echo "- Batch $BATCH_NUM: dispatched $CVE_COUNT CVEs" >> "$GITHUB_STEP_SUMMARY" - echo " Batch $BATCH_NUM: OK ($CVE_COUNT CVEs)" - else - ERR=$(cat /tmp/dispatch-err-$$.txt 2>/dev/null || echo "unknown error") - echo "::warning::CVE dispatch batch $BATCH_NUM failed: $ERR" - echo "- Batch $BATCH_NUM: FAILED -- $ERR" >> "$GITHUB_STEP_SUMMARY" - FAILED=$((FAILED + 1)) - fi - rm -f "/tmp/dispatch-err-$$.txt" - done <<< "$BATCHES" - - echo "" >> "$GITHUB_STEP_SUMMARY" - echo "**Total batches dispatched**: $BATCH_NUM ($FAILED failed)" >> "$GITHUB_STEP_SUMMARY" - echo "Dispatch complete: $BATCH_NUM batch(es), $FAILED failure(s)" - exit 0 # Never fail the parent workflow - - # ============================================ - # CLEANUP GHCR IMAGES + # SCAN: alpine (Dockerfile.alpine) # ============================================ - cleanup-ghcr: - needs: [vulnerability-scan] - if: always() - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - image: - [ - { ghcr_name: community }, - { ghcr_name: alpine }, - { ghcr_name: secure }, - ] - name: Cleanup ${{ matrix.image.ghcr_name }} - permissions: - packages: write - steps: - - name: Delete GHCR image - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - REPO_NAME="${{ github.event.repository.name }}" - PACKAGE_NAME="${REPO_NAME}/liquibase-${{ matrix.image.ghcr_name }}" - ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-${{ matrix.image.ghcr_name }}" - TAG="${{ github.sha }}" - VERSION_ID=$(gh api \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ - --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") - if [ -n "$VERSION_ID" ]; then - gh api --method DELETE \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" - echo "Deleted ${PACKAGE_NAME}:${TAG}" - else - echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" - fi + scan-alpine: + name: Scan liquibase/liquibase-alpine + uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@dat-22876-reusables + with: + dockerfile_path: Dockerfile.alpine + image_name: liquibase/liquibase + suffix: "-alpine" + vex_enabled: false + upload_sarif: true + dispatch_new_cves: true + scout_enabled: true + build_logic_ref: dat-22876-reusables + secrets: inherit # ============================================ - # SLACK NOTIFICATION ON FAILURE + # SCAN: secure (DockerfileSecure) — VEX enabled # ============================================ - notify-failure: - needs: [build, vulnerability-scan, cleanup-ghcr] - if: failure() - runs-on: "ubuntu-22.04" - steps: - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - - name: Notify Slack on Build Failure - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 - env: - SLACK_COLOR: "failure" - SLACK_MESSAGE: "View details on GitHub Actions: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}. Triggered by repository: ${{ github.repository }}" - SLACK_TITLE: "❌ ${{ github.repository }} ❌ Trivy failed on branch ${{ github.ref_name }} for commit ${{ github.sha }} in repository ${{ github.repository }}" - SLACK_USERNAME: liquibot - SLACK_WEBHOOK: ${{ env.DOCKER_SLACK_WEBHOOK_URL }} - SLACK_ICON_EMOJI: ":whale:" - SLACK_FOOTER: "${{ github.repository }}" - SLACK_LINK_NAMES: true - - scout: - strategy: - fail-fast: false - matrix: - image: - [ - { dockerfile: Dockerfile, name: liquibase/liquibase, suffix: "" }, - { - dockerfile: Dockerfile.alpine, - name: liquibase/liquibase, - suffix: "-alpine", - }, - { - dockerfile: DockerfileSecure, - name: liquibase/liquibase-secure, - suffix: "", - }, - ] - name: Scout - runs-on: "ubuntu-22.04" - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Build ${{ matrix.image.name }}${{ matrix.image.suffix }} from Dockerfile - run: | - docker build -f ${{ matrix.image.dockerfile }} -t ${{ matrix.image.name }}${{ matrix.image.suffix }}:${{ github.sha }} . - - - name: Configure AWS credentials for vault access - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 - with: - role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Get secrets from vault - id: vault-secrets - uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 - with: - secret-ids: | - ,/vault/liquibase - parse-json-secrets: true - - - name: Decode DOCKERHUB_USERNAME - run: | - decoded_username=$(echo "${{ env.DOCKERHUB_USERNAME }}" | base64 -d) - echo "DOCKERHUB_USERNAME_DECODED=$decoded_username" >> $GITHUB_ENV - - - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - username: ${{ env.DOCKERHUB_USERNAME_DECODED }} - password: ${{ env.DOCKERHUB_TOKEN }} - - - name: Download VEX files for Scout - if: matrix.image.name == 'liquibase/liquibase-secure' - run: | - mkdir -p ./vex - curl -sSfL "https://raw.githubusercontent.com/liquibase/vex-repo/main/pkg/maven/org.liquibase/liquibase-core/vex.openvex.json" \ - -o ./vex/liquibase-core.vex.json - echo "VEX file downloaded: $(jq '.statements | length' ./vex/liquibase-core.vex.json) statements" - - - name: Docker Scout (with VEX) - if: matrix.image.name == 'liquibase/liquibase-secure' - uses: docker/scout-action@8910519cee8ac046f3ee99686b0dc6654d5ba1a7 # v1.20.3 - with: - command: cves - image: "${{ matrix.image.name }}${{ matrix.image.suffix }}:${{ github.sha }}" - github-token: ${{ secrets.GITHUB_TOKEN }} - write-comment: true - sarif-file: "scout-results.sarif" - summary: true - exit-code: true - only-severities: "critical,high" - vex-location: ./vex - only-vex-affected: true - vex-author: "Liquibase Security Team" - - - name: Docker Scout (without VEX) - if: matrix.image.name != 'liquibase/liquibase-secure' - uses: docker/scout-action@8910519cee8ac046f3ee99686b0dc6654d5ba1a7 # v1.20.3 - with: - command: cves - image: "${{ matrix.image.name }}${{ matrix.image.suffix }}:${{ github.sha }}" - github-token: ${{ secrets.GITHUB_TOKEN }} - write-comment: true - sarif-file: "scout-results.sarif" - summary: true - exit-code: true - only-severities: "critical,high" - - - name: Docker Scout JSON output - if: always() - run: | - SCOUT_ARGS=( - --format json - --output scout-results.json - --only-severities critical,high - ) - if [[ "${{ matrix.image.name }}" == "liquibase/liquibase-secure" ]]; then - SCOUT_ARGS+=(--vex-location ./vex --only-vex-affected --vex-author "Liquibase Security Team") - fi - docker scout cves "${SCOUT_ARGS[@]}" \ - "${{ matrix.image.name }}${{ matrix.image.suffix }}:${{ github.sha }}" || true - - - name: Upload Scout JSON results - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: scout-results${{ matrix.image.dockerfile == 'DockerfileSecure' && '-secure' || matrix.image.suffix }} - path: scout-results.json - if-no-files-found: warn - - - name: Notify Slack on Build Failure - if: failure() - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 - env: - SLACK_COLOR: "failure" - SLACK_MESSAGE: "View details on GitHub Actions: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}. Triggered by repository: ${{ github.repository }} and job: ${{ github.job }}" - SLACK_TITLE: "❌ ${{ github.repository }} ❌ Docker Scout failed on branch ${{ github.ref_name }} for commit ${{ github.sha }} in repository ${{ github.repository }}" - SLACK_USERNAME: liquibot - SLACK_WEBHOOK: ${{ env.DOCKER_SLACK_WEBHOOK_URL }} - SLACK_ICON_EMOJI: ":whale:" - SLACK_FOOTER: "${{ github.repository }} - ${{ matrix.image.name }}${{ matrix.image.suffix }}:${{ github.sha }}" - SLACK_LINK_NAMES: true - - - name: Upload Scout scan results to GitHub Security tab - if: always() - uses: github/codeql-action/upload-sarif@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 - with: - sarif_file: "scout-results.sarif" - category: "${{ matrix.image.name }}${{ matrix.image.suffix }}" - - - name: Generate Security Report - if: always() - uses: rsdmike/github-security-report-action@a149b24539044c92786ec39af8ba38c93496495d # v3.0.4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - outputDir: ./reports/scout${{ matrix.image.dockerfile == 'DockerfileSecure' && '-secure' || matrix.image.suffix }}/ - sarifReportDir: . - - - name: Upload Security Report - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: security-report-scout${{ matrix.image.dockerfile == 'DockerfileSecure' && '-secure' || matrix.image.suffix }} - path: ./reports/scout${{ matrix.image.dockerfile == 'DockerfileSecure' && '-secure' || matrix.image.suffix }}/summary.pdf + scan-secure: + name: Scan liquibase/liquibase-secure + uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@dat-22876-reusables + with: + dockerfile_path: DockerfileSecure + image_name: liquibase/liquibase-secure + suffix: "" + vex_enabled: true + upload_sarif: true + dispatch_new_cves: true + scout_enabled: true + build_logic_ref: dat-22876-reusables + secrets: inherit # ============================================ # PERSIST SCAN RESULTS TO scan-results BRANCH # ============================================ persist-results: name: Persist Scan Results - needs: [vulnerability-scan, scout] - if: always() && github.event_name != 'pull_request' && needs.vulnerability-scan.result != 'cancelled' + needs: [scan-community, scan-alpine, scan-secure] + if: always() && github.event_name != 'pull_request' && needs.scan-community.result != 'cancelled' runs-on: ubuntu-22.04 permissions: actions: read @@ -600,3 +151,36 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" scripts/persist-scan-results.sh scan-artifacts + + # ============================================ + # SLACK NOTIFICATION ON FAILURE + # ============================================ + notify-failure: + needs: [scan-community, scan-alpine, scan-secure] + if: failure() + runs-on: "ubuntu-22.04" + steps: + - name: Configure AWS credentials for vault access + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 + with: + role-to-assume: ${{ secrets.LIQUIBASE_VAULT_OIDC_ROLE_ARN }} + aws-region: us-east-1 + + - name: Get secrets from vault + uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802 # v2.0.10 + with: + secret-ids: | + ,/vault/liquibase + parse-json-secrets: true + + - name: Notify Slack on Build Failure + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 + env: + SLACK_COLOR: "failure" + SLACK_MESSAGE: "View details on GitHub Actions: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}. Triggered by repository: ${{ github.repository }}" + SLACK_TITLE: "❌ ${{ github.repository }} ❌ Trivy failed on branch ${{ github.ref_name }} for commit ${{ github.sha }} in repository ${{ github.repository }}" + SLACK_USERNAME: liquibot + SLACK_WEBHOOK: ${{ env.DOCKER_SLACK_WEBHOOK_URL }} + SLACK_ICON_EMOJI: ":whale:" + SLACK_FOOTER: "${{ github.repository }}" + SLACK_LINK_NAMES: true From acaace5c3a83aeee3405d3a99247ba4c633d7158 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 07:44:17 +0200 Subject: [PATCH 02/23] feat(ci): expose dry_run input on README publish workflow_dispatch Enables safe validation runs that preview the Docker Hub README push without updating it. dry_run passes through to the new dry_run input on reusable-docker-readme.yml (build-logic commit 0ea...). Push-triggered runs remain unchanged (dry_run defaults to false). DAT-22876 --- .github/workflows/publish-liquibase-secure-readme.yml | 7 +++++++ .github/workflows/publish-oss-readme.yml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/.github/workflows/publish-liquibase-secure-readme.yml b/.github/workflows/publish-liquibase-secure-readme.yml index d354706b..f8590212 100644 --- a/.github/workflows/publish-liquibase-secure-readme.yml +++ b/.github/workflows/publish-liquibase-secure-readme.yml @@ -7,6 +7,12 @@ on: branches: - main workflow_dispatch: + inputs: + dry_run: + description: 'Preview README push without updating Docker Hub (for validation runs)' + required: false + type: boolean + default: false permissions: contents: write @@ -19,4 +25,5 @@ jobs: target_image: liquibase/liquibase-secure readme_path: README-secure.md short_description: "Liquibase Secure" + dry_run: ${{ inputs.dry_run || false }} secrets: inherit diff --git a/.github/workflows/publish-oss-readme.yml b/.github/workflows/publish-oss-readme.yml index f9e17536..c8917eb9 100644 --- a/.github/workflows/publish-oss-readme.yml +++ b/.github/workflows/publish-oss-readme.yml @@ -7,6 +7,12 @@ on: branches: - main workflow_dispatch: + inputs: + dry_run: + description: 'Preview README push without updating Docker Hub (for validation runs)' + required: false + type: boolean + default: false permissions: id-token: write @@ -18,4 +24,5 @@ jobs: target_image: liquibase/liquibase readme_path: README.md short_description: "Liquibase Community" + dry_run: ${{ inputs.dry_run || false }} secrets: inherit From 4819e1e21f33ac3249431f7a0048032330ae7b7b Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 07:51:58 +0200 Subject: [PATCH 03/23] fix(ci): grant contents:read to publish-oss-readme caller The reusable-docker-readme.yml reusable needs contents:read at job level to checkout the caller repo. The top-level permissions block on publish-oss-readme.yml restricted to id-token:write only, implicitly denying contents. This caused startup_failure on workflow_dispatch. Matches the permissions block on publish-liquibase-secure-readme.yml (minus contents:write which Secure needs for a different reason). DAT-22876 --- .github/workflows/publish-oss-readme.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-oss-readme.yml b/.github/workflows/publish-oss-readme.yml index c8917eb9..5c62336d 100644 --- a/.github/workflows/publish-oss-readme.yml +++ b/.github/workflows/publish-oss-readme.yml @@ -15,6 +15,7 @@ on: default: false permissions: + contents: read id-token: write jobs: From 565bf834cc3f8695a0666202de2deaef00a9e879 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 07:59:57 +0200 Subject: [PATCH 04/23] refactor(ci): split build-qa-docker into explicit named jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Actions workflow parser rejects dynamic 'strategy.matrix: ${{ fromJSON(...) }}' combined with 'uses:' reusable workflow call — causes startup_failure at workflow parse time. Split into 3 named build jobs (community, alpine, secure) + 3 vuln-scan jobs + 3 cleanup jobs with 'if:' gates based on buildTargets input. Mirrors the proven pattern in trivy.yml. DAT-22876 --- .github/workflows/build-qa-docker.yml | 247 +++++++++++++++++++------- 1 file changed, 179 insertions(+), 68 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index dee114c2..6ffb1223 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -31,17 +31,18 @@ on: type: string jobs: + # ============================================ + # DETECT RC BUILD + # ============================================ set-matrix: - name: "Generate Build Matrix" + name: "Detect RC Build" runs-on: ubuntu-latest outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} + is_rc_build: ${{ steps.set-matrix.outputs.is_rc_build }} steps: - - name: Set matrix dynamically + - name: Detect RC build and log selected targets id: set-matrix run: | - matrix_items=() - # Determine if this is an RC build (secure-version contains "-RC") IS_RC_BUILD="false" if [[ -n "${{ inputs.secure-version }}" && "${{ inputs.secure-version }}" =~ -RC[0-9]+$ ]]; then @@ -49,91 +50,201 @@ jobs: echo "Detected RC build with version: ${{ inputs.secure-version }}" fi - case "${{ inputs.buildTargets }}" in - "All (Community + Alpine + Secure)") - matrix_items+=('{"dockerfile": "Dockerfile", "image_name": "liquibase-qa", "suffix": "", "build_type": "Community", "is_rc": false, "ghcr_name": "community"}') - matrix_items+=('{"dockerfile": "Dockerfile.alpine", "image_name": "liquibase-qa-alpine", "suffix": "-alpine", "build_type": "Community", "is_rc": false, "ghcr_name": "alpine"}') - if [[ "$IS_RC_BUILD" == "true" ]]; then - matrix_items+=('{"dockerfile": "DockerfileSecure", "image_name": "liquibase-secure-rc", "suffix": "-secure", "build_type": "secure", "is_rc": true, "ghcr_name": "secure"}') - else - matrix_items+=('{"dockerfile": "DockerfileSecure", "image_name": "liquibase-secure-qa", "suffix": "-secure", "build_type": "secure", "is_rc": false, "ghcr_name": "secure"}') - fi - ;; - "Community Only (Standard + Alpine)") - matrix_items+=('{"dockerfile": "Dockerfile", "image_name": "liquibase-qa", "suffix": "", "build_type": "Community", "is_rc": false, "ghcr_name": "community"}') - matrix_items+=('{"dockerfile": "Dockerfile.alpine", "image_name": "liquibase-qa-alpine", "suffix": "-alpine", "build_type": "Community", "is_rc": false, "ghcr_name": "alpine"}') - ;; - "Secure Only") - if [[ "$IS_RC_BUILD" == "true" ]]; then - matrix_items+=('{"dockerfile": "DockerfileSecure", "image_name": "liquibase-secure-rc", "suffix": "-secure", "build_type": "secure", "is_rc": true, "ghcr_name": "secure"}') - else - matrix_items+=('{"dockerfile": "DockerfileSecure", "image_name": "liquibase-secure-qa", "suffix": "-secure", "build_type": "secure", "is_rc": false, "ghcr_name": "secure"}') - fi - ;; - "Standard Community Only") - matrix_items+=('{"dockerfile": "Dockerfile", "image_name": "liquibase-qa", "suffix": "", "build_type": "Community", "is_rc": false, "ghcr_name": "community"}') - ;; - "Alpine Community Only") - matrix_items+=('{"dockerfile": "Dockerfile.alpine", "image_name": "liquibase-qa-alpine", "suffix": "-alpine", "build_type": "Community", "is_rc": false, "ghcr_name": "alpine"}') - ;; - esac - - # Join array elements with commas - IFS=',' - matrix_json="{\"include\":[${matrix_items[*]}]}" - echo "Selected build targets: ${{ inputs.buildTargets }}" echo "Is RC build: $IS_RC_BUILD" - echo "Generated matrix: $matrix_json" - echo "matrix=$matrix_json" >> $GITHUB_OUTPUT + echo "is_rc_build=${IS_RC_BUILD}" >> "$GITHUB_OUTPUT" + + # ============================================ + # BUILD: community (Dockerfile) + # ============================================ + build-qa-community: + name: Build Community QA + needs: set-matrix + if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Community Only (Standard + Alpine)","Standard Community Only"]'), inputs.buildTargets) }} + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + with: + image_name: liquibase-qa + dockerfile_path: Dockerfile + suffix: "" + ghcr_name: community + branch_name: ${{ inputs.liquibaseBranch }} + secure_version: ${{ inputs.secure-version || '' }} + build_type: Community + is_rc: "false" + push_nexus: true + push_ghcr: true + build_logic_ref: dat-22876-reusables + secrets: inherit + + # ============================================ + # BUILD: alpine (Dockerfile.alpine) + # ============================================ + build-qa-alpine: + name: Build Alpine QA + needs: set-matrix + if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Community Only (Standard + Alpine)","Alpine Community Only"]'), inputs.buildTargets) }} + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + with: + image_name: liquibase-qa-alpine + dockerfile_path: Dockerfile.alpine + suffix: "-alpine" + ghcr_name: alpine + branch_name: ${{ inputs.liquibaseBranch }} + secure_version: ${{ inputs.secure-version || '' }} + build_type: Community + is_rc: "false" + push_nexus: true + push_ghcr: true + build_logic_ref: dat-22876-reusables + secrets: inherit - build-qa-docker: - name: Build ${{ matrix.image_name }} + # ============================================ + # BUILD: secure (DockerfileSecure) + # ============================================ + build-qa-secure: + name: Build Secure QA needs: set-matrix - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.set-matrix.outputs.matrix) }} + if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Secure Only"]'), inputs.buildTargets) }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: - image_name: ${{ matrix.image_name }} - dockerfile_path: ${{ matrix.dockerfile }} - suffix: ${{ matrix.suffix }} - ghcr_name: ${{ matrix.ghcr_name }} + image_name: ${{ needs.set-matrix.outputs.is_rc_build == 'true' && 'liquibase-secure-rc' || 'liquibase-secure-qa' }} + dockerfile_path: DockerfileSecure + suffix: "-secure" + ghcr_name: secure branch_name: ${{ inputs.liquibaseBranch }} secure_version: ${{ inputs.secure-version || '' }} - build_type: ${{ matrix.build_type }} - is_rc: ${{ matrix.is_rc }} + build_type: secure + is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} push_nexus: true push_ghcr: true build_logic_ref: dat-22876-reusables secrets: inherit - vulnerability-scan: - needs: [set-matrix, build-qa-docker] - if: ${{ !cancelled() && needs.build-qa-docker.result == 'success' }} - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.set-matrix.outputs.matrix) }} - name: Scan ${{ matrix.image_name }} + # ============================================ + # SCAN: community + # ============================================ + vuln-scan-community: + name: Scan Community QA + needs: [build-qa-community] + if: ${{ !cancelled() && needs.build-qa-community.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-community:${{ github.sha }} + image_name: liquibase-qa + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit + + # ============================================ + # SCAN: alpine + # ============================================ + vuln-scan-alpine: + name: Scan Alpine QA + needs: [build-qa-alpine] + if: ${{ !cancelled() && needs.build-qa-alpine.result == 'success' }} uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main with: mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-${{ matrix.ghcr_name }}:${{ github.sha }} - image_name: ${{ matrix.image_name }} + source: ghcr.io/${{ github.repository }}/liquibase-alpine:${{ github.sha }} + image_name: liquibase-qa-alpine image_tag: qa fail_on_vulnerabilities: true upload_sarif: false generate_sbom: true build_logic_ref: main + secrets: inherit + + # ============================================ + # SCAN: secure + # ============================================ + vuln-scan-secure: + name: Scan Secure QA + needs: [set-matrix, build-qa-secure] + if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} + image_name: ${{ needs.set-matrix.outputs.is_rc_build == 'true' && 'liquibase-secure-rc' || 'liquibase-secure-qa' }} + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit + + # ============================================ + # CLEANUP: community + # ============================================ + cleanup-ghcr-community: + name: Cleanup Community GHCR + needs: [vuln-scan-community] + if: always() + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - name: Delete GHCR image + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO_NAME="${{ github.event.repository.name }}" + PACKAGE_NAME="${REPO_NAME}/liquibase-community" + ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-community" + TAG="${{ github.sha }}" + VERSION_ID=$(gh api \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ + --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") + if [ -n "$VERSION_ID" ]; then + gh api --method DELETE \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" + echo "Deleted ${PACKAGE_NAME}:${TAG}" + else + echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" + fi + + # ============================================ + # CLEANUP: alpine + # ============================================ + cleanup-ghcr-alpine: + name: Cleanup Alpine GHCR + needs: [vuln-scan-alpine] + if: always() + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - name: Delete GHCR image + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO_NAME="${{ github.event.repository.name }}" + PACKAGE_NAME="${REPO_NAME}/liquibase-alpine" + ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-alpine" + TAG="${{ github.sha }}" + VERSION_ID=$(gh api \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ + --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") + if [ -n "$VERSION_ID" ]; then + gh api --method DELETE \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" + echo "Deleted ${PACKAGE_NAME}:${TAG}" + else + echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" + fi - cleanup-ghcr: - needs: [set-matrix, vulnerability-scan] + # ============================================ + # CLEANUP: secure + # ============================================ + cleanup-ghcr-secure: + name: Cleanup Secure GHCR + needs: [vuln-scan-secure] if: always() runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.set-matrix.outputs.matrix) }} - name: Cleanup ${{ matrix.image_name }} permissions: packages: write steps: @@ -142,8 +253,8 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | REPO_NAME="${{ github.event.repository.name }}" - PACKAGE_NAME="${REPO_NAME}/liquibase-${{ matrix.ghcr_name }}" - ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-${{ matrix.ghcr_name }}" + PACKAGE_NAME="${REPO_NAME}/liquibase-secure" + ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-secure" TAG="${{ github.sha }}" VERSION_ID=$(gh api \ "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ From 16466f45ed63063eb67459e79a5cc1f4800155ed Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:02:56 +0200 Subject: [PATCH 05/23] fix(ci): remove ternary expressions from reusable with: blocks Move secure_image_name computation to set-matrix step outputs to avoid ternary '&&/||' pattern in reusable workflow with: inputs. Also remove '|| empty-string' fallback from secure-version input (reusable default handles the empty case). Both patterns can trigger startup_failure on GitHub's static parse validation. DAT-22876 --- .github/workflows/build-qa-docker.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 6ffb1223..9c3544fd 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -39,6 +39,7 @@ jobs: runs-on: ubuntu-latest outputs: is_rc_build: ${{ steps.set-matrix.outputs.is_rc_build }} + secure_image_name: ${{ steps.set-matrix.outputs.secure_image_name }} steps: - name: Detect RC build and log selected targets id: set-matrix @@ -54,6 +55,14 @@ jobs: echo "Is RC build: $IS_RC_BUILD" echo "is_rc_build=${IS_RC_BUILD}" >> "$GITHUB_OUTPUT" + # Compute secure image name here to avoid ternary expressions in reusable with: blocks + if [[ "$IS_RC_BUILD" == "true" ]]; then + SECURE_IMAGE_NAME="liquibase-secure-rc" + else + SECURE_IMAGE_NAME="liquibase-secure-qa" + fi + echo "secure_image_name=${SECURE_IMAGE_NAME}" >> "$GITHUB_OUTPUT" + # ============================================ # BUILD: community (Dockerfile) # ============================================ @@ -68,7 +77,7 @@ jobs: suffix: "" ghcr_name: community branch_name: ${{ inputs.liquibaseBranch }} - secure_version: ${{ inputs.secure-version || '' }} + secure_version: ${{ inputs.secure-version }} build_type: Community is_rc: "false" push_nexus: true @@ -90,7 +99,7 @@ jobs: suffix: "-alpine" ghcr_name: alpine branch_name: ${{ inputs.liquibaseBranch }} - secure_version: ${{ inputs.secure-version || '' }} + secure_version: ${{ inputs.secure-version }} build_type: Community is_rc: "false" push_nexus: true @@ -107,12 +116,12 @@ jobs: if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Secure Only"]'), inputs.buildTargets) }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: - image_name: ${{ needs.set-matrix.outputs.is_rc_build == 'true' && 'liquibase-secure-rc' || 'liquibase-secure-qa' }} + image_name: ${{ needs.set-matrix.outputs.secure_image_name }} dockerfile_path: DockerfileSecure suffix: "-secure" ghcr_name: secure branch_name: ${{ inputs.liquibaseBranch }} - secure_version: ${{ inputs.secure-version || '' }} + secure_version: ${{ inputs.secure-version }} build_type: secure is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} push_nexus: true @@ -169,7 +178,7 @@ jobs: with: mode: docker source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} - image_name: ${{ needs.set-matrix.outputs.is_rc_build == 'true' && 'liquibase-secure-rc' || 'liquibase-secure-qa' }} + image_name: ${{ needs.set-matrix.outputs.secure_image_name }} image_tag: qa fail_on_vulnerabilities: true upload_sarif: false From cca240a6aed1b9177881cdd765f8af54542ddc86 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:04:20 +0200 Subject: [PATCH 06/23] fix(ci): replace contains(fromJSON()) with explicit OR conditions in if: gates The contains(fromJSON('[...]')) pattern may trigger GitHub's static parse validation on job-level if: conditions for reusable workflow callers. Replace with explicit equality checks joined by || operators. DAT-22876 --- .github/workflows/build-qa-docker.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 9c3544fd..00f73c2e 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -69,7 +69,7 @@ jobs: build-qa-community: name: Build Community QA needs: set-matrix - if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Community Only (Standard + Alpine)","Standard Community Only"]'), inputs.buildTargets) }} + if: ${{ inputs.buildTargets == 'All (Community + Alpine + Secure)' || inputs.buildTargets == 'Community Only (Standard + Alpine)' || inputs.buildTargets == 'Standard Community Only' }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa @@ -91,7 +91,7 @@ jobs: build-qa-alpine: name: Build Alpine QA needs: set-matrix - if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Community Only (Standard + Alpine)","Alpine Community Only"]'), inputs.buildTargets) }} + if: ${{ inputs.buildTargets == 'All (Community + Alpine + Secure)' || inputs.buildTargets == 'Community Only (Standard + Alpine)' || inputs.buildTargets == 'Alpine Community Only' }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa-alpine @@ -113,7 +113,7 @@ jobs: build-qa-secure: name: Build Secure QA needs: set-matrix - if: ${{ contains(fromJSON('["All (Community + Alpine + Secure)","Secure Only"]'), inputs.buildTargets) }} + if: ${{ inputs.buildTargets == 'All (Community + Alpine + Secure)' || inputs.buildTargets == 'Secure Only' }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: ${{ needs.set-matrix.outputs.secure_image_name }} From 3d46031c7da7a2f58ea3d75e23825e7ff733465a Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:06:57 +0200 Subject: [PATCH 07/23] fix(ci): simplify vuln-scan-secure needs chain to isolate startup_failure Remove needs on set-matrix from vuln-scan-secure to avoid potential GitHub Actions constraint on reusable-caller depending on another job that also chains needs from a reusable. Use static image_name for reporting (does not affect scan target). DAT-22876 --- .github/workflows/build-qa-docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 00f73c2e..c0f7c774 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -172,13 +172,13 @@ jobs: # ============================================ vuln-scan-secure: name: Scan Secure QA - needs: [set-matrix, build-qa-secure] + needs: [build-qa-secure] if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main with: mode: docker source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} - image_name: ${{ needs.set-matrix.outputs.secure_image_name }} + image_name: liquibase-secure-qa image_tag: qa fail_on_vulnerabilities: true upload_sarif: false From f59b75455353a3c82c5f9f3dcfbc4c9fe7da2917 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:09:00 +0200 Subject: [PATCH 08/23] fix(ci): move buildTargets gate to set-matrix outputs, use needs.* in if: GitHub Actions may not allow 'inputs.*' context in job-level if: for reusable workflow callers. Compute per-target build flags (build_community, build_alpine, build_secure) as set-matrix outputs and gate subsequent reusable caller jobs via needs.set-matrix.outputs.* comparisons instead. DAT-22876 --- .github/workflows/build-qa-docker.yml | 39 ++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index c0f7c774..ed394e4a 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -40,6 +40,9 @@ jobs: outputs: is_rc_build: ${{ steps.set-matrix.outputs.is_rc_build }} secure_image_name: ${{ steps.set-matrix.outputs.secure_image_name }} + build_community: ${{ steps.set-matrix.outputs.build_community }} + build_alpine: ${{ steps.set-matrix.outputs.build_alpine }} + build_secure: ${{ steps.set-matrix.outputs.build_secure }} steps: - name: Detect RC build and log selected targets id: set-matrix @@ -63,13 +66,43 @@ jobs: fi echo "secure_image_name=${SECURE_IMAGE_NAME}" >> "$GITHUB_OUTPUT" + # Compute per-target build flags for use in if: conditions (avoids inputs.* on reusable callers) + BUILD_TARGETS="${{ inputs.buildTargets }}" + case "$BUILD_TARGETS" in + "All (Community + Alpine + Secure)") + echo "build_community=true" >> "$GITHUB_OUTPUT" + echo "build_alpine=true" >> "$GITHUB_OUTPUT" + echo "build_secure=true" >> "$GITHUB_OUTPUT" + ;; + "Community Only (Standard + Alpine)") + echo "build_community=true" >> "$GITHUB_OUTPUT" + echo "build_alpine=true" >> "$GITHUB_OUTPUT" + echo "build_secure=false" >> "$GITHUB_OUTPUT" + ;; + "Secure Only") + echo "build_community=false" >> "$GITHUB_OUTPUT" + echo "build_alpine=false" >> "$GITHUB_OUTPUT" + echo "build_secure=true" >> "$GITHUB_OUTPUT" + ;; + "Standard Community Only") + echo "build_community=true" >> "$GITHUB_OUTPUT" + echo "build_alpine=false" >> "$GITHUB_OUTPUT" + echo "build_secure=false" >> "$GITHUB_OUTPUT" + ;; + "Alpine Community Only") + echo "build_community=false" >> "$GITHUB_OUTPUT" + echo "build_alpine=true" >> "$GITHUB_OUTPUT" + echo "build_secure=false" >> "$GITHUB_OUTPUT" + ;; + esac + # ============================================ # BUILD: community (Dockerfile) # ============================================ build-qa-community: name: Build Community QA needs: set-matrix - if: ${{ inputs.buildTargets == 'All (Community + Alpine + Secure)' || inputs.buildTargets == 'Community Only (Standard + Alpine)' || inputs.buildTargets == 'Standard Community Only' }} + if: ${{ needs.set-matrix.outputs.build_community == 'true' }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa @@ -91,7 +124,7 @@ jobs: build-qa-alpine: name: Build Alpine QA needs: set-matrix - if: ${{ inputs.buildTargets == 'All (Community + Alpine + Secure)' || inputs.buildTargets == 'Community Only (Standard + Alpine)' || inputs.buildTargets == 'Alpine Community Only' }} + if: ${{ needs.set-matrix.outputs.build_alpine == 'true' }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa-alpine @@ -113,7 +146,7 @@ jobs: build-qa-secure: name: Build Secure QA needs: set-matrix - if: ${{ inputs.buildTargets == 'All (Community + Alpine + Secure)' || inputs.buildTargets == 'Secure Only' }} + if: ${{ needs.set-matrix.outputs.build_secure == 'true' }} uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: ${{ needs.set-matrix.outputs.secure_image_name }} From 847f6f6543069ce01fdbea7acc36692684abea4b Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:11:26 +0200 Subject: [PATCH 09/23] fix(ci): try bare expression syntax in if: for reusable caller jobs Test whether removing the ${{ }} wrapper from if: expressions on reusable caller jobs resolves startup_failure. GitHub documentation shows both syntaxes work but bare expression may avoid parse issues. DAT-22876 --- .github/workflows/build-qa-docker.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index ed394e4a..6ea43fe6 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -32,7 +32,7 @@ on: jobs: # ============================================ - # DETECT RC BUILD + # DETECT RC BUILD AND COMPUTE BUILD FLAGS # ============================================ set-matrix: name: "Detect RC Build" @@ -58,7 +58,7 @@ jobs: echo "Is RC build: $IS_RC_BUILD" echo "is_rc_build=${IS_RC_BUILD}" >> "$GITHUB_OUTPUT" - # Compute secure image name here to avoid ternary expressions in reusable with: blocks + # Compute secure image name if [[ "$IS_RC_BUILD" == "true" ]]; then SECURE_IMAGE_NAME="liquibase-secure-rc" else @@ -66,7 +66,7 @@ jobs: fi echo "secure_image_name=${SECURE_IMAGE_NAME}" >> "$GITHUB_OUTPUT" - # Compute per-target build flags for use in if: conditions (avoids inputs.* on reusable callers) + # Compute per-target build flags BUILD_TARGETS="${{ inputs.buildTargets }}" case "$BUILD_TARGETS" in "All (Community + Alpine + Secure)") @@ -101,8 +101,8 @@ jobs: # ============================================ build-qa-community: name: Build Community QA - needs: set-matrix - if: ${{ needs.set-matrix.outputs.build_community == 'true' }} + needs: [set-matrix] + if: needs.set-matrix.outputs.build_community == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa @@ -123,8 +123,8 @@ jobs: # ============================================ build-qa-alpine: name: Build Alpine QA - needs: set-matrix - if: ${{ needs.set-matrix.outputs.build_alpine == 'true' }} + needs: [set-matrix] + if: needs.set-matrix.outputs.build_alpine == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa-alpine @@ -145,8 +145,8 @@ jobs: # ============================================ build-qa-secure: name: Build Secure QA - needs: set-matrix - if: ${{ needs.set-matrix.outputs.build_secure == 'true' }} + needs: [set-matrix] + if: needs.set-matrix.outputs.build_secure == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: ${{ needs.set-matrix.outputs.secure_image_name }} From 4a84ae90f518855198b8e40d4004f604fbbc136b Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:11:59 +0200 Subject: [PATCH 10/23] debug(ci): minimal single reusable job to isolate startup_failure Stripped to absolute minimum: one job, no needs, no if, calling reusable-docker-build-qa.yml@dat-22876-reusables. If this still gets startup_failure, the issue is in the reusable workflow itself. DAT-22876 --- .github/workflows/build-qa-docker.yml | 261 -------------------------- 1 file changed, 261 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 6ea43fe6..47bf8574 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -31,78 +31,8 @@ on: type: string jobs: - # ============================================ - # DETECT RC BUILD AND COMPUTE BUILD FLAGS - # ============================================ - set-matrix: - name: "Detect RC Build" - runs-on: ubuntu-latest - outputs: - is_rc_build: ${{ steps.set-matrix.outputs.is_rc_build }} - secure_image_name: ${{ steps.set-matrix.outputs.secure_image_name }} - build_community: ${{ steps.set-matrix.outputs.build_community }} - build_alpine: ${{ steps.set-matrix.outputs.build_alpine }} - build_secure: ${{ steps.set-matrix.outputs.build_secure }} - steps: - - name: Detect RC build and log selected targets - id: set-matrix - run: | - # Determine if this is an RC build (secure-version contains "-RC") - IS_RC_BUILD="false" - if [[ -n "${{ inputs.secure-version }}" && "${{ inputs.secure-version }}" =~ -RC[0-9]+$ ]]; then - IS_RC_BUILD="true" - echo "Detected RC build with version: ${{ inputs.secure-version }}" - fi - - echo "Selected build targets: ${{ inputs.buildTargets }}" - echo "Is RC build: $IS_RC_BUILD" - echo "is_rc_build=${IS_RC_BUILD}" >> "$GITHUB_OUTPUT" - - # Compute secure image name - if [[ "$IS_RC_BUILD" == "true" ]]; then - SECURE_IMAGE_NAME="liquibase-secure-rc" - else - SECURE_IMAGE_NAME="liquibase-secure-qa" - fi - echo "secure_image_name=${SECURE_IMAGE_NAME}" >> "$GITHUB_OUTPUT" - - # Compute per-target build flags - BUILD_TARGETS="${{ inputs.buildTargets }}" - case "$BUILD_TARGETS" in - "All (Community + Alpine + Secure)") - echo "build_community=true" >> "$GITHUB_OUTPUT" - echo "build_alpine=true" >> "$GITHUB_OUTPUT" - echo "build_secure=true" >> "$GITHUB_OUTPUT" - ;; - "Community Only (Standard + Alpine)") - echo "build_community=true" >> "$GITHUB_OUTPUT" - echo "build_alpine=true" >> "$GITHUB_OUTPUT" - echo "build_secure=false" >> "$GITHUB_OUTPUT" - ;; - "Secure Only") - echo "build_community=false" >> "$GITHUB_OUTPUT" - echo "build_alpine=false" >> "$GITHUB_OUTPUT" - echo "build_secure=true" >> "$GITHUB_OUTPUT" - ;; - "Standard Community Only") - echo "build_community=true" >> "$GITHUB_OUTPUT" - echo "build_alpine=false" >> "$GITHUB_OUTPUT" - echo "build_secure=false" >> "$GITHUB_OUTPUT" - ;; - "Alpine Community Only") - echo "build_community=false" >> "$GITHUB_OUTPUT" - echo "build_alpine=true" >> "$GITHUB_OUTPUT" - echo "build_secure=false" >> "$GITHUB_OUTPUT" - ;; - esac - - # ============================================ - # BUILD: community (Dockerfile) - # ============================================ build-qa-community: name: Build Community QA - needs: [set-matrix] - if: needs.set-matrix.outputs.build_community == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa @@ -117,194 +47,3 @@ jobs: push_ghcr: true build_logic_ref: dat-22876-reusables secrets: inherit - - # ============================================ - # BUILD: alpine (Dockerfile.alpine) - # ============================================ - build-qa-alpine: - name: Build Alpine QA - needs: [set-matrix] - if: needs.set-matrix.outputs.build_alpine == 'true' - uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables - with: - image_name: liquibase-qa-alpine - dockerfile_path: Dockerfile.alpine - suffix: "-alpine" - ghcr_name: alpine - branch_name: ${{ inputs.liquibaseBranch }} - secure_version: ${{ inputs.secure-version }} - build_type: Community - is_rc: "false" - push_nexus: true - push_ghcr: true - build_logic_ref: dat-22876-reusables - secrets: inherit - - # ============================================ - # BUILD: secure (DockerfileSecure) - # ============================================ - build-qa-secure: - name: Build Secure QA - needs: [set-matrix] - if: needs.set-matrix.outputs.build_secure == 'true' - uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables - with: - image_name: ${{ needs.set-matrix.outputs.secure_image_name }} - dockerfile_path: DockerfileSecure - suffix: "-secure" - ghcr_name: secure - branch_name: ${{ inputs.liquibaseBranch }} - secure_version: ${{ inputs.secure-version }} - build_type: secure - is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} - push_nexus: true - push_ghcr: true - build_logic_ref: dat-22876-reusables - secrets: inherit - - # ============================================ - # SCAN: community - # ============================================ - vuln-scan-community: - name: Scan Community QA - needs: [build-qa-community] - if: ${{ !cancelled() && needs.build-qa-community.result == 'success' }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main - with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-community:${{ github.sha }} - image_name: liquibase-qa - image_tag: qa - fail_on_vulnerabilities: true - upload_sarif: false - generate_sbom: true - build_logic_ref: main - secrets: inherit - - # ============================================ - # SCAN: alpine - # ============================================ - vuln-scan-alpine: - name: Scan Alpine QA - needs: [build-qa-alpine] - if: ${{ !cancelled() && needs.build-qa-alpine.result == 'success' }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main - with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-alpine:${{ github.sha }} - image_name: liquibase-qa-alpine - image_tag: qa - fail_on_vulnerabilities: true - upload_sarif: false - generate_sbom: true - build_logic_ref: main - secrets: inherit - - # ============================================ - # SCAN: secure - # ============================================ - vuln-scan-secure: - name: Scan Secure QA - needs: [build-qa-secure] - if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main - with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} - image_name: liquibase-secure-qa - image_tag: qa - fail_on_vulnerabilities: true - upload_sarif: false - generate_sbom: true - build_logic_ref: main - secrets: inherit - - # ============================================ - # CLEANUP: community - # ============================================ - cleanup-ghcr-community: - name: Cleanup Community GHCR - needs: [vuln-scan-community] - if: always() - runs-on: ubuntu-latest - permissions: - packages: write - steps: - - name: Delete GHCR image - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - REPO_NAME="${{ github.event.repository.name }}" - PACKAGE_NAME="${REPO_NAME}/liquibase-community" - ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-community" - TAG="${{ github.sha }}" - VERSION_ID=$(gh api \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ - --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") - if [ -n "$VERSION_ID" ]; then - gh api --method DELETE \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" - echo "Deleted ${PACKAGE_NAME}:${TAG}" - else - echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" - fi - - # ============================================ - # CLEANUP: alpine - # ============================================ - cleanup-ghcr-alpine: - name: Cleanup Alpine GHCR - needs: [vuln-scan-alpine] - if: always() - runs-on: ubuntu-latest - permissions: - packages: write - steps: - - name: Delete GHCR image - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - REPO_NAME="${{ github.event.repository.name }}" - PACKAGE_NAME="${REPO_NAME}/liquibase-alpine" - ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-alpine" - TAG="${{ github.sha }}" - VERSION_ID=$(gh api \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ - --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") - if [ -n "$VERSION_ID" ]; then - gh api --method DELETE \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" - echo "Deleted ${PACKAGE_NAME}:${TAG}" - else - echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" - fi - - # ============================================ - # CLEANUP: secure - # ============================================ - cleanup-ghcr-secure: - name: Cleanup Secure GHCR - needs: [vuln-scan-secure] - if: always() - runs-on: ubuntu-latest - permissions: - packages: write - steps: - - name: Delete GHCR image - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - REPO_NAME="${{ github.event.repository.name }}" - PACKAGE_NAME="${REPO_NAME}/liquibase-secure" - ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-secure" - TAG="${{ github.sha }}" - VERSION_ID=$(gh api \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ - --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") - if [ -n "$VERSION_ID" ]; then - gh api --method DELETE \ - "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" - echo "Deleted ${PACKAGE_NAME}:${TAG}" - else - echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" - fi From 495a56dd9089d3689b7fdeca75797bd83c8174f1 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:12:35 +0200 Subject: [PATCH 11/23] debug(ci): needs + if + reusable test Test: set-matrix + needs + if (bare expression) + reusable call. DAT-22876 --- .github/workflows/build-qa-docker.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 47bf8574..0de24f50 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -31,8 +31,29 @@ on: type: string jobs: + set-matrix: + name: "Detect RC Build" + runs-on: ubuntu-latest + outputs: + build_community: ${{ steps.set-matrix.outputs.build_community }} + steps: + - name: Detect build targets + id: set-matrix + run: | + BUILD_TARGETS="${{ inputs.buildTargets }}" + case "$BUILD_TARGETS" in + "All (Community + Alpine + Secure)"|"Community Only (Standard + Alpine)"|"Standard Community Only") + echo "build_community=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "build_community=false" >> "$GITHUB_OUTPUT" + ;; + esac + build-qa-community: name: Build Community QA + needs: [set-matrix] + if: needs.set-matrix.outputs.build_community == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa From b3c7e00ca9fd6b2815040d469e899a8a1ae24368 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:13:58 +0200 Subject: [PATCH 12/23] debug(ci): test all 3 build jobs without vuln-scan DAT-22876 --- .github/workflows/build-qa-docker.yml | 77 +++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 0de24f50..971fc984 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -35,18 +35,51 @@ jobs: name: "Detect RC Build" runs-on: ubuntu-latest outputs: + is_rc_build: ${{ steps.set-matrix.outputs.is_rc_build }} + secure_image_name: ${{ steps.set-matrix.outputs.secure_image_name }} build_community: ${{ steps.set-matrix.outputs.build_community }} + build_alpine: ${{ steps.set-matrix.outputs.build_alpine }} + build_secure: ${{ steps.set-matrix.outputs.build_secure }} steps: - - name: Detect build targets + - name: Detect RC build and log selected targets id: set-matrix run: | + IS_RC_BUILD="false" + if [[ -n "${{ inputs.secure-version }}" && "${{ inputs.secure-version }}" =~ -RC[0-9]+$ ]]; then + IS_RC_BUILD="true" + fi + echo "is_rc_build=${IS_RC_BUILD}" >> "$GITHUB_OUTPUT" + if [[ "$IS_RC_BUILD" == "true" ]]; then + echo "secure_image_name=liquibase-secure-rc" >> "$GITHUB_OUTPUT" + else + echo "secure_image_name=liquibase-secure-qa" >> "$GITHUB_OUTPUT" + fi BUILD_TARGETS="${{ inputs.buildTargets }}" case "$BUILD_TARGETS" in - "All (Community + Alpine + Secure)"|"Community Only (Standard + Alpine)"|"Standard Community Only") + "All (Community + Alpine + Secure)") echo "build_community=true" >> "$GITHUB_OUTPUT" + echo "build_alpine=true" >> "$GITHUB_OUTPUT" + echo "build_secure=true" >> "$GITHUB_OUTPUT" ;; - *) + "Community Only (Standard + Alpine)") + echo "build_community=true" >> "$GITHUB_OUTPUT" + echo "build_alpine=true" >> "$GITHUB_OUTPUT" + echo "build_secure=false" >> "$GITHUB_OUTPUT" + ;; + "Secure Only") echo "build_community=false" >> "$GITHUB_OUTPUT" + echo "build_alpine=false" >> "$GITHUB_OUTPUT" + echo "build_secure=true" >> "$GITHUB_OUTPUT" + ;; + "Standard Community Only") + echo "build_community=true" >> "$GITHUB_OUTPUT" + echo "build_alpine=false" >> "$GITHUB_OUTPUT" + echo "build_secure=false" >> "$GITHUB_OUTPUT" + ;; + "Alpine Community Only") + echo "build_community=false" >> "$GITHUB_OUTPUT" + echo "build_alpine=true" >> "$GITHUB_OUTPUT" + echo "build_secure=false" >> "$GITHUB_OUTPUT" ;; esac @@ -68,3 +101,41 @@ jobs: push_ghcr: true build_logic_ref: dat-22876-reusables secrets: inherit + + build-qa-alpine: + name: Build Alpine QA + needs: [set-matrix] + if: needs.set-matrix.outputs.build_alpine == 'true' + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + with: + image_name: liquibase-qa-alpine + dockerfile_path: Dockerfile.alpine + suffix: "-alpine" + ghcr_name: alpine + branch_name: ${{ inputs.liquibaseBranch }} + secure_version: ${{ inputs.secure-version }} + build_type: Community + is_rc: "false" + push_nexus: true + push_ghcr: true + build_logic_ref: dat-22876-reusables + secrets: inherit + + build-qa-secure: + name: Build Secure QA + needs: [set-matrix] + if: needs.set-matrix.outputs.build_secure == 'true' + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + with: + image_name: ${{ needs.set-matrix.outputs.secure_image_name }} + dockerfile_path: DockerfileSecure + suffix: "-secure" + ghcr_name: secure + branch_name: ${{ inputs.liquibaseBranch }} + secure_version: ${{ inputs.secure-version }} + build_type: secure + is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} + push_nexus: true + push_ghcr: true + build_logic_ref: dat-22876-reusables + secrets: inherit From 5692315f5ea68c719a5e141fbaf645cb7ce1d170 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:14:48 +0200 Subject: [PATCH 13/23] debug(ci): test 3 build + 3 vuln-scan jobs without cleanup DAT-22876 --- .github/workflows/build-qa-docker.yml | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 971fc984..3b3b0b69 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -139,3 +139,51 @@ jobs: push_ghcr: true build_logic_ref: dat-22876-reusables secrets: inherit + + vuln-scan-community: + name: Scan Community QA + needs: [build-qa-community] + if: ${{ !cancelled() && needs.build-qa-community.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-community:${{ github.sha }} + image_name: liquibase-qa + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit + + vuln-scan-alpine: + name: Scan Alpine QA + needs: [build-qa-alpine] + if: ${{ !cancelled() && needs.build-qa-alpine.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-alpine:${{ github.sha }} + image_name: liquibase-qa-alpine + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit + + vuln-scan-secure: + name: Scan Secure QA + needs: [build-qa-secure] + if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} + image_name: liquibase-secure-qa + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit From cbbed0980ed1d80d9a06628d5c0b95532453b491 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:15:34 +0200 Subject: [PATCH 14/23] debug(ci): test vuln-scan with @dat-22876-reusables instead of @main Test whether mixing @dat-22876-reusables and @main refs causes startup_failure. DAT-22876 --- .github/workflows/build-qa-docker.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 3b3b0b69..fbc03a63 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -144,7 +144,7 @@ jobs: name: Scan Community QA needs: [build-qa-community] if: ${{ !cancelled() && needs.build-qa-community.result == 'success' }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker source: ghcr.io/${{ github.repository }}/liquibase-community:${{ github.sha }} @@ -153,14 +153,14 @@ jobs: fail_on_vulnerabilities: true upload_sarif: false generate_sbom: true - build_logic_ref: main + build_logic_ref: dat-22876-reusables secrets: inherit vuln-scan-alpine: name: Scan Alpine QA needs: [build-qa-alpine] if: ${{ !cancelled() && needs.build-qa-alpine.result == 'success' }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker source: ghcr.io/${{ github.repository }}/liquibase-alpine:${{ github.sha }} @@ -169,14 +169,14 @@ jobs: fail_on_vulnerabilities: true upload_sarif: false generate_sbom: true - build_logic_ref: main + build_logic_ref: dat-22876-reusables secrets: inherit vuln-scan-secure: name: Scan Secure QA needs: [build-qa-secure] if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} @@ -185,5 +185,5 @@ jobs: fail_on_vulnerabilities: true upload_sarif: false generate_sbom: true - build_logic_ref: main + build_logic_ref: dat-22876-reusables secrets: inherit From da7f49cce2afc6f4b02ace37606c3e30b5eaf828 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:16:22 +0200 Subject: [PATCH 15/23] debug(ci): use string if: on vuln-scan jobs DAT-22876 --- .github/workflows/build-qa-docker.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index fbc03a63..f4aefcba 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -143,7 +143,7 @@ jobs: vuln-scan-community: name: Scan Community QA needs: [build-qa-community] - if: ${{ !cancelled() && needs.build-qa-community.result == 'success' }} + if: "!cancelled() && needs.build-qa-community.result == 'success'" uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker @@ -159,7 +159,7 @@ jobs: vuln-scan-alpine: name: Scan Alpine QA needs: [build-qa-alpine] - if: ${{ !cancelled() && needs.build-qa-alpine.result == 'success' }} + if: "!cancelled() && needs.build-qa-alpine.result == 'success'" uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker @@ -175,7 +175,7 @@ jobs: vuln-scan-secure: name: Scan Secure QA needs: [build-qa-secure] - if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} + if: "!cancelled() && needs.build-qa-secure.result == 'success'" uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker From f8a22da6d647bd3234de4766c49658412b01df37 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:16:49 +0200 Subject: [PATCH 16/23] debug(ci): remove if: from vuln-scan jobs entirely DAT-22876 --- .github/workflows/build-qa-docker.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index f4aefcba..7930bd98 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -143,7 +143,6 @@ jobs: vuln-scan-community: name: Scan Community QA needs: [build-qa-community] - if: "!cancelled() && needs.build-qa-community.result == 'success'" uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker @@ -159,7 +158,6 @@ jobs: vuln-scan-alpine: name: Scan Alpine QA needs: [build-qa-alpine] - if: "!cancelled() && needs.build-qa-alpine.result == 'success'" uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker @@ -175,7 +173,6 @@ jobs: vuln-scan-secure: name: Scan Secure QA needs: [build-qa-secure] - if: "!cancelled() && needs.build-qa-secure.result == 'success'" uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables with: mode: docker From 5d68883dbaeef4acc221bbd0bd06f5f051037af0 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:18:10 +0200 Subject: [PATCH 17/23] debug(ci): 3 build + 1 vuln-scan only DAT-22876 --- .github/workflows/build-qa-docker.yml | 30 --------------------------- 1 file changed, 30 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 7930bd98..ab36bb56 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -154,33 +154,3 @@ jobs: generate_sbom: true build_logic_ref: dat-22876-reusables secrets: inherit - - vuln-scan-alpine: - name: Scan Alpine QA - needs: [build-qa-alpine] - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables - with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-alpine:${{ github.sha }} - image_name: liquibase-qa-alpine - image_tag: qa - fail_on_vulnerabilities: true - upload_sarif: false - generate_sbom: true - build_logic_ref: dat-22876-reusables - secrets: inherit - - vuln-scan-secure: - name: Scan Secure QA - needs: [build-qa-secure] - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables - with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} - image_name: liquibase-secure-qa - image_tag: qa - fail_on_vulnerabilities: true - upload_sarif: false - generate_sbom: true - build_logic_ref: dat-22876-reusables - secrets: inherit From cccea14803c471c56dea9bbc060396d7b3f5255e Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:19:02 +0200 Subject: [PATCH 18/23] debug(ci): 3 parallel build (no if/needs) + 1 vuln-scan DAT-22876 --- .github/workflows/build-qa-docker.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index ab36bb56..a10d24a8 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -85,8 +85,6 @@ jobs: build-qa-community: name: Build Community QA - needs: [set-matrix] - if: needs.set-matrix.outputs.build_community == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa @@ -104,8 +102,6 @@ jobs: build-qa-alpine: name: Build Alpine QA - needs: [set-matrix] - if: needs.set-matrix.outputs.build_alpine == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa-alpine @@ -123,18 +119,16 @@ jobs: build-qa-secure: name: Build Secure QA - needs: [set-matrix] - if: needs.set-matrix.outputs.build_secure == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: - image_name: ${{ needs.set-matrix.outputs.secure_image_name }} + image_name: liquibase-secure-qa dockerfile_path: DockerfileSecure suffix: "-secure" ghcr_name: secure branch_name: ${{ inputs.liquibaseBranch }} secure_version: ${{ inputs.secure-version }} build_type: secure - is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} + is_rc: "false" push_nexus: true push_ghcr: true build_logic_ref: dat-22876-reusables From b877b5e4a25cd0707bde0802b4dcac7b31a1b078 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:19:48 +0200 Subject: [PATCH 19/23] debug(ci): test reusable-caller -> reusable-caller chain (same reusable) DAT-22876 --- .github/workflows/build-qa-docker.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index a10d24a8..3e71e344 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -134,17 +134,20 @@ jobs: build_logic_ref: dat-22876-reusables secrets: inherit - vuln-scan-community: - name: Scan Community QA + build-qa-community-2: + name: Build Community QA 2 needs: [build-qa-community] - uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: - mode: docker - source: ghcr.io/${{ github.repository }}/liquibase-community:${{ github.sha }} - image_name: liquibase-qa - image_tag: qa - fail_on_vulnerabilities: true - upload_sarif: false - generate_sbom: true + image_name: liquibase-qa-2 + dockerfile_path: Dockerfile + suffix: "" + ghcr_name: community + branch_name: ${{ inputs.liquibaseBranch }} + secure_version: ${{ inputs.secure-version }} + build_type: Community + is_rc: "false" + push_nexus: true + push_ghcr: true build_logic_ref: dat-22876-reusables secrets: inherit From a3843fbf87b81a31ea4ffa4d83619930243a5812 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:20:19 +0200 Subject: [PATCH 20/23] debug(ci): test vuln-scan@main after reusable-caller chain DAT-22876 --- .github/workflows/build-qa-docker.yml | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 3e71e344..0e93ef90 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -134,20 +134,17 @@ jobs: build_logic_ref: dat-22876-reusables secrets: inherit - build-qa-community-2: - name: Build Community QA 2 + vuln-scan-community: + name: Scan Community QA needs: [build-qa-community] - uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main with: - image_name: liquibase-qa-2 - dockerfile_path: Dockerfile - suffix: "" - ghcr_name: community - branch_name: ${{ inputs.liquibaseBranch }} - secure_version: ${{ inputs.secure-version }} - build_type: Community - is_rc: "false" - push_nexus: true - push_ghcr: true - build_logic_ref: dat-22876-reusables + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-community:${{ github.sha }} + image_name: liquibase-qa + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main secrets: inherit From 93230189fcc332fca54fd422d30d4c84eb1503ea Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:20:47 +0200 Subject: [PATCH 21/23] debug(ci): add security-events:write permission (required by vuln-scan reusable) DAT-22876 --- .github/workflows/build-qa-docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 0e93ef90..33bd90e7 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -5,6 +5,7 @@ permissions: id-token: write actions: read packages: write + security-events: write on: workflow_dispatch: From 3a1d319be2cc8e522169b730d46e2f542b2dc6d0 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 08:21:55 +0200 Subject: [PATCH 22/23] refactor(ci): complete split into explicit named jobs with security-events:write Root cause found: missing 'security-events: write' top-level permission. GitHub's static parse validation rejects caller workflows that call reusable-vulnerability-scan.yml (which declares security-events: write at job level) when the caller's top-level permissions block doesn't include it. This causes startup_failure before any job runs. Full structure: - set-matrix: computes RC flag, image names, per-target build flags as outputs - build-qa-{community,alpine,secure}: gated on set-matrix outputs via needs.*.outputs - vuln-scan-{community,alpine,secure}: gated on corresponding build job success - cleanup-ghcr-{community,alpine,secure}: always-run cleanup Eliminates dynamic strategy.matrix + uses: combination that caused the original startup_failure. Mirrors trivy.yml pattern with explicit named jobs. DAT-22876 --- .github/workflows/build-qa-docker.yml | 163 +++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 33bd90e7..75425332 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -32,6 +32,9 @@ on: type: string jobs: + # ============================================ + # DETECT RC BUILD AND COMPUTE BUILD FLAGS + # ============================================ set-matrix: name: "Detect RC Build" runs-on: ubuntu-latest @@ -45,16 +48,25 @@ jobs: - name: Detect RC build and log selected targets id: set-matrix run: | + # Determine if this is an RC build (secure-version contains "-RC") IS_RC_BUILD="false" if [[ -n "${{ inputs.secure-version }}" && "${{ inputs.secure-version }}" =~ -RC[0-9]+$ ]]; then IS_RC_BUILD="true" + echo "Detected RC build with version: ${{ inputs.secure-version }}" fi + + echo "Selected build targets: ${{ inputs.buildTargets }}" + echo "Is RC build: $IS_RC_BUILD" echo "is_rc_build=${IS_RC_BUILD}" >> "$GITHUB_OUTPUT" + + # Compute secure image name to avoid ternary expressions in reusable with: blocks if [[ "$IS_RC_BUILD" == "true" ]]; then echo "secure_image_name=liquibase-secure-rc" >> "$GITHUB_OUTPUT" else echo "secure_image_name=liquibase-secure-qa" >> "$GITHUB_OUTPUT" fi + + # Compute per-target build flags for use in if: conditions BUILD_TARGETS="${{ inputs.buildTargets }}" case "$BUILD_TARGETS" in "All (Community + Alpine + Secure)") @@ -84,8 +96,13 @@ jobs: ;; esac + # ============================================ + # BUILD: community (Dockerfile) + # ============================================ build-qa-community: name: Build Community QA + needs: [set-matrix] + if: needs.set-matrix.outputs.build_community == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa @@ -101,8 +118,13 @@ jobs: build_logic_ref: dat-22876-reusables secrets: inherit + # ============================================ + # BUILD: alpine (Dockerfile.alpine) + # ============================================ build-qa-alpine: name: Build Alpine QA + needs: [set-matrix] + if: needs.set-matrix.outputs.build_alpine == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: image_name: liquibase-qa-alpine @@ -118,26 +140,35 @@ jobs: build_logic_ref: dat-22876-reusables secrets: inherit + # ============================================ + # BUILD: secure (DockerfileSecure) + # ============================================ build-qa-secure: name: Build Secure QA + needs: [set-matrix] + if: needs.set-matrix.outputs.build_secure == 'true' uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables with: - image_name: liquibase-secure-qa + image_name: ${{ needs.set-matrix.outputs.secure_image_name }} dockerfile_path: DockerfileSecure suffix: "-secure" ghcr_name: secure branch_name: ${{ inputs.liquibaseBranch }} secure_version: ${{ inputs.secure-version }} build_type: secure - is_rc: "false" + is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} push_nexus: true push_ghcr: true build_logic_ref: dat-22876-reusables secrets: inherit + # ============================================ + # SCAN: community + # ============================================ vuln-scan-community: name: Scan Community QA needs: [build-qa-community] + if: ${{ !cancelled() && needs.build-qa-community.result == 'success' }} uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main with: mode: docker @@ -149,3 +180,131 @@ jobs: generate_sbom: true build_logic_ref: main secrets: inherit + + # ============================================ + # SCAN: alpine + # ============================================ + vuln-scan-alpine: + name: Scan Alpine QA + needs: [build-qa-alpine] + if: ${{ !cancelled() && needs.build-qa-alpine.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-alpine:${{ github.sha }} + image_name: liquibase-qa-alpine + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit + + # ============================================ + # SCAN: secure + # ============================================ + vuln-scan-secure: + name: Scan Secure QA + needs: [build-qa-secure] + if: ${{ !cancelled() && needs.build-qa-secure.result == 'success' }} + uses: liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main + with: + mode: docker + source: ghcr.io/${{ github.repository }}/liquibase-secure:${{ github.sha }} + image_name: liquibase-secure-qa + image_tag: qa + fail_on_vulnerabilities: true + upload_sarif: false + generate_sbom: true + build_logic_ref: main + secrets: inherit + + # ============================================ + # CLEANUP: community + # ============================================ + cleanup-ghcr-community: + name: Cleanup Community GHCR + needs: [vuln-scan-community] + if: always() + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - name: Delete GHCR image + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO_NAME="${{ github.event.repository.name }}" + PACKAGE_NAME="${REPO_NAME}/liquibase-community" + ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-community" + TAG="${{ github.sha }}" + VERSION_ID=$(gh api \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ + --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") + if [ -n "$VERSION_ID" ]; then + gh api --method DELETE \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" + echo "Deleted ${PACKAGE_NAME}:${TAG}" + else + echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" + fi + + # ============================================ + # CLEANUP: alpine + # ============================================ + cleanup-ghcr-alpine: + name: Cleanup Alpine GHCR + needs: [vuln-scan-alpine] + if: always() + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - name: Delete GHCR image + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO_NAME="${{ github.event.repository.name }}" + PACKAGE_NAME="${REPO_NAME}/liquibase-alpine" + ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-alpine" + TAG="${{ github.sha }}" + VERSION_ID=$(gh api \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ + --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") + if [ -n "$VERSION_ID" ]; then + gh api --method DELETE \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" + echo "Deleted ${PACKAGE_NAME}:${TAG}" + else + echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" + fi + + # ============================================ + # CLEANUP: secure + # ============================================ + cleanup-ghcr-secure: + name: Cleanup Secure GHCR + needs: [vuln-scan-secure] + if: always() + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - name: Delete GHCR image + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO_NAME="${{ github.event.repository.name }}" + PACKAGE_NAME="${REPO_NAME}/liquibase-secure" + ENCODED_PACKAGE_NAME="${REPO_NAME}%2Fliquibase-secure" + TAG="${{ github.sha }}" + VERSION_ID=$(gh api \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions" \ + --jq ".[] | select(.metadata.container.tags[] == \"${TAG}\") | .id" 2>/dev/null || echo "") + if [ -n "$VERSION_ID" ]; then + gh api --method DELETE \ + "/orgs/${{ github.repository_owner }}/packages/container/${ENCODED_PACKAGE_NAME}/versions/${VERSION_ID}" + echo "Deleted ${PACKAGE_NAME}:${TAG}" + else + echo "No version found for ${PACKAGE_NAME}:${TAG}, skipping" + fi From 76c1afbe68eb65a240034494cf79a7f9b5b1528c Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 21 Apr 2026 09:04:23 +0200 Subject: [PATCH 23/23] refactor(ci): pin reusable workflow refs to @main after build-logic merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit liquibase/build-logic#555 merged — flip all @dat-22876-reusables refs to @main across all 6 caller workflows. No functional change expected; re-validation via workflow_dispatch confirms @main resolves identically. DAT-22876 --- .github/workflows/build-qa-docker.yml | 12 ++++++------ .github/workflows/create-release.yml | 16 ++++++++-------- .../publish-liquibase-secure-readme.yml | 2 +- .github/workflows/publish-oss-readme.yml | 2 +- .github/workflows/test.yml | 4 ++-- .github/workflows/trivy.yml | 12 ++++++------ 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build-qa-docker.yml b/.github/workflows/build-qa-docker.yml index 75425332..8beb9d87 100644 --- a/.github/workflows/build-qa-docker.yml +++ b/.github/workflows/build-qa-docker.yml @@ -103,7 +103,7 @@ jobs: name: Build Community QA needs: [set-matrix] if: needs.set-matrix.outputs.build_community == 'true' - uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@main with: image_name: liquibase-qa dockerfile_path: Dockerfile @@ -115,7 +115,7 @@ jobs: is_rc: "false" push_nexus: true push_ghcr: true - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -125,7 +125,7 @@ jobs: name: Build Alpine QA needs: [set-matrix] if: needs.set-matrix.outputs.build_alpine == 'true' - uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@main with: image_name: liquibase-qa-alpine dockerfile_path: Dockerfile.alpine @@ -137,7 +137,7 @@ jobs: is_rc: "false" push_nexus: true push_ghcr: true - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -147,7 +147,7 @@ jobs: name: Build Secure QA needs: [set-matrix] if: needs.set-matrix.outputs.build_secure == 'true' - uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build-qa.yml@main with: image_name: ${{ needs.set-matrix.outputs.secure_image_name }} dockerfile_path: DockerfileSecure @@ -159,7 +159,7 @@ jobs: is_rc: ${{ needs.set-matrix.outputs.is_rc_build }} push_nexus: true push_ghcr: true - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 05e987e0..c84114d4 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -234,7 +234,7 @@ jobs: name: "Build liquibase/liquibase" needs: update-dockerfiles if: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' }} - uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@main with: dockerfile_path: Dockerfile image_name: liquibase/liquibase @@ -256,7 +256,7 @@ jobs: image_source_url: https://github.com/${{ github.repository }} image_description: "Liquibase Container Image" image_licenses: FSL-1.1-ALv2 - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -266,7 +266,7 @@ jobs: name: "Build liquibase/liquibase-alpine" needs: update-dockerfiles if: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' }} - uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@main with: dockerfile_path: Dockerfile.alpine image_name: liquibase/liquibase @@ -288,7 +288,7 @@ jobs: image_source_url: https://github.com/${{ github.repository }} image_description: "Liquibase Container Image (Alpine)" image_licenses: FSL-1.1-ALv2 - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -298,7 +298,7 @@ jobs: name: "Build liquibase/liquibase-secure" needs: update-dockerfiles if: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' }} - uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-build.yml@main with: dockerfile_path: DockerfileSecure image_name: liquibase/liquibase-secure @@ -321,7 +321,7 @@ jobs: image_description: "Liquibase Secure Container Image" image_licenses: LicenseRef-Liquibase-EULA image_licenses_url: https://www.liquibase.com/eula - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -338,11 +338,11 @@ jobs: (needs.update-dockerfiles.outputs.releaseType == 'liquibase-release' && needs.build-community.result == 'success' && needs.build-alpine.result == 'success') || (needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && needs.build-secure.result == 'success') ) - uses: liquibase/build-logic/.github/workflows/reusable-docker-publish.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-publish.yml@main with: release_type: ${{ needs.update-dockerfiles.outputs.releaseType }} version: ${{ needs.update-dockerfiles.outputs.extensionVersion }} tag_suffix: ${{ needs.update-dockerfiles.outputs.releaseType == 'liquibase-secure-release' && '-SECURE' || '' }} dry_run: false - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit diff --git a/.github/workflows/publish-liquibase-secure-readme.yml b/.github/workflows/publish-liquibase-secure-readme.yml index f8590212..80c7e19e 100644 --- a/.github/workflows/publish-liquibase-secure-readme.yml +++ b/.github/workflows/publish-liquibase-secure-readme.yml @@ -20,7 +20,7 @@ permissions: jobs: update-readme: - uses: liquibase/build-logic/.github/workflows/reusable-docker-readme.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-readme.yml@main with: target_image: liquibase/liquibase-secure readme_path: README-secure.md diff --git a/.github/workflows/publish-oss-readme.yml b/.github/workflows/publish-oss-readme.yml index 5c62336d..0af4912b 100644 --- a/.github/workflows/publish-oss-readme.yml +++ b/.github/workflows/publish-oss-readme.yml @@ -20,7 +20,7 @@ permissions: jobs: update-readme: - uses: liquibase/build-logic/.github/workflows/reusable-docker-readme.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-readme.yml@main with: target_image: liquibase/liquibase readme_path: README.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e718b21c..b90cbc5c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,9 +37,9 @@ jobs: matrix: dockerfile: [Dockerfile, Dockerfile.alpine, DockerfileSecure] os: [ubuntu-latest, macos-15-intel] - uses: liquibase/build-logic/.github/workflows/reusable-docker-test.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-test.yml@main with: dockerfile_path: ${{ matrix.dockerfile }} runs_on: ${{ matrix.os }} - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index e4a226b2..a741a793 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -40,7 +40,7 @@ jobs: # ============================================ scan-community: name: Scan liquibase/liquibase - uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@main with: dockerfile_path: Dockerfile image_name: liquibase/liquibase @@ -49,7 +49,7 @@ jobs: upload_sarif: true dispatch_new_cves: true scout_enabled: true - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -57,7 +57,7 @@ jobs: # ============================================ scan-alpine: name: Scan liquibase/liquibase-alpine - uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@main with: dockerfile_path: Dockerfile.alpine image_name: liquibase/liquibase @@ -66,7 +66,7 @@ jobs: upload_sarif: true dispatch_new_cves: true scout_enabled: true - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================ @@ -74,7 +74,7 @@ jobs: # ============================================ scan-secure: name: Scan liquibase/liquibase-secure - uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@dat-22876-reusables + uses: liquibase/build-logic/.github/workflows/reusable-docker-scan.yml@main with: dockerfile_path: DockerfileSecure image_name: liquibase/liquibase-secure @@ -83,7 +83,7 @@ jobs: upload_sarif: true dispatch_new_cves: true scout_enabled: true - build_logic_ref: dat-22876-reusables + build_logic_ref: main secrets: inherit # ============================================