name: ZAP Security Scan on: workflow_dispatch: inputs: url: description: "URL to scan (default is the GitHub Pages site)" required: false default: "https://hack23.github.io/game/" scan_type: description: "Scan type: 'baseline' (fast, passive) or 'full' (active, slow)" required: false # Default to the safe/passive scan; full active scan must be opted into. default: "baseline" type: choice options: - baseline - full # Run a baseline scan against the public site every Monday at 06:00 UTC. # This is a low-traffic window that gives us continuous DAST coverage at the # start of each working week without manual dispatch and without competing # with weekday CI load. schedule: - cron: "0 6 * * 1" # Restrict permissions to minimum required permissions: contents: read issues: write # Required if you want ZAP to create GitHub issues for vulnerabilities jobs: zap_baseline_scan: name: ZAP Baseline Scan (passive) # Baseline runs on schedule, on workflow_dispatch when not explicitly "full", # and is the safe default. It performs only passive checks (≈1-3 minutes). if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.scan_type != 'full') runs-on: ubuntu-26.04 timeout-minutes: 30 steps: - name: Harden Runner uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit - name: Checkout repository (for rules file) uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: ZAP Baseline Scan uses: zaproxy/action-baseline@de8ad967d3548d44ef623df22cf95c3b0baf8b25 # v0.15.0 with: token: ${{ github.token }} # Pin to immutable digest of ghcr.io/zaproxy/zaproxy:stable so scheduled # scans are reproducible week-to-week and not subject to silent base-image # updates. Update this digest in lockstep with ZAP releases. docker_name: "ghcr.io/zaproxy/zaproxy:stable@sha256:8770b23f9e8b49038f413cb2b10c58c901e5b6717be221a22b1bcab5c9771b8a" target: ${{ github.event.inputs.url || 'https://hack23.github.io/game/' }} rules_file_name: ".zap/rules.tsv" allow_issue_writing: true fail_action: false artifact_name: zap-baseline-report zap_full_scan: name: ZAP Full Scan (active) # Full scan only runs when explicitly requested via workflow_dispatch with # scan_type=full. It is significantly slower (≥30 minutes) and performs # active attacks, so we never run it on schedule. if: github.event_name == 'workflow_dispatch' && github.event.inputs.scan_type == 'full' runs-on: ubuntu-26.04 timeout-minutes: 120 steps: - name: Harden Runner uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit - name: Checkout repository (for rules file) uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: ZAP Full Scan uses: zaproxy/action-full-scan@3c58388149901b9a03b7718852c5ba889646c27c # v0.13.0 with: token: ${{ github.token }} # Pin to immutable digest of ghcr.io/zaproxy/zaproxy:stable for # reproducibility of full active scans. Keep in sync with the digest # used by the baseline job above. docker_name: "ghcr.io/zaproxy/zaproxy:stable@sha256:8770b23f9e8b49038f413cb2b10c58c901e5b6717be221a22b1bcab5c9771b8a" target: ${{ github.event.inputs.url }} rules_file_name: ".zap/rules.tsv" allow_issue_writing: true fail_action: false artifact_name: zap-full-report