Conversation
📝 WalkthroughWalkthroughAdds GHCR integration and tagging to the QA Docker build workflow, extends the build matrix with Changes
Sequence Diagram(s)sequenceDiagram
participant Trigger as Workflow Trigger
participant Matrix as set-matrix
participant Build as build-qa-docker
participant GHCR as GHCR (ghcr.io)
participant Nexus as Nexus / existing registry
participant Scan as vulnerability-scan (reusable workflow)
participant Cleanup as cleanup-ghcr
Trigger->>Matrix: compute per-image matrix (includes ghcr_name)
Matrix->>Build: start per-image build jobs
Build->>GHCR: login to GHCR (docker/login-action)
Build->>Build: build image (artifact-based or fallback)
Build->>Nexus: push image to existing registry
Build->>GHCR: push image to GHCR with ghcr_name tags
Build->>Scan: invoke vulnerability-scan with GHCR image ref
Scan->>Build: return scan results (workflow output)
Build->>Cleanup: enqueue GHCR cleanup (always run)
Cleanup->>GHCR: query & delete matching package versions
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR enhances the QA Docker image build workflow by adding automated vulnerability scanning. It enables the workflow to push QA images to GitHub Container Registry (GHCR) in addition to the existing Nexus registry, allowing the reusable vulnerability scan workflow from build-logic to access and scan these images. The implementation follows the established pattern from the trivy.yml workflow.
Changes:
- Added
packages: writepermission for GHCR push operations - Extended matrix configuration with
ghcr_namefield for all build variants (community, alpine, secure) - Added vulnerability scanning job that runs after successful builds using the reusable workflow from build-logic
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
.github/workflows/build-qa-docker.yml (2)
528-534: CodeQL:docker/login-action@v3is an unpinned mutable tag.This is flagged by the CodeQL static analysis. Pinning to a commit SHA ensures supply-chain integrity. The GitHub official documentation pins
docker/login-actionto a specific commit hash rather than a semver tag.🔒 Pin to commit SHA
- uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/build-qa-docker.yml around lines 528 - 534, The step named "Login to GHCR" uses the mutable tag "docker/login-action@v3"; replace this with the action pinned to an immutable commit SHA (e.g., "docker/login-action@<commit-sha>") to satisfy CodeQL supply-chain checks—update the uses field in that step to the specific commit SHA for docker/login-action and commit the workflow change.
3-7:packages: writegranted at workflow level rather than job level.All three jobs (
set-matrix,build-qa-docker,vulnerability-scan) now inheritpackages: write. Onlybuild-qa-dockerneeds write access;vulnerability-scanonly needspackages: read, andset-matrixneeds no package access. Consider moving this permission to thebuild-qa-dockerjob level to enforce least privilege.🔒 Suggested job-level scoping
permissions: contents: read id-token: write actions: read - packages: writeThen in the
build-qa-dockerjob:build-qa-docker: name: "Build and Push QA Docker Images" runs-on: ubuntu-latest needs: set-matrix + permissions: + contents: read + id-token: write + actions: read + packages: write strategy:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/build-qa-docker.yml around lines 3 - 7, The workflow-level permissions currently grant packages: write to all jobs; change this to enforce least privilege by moving packages: write into the build-qa-docker job's permissions block (so build-qa-docker keeps write access), set packages: read in the vulnerability-scan job's permissions block, and remove or omit any packages permission from the set-matrix job (so it has no package access); update the permissions stanza references for the jobs named build-qa-docker, vulnerability-scan, and set-matrix accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/build-qa-docker.yml:
- Around line 622-638: The build matrix job "build-qa-docker" currently omits
fail-fast configuration so a single variant failure can short-circuit the entire
matrix and prevent downstream scans; open the job block for build-qa-docker and
add strategy.fail-fast: false (alongside the existing matrix: ${{
fromJSON(needs.set-matrix.outputs.matrix) }}) so each variant runs
independently; while there, optionally review the uses of
reusable-vulnerability-scan.yml (image_name/image_tag) for secrets forwarding
and consider pinning build_logic_ref, but the required fix is adding fail-fast:
false to the build-qa-docker strategy.
---
Nitpick comments:
In @.github/workflows/build-qa-docker.yml:
- Around line 528-534: The step named "Login to GHCR" uses the mutable tag
"docker/login-action@v3"; replace this with the action pinned to an immutable
commit SHA (e.g., "docker/login-action@<commit-sha>") to satisfy CodeQL
supply-chain checks—update the uses field in that step to the specific commit
SHA for docker/login-action and commit the workflow change.
- Around line 3-7: The workflow-level permissions currently grant packages:
write to all jobs; change this to enforce least privilege by moving packages:
write into the build-qa-docker job's permissions block (so build-qa-docker keeps
write access), set packages: read in the vulnerability-scan job's permissions
block, and remove or omit any packages permission from the set-matrix job (so it
has no package access); update the permissions stanza references for the jobs
named build-qa-docker, vulnerability-scan, and set-matrix accordingly.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
.github/workflows/build-qa-docker.yml (2)
547-547: Add a GHCR image cleanup step after scanning to prevent accumulation.SHA-tagged QA images (
ghcr.io/…/liquibase-{community|alpine|secure}:<sha>) are ephemeral by design but will accumulate in GHCR indefinitely. Consider adding a post-scan cleanup step usingactions/delete-package-versionsor a lifecycle policy on GHCR to auto-expire old untagged/SHA-tagged packages.Also applies to: 632-632
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/build-qa-docker.yml at line 547, Add a GHCR image cleanup step after the scan job to delete the ephemeral SHA-tagged images (e.g., ghcr.io/${{ github.repository }}/liquibase-${{ matrix.ghcr_name }}:${{ github.sha }}). Implement this by adding a new job step that runs actions/delete-package-versions (or a similar action) and targets the package name built from github.repository and liquibase-${{ matrix.ghcr_name }} with the version equal to ${{ github.sha }} (or a filter for SHA tags), supplying the required GITHUB_TOKEN and repository/package identifiers; ensure the step runs after the scan step and/or is conditional on scan success so SHA-tagged QA images are removed automatically.
3-7: Scopepackages: writeto the job that needs it.Setting
packages: writeat the workflow top-level grants it to every job (set-matrix,vulnerability-scan, etc.). Onlybuild-qa-dockerpushes to GHCR; tightening this to job-level permissions follows least-privilege.♻️ Proposed scoping
permissions: contents: read id-token: write actions: read - packages: writeThen inside
build-qa-docker:build-qa-docker: name: Build ${{ matrix.image_name }} runs-on: ubuntu-latest needs: set-matrix + permissions: + packages: write strategy:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/build-qa-docker.yml around lines 3 - 7, The top-level permissions block currently grants packages: write globally; restrict it by removing or changing packages at top-level to read (keep contents: read and id-token: write as needed) and add packages: write specifically to the build-qa-docker job's permissions block so only the build-qa-docker job has write access to GHCR; update the workflow's permissions stanza and the build-qa-docker job (identified as build-qa-docker) to reflect this least-privilege change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In @.github/workflows/build-qa-docker.yml:
- Around line 622-638: The vulnerability-scan job comment flags three issues:
make the upstream build matrix non-fail-fast so needs.build-qa-docker.result
reflects per-variant results (add strategy: fail-fast: false to the
build-qa-docker job definition), ensure secrets are forwarded to the reusable
workflow (add secrets: inherit to the vulnerability-scan job that calls uses:
liquibase/build-logic/.github/workflows/reusable-vulnerability-scan.yml@main),
and pin the reusable workflow reference instead of using mutable `@main` (replace
uses: …@main and the build_logic_ref: main input with a fixed tag or commit
SHA); update the build-qa-docker job, the vulnerability-scan job’s uses
invocation, and the build_logic_ref input accordingly.
---
Nitpick comments:
In @.github/workflows/build-qa-docker.yml:
- Line 547: Add a GHCR image cleanup step after the scan job to delete the
ephemeral SHA-tagged images (e.g., ghcr.io/${{ github.repository
}}/liquibase-${{ matrix.ghcr_name }}:${{ github.sha }}). Implement this by
adding a new job step that runs actions/delete-package-versions (or a similar
action) and targets the package name built from github.repository and
liquibase-${{ matrix.ghcr_name }} with the version equal to ${{ github.sha }}
(or a filter for SHA tags), supplying the required GITHUB_TOKEN and
repository/package identifiers; ensure the step runs after the scan step and/or
is conditional on scan success so SHA-tagged QA images are removed
automatically.
- Around line 3-7: The top-level permissions block currently grants packages:
write globally; restrict it by removing or changing packages at top-level to
read (keep contents: read and id-token: write as needed) and add packages: write
specifically to the build-qa-docker job's permissions block so only the
build-qa-docker job has write access to GHCR; update the workflow's permissions
stanza and the build-qa-docker job (identified as build-qa-docker) to reflect
this least-privilege change.
|
Claude finished @jandroav's task in 1m 36s —— View job Review
Previous issues have been addressed in follow-up commits: Unfixed - Design limitation - scan condition blocks on any single build failure ( Both are non-blocking for merge; the core implementation is correct. |
Push QA images to GHCR alongside Nexus so the reusable vulnerability scan workflow can pull and scan them before QA testing begins. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GHCR packages are namespaced under the repo name (docker/liquibase-*), requiring URL-encoded slashes in API paths. Also adds fail-fast: false to build-qa-docker strategy. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Suppress gh api errors when package doesn't exist yet so the cleanup step doesn't fail on first run. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Claude finished @jnewton03's task in 1m 26s —— View job Review
Fixed since last review:
One remaining issue:
Design note (non-blocking): The scan condition |
|
|
||
| - name: Login to GHCR | ||
| if: ${{ steps.validate-build.outcome == 'success' }} | ||
| uses: docker/login-action@v3 |
There was a problem hiding this comment.
docker/login-action@v3 is still a mutable tag, flagged by CodeQL (same as the existing Nexus login step above it). Pin to a commit SHA to satisfy supply-chain checks:
| uses: docker/login-action@v3 | |
| uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/build-qa-docker.yml (1)
641-669: Extract duplicated cleanup script into a composite action.The
cleanup-ghcrstep script (lines 651–669) is byte-for-byte identical to the one added intrivy.yml(lines 154–171). Any future changes (e.g., pagination, error handling, different API endpoint) need to be applied in two places.Consider extracting this into a local composite action (e.g.,
.github/actions/cleanup-ghcr/action.yml) and invoking it from both workflows.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/build-qa-docker.yml around lines 641 - 669, The inline GHCR deletion script is duplicated in the cleanup-ghcr job (step "Delete GHCR image") and in trivy.yml; extract it into a reusable composite action named cleanup-ghcr and replace both inline steps with a single call to that action. Implement the composite action to accept inputs/env for GH_TOKEN, repository name/owner, ghcr_name and tag/sha, move the shell logic (gh api calls and VERSION_ID handling) into the composite action's run step, and update both workflows to invoke the cleanup-ghcr action and pass the required inputs/env so future fixes are made in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In @.github/workflows/build-qa-docker.yml:
- Around line 91-96: The CI workflow's matrix strategy was missing fail-fast
behavior control; add or ensure strategy: fail-fast: false is present under the
workflow's strategy for the Build ${{ matrix.image_name }} job so individual
matrix variants won't cancel siblings—place the fail-fast: false key directly
under the strategy mapping (alongside matrix: ...) and verify YAML indentation
and syntax around the strategy block so the key is recognized.
- Around line 623-639: The vulnerability-scan job is skipping all scans because
its if condition checks needs.build-qa-docker.result == 'success' which becomes
false when any matrix build fails; remove that result check so the job runs
per-matrix for all variants that were produced. Concretely, keep needs:
[set-matrix, build-qa-docker] and strategy/fail-fast as-is, but change the if on
the vulnerability-scan job to not reference needs.build-qa-docker.result (e.g.,
if: ${{ !cancelled() }} or remove the if line) so the reusable workflow
invocation (uses: liquibase/build-logic/.../reusable-vulnerability-scan.yml)
runs for each matrix entry and will independently fail for missing images.
---
Nitpick comments:
In @.github/workflows/build-qa-docker.yml:
- Around line 641-669: The inline GHCR deletion script is duplicated in the
cleanup-ghcr job (step "Delete GHCR image") and in trivy.yml; extract it into a
reusable composite action named cleanup-ghcr and replace both inline steps with
a single call to that action. Implement the composite action to accept
inputs/env for GH_TOKEN, repository name/owner, ghcr_name and tag/sha, move the
shell logic (gh api calls and VERSION_ID handling) into the composite action's
run step, and update both workflows to invoke the cleanup-ghcr action and pass
the required inputs/env so future fixes are made in one place.
|
https://github.com/liquibase/docker/actions/runs/22169513679 this looks false positive, right? |
@rberezen it is also present in the production images https://github.com/liquibase/docker/actions/runs/22191852510 @filipelautert could you confirm? |
Summary
vulnerability-scanjob usingreusable-vulnerability-scan.ymlfrombuild-logic, matching the pattern used bytrivy.ymlfail_on_vulnerabilities: trueto catch CVEs before QA testingChanges
packages: writepermission for GHCR pushghcr_namefield to all matrix itemsvulnerability-scanjob calling the reusable workflowTest plan
Build QA Docker ImageswithAll (Community + Alpine + Secure)vulnerability-scanjobs run for each variantGenerated with Claude Code