Skip to content

Security Scan

Security Scan #3

Workflow file for this run

name: Security Scan
on:
pull_request:
paths:
- 'skills/**'
push:
branches:
- main
paths:
- 'skills/**'
schedule:
# Run daily security scan at 06:00 UTC
- cron: '0 6 * * *'
workflow_dispatch:
permissions:
contents: read
issues: write
pull-requests: write
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install pyyaml jsonschema
- name: Run security scanner
id: scan
run: |
python scripts/security_scanner.py skills/ --output security-report.json
continue-on-error: true
- name: Upload security report
uses: actions/upload-artifact@v4
if: always()
with:
name: security-report
path: security-report.json
- name: Check results
run: |
if [ -f security-report.json ]; then
FAILED=$(jq -r '.failed' security-report.json)
PASSED=$(jq -r '.passed' security-report.json)
TOTAL=$(jq -r '.total' security-report.json)
echo "## Security Scan Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Total skills: $TOTAL" >> $GITHUB_STEP_SUMMARY
echo "- ✓ Passed: $PASSED" >> $GITHUB_STEP_SUMMARY
echo "- ✗ Failed: $FAILED" >> $GITHUB_STEP_SUMMARY
if [ "$FAILED" -gt "0" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Failed Skills:" >> $GITHUB_STEP_SUMMARY
jq -r '.skills[] | select(.safe == false) | "- `\(.path)`"' security-report.json >> $GITHUB_STEP_SUMMARY
exit 1
fi
fi
- name: Comment on PR
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (!fs.existsSync('security-report.json')) return;
const report = JSON.parse(fs.readFileSync('security-report.json', 'utf8'));
let comment = '## 🔒 Security Scan Results\n\n';
comment += `- **Total skills**: ${report.total}\n`;
comment += `- ✅ **Passed**: ${report.passed}\n`;
comment += `- ❌ **Failed**: ${report.failed}\n\n`;
if (report.failed > 0) {
comment += '### ⚠️ Issues Found:\n\n';
for (const skill of report.skills) {
if (!skill.safe) {
comment += `#### \`${skill.path}\`\n`;
for (const issue of skill.issues) {
if (issue.severity === 'error') {
comment += `- ❌ **${issue.type}**: ${issue.message}\n`;
} else {
comment += `- ⚠️ ${issue.type}: ${issue.message}\n`;
}
}
comment += '\n';
}
}
} else {
comment += '✅ All skills passed security validation!\n';
}
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
codeql-analysis:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python, javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
dependency-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run Trivy security scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'