Skip to content

Commit 60d6f70

Browse files
vmrh21claude
andcommitted
feat: add base image detection and FROM line update for base image CVEs
When a vulnerable package is not found in application manifests (requirements.txt, go.mod, package.json), check if it comes from the container base image (Dockerfile.konflux FROM line): - Use skopeo list-tags to check for newer base image tags - If newer tag available: update FROM line → real PR with note to verify the fix is included in the new tag before merging - If no newer tag: add Jira comment asking base image team (e.g. AIPCC for quay.io/aipcc/*) to release updated image → no PR created - If no Dockerfile found: fall back to transitive dependency guidance This covers both the general "base image CVE" case and the AIPCC-specific scenario with a single generic mechanism — no AIPCC-specific handling needed. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 841df52 commit 60d6f70

1 file changed

Lines changed: 59 additions & 4 deletions

File tree

workflows/cve-fixer/.claude/commands/cve.fix.md

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,14 +393,69 @@ Summary:
393393
- **Package found at a version** → compare against CVE affected version range
394394
- If version is in affected range → proceed with fix
395395
- If version is already patched → mark as already fixed (see below)
396-
- **Package not found in any manifest** → it may be transitive or RPM-installed
396+
- **Package not found in any manifest** → check whether it comes from the base image (Step 5.2.1b below) before falling back to transitive/RPM handling
397+
398+
**5.2.1b: Base image check (when package not found in application manifests)**
399+
400+
The package may be pre-installed in the container's base image rather than declared by the application.
401+
402+
```bash
403+
# Find Dockerfile.konflux (or Dockerfile) in the repo root
404+
DOCKERFILE=$(ls Dockerfile.konflux Dockerfile.konflux.* Dockerfile 2>/dev/null | head -1)
405+
406+
if [ -n "$DOCKERFILE" ]; then
407+
# Extract FROM line(s) — may be multiple stages
408+
BASE_IMAGES=$(grep -E '^FROM ' "$DOCKERFILE" | awk '{print $2}')
409+
echo "Base images in use: $BASE_IMAGES"
410+
fi
411+
```
412+
413+
**For each base image found:**
414+
```bash
415+
for BASE_IMAGE in $BASE_IMAGES; do
416+
REGISTRY=$(echo "$BASE_IMAGE" | cut -d/ -f1)
417+
IMAGE_REF=$(echo "$BASE_IMAGE" | sed 's/:.*$//') # strip tag
418+
CURRENT_TAG=$(echo "$BASE_IMAGE" | grep -oP '(?<=:)[^@]+' || echo "latest")
419+
420+
echo "Checking for newer tags of: $IMAGE_REF (current: $CURRENT_TAG)"
421+
422+
# List available tags (works for quay.io, registry.access.redhat.com, etc.)
423+
AVAILABLE_TAGS=$(skopeo list-tags "docker://${IMAGE_REF}" 2>/dev/null | \
424+
jq -r '.Tags[]' | sort -V)
425+
426+
# Find tags newer than current
427+
NEWER_TAGS=$(echo "$AVAILABLE_TAGS" | awk -v cur="$CURRENT_TAG" '$0 > cur')
428+
done
429+
```
430+
431+
**Interpret base image check results:**
432+
433+
- **Newer base image tag available** → the fix may already be in a newer tag. Update the `FROM` line in the Dockerfile:
434+
```bash
435+
LATEST_TAG=$(echo "$AVAILABLE_TAGS" | tail -1)
436+
sed -i "s|${BASE_IMAGE}|${IMAGE_REF}:${LATEST_TAG}|g" "$DOCKERFILE"
437+
```
438+
- Create a PR with this change
439+
- PR title: `fix(cve): CVE-YYYY-XXXXX — update base image to ${LATEST_TAG}`
440+
- PR note: "⚠️ This CVE is in the base image layer, not application code. Updated base image from `${CURRENT_TAG}` to `${LATEST_TAG}`. Verify the new tag includes the fix for `${PACKAGE}` before merging."
441+
- **Stop here — do not attempt application manifest fixes**
442+
443+
- **No newer base image tag available** → base image hasn't been updated yet:
444+
- Do NOT create a PR (no code change to make)
445+
- Add Jira comment: "CVE is in the base image layer (`${BASE_IMAGE}`). No updated base image tag is currently available. The base image team (e.g. AIPCC for `quay.io/aipcc/*`) needs to release an updated image before this can be resolved."
446+
- Document in `artifacts/cve-fixer/fixes/base-image-pending-CVE-YYYY-XXXXX.md`
447+
- Print: "⚠️ CVE-YYYY-XXXXX is in base image ${BASE_IMAGE} — no fix available yet. Jira comment added."
448+
- **Stop here — skip VEX justification and PR creation**
449+
450+
- **No Dockerfile found** → package may be a transitive or RPM dependency. Fall back to original guidance:
397451
- **Do NOT blindly add a direct dependency** — this can cause version conflicts or unnecessary bloat
398452
- Instead, document the situation and create PR with guidance:
399453
- **Go**: transitive deps require a `replace` directive in go.mod — add it only if intentional
400-
- **Python**: adding to requirements.txt may conflict with what pip resolves transitively; prefer updating the parent package that pulls it in
454+
- **Python**: prefer updating the parent package that pulls it in; use `pip-compile` to trace the dependency
401455
- **Node**: use npm `overrides` to force a safe version without adding a direct dep
402-
- Include note in PR: "⚠️ Package not found directly in manifests — may be a transitive or RPM-installed dependency. Manual review required to confirm the right fix approach."
403-
- **Both scan AND version check find nothing** → CVE not present in this repo. Do NOT create a PR.
456+
- Include note in PR: "⚠️ Package not found in application manifests — may be a transitive or RPM-installed dependency. Manual review required."
457+
458+
- **Both scan AND version check find nothing AND no base image issue** → CVE not present in this repo. Do NOT create a PR.
404459
Determine the appropriate VEX "Not Affected" justification and add it to the Jira issue:
405460
406461
**5.2.2: Determine VEX justification**

0 commit comments

Comments
 (0)