|
1 | 1 | # SPDX-License-Identifier: MPL-2.0 |
2 | | -# Hypatia Neurosymbolic CI/CD Security Scan |
3 | 2 | name: Hypatia Security Scan |
4 | 3 |
|
5 | 4 | on: |
6 | 5 | push: |
7 | | - branches: [ main, master, develop ] |
| 6 | + branches: [main, master, develop] |
8 | 7 | pull_request: |
9 | | - branches: [ main, master ] |
| 8 | + branches: [main, master] |
10 | 9 | schedule: |
11 | | - - cron: '0 0 * * 0' # Weekly on Sunday |
| 10 | + - cron: '0 0 * * 0' |
12 | 11 | workflow_dispatch: |
13 | 12 |
|
14 | | -permissions: read-all |
| 13 | +permissions: |
| 14 | + actions: read |
| 15 | + contents: read |
| 16 | + security-events: write |
15 | 17 |
|
16 | 18 | jobs: |
17 | 19 | scan: |
18 | | - name: Hypatia Neurosymbolic Analysis |
19 | | - runs-on: ubuntu-latest |
20 | | - timeout-minutes: 20 |
21 | | - |
22 | | - steps: |
23 | | - - name: Checkout repository |
24 | | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 |
25 | | - with: |
26 | | - fetch-depth: 0 # Full history for better pattern analysis |
27 | | - |
28 | | - - name: Setup Elixir for Hypatia scanner |
29 | | - uses: erlef/setup-beam@2f0cc07b4b9bea248ae098aba9e1a8a1de5ec24c # v1.18.2 |
30 | | - with: |
31 | | - elixir-version: '1.18' |
32 | | - otp-version: '27' |
33 | | - |
34 | | - - name: Clone Hypatia |
35 | | - run: | |
36 | | - if [ ! -d "$HOME/hypatia" ]; then |
37 | | - git clone https://github.com/hyperpolymath/hypatia.git "$HOME/hypatia" |
38 | | - fi |
39 | | -
|
40 | | - - name: Build Hypatia scanner (if needed) |
41 | | - working-directory: ${{ env.HOME }}/hypatia |
42 | | - run: | |
43 | | - if [ ! -f hypatia-v2 ]; then |
44 | | - echo "Building hypatia-v2 scanner..." |
45 | | - cd scanner |
46 | | - mix deps.get |
47 | | - mix escript.build |
48 | | - mv hypatia ../hypatia-v2 |
49 | | - fi |
50 | | -
|
51 | | - - name: Run Hypatia scan |
52 | | - id: scan |
53 | | - run: | |
54 | | - echo "Scanning repository: ${{ github.repository }}" |
55 | | -
|
56 | | - # Run scanner |
57 | | - HYPATIA_FORMAT=json "$HOME/hypatia/hypatia-cli.sh" scan . > hypatia-findings.json |
58 | | -
|
59 | | - # Count findings |
60 | | - FINDING_COUNT=$(jq '. | length' hypatia-findings.json 2>/dev/null || echo 0) |
61 | | - echo "findings_count=$FINDING_COUNT" >> $GITHUB_OUTPUT |
62 | | -
|
63 | | - # Extract severity counts |
64 | | - CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' hypatia-findings.json) |
65 | | - HIGH=$(jq '[.[] | select(.severity == "high")] | length' hypatia-findings.json) |
66 | | - MEDIUM=$(jq '[.[] | select(.severity == "medium")] | length' hypatia-findings.json) |
67 | | -
|
68 | | - echo "critical=$CRITICAL" >> $GITHUB_OUTPUT |
69 | | - echo "high=$HIGH" >> $GITHUB_OUTPUT |
70 | | - echo "medium=$MEDIUM" >> $GITHUB_OUTPUT |
71 | | -
|
72 | | - echo "## Hypatia Scan Results" >> $GITHUB_STEP_SUMMARY |
73 | | - echo "- Total findings: $FINDING_COUNT" >> $GITHUB_STEP_SUMMARY |
74 | | - echo "- Critical: $CRITICAL" >> $GITHUB_STEP_SUMMARY |
75 | | - echo "- High: $HIGH" >> $GITHUB_STEP_SUMMARY |
76 | | - echo "- Medium: $MEDIUM" >> $GITHUB_STEP_SUMMARY |
77 | | -
|
78 | | - - name: Upload findings artifact |
79 | | - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 |
80 | | - with: |
81 | | - name: hypatia-findings |
82 | | - path: hypatia-findings.json |
83 | | - retention-days: 90 |
84 | | - |
85 | | - - name: Submit findings to gitbot-fleet (Phase 2) |
86 | | - if: steps.scan.outputs.findings_count > 0 |
87 | | - env: |
88 | | - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
89 | | - GITHUB_REPOSITORY: ${{ github.repository }} |
90 | | - GITHUB_SHA: ${{ github.sha }} |
91 | | - run: | |
92 | | - echo "📤 Submitting ${{ steps.scan.outputs.findings_count }} findings to gitbot-fleet..." |
93 | | -
|
94 | | - # Clone gitbot-fleet to temp directory |
95 | | - FLEET_DIR="/tmp/gitbot-fleet-$$" |
96 | | - git clone https://github.com/hyperpolymath/gitbot-fleet.git "$FLEET_DIR" |
97 | | -
|
98 | | - # Run submission script |
99 | | - bash "$FLEET_DIR/scripts/submit-finding.sh" hypatia-findings.json |
100 | | -
|
101 | | - # Cleanup |
102 | | - rm -rf "$FLEET_DIR" |
103 | | -
|
104 | | - echo "✅ Finding submission complete" |
105 | | -
|
106 | | - - name: Check for critical issues |
107 | | - if: steps.scan.outputs.critical > 0 |
108 | | - run: | |
109 | | - echo "⚠️ Critical security issues found!" |
110 | | - echo "Review hypatia-findings.json for details" |
111 | | - # Don't fail the build yet - just warn |
112 | | - # exit 1 |
113 | | -
|
114 | | - - name: Generate scan report |
115 | | - run: | |
116 | | - cat << EOF > hypatia-report.md |
117 | | - # Hypatia Security Scan Report |
118 | | -
|
119 | | - **Repository:** ${{ github.repository }} |
120 | | - **Scan Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") |
121 | | - **Commit:** ${{ github.sha }} |
122 | | -
|
123 | | - ## Summary |
124 | | -
|
125 | | - | Severity | Count | |
126 | | - |----------|-------| |
127 | | - | Critical | ${{ steps.scan.outputs.critical }} | |
128 | | - | High | ${{ steps.scan.outputs.high }} | |
129 | | - | Medium | ${{ steps.scan.outputs.medium }} | |
130 | | - | **Total**| ${{ steps.scan.outputs.findings_count }} | |
131 | | -
|
132 | | - ## Next Steps |
133 | | -
|
134 | | - 1. Review findings in the artifact: hypatia-findings.json |
135 | | - 2. Auto-fixable issues will be addressed by robot-repo-automaton (Phase 3) |
136 | | - 3. Manual review required for complex issues |
137 | | -
|
138 | | - ## Learning |
139 | | -
|
140 | | - These findings feed Hypatia's learning engine to improve future rules. |
141 | | -
|
142 | | - --- |
143 | | - *Powered by [Hypatia](https://github.com/hyperpolymath/hypatia) - Neurosymbolic CI/CD Intelligence* |
144 | | - EOF |
145 | | -
|
146 | | - cat hypatia-report.md >> $GITHUB_STEP_SUMMARY |
147 | | -
|
148 | | - - name: Comment on PR with findings |
149 | | - if: github.event_name == 'pull_request' && steps.scan.outputs.findings_count > 0 |
150 | | - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 |
151 | | - with: |
152 | | - script: | |
153 | | - const fs = require('fs'); |
154 | | - const findings = JSON.parse(fs.readFileSync('hypatia-findings.json', 'utf8')); |
155 | | -
|
156 | | - const critical = findings.filter(f => f.severity === 'critical').length; |
157 | | - const high = findings.filter(f => f.severity === 'high').length; |
158 | | -
|
159 | | - let comment = `## 🔍 Hypatia Security Scan\n\n`; |
160 | | - comment += `**Findings:** ${findings.length} issues detected\n\n`; |
161 | | - comment += `| Severity | Count |\n|----------|-------|\n`; |
162 | | - comment += `| 🔴 Critical | ${critical} |\n`; |
163 | | - comment += `| 🟠 High | ${high} |\n`; |
164 | | - comment += `| 🟡 Medium | ${findings.length - critical - high} |\n\n`; |
165 | | -
|
166 | | - if (critical > 0) { |
167 | | - comment += `⚠️ **Action Required:** Critical security issues found!\n\n`; |
168 | | - } |
169 | | -
|
170 | | - comment += `<details><summary>View findings</summary>\n\n`; |
171 | | - comment += `\`\`\`json\n${JSON.stringify(findings.slice(0, 10), null, 2)}\n\`\`\`\n`; |
172 | | - comment += `</details>\n\n`; |
173 | | - comment += `*Powered by Hypatia Neurosymbolic CI/CD Intelligence*`; |
174 | | -
|
175 | | - github.rest.issues.createComment({ |
176 | | - owner: context.repo.owner, |
177 | | - repo: context.repo.repo, |
178 | | - issue_number: context.issue.number, |
179 | | - body: comment |
180 | | - }); |
| 20 | + uses: ../.github/workflows/hypatia-scan-reusable.yml |
| 21 | + secrets: inherit |
0 commit comments