Merge pull request #224 from MerlinTheWhiz/fix/stale-accrual-before-b… #194
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Credence-Contracts Security Scanning | |
| # Automated security analysis for smart contracts | |
| # Runs on push and PR to main/develop branches | |
| name: Security Scanning | |
| on: | |
| push: | |
| branches: [main, master, develop] | |
| pull_request: | |
| branches: [main, master, develop] | |
| # Allow manual trigger for ad-hoc scans | |
| workflow_dispatch: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| cargo-audit: | |
| name: Dependency Vulnerability Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit --version 0.22.0 --locked | |
| - name: Cache cargo | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-audit-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-audit- | |
| - name: Run cargo audit | |
| run: | | |
| cargo audit --json > audit-report.json || true | |
| cargo audit | |
| - name: Check for critical vulnerabilities | |
| run: | | |
| CRITICAL_COUNT=$(jq '[.vulnerabilities.list[] | select(.advisory.severity == "critical")] | length' audit-report.json) | |
| echo "Critical vulnerabilities found: $CRITICAL_COUNT" | |
| if [ "$CRITICAL_COUNT" -gt 0 ]; then | |
| echo "❌ CRITICAL vulnerabilities detected - failing pipeline" | |
| exit 1 | |
| fi | |
| echo "✅ No critical vulnerabilities found" | |
| - name: Upload audit report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: cargo-audit-report | |
| path: audit-report.json | |
| retention-days: 30 | |
| clippy-security: | |
| name: Static Analysis (Clippy Security Lints) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - name: Cache cargo | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-clippy- | |
| - name: Run Clippy with security lints | |
| run: | | |
| cargo clippy --all-targets --message-format=json -- \ | |
| -W clippy::integer_arithmetic \ | |
| -W clippy::unwrap_used \ | |
| -W clippy::expect_used \ | |
| -W clippy::panic \ | |
| -W clippy::todo \ | |
| -W clippy::unimplemented \ | |
| -W clippy::indexing_slicing \ | |
| -W clippy::cast_possible_truncation \ | |
| -W clippy::cast_sign_loss \ | |
| -D warnings \ | |
| 2>&1 | tee clippy-output.json | |
| - name: Parse Clippy results | |
| if: always() | |
| run: | | |
| # Extract warnings and errors from JSON output | |
| echo "## Clippy Security Analysis Summary" > clippy-summary.txt | |
| echo "" >> clippy-summary.txt | |
| # Count issues by severity | |
| ERRORS=$(grep -c '"level":"error"' clippy-output.json || echo "0") | |
| WARNINGS=$(grep -c '"level":"warning"' clippy-output.json || echo "0") | |
| echo "- Errors: $ERRORS" >> clippy-summary.txt | |
| echo "- Warnings: $WARNINGS" >> clippy-summary.txt | |
| echo "" >> clippy-summary.txt | |
| cat clippy-summary.txt | |
| # Generate HTML report | |
| echo "<html><head><title>Clippy Security Report</title></head><body>" > clippy-report.html | |
| echo "<h1>Clippy Security Analysis</h1>" >> clippy-report.html | |
| echo "<pre>" >> clippy-report.html | |
| cat clippy-summary.txt >> clippy-report.html | |
| echo "</pre>" >> clippy-report.html | |
| echo "<h2>Detailed Output</h2><pre>" >> clippy-report.html | |
| cat clippy-output.json >> clippy-report.html | |
| echo "</pre></body></html>" >> clippy-report.html | |
| - name: Upload Clippy report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: clippy-security-report | |
| path: | | |
| clippy-report.html | |
| clippy-output.json | |
| clippy-summary.txt | |
| retention-days: 30 | |
| cargo-geiger: | |
| name: Unsafe Code Detection | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-geiger | |
| run: cargo install cargo-geiger --version 0.12.0 --locked | |
| - name: Cache cargo | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-geiger-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-geiger- | |
| - name: Run cargo-geiger on contracts | |
| run: | | |
| # Get list of workspace members | |
| MEMBERS=$(cargo metadata --no-deps --format-version 1 | jq -r '.workspace_members[]' | cut -d' ' -f1) | |
| echo "# Cargo Geiger Report" > geiger-report.md | |
| echo "" >> geiger-report.md | |
| # Run cargo geiger for each workspace member | |
| for member in $MEMBERS; do | |
| echo "## Package: $member" >> geiger-report.md | |
| echo "" >> geiger-report.md | |
| cargo geiger -p "$member" --output-format GitHubMarkdown >> geiger-report.md 2>&1 || true | |
| echo "" >> geiger-report.md | |
| done | |
| # Also run a summary scan | |
| echo "## Summary" >> geiger-report.md | |
| cargo geiger 2>&1 || true | |
| - name: Check for unsafe code in contracts | |
| run: | | |
| # Get list of workspace members | |
| MEMBERS=$(cargo metadata --no-deps --format-version 1 | jq -r '.workspace_members[]' | cut -d' ' -f1) | |
| TOTAL_UNSAFE=0 | |
| # Check each contract package | |
| for member in $MEMBERS; do | |
| if [[ "$member" == credence_* ]]; then | |
| UNSAFE_COUNT=$(cargo geiger -p "$member" --output-format Json 2>/dev/null | jq '[.packages[] | select(.name | startswith("credence_")) | .unsafety.used.functions + .unsafety.used.exprs + .unsafety.used.impls + .unsafety.used.traits + .unsafety.used.methods] | add // 0' || echo "0") | |
| echo "Unsafe code in $member: $UNSAFE_COUNT" | |
| TOTAL_UNSAFE=$((TOTAL_UNSAFE + UNSAFE_COUNT)) | |
| fi | |
| done | |
| echo "Total unsafe code blocks in contracts: $TOTAL_UNSAFE" | |
| if [ "$TOTAL_UNSAFE" -gt 0 ]; then | |
| echo "⚠️ WARNING: Unsafe code detected in contracts - review required" | |
| echo "This is a warning only - pipeline will continue" | |
| else | |
| echo "✅ No unsafe code in contracts" | |
| fi | |
| - name: Upload geiger report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: cargo-geiger-report | |
| path: geiger-report.md | |
| retention-days: 30 | |
| security-summary: | |
| name: Security Scan Summary | |
| runs-on: ubuntu-latest | |
| needs: [cargo-audit, clippy-security, cargo-geiger] | |
| if: always() | |
| steps: | |
| - name: Download all reports | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: security-reports | |
| - name: Generate summary | |
| run: | | |
| echo "# Security Scan Summary" > summary.md | |
| echo "" >> summary.md | |
| echo "## Scan Results" >> summary.md | |
| echo "" >> summary.md | |
| # Check job statuses | |
| AUDIT_STATUS="${{ needs.cargo-audit.result }}" | |
| CLIPPY_STATUS="${{ needs.clippy-security.result }}" | |
| GEIGER_STATUS="${{ needs.cargo-geiger.result }}" | |
| echo "- Dependency Audit: $AUDIT_STATUS" >> summary.md | |
| echo "- Clippy Security Lints: $CLIPPY_STATUS" >> summary.md | |
| echo "- Unsafe Code Detection: $GEIGER_STATUS" >> summary.md | |
| echo "" >> summary.md | |
| if [ "$AUDIT_STATUS" = "failure" ]; then | |
| echo "❌ **CRITICAL**: Dependency vulnerabilities detected" >> summary.md | |
| elif [ "$CLIPPY_STATUS" = "failure" ]; then | |
| echo "❌ **CRITICAL**: Security lint violations detected" >> summary.md | |
| else | |
| echo "✅ All security scans passed" >> summary.md | |
| fi | |
| cat summary.md | |
| - name: Upload summary | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: security-summary | |
| path: summary.md | |
| retention-days: 30 |