Skip to content

Commit 9c04214

Browse files
authored
Merge pull request #1 from davidapp/feat/add_ai_audit
feat(ci): add AI security audit workflow
2 parents e50feab + 5a653c4 commit 9c04214

1 file changed

Lines changed: 177 additions & 0 deletions

File tree

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
name: AI Security Audit
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
11+
jobs:
12+
ai-security-audit:
13+
runs-on: ubuntu-latest
14+
timeout-minutes: 15
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Check ANTHROPIC_API_KEY
23+
env:
24+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
25+
run: |
26+
if [ -z "$ANTHROPIC_API_KEY" ]; then
27+
echo "::error::ANTHROPIC_API_KEY is not configured. Please add it to your repository secrets (Settings > Secrets and variables > Actions > New repository secret). The AI security audit cannot run without this key."
28+
exit 1
29+
fi
30+
31+
- name: Get PR diff
32+
id: diff
33+
env:
34+
GH_TOKEN: ${{ github.token }}
35+
run: |
36+
gh pr diff ${{ github.event.pull_request.number }} > pr_diff.txt
37+
echo "diff_size=$(wc -c < pr_diff.txt | tr -d ' ')" >> "$GITHUB_OUTPUT"
38+
39+
- name: Check diff size
40+
id: check
41+
run: |
42+
if [ "${{ steps.diff.outputs.diff_size }}" -eq 0 ]; then
43+
echo "skip=true" >> "$GITHUB_OUTPUT"
44+
echo "No diff found, skipping audit."
45+
elif [ "${{ steps.diff.outputs.diff_size }}" -gt 200000 ]; then
46+
echo "skip=true" >> "$GITHUB_OUTPUT"
47+
echo "Diff too large (>200KB), skipping AI audit."
48+
else
49+
echo "skip=false" >> "$GITHUB_OUTPUT"
50+
fi
51+
52+
- name: Install Claude Code
53+
if: steps.check.outputs.skip != 'true'
54+
run: npm install -g @anthropic-ai/claude-code
55+
56+
- name: Run AI security audit
57+
if: steps.check.outputs.skip != 'true'
58+
id: audit
59+
env:
60+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
61+
run: |
62+
PROMPT=$(cat <<'AUDIT_PROMPT'
63+
You are a senior security engineer performing a security audit on a pull request diff.
64+
Analyze the following code diff and provide a structured security audit report.
65+
66+
Focus on these areas:
67+
1. **Critical Vulnerabilities**: SQL injection, command injection, XSS, SSRF, deserialization flaws, path traversal
68+
2. **Authentication & Authorization**: Broken auth, missing access controls, credential exposure
69+
3. **Cryptography Issues**: Weak algorithms, hardcoded keys/secrets, improper random number generation
70+
4. **Data Exposure**: Sensitive data leaks, PII exposure, excessive logging of secrets
71+
5. **Dependency Risks**: Known vulnerable patterns, unsafe deserialization
72+
6. **Blockchain-Specific**: Private key handling, transaction signing flaws, smart contract interaction risks, address validation
73+
7. **Input Validation**: Missing or insufficient validation, type confusion, buffer issues
74+
8. **Configuration & Infrastructure**: Insecure defaults, debug mode in production, permissive CORS
75+
76+
Output format (use GitHub-flavored Markdown):
77+
78+
## AI Security Audit Report
79+
80+
### Summary
81+
[One-paragraph overall assessment with risk level: CRITICAL / HIGH / MEDIUM / LOW / CLEAN]
82+
83+
### Findings
84+
85+
For each finding:
86+
#### [SEVERITY] Finding Title
87+
- **File**: `filename:line_number`
88+
- **Category**: [category from above]
89+
- **Description**: What the issue is
90+
- **Impact**: What could go wrong
91+
- **Recommendation**: How to fix it
92+
93+
If no security issues are found, state that the code appears clean and list what was checked.
94+
95+
### Statistics
96+
- Files analyzed: X
97+
- Issues found: X (critical: X, high: X, medium: X, low: X)
98+
99+
---
100+
*This report was generated by AI security audit. Please verify findings manually.*
101+
102+
Here is the diff to audit:
103+
AUDIT_PROMPT
104+
)
105+
106+
DIFF_CONTENT=$(cat pr_diff.txt)
107+
FULL_PROMPT="${PROMPT}
108+
\`\`\`diff
109+
${DIFF_CONTENT}
110+
\`\`\`"
111+
112+
# Run claude and capture output
113+
AUDIT_RESULT=$(echo "$FULL_PROMPT" | claude -p --output-format text 2>&1) || true
114+
115+
# Save result to file (avoid shell escaping issues)
116+
echo "$AUDIT_RESULT" > audit_result.md
117+
118+
- name: Post audit comment
119+
if: steps.check.outputs.skip != 'true'
120+
env:
121+
GH_TOKEN: ${{ github.token }}
122+
run: |
123+
# Build comment body
124+
{
125+
echo "<!-- ai-security-audit -->"
126+
echo ""
127+
cat audit_result.md
128+
} > comment_body.md
129+
130+
PR_NUMBER=${{ github.event.pull_request.number }}
131+
132+
# Delete previous audit comment if exists
133+
EXISTING_COMMENT_ID=$(gh api \
134+
"repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
135+
--jq '.[] | select(.body | contains("<!-- ai-security-audit -->")) | .id' \
136+
| head -1)
137+
138+
if [ -n "$EXISTING_COMMENT_ID" ]; then
139+
gh api \
140+
--method DELETE \
141+
"repos/${{ github.repository }}/issues/comments/${EXISTING_COMMENT_ID}" \
142+
|| true
143+
fi
144+
145+
# Post new comment
146+
gh pr comment "$PR_NUMBER" --body-file comment_body.md
147+
148+
- name: Post skip comment
149+
if: steps.check.outputs.skip == 'true'
150+
env:
151+
GH_TOKEN: ${{ github.token }}
152+
run: |
153+
PR_NUMBER=${{ github.event.pull_request.number }}
154+
REASON="No diff found"
155+
if [ "${{ steps.diff.outputs.diff_size }}" -gt 200000 ]; then
156+
REASON="Diff too large (>200KB) for AI audit"
157+
fi
158+
159+
BODY="<!-- ai-security-audit -->
160+
## AI Security Audit Report
161+
**Skipped**: ${REASON}.
162+
Please perform a manual security review."
163+
164+
# Delete previous audit comment if exists
165+
EXISTING_COMMENT_ID=$(gh api \
166+
"repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
167+
--jq '.[] | select(.body | contains("<!-- ai-security-audit -->")) | .id' \
168+
| head -1)
169+
170+
if [ -n "$EXISTING_COMMENT_ID" ]; then
171+
gh api \
172+
--method DELETE \
173+
"repos/${{ github.repository }}/issues/comments/${EXISTING_COMMENT_ID}" \
174+
|| true
175+
fi
176+
177+
gh pr comment "$PR_NUMBER" --body "$BODY"

0 commit comments

Comments
 (0)