diff --git a/.github/workflows/container-rescan.yaml b/.github/workflows/container-rescan.yaml new file mode 100644 index 000000000..2ea14f914 --- /dev/null +++ b/.github/workflows/container-rescan.yaml @@ -0,0 +1,68 @@ +name: Scheduled Container Rescan + +on: + schedule: + - cron: '0 6 * * *' + workflow_dispatch: + +jobs: + rescan: + name: Rescan Container Image + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + actions: read + contents: read + security-events: write + env: + TRIVY_DISABLE_VEX_NOTICE: "true" + IMAGE_REF: docker.io/netboxlabs/pktvisor:latest-develop + + steps: + - name: Pull image + run: docker pull "$IMAGE_REF" + + - name: Scan for vulnerabilities + uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 + with: + image-ref: ${{ env.IMAGE_REF }} + format: json + output: trivy-output.json + vuln-type: os,library + scanners: vuln,secret + severity: CRITICAL,HIGH,MEDIUM,LOW + ignore-unfixed: true + exit-code: "0" + + - name: Build rescan summary + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const fs = require('fs'); + const data = JSON.parse(fs.readFileSync('trivy-output.json', 'utf8')); + const vulns = (data.Results || []).flatMap(r => + (r.Vulnerabilities || []).map(v => ({ ...v, target: r.Target })) + ); + const SEVERITY_LABEL = { CRITICAL: '🔴 **CRITICAL**', HIGH: '🟠 **HIGH**', MEDIUM: '🟡 MEDIUM', LOW: '⚪ LOW' }; + let summary = `### Rescan Complete\n\n**Image:** \`${process.env.IMAGE_REF}\`\n**Scanned at:** ${new Date().toISOString().replace('T', ' ').split('.')[0]} UTC\n\n`; + if (vulns.length === 0) { + summary += '_No vulnerabilities found._\n'; + } else { + summary += '| Library | CVE | Severity | Installed | Fixed | Title |\n|---|---|---|---|---|---|\n'; + for (const v of vulns) { + const title = (v.Title || '').replace(/\|/g, '\\|').substring(0, 80); + const cve = v.PrimaryURL ? `[${v.VulnerabilityID}](${v.PrimaryURL})` : v.VulnerabilityID; + summary += `| ${v.PkgName} | ${cve} | ${SEVERITY_LABEL[v.Severity] || v.Severity} | ${v.InstalledVersion} | ${v.FixedVersion || 'N/A'} | ${title} |\n`; + } + } + fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary); + + - name: Convert scan results to SARIF + if: "!cancelled()" + run: trivy convert --format sarif --output trivy-results.sarif trivy-output.json + + - name: Upload SARIF to GitHub Code Scanning + if: "!cancelled()" + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 + with: + sarif_file: trivy-results.sarif