Skip to content

Security Scan

Security Scan #13

Workflow file for this run

name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Run weekly on Monday at 09:00 UTC
- cron: '0 9 * * 1'
workflow_dispatch:
jobs:
security-scan:
runs-on: ubuntu-latest
if: github.repository == 'basher83/Zammad-MCP'
permissions:
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "latest"
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.14'
- name: Install dependencies
run: |
uv sync --dev --frozen
- name: Run Bandit (HIGH/CRITICAL only)
run: |
# Full recursive scan of the entire codebase
# --severity-level high: Only fail on HIGH and CRITICAL severity issues
echo "Running Bandit security scan (HIGH/CRITICAL only)..."
uv run bandit -r mcp_zammad/ --severity-level high -f json -o bandit-report.json
- name: Generate Bandit SARIF report
continue-on-error: true
run: |
# Generate SARIF for GitHub Security tab (includes all severities for visibility)
echo "Generating Bandit SARIF report for Security tab..."
uv run bandit -r mcp_zammad/ -f sarif -o bandit-sarif.json
- name: Upload Bandit results to GitHub Security
uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4
if: always()
with:
sarif_file: bandit-sarif.json
category: bandit
- name: Run safety scan
uses: pyupio/safety-action@2591cf2f3e67ba68b923f4c92f0d36e281c65023 # v1.0.1 tag target commit
continue-on-error: true
with:
api-key: ${{ github.repository == 'basher83/Zammad-MCP' && secrets.SAFETY_API_KEY || '' }}
- name: Run pip-audit
continue-on-error: true
run: |
echo "Running pip-audit dependency scan..."
# Will exit non-zero if vulnerabilities are found
uv run pip-audit --format json --output pip-audit-report.json || {
EXIT_CODE=$?
echo "⚠️ pip-audit found vulnerabilities (exit code: $EXIT_CODE)"
# Generate a summary of vulnerabilities
if [ -f pip-audit-report.json ]; then
VULN_COUNT=$(jq '.vulnerabilities | length' pip-audit-report.json)
echo "Found $VULN_COUNT vulnerability(ies) in dependencies"
echo ""
jq -r '.vulnerabilities[] | "Package: \(.name) \(.version)\nVulnerability: \(.id)\nDescription: \(.description)\nFix: \(if .fix_versions | length > 0 then "Upgrade to " + (.fix_versions | join(", ")) else "Check advisory" end)\n"' pip-audit-report.json
fi
exit $EXIT_CODE
}
echo "✅ No dependency vulnerabilities found"
- name: Upload security reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: always()
with:
name: security-reports
path: |
bandit-report.json
bandit-sarif.json
pip-audit-report.json
- name: Generate Security Summary
if: always()
run: |
echo "## 🔒 Security Scan Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Check Bandit results
if [ -f bandit-report.json ]; then
HIGH_COUNT=$(jq '[.results[] | select(.issue_severity == "HIGH")] | length' bandit-report.json)
MED_COUNT=$(jq '[.results[] | select(.issue_severity == "MEDIUM")] | length' bandit-report.json)
LOW_COUNT=$(jq '[.results[] | select(.issue_severity == "LOW")] | length' bandit-report.json)
echo "### Bandit Static Analysis" >> $GITHUB_STEP_SUMMARY
if [ "$HIGH_COUNT" -gt 0 ]; then
echo "❌ **Failed**: Found $HIGH_COUNT HIGH severity issues" >> $GITHUB_STEP_SUMMARY
else
echo "✅ **Passed**: No HIGH/CRITICAL issues (Medium: $MED_COUNT, Low: $LOW_COUNT)" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
fi
# Check safety results
echo "### Dependency Vulnerability Scans" >> $GITHUB_STEP_SUMMARY
echo "✅ **Safety**: Check performed via GitHub Action (see job output for details)" >> $GITHUB_STEP_SUMMARY
# Check pip-audit results
if [ -f pip-audit-report.json ]; then
AUDIT_VULNS=$(jq '.vulnerabilities | length' pip-audit-report.json)
if [ "$AUDIT_VULNS" -gt 0 ]; then
echo "❌ **pip-audit**: Found $AUDIT_VULNS vulnerabilities" >> $GITHUB_STEP_SUMMARY
else
echo "✅ **pip-audit**: No vulnerabilities" >> $GITHUB_STEP_SUMMARY
fi
fi