Skip to content

Vulnerability Scan

Vulnerability Scan #80

Workflow file for this run

name: Vulnerability Scan
on:
workflow_dispatch: # Allows manual triggering
schedule:
- cron: "0 2 * * 1" # Run weekly at 2 AM on Monday
pull_request:
paths:
- 'Dockerfile'
- '.github/workflows/security.yaml'
permissions:
contents: write
packages: write
issues: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-image:
name: Build Docker Image
runs-on: ubuntu-latest
outputs:
image_name: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Log in to the GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: type=sha,prefix=scan-
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Save image to a tar file
run: docker save ${{ steps.meta.outputs.tags }} -o image.tar
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: image-tar
path: image.tar
retention-days: 1
scan-and-report:
name: Vulnerability Scan
needs: build-image
runs-on: [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium]
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Download image artifact
uses: actions/download-artifact@v4
with:
name: image-tar
- name: Install secscan client
run: |
sudo snap install canonical-secscan-client
sudo snap connect canonical-secscan-client:home system:home
- name: Run security scan
continue-on-error: true
id: scan
run: |
secscan-client --batch submit \
--ssdlc-product-name 'landscape-ui' \
--ssdlc-cycle '25.10' \
--ssdlc-product-version '1.17.0' \
--ssdlc-product-channel 'edge' \
--scanner trivy \
--type container-image \
--format oci \
image.tar \
--wait-and-print > secscan-results.txt
- name: Analyze Scan Results and Determine Job Status
if: always()
id: analysis
run: |
EXIT_CODE=${{ steps.scan.exit_code }}
echo "Scan step exited with code: $EXIT_CODE"
# Exit code 0 means a clean scan
if [ "$EXIT_CODE" == "0" ]; then
echo "Success: Scan completed and no vulnerabilities were found."
exit 0
fi
# Exit codes 100-199 mean CVEs were found
if [ "$EXIT_CODE" -ge 100 ] && [ "$EXIT_CODE" -lt 200 ]; then
echo "::error::Vulnerabilities were detected by the scan."
if grep -q -E 'CRITICAL|HIGH' secscan-results.txt; then
echo "::error::High or Critical vulnerabilities found."
else
echo "::warning::Medium or Low vulnerabilities found."
fi
exit 1 # Fail the job
fi
# Any other non-zero exit code is a processing error
echo "::error::The security scan failed to run properly. Exit code: $EXIT_CODE"
if [ -f secscan-results.txt ] && grep -q -i 'Scan has failed' secscan-results.txt; then
echo "::error::The secscan tool reported a failure in its output. See results for details."
fi
exit 1
- name: Upload Scan Results on Success
if: success()
uses: actions/upload-artifact@v4
with:
name: secscan-results
path: secscan-results.txt
- name: Create Issue on Failure
if: failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Vulnerability scan found high/critical issues or failed to run." > issue-body.txt
echo "" >> issue-body.txt
echo "Please check the workflow run logs for the 'Run security scan' step for details." >> issue-body.txt
echo "" >> issue-body.txt
echo "### Scan Output" >> issue-body.txt
echo '```' >> issue-body.txt
if [ -f secscan-results.txt ]; then
cat secscan-results.txt
else
echo "Scan results file not found."
fi >> issue-body.txt
echo '```' >> issue-body.txt
gh issue create --title "High/Critical Vulnerabilities Detected in Landscape UI" --body-file issue-body.txt --label "security,bug"
generate-and-submit-sbom:
name: Generate and Submit SBOM
needs: build-image
runs-on: ubuntu-latest
steps:
- name: Log in to the GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run Trivy to generate SBOM and submit to Dependency Graph
uses: aquasecurity/trivy-action@0.33.1
with:
image-ref: ${{ needs.build-image.outputs.image_name }}
format: 'spdx-json'
output: 'dependency-results.sbom.json'
github-pat: ${{ secrets.GITHUB_TOKEN }}
severity: "HIGH,CRITICAL"
scanners: "vuln"
- name: Upload SBOM as an Artifact
uses: actions/upload-artifact@v4
with:
name: sbom-report-json
path: 'dependency-results.sbom.json'
retention-days: 30