sdk-github-actions.yml
# Argus Security Scan — GitHub Actions
#
# Runs argus scan on push/PR, posts results as a PR comment,
# and uploads SARIF to GitHub Code Security.
#
# Prerequisites:
# - argus.yml in the repository root (run: argus init)
# - Docker available on the runner (default for ubuntu-latest)
#
# Customize:
# - Adjust severity_threshold in argus.yml or via --severity-threshold flag
# - Add/remove scanners in argus.yml
# - Set fail_on_severity to control when the job fails
name: Argus Security Scan
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
pull-requests: write
security-events: write
jobs:
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for gitleaks
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install pyyaml # Will become: pip install argus-security
- name: Run Argus scan
id: scan
run: |
python -m argus scan \
--format sarif --format json --format markdown \
--output-dir ./argus-results \
--output-vars ./argus-results/counts.env \
--no-timestamp \
|| true
# Forward scan counts as job outputs
[ -f argus-results/counts.env ] && cat argus-results/counts.env >> "$GITHUB_OUTPUT"
- name: Upload SARIF to Code Security
if: always() && hashFiles('argus-results/argus-results.sarif') != ''
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: argus-results/argus-results.sarif
continue-on-error: true
- name: Upload scan artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: argus-results
path: argus-results/
retention-days: 30
# Post results as PR comment
- name: Comment PR with scan results
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summaryPath = 'argus-results/argus-summary.md';
if (!fs.existsSync(summaryPath)) {
console.log('No summary file found, skipping PR comment');
return;
}
const body = [
'## 🔒 Argus Security Scan Results',
'',
`<!-- argus-scan-comment -->`,
'',
fs.readFileSync(summaryPath, 'utf8'),
'',
'---',
`_Scanned at commit \`${context.sha.substring(0, 7)}\` by [Argus](https://github.com/huntridge-labs/argus)_`,
].join('\n');
// Update existing comment or create new one
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.data.find(c =>
c.body.includes('argus-scan-comment') &&
(c.user.login === 'github-actions[bot]' || c.user.type === 'Bot')
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
# Fail the job based on severity threshold
- name: Check scan results
if: always()
run: |
if [ "${{ steps.scan.outputs.passed }}" = "false" ]; then
echo "::error::Security findings exceed severity threshold"
exit 1
fi