name: Security Audit
on:
schedule:
- cron: "0 2 * * *"
workflow_dispatch:
pull_request:
paths:
- "Cargo.toml"
- "Cargo.lock"
env:
CARGO_TERM_COLOR: always
jobs:
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Run security audit
run: cargo audit --deny warnings
- name: Create issue on failure
if: failure()
uses: actions/github-script@v8
with:
script: |
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🔒 Security Audit Failed',
body: `Security vulnerabilities detected in dependencies.
**Action Required**: Review and update vulnerable dependencies.
Run locally:
\`\`\`bash
cargo audit
\`\`\`
See the [workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`,
labels: ['security', 'dependencies']
});
dependency-check:
name: Dependency Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-outdated
run: cargo install cargo-outdated
- name: Check for outdated dependencies
run: cargo outdated --exit-code 1 || true
- name: Comment on PR with outdated deps
if: github.event_name == 'pull_request'
uses: actions/github-script@v8
with:
script: |
const { execSync } = require('child_process');
try {
const output = execSync('cargo outdated', { encoding: 'utf-8' });
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## Outdated Dependencies\n\n\`\`\`\n${output}\n\`\`\``
});
} catch (error) {
console.log('No outdated dependencies or error:', error.message);
}
license-check:
name: License Compliance
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deny
run: cargo install cargo-deny
- name: Check licenses
run: |
cat > deny.toml << 'EOF'
[licenses]
version = 2
# We want high confidence that the licenses are valid
confidence-threshold = 0.8
# Allowed licenses (permissive open source)
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unlicense",
"0BSD",
"Unicode-DFS-2016",
"Unicode-3.0",
]
[bans]
# Warn on multiple versions of the same crate
multiple-versions = "warn"
wildcards = "allow"
EOF
cargo deny check licenses
sast-scan:
name: SAST Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-geiger (unsafe code scanner)
run: cargo install cargo-geiger
- name: Scan for unsafe code
run: cargo geiger --all-features --output-format GitHubMarkdown >> $GITHUB_STEP_SUMMARY || true
- name: Run clippy with security lints
run: |
cargo clippy --all-targets --all-features -- \
-W clippy::all \
-W clippy::pedantic \
-W clippy::cargo \
-W clippy::nursery