Files
Charon/docs/plans/supply_chain_fix.md
GitHub Actions 28865a5f36 fix: harden supply chain workflow vulnerability reporting
Forced workflow failure if scan results are missing (prevents false negatives)
Fixed "Fail on critical" step to use calculated counts instead of missing action outputs
Added debug logging and file verification for Grype scans
Refactored shell scripts to prevent injection vulnerabilities
2026-02-06 08:06:01 +00:00

111 lines
5.1 KiB
Markdown

# Plan: Fix Supply Chain Vulnerability Reporting
## Objective
Fix the `supply-chain-pr.yml` workflow where PR comments report 0 vulnerabilities despite known CVEs, and ensure the workflow correctly fails on critical vulnerabilities.
## Context
The current workflow uses `anchore/scan-action` to scan for vulnerabilities. However, there are potential issues with:
1. **Output File Handling:** The workflow assumes `results.json` is created, but `anchore/scan-action` with `output-format: json` might not produce this file by default without an explicit `output-file` parameter or capturing output.
2. **Parsing Logic:** If the file is missing, the `jq` parsing gracefully falls back to 0, masking the error.
3. **Failure Condition:** The failure step references `${{ steps.grype-scan.outputs.critical_count }}`, which likely does not exist on the `anchore/scan-action` step. It should reference the calculated output from the parsing step.
## Research & Diagnosis Steps
### 1. Debug Output paths
We need to verify if `results.json` is actually generated.
- **Action:** Add a step to list files in the workspace immediately after the scan.
- **Action:** Add a debug `cat` of the results file if it exists, or header of it.
### 2. Verify `anchore/scan-action` behavior
The `anchore/scan-action` (v7.3.2) documentation suggests that `output-format` is used, but typically it defaults to `results.[format]`. However, explicit `output-file` prevents ambiguity.
## Implementation Plan
### Phase 1: Robust Path & Debugging
1. **Explicit Output File:** Modify the `anchore/scan-action` step to explicitly set `output-format: json` AND likely we should try to rely on the default behavior but *check* it.
*Actually, better practice:* The action supports `output-format` as a list. If we want a file, we usually just look for it.
*Correction:* We will explicitly check for the file and fail if missing, rather than defaulting to 0.
2. **List Files:** Add `ls -la` after scan to see exactly what files are created.
### Phase 2: Fix Logic Errors
1. **Update "Fail on critical vulnerabilities" step**:
- Change `${{ steps.grype-scan.outputs.critical_count }}` to `${{ steps.vuln-summary.outputs.critical_count }}`.
2. **Robust `jq` parsing**:
- In `Process vulnerability results`, explicitly check for existence of `results.json` (or whatever the action outputs).
- If missing, **EXIT 1** instead of setting counts to 0. This forces us to fix the path issue rather than silently passing.
- Use `tee` or `cat` to print the first few lines of the JSON to stdout for debugging logs.
### Phase 3: Validation
1. Run the workflow on a PR (or simulate via push).
2. Verify the PR comment shows actual numbers.
3. Verify the workflow fails if critical vulnerabilities are found (or we can lower the threshold to test).
## Detailed Changes
### `supply-chain-pr.yml`
```yaml
# ... inside steps ...
- name: Scan for vulnerabilities
if: steps.set-target.outputs.image_name != ''
uses: anchore/scan-action@7037fa011853d5a11690026fb85feee79f4c946c # v7.3.2
id: grype-scan
with:
sbom: sbom.cyclonedx.json
fail-build: false
output-format: json
# We might need explicit output selection implies asking for 'json' creates 'results.json'
- name: Debug Output Files
if: steps.set-target.outputs.image_name != ''
run: |
echo "📂 Listing workspace files:"
ls -la
- name: Process vulnerability results
if: steps.set-target.outputs.image_name != ''
id: vuln-summary
run: |
# The scan-action output behavior verification
JSON_RESULT="results.json"
SARIF_RESULT="results.sarif"
# [NEW] Check if scan actually produced output
if [[ ! -f "$JSON_RESULT" ]]; then
echo "❌ Error: $JSON_RESULT not found!"
echo "Available files:"
ls -la
exit 1
fi
mv "$JSON_RESULT" grype-results.json
# Debug content (head)
echo "📄 Grype JSON Preview:"
head -n 20 grype-results.json
# ... existing renaming for sarif ...
# ... existing jq logic, but remove 'else' block for missing file since we exit above ...
# ...
- name: Fail on critical vulnerabilities
if: steps.set-target.outputs.image_name != ''
run: |
# [FIX] Use the output from the summary step, NOT the scan step
CRITICAL_COUNT="${{ steps.vuln-summary.outputs.critical_count }}"
if [[ "${CRITICAL_COUNT}" -gt 0 ]]; then
echo "🚨 Found ${CRITICAL_COUNT} CRITICAL vulnerabilities!"
echo "Please review the vulnerability report and address critical issues before merging."
exit 1
fi
```
### Acceptance Criteria
- [ ] Workflow "Fail on critical vulnerabilities" uses `steps.vuln-summary.outputs.critical_count`.
- [ ] `Process vulnerability results` step fails if the scan output file is missing.
- [ ] Debug logging (ls -la) is present to confirm file placement.