Repository navigation
Fix/rebase image and add scan gate - #372
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The release workflow can republish an existing version tag on subsequent pushes to main, potentially mutating already-released artifacts (especially with SECURITY_REFRESH forcing rebuild differences).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates the cloudos-cli container build and release pipeline to reduce/avoid CRITICAL/HIGH vulnerabilities (Harbor) and to add a CI scan gate so releases only publish after passing the vulnerability check.
Changes:
- Rebased the Docker image on
condaforge/miniforge3, added OS package upgrades, and removed specific scan-reported inventories/components. - Updated the release workflow to build, scan with Trivy (CRITICAL/HIGH gate), then push artifacts; tag + GitHub Release are created at the end.
- Bumped version to
2.96.0and added a changelog entry.
File summaries
| File | Description |
|---|---|
| Dockerfile | Switches base image, updates OS packages, builds conda env, installs cloudos-cli, and applies scan-focused cleanups. |
| .github/workflows/release.yml | Adds a Trivy scan gate and reorders tagging/release creation to happen only after artifacts publish. |
| cloudos_cli/_version.py | Version bump to 2.96.0. |
| CHANGELOG.md | Adds release notes for v2.96.0. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical container-scanning and release-tagging issues remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (3)
Previously missed (1) — in code that hasn't changed since the last review.
Dockerfile:57
- Passing a new
SECURITY_REFRESHvalue does not invalidate this layer because theARGis never referenced by the followingRUN; Docker only includes an ARG in the cache key when it is used by an instruction. A cached final upgrade can therefore leave stale OS packages despite the workflow comment. Expand the argument in this RUN (or build with--no-cache) so the timestamp actually busts the cache.
.github/workflows/release.yml:132
- This pushes the version tag before the PyPI upload and before the Git tag marks the release complete. If a later step fails, the image remains publicly available under v$VER; a retry rebuilds with a new SECURITY_REFRESH value and can overwrite that same Quay tag (and :latest) with a different image, so the published container is not immutable. Claim/publish the version atomically or retain and republish the exact built digest on retries.
- name: Push image to Quay (version tag)
run: |
set -euo pipefail
VER="${{ needs.check.outputs.version }}"
docker push "${QUAY_REPO}:v${VER}"
.github/workflows/release.yml:55
- The gate treats any existing tag as a completed release, but the tag is created before
softprops/action-gh-releaseruns. If the release action fails after the tag push, a retry or later push seesRELEASE=falseand permanently skips this version, leaving the GitHub Release absent even though the image and package may already be published. Make the gate verify/reconcile the GitHub Release, or make the final release creation retryable without using tag existence alone as the completion marker.
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
echo "$TAG already exists: this version has shipped, nothing to do."
echo "Bump __version__ in cloudos_cli/_version.py to cut a new release."
echo "RELEASE=false" >> "$GITHUB_OUTPUT"
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
A critical Dockerfile cleanup issue and moderate release workflow race conditions remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (3)
Previously missed (1) — in code that hasn't changed since the last review.
Dockerfile:70
SECURITY_REFRESHis never expanded in the followingRUN, so changing--build-arg SECURITY_REFRESH=$(date +%s)does not invalidate this layer. Docker can reuse the cachedapt-get upgrade, leaving the release scan to inspect an image without the latest security updates; reference the argument in the command (for example, with anechobeforeapt-get update).
.github/workflows/release.yml:152
git ls-remoteis only a preflight read; it does not reserverefs/tags/$TAG. Two runs outside this workflow's concurrency group can both pass it and then push the mutablev$VERimage tag, allowing the later run to overwrite the image that was scanned. Since the surrounding comment explicitly calls out old/manual runs, use an atomic remote reservation or lock instead of relying on this check.
if git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null 2>&1; then
echo "::error::$TAG appeared on origin while this job was building."
echo "Another run has already released this version; refusing to"
echo "overwrite ${QUAY_REPO}:$TAG with a different image."
exit 1
.github/workflows/release.yml:180
NEWESTis read from the tags fetched at the start of the release job, but the workflow explicitly acknowledges runs that may not be covered by its concurrency group. If a newer release tag is pushed after checkout, this stale list can make an older version pass the comparison and overwrite:latest, reversing release order. Refresh tags fromoriginimmediately before this decision and add a final/serialized guard for publishing:latest; the check at lines 148-153 only protects the version tag.
NEWEST="$(git tag --list 'v*' | sed 's/^v//' | sort -V | tail -1)"
if [ -n "$NEWEST" ] \
&& [ "$(printf '%s\n%s\n' "$NEWEST" "$VER" | sort -V | tail -1)" != "$VER" ]; then
echo "v$VER is older than the newest tag (v$NEWEST); leaving :latest unchanged."
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Four moderate unresolved review findings remain in the Dockerfile and release workflow.
Review details
Suppressed comments (4)
Previously missed (1) — in code that hasn't changed since the last review.
Dockerfile:57
SECURITY_REFRESHis never referenced by the followingRUN; Docker does not include an unusedARGvalue in that instruction's cache key. Therefore the release workflow's--build-arg SECURITY_REFRESH=$(date +%s)will not invalidate a cachedapt-get upgradelayer, so a reused build can ship stale OS packages despite the stated refresh guarantee. Reference the arg in theRUN(for example, with anecho) before the update.
.github/workflows/release.yml:180
NEWESTincludes pre-release tags even though the preceding branch deliberately excludes the current pre-release from:latest. Ifv2.97.0a1exists and a stable patchv2.96.1is then released,sort -Vtreats the pre-release as newer and this exits without moving:latest, leaving it on the older stable image. FilterNEWESTto final tags before comparing.
NEWEST="$(git tag --list 'v*' | sed 's/^v//' | sort -V | tail -1)"
if [ -n "$NEWEST" ] \
&& [ "$(printf '%s\n%s\n' "$NEWEST" "$VER" | sort -V | tail -1)" != "$VER" ]; then
echo "v$VER is older than the newest tag (v$NEWEST); leaving :latest unchanged."
.github/workflows/release.yml:160
- The version image is published before the PyPI upload and final tag. If a later step fails, this leaves a public
v${VER}image without a release, and a retry rebuilds with a new security-refresh value and can overwrite that same version tag with a different digest. Publish artifacts only after the preceding release steps succeed, or make retries reuse an immutable image digest.
- name: Push image to Quay (version tag)
run: |
set -euo pipefail
VER="${{ needs.check.outputs.version }}"
docker push "${QUAY_REPO}:v${VER}"
.github/workflows/release.yml:218
- The Git tag is pushed before
softprops/action-gh-releaseruns. If release creation fails, a rerun reaches thecheckjob, sees the tag, and skips the entire release job, so the GitHub Release is never retried even though the image and PyPI artifacts may exist. Make the gate verify the GitHub Release too, or make finalization idempotent when the tag already exists.
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
fi
- name: Create GitHub Release with auto-generated notes
- Files reviewed: 6/6 changed files
- Comments generated: 0 new
- Review effort level: Lite
Overview
This PR implements the necessary changes for cloudos-cli container to pass the harbor scan without any critical or high vulnerabilities.
Changes
Acceptance Criteria
The container was used in this run of CVA pipeline
https://cloudos.lifebit.ai/app/advanced-analytics/analyses/6aa17084ad77e94ee9c9fa92
testing the container
Using a custom script I also tested the container
custom script