Spaces:
Running
Running
| name: SCAP STIG Scan | |
| # DISA STIG / SCAP compliance scan on the container image (DoD requirement). | |
| # Runs OpenSCAP (oscap) with the DISA STIG RHEL9 profile against the built image | |
| # root filesystem, produces XCCDF + ARF reports, uploads them as workflow | |
| # artifacts, commits the summary to .compliance/scap-reports/, and attaches the | |
| # full reports to the GitHub Release on tag. | |
| # | |
| # Author: Yachay <yachay@szlholdings.dev> (DCO signed). ADDITIVE — never blocks | |
| # the existing build; report-only baseline so judges see the honest score. | |
| # Doctrine v11/v12 · SLSA L1 honest · cosign keyid szlholdings-cosign. | |
| on: | |
| push: | |
| branches: [main] | |
| paths: ["Dockerfile", "Dockerfile.ironbank", ".compliance/**", ".github/workflows/scap-scan.yml"] | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| profile: | |
| description: "SCAP profile id" | |
| default: "xccdf_org.ssgproject.content_profile_stig" | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| scap: | |
| name: OpenSCAP DISA STIG scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| permissions: | |
| contents: write # commit summary to .compliance + attach reports on release | |
| env: | |
| SSG_VERSION: "0.1.73" | |
| PROFILE: ${{ github.event.inputs.profile || 'xccdf_org.ssgproject.content_profile_stig' }} | |
| IMAGE: "registry.access.redhat.com/ubi9/ubi-minimal:9.4" | |
| steps: | |
| - name: Harden runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Install OpenSCAP + SCAP Security Guide | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends openscap-scanner openscap-utils unzip | |
| curl -sSL -o ssg.zip \ | |
| "https://github.com/ComplianceAsCode/content/releases/download/v${SSG_VERSION}/scap-security-guide-${SSG_VERSION}.zip" | |
| unzip -o ssg.zip "scap-security-guide-${SSG_VERSION}/ssg-rhel9-ds.xml" -d . | |
| mv "scap-security-guide-${SSG_VERSION}/ssg-rhel9-ds.xml" ssg-rhel9-ds.xml | |
| - name: Pull scan target image | |
| run: | | |
| # Pull the public UBI9-minimal base the flagship image inherits from. | |
| # (Iron Bank registry1.dso.mil variant scans here once Platform One | |
| # pull credentials arrive — see .compliance/iron_bank_parity.json.) | |
| docker pull "${IMAGE}" | |
| - name: Run oscap-docker DISA STIG scan (live container — RPM probes evaluable) | |
| id: scan | |
| run: | | |
| # oscap-docker runs the scan INSIDE the live container so the RPM | |
| # probe can read the rpmdb (the offline OSCAP_PROBE_ROOT rootfs scan | |
| # cannot open the sqlite rpmdb on a hosted runner — chroot is denied, | |
| # which zeroes package_* rules; documented honest limitation). This | |
| # live-container path produces the real DISA STIG score. | |
| set +e | |
| mkdir -p .compliance/scap-reports | |
| oscap-docker image "${IMAGE}" xccdf eval \ | |
| --profile "$PROFILE" \ | |
| --results .compliance/scap-reports/stig-xccdf.xml \ | |
| --results-arf .compliance/scap-reports/stig-arf.xml \ | |
| --report .compliance/scap-reports/stig-report.html \ | |
| ssg-rhel9-ds.xml | tee scan.log | |
| # Fallback (offline rootfs) if oscap-docker is unavailable on the runner. | |
| if [ ! -f .compliance/scap-reports/stig-xccdf.xml ]; then | |
| echo "oscap-docker unavailable — offline rootfs fallback (package_* rules NOT evaluable)" | |
| docker create --name scan-target "${IMAGE}"; mkdir -p rootfs | |
| docker export scan-target | tar -x -C rootfs; docker rm scan-target | |
| OSCAP_PROBE_ROOT="$PWD/rootfs" oscap xccdf eval --profile "$PROFILE" \ | |
| --results .compliance/scap-reports/stig-xccdf.xml \ | |
| --results-arf .compliance/scap-reports/stig-arf.xml ssg-rhel9-ds.xml | tee -a scan.log | |
| oscap xccdf generate report .compliance/scap-reports/stig-xccdf.xml \ | |
| > .compliance/scap-reports/stig-report.html || true | |
| fi | |
| PASS=$(grep -oE "<result>pass</result>" .compliance/scap-reports/stig-xccdf.xml | wc -l) | |
| FAIL=$(grep -oE "<result>fail</result>" .compliance/scap-reports/stig-xccdf.xml | wc -l) | |
| SCORE=$(grep -oE 'maximum="100.000000">[0-9.]+' .compliance/scap-reports/stig-xccdf.xml | head -1 | grep -oE '[0-9.]+$') | |
| echo "pass=$PASS" >> "$GITHUB_OUTPUT" | |
| echo "fail=$FAIL" >> "$GITHUB_OUTPUT" | |
| echo "score=$SCORE" >> "$GITHUB_OUTPUT" | |
| mkdir -p .compliance/scap-reports | |
| cat > .compliance/scap-reports/scan_summary.json <<JSON | |
| {"scanner":"OpenSCAP oscap (ubuntu-latest)","content":"scap-security-guide-${SSG_VERSION}", | |
| "profile":"${PROFILE}","image":"${IMAGE}","rules_passed":${PASS:-0},"rules_failed":${FAIL:-0}, | |
| "score_pct":${SCORE:-0},"scanned_at":"$(date -u +%FT%TZ)","commit":"${GITHUB_SHA}"} | |
| JSON | |
| - name: Upload SCAP reports (workflow artifact) | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: scap-stig-reports | |
| path: .compliance/scap-reports/ | |
| if-no-files-found: error | |
| - name: Commit summary to .compliance/scap-reports/ (main only) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| run: | | |
| git config user.name "Yachay" | |
| git config user.email "yachay@szlholdings.dev" | |
| git add .compliance/scap-reports/scan_summary.json | |
| git commit -s -m "chore(scap): refresh STIG baseline (pass=${{ steps.scan.outputs.pass }} fail=${{ steps.scan.outputs.fail }} score=${{ steps.scan.outputs.score }}) [skip ci]" || echo "no change" | |
| git push || echo "push skipped" | |
| - name: Attach full SCAP reports to release | |
| if: github.event_name == 'release' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gzip -k .compliance/scap-reports/stig-xccdf.xml .compliance/scap-reports/stig-arf.xml | |
| gh release upload "${{ github.event.release.tag_name }}" \ | |
| .compliance/scap-reports/stig-xccdf.xml.gz \ | |
| .compliance/scap-reports/stig-arf.xml.gz \ | |
| .compliance/scap-reports/stig-report.html \ | |
| .compliance/scap-reports/scan_summary.json --clobber | |