name: Security Audit on: push: branches: - main pull_request: types: [opened, synchronize, reopened, ready_for_review] # Run weekly on Monday at 06:00 UTC schedule: - cron: "0 6 * * 1" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: isdraft: # Skip draft PRs but always run on schedule/push if: github.event_name != 'pull_request' || !github.event.pull_request.draft runs-on: ubuntu-latest steps: - run: echo "Not a draft" cargo-deny: needs: isdraft runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false matrix: checks: - advisories - licenses - sources steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979 # v2.0.15 with: command: check ${{ matrix.checks }} cargo-audit: needs: isdraft runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install cargo-audit run: cargo install cargo-audit --locked - name: Run cargo audit run: | echo "## Cargo Audit Results" >> $GITHUB_STEP_SUMMARY # Ignored advisories: upstream transitive deps with no available fix. # Review quarterly and remove ignores when patches become available. cargo audit \ --ignore RUSTSEC-2026-0006 \ --ignore RUSTSEC-2026-0020 \ --ignore RUSTSEC-2026-0021 \ --ignore RUSTSEC-2026-0049 \ 2>&1 | tee audit-output.txt RESULT=${PIPESTATUS[0]} if [ $RESULT -ne 0 ]; then echo "### Vulnerabilities found" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY head -500 audit-output.txt >> $GITHUB_STEP_SUMMARY if [ "$(wc -l < audit-output.txt)" -gt 500 ]; then echo "... (truncated, see full output in job logs)" >> $GITHUB_STEP_SUMMARY fi echo '```' >> $GITHUB_STEP_SUMMARY exit $RESULT else echo "### No vulnerabilities found" >> $GITHUB_STEP_SUMMARY fi confirm-security-audit-passed: runs-on: ubuntu-latest name: Security audit summary needs: [cargo-deny, cargo-audit] if: always() && !cancelled() steps: - run: | tee resultfile <<< '${{ toJSON(needs) }}' FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) if [ $FAILURES -gt 0 ]; then echo "### Security audit FAILED" >> $GITHUB_STEP_SUMMARY echo "Review the cargo-deny and cargo-audit job outputs for details." >> $GITHUB_STEP_SUMMARY exit 1 else echo '### All security audits passed' >> $GITHUB_STEP_SUMMARY fi