@@ -4,9 +4,9 @@ name: Hypatia Security Scan
44
55on :
66 push :
7- branches : [ main, master, develop ]
7+ branches : ['**' ]
88 pull_request :
9- branches : [ main, master ]
9+ branches : ['**' ]
1010 schedule :
1111 - cron : ' 0 0 * * 0' # Weekly on Sunday
1212 workflow_dispatch :
@@ -40,12 +40,10 @@ jobs:
4040 - name : Build Hypatia scanner (if needed)
4141 working-directory : ${{ env.HOME }}/hypatia
4242 run : |
43- if [ ! -f hypatia-v2 ]; then
44- echo "Building hypatia-v2 scanner..."
45- cd scanner
43+ if [ ! -x hypatia ] && [ ! -x hypatia-v2 ]; then
44+ echo "Building hypatia scanner escript..."
4645 mix deps.get
4746 mix escript.build
48- mv hypatia ../hypatia-v2
4947 fi
5048
5149 - name : Run Hypatia scan
@@ -64,52 +62,148 @@ jobs:
6462 CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' hypatia-findings.json)
6563 HIGH=$(jq '[.[] | select(.severity == "high")] | length' hypatia-findings.json)
6664 MEDIUM=$(jq '[.[] | select(.severity == "medium")] | length' hypatia-findings.json)
65+ SECRET_COUNT=$(jq '[.[] | select(((.type // "") | test("secret"; "i")) or ((.reason // "") | test("secret"; "i")) or ((.rule // "") | test("secret"; "i")))] | length' hypatia-findings.json)
66+ VULNERABILITY_COUNT=$(jq '[.[] | select(((.type // "") | test("vuln|vulnerab|cve"; "i")) or ((.reason // "") | test("vuln|vulnerab|cve"; "i")) or ((.rule // "") | test("vuln|vulnerab|cve"; "i")))] | length' hypatia-findings.json)
67+ INCIDENT_COUNT=$((SECRET_COUNT + VULNERABILITY_COUNT))
6768
6869 echo "critical=$CRITICAL" >> $GITHUB_OUTPUT
6970 echo "high=$HIGH" >> $GITHUB_OUTPUT
7071 echo "medium=$MEDIUM" >> $GITHUB_OUTPUT
72+ echo "secret_count=$SECRET_COUNT" >> $GITHUB_OUTPUT
73+ echo "vulnerability_count=$VULNERABILITY_COUNT" >> $GITHUB_OUTPUT
74+ echo "incident_count=$INCIDENT_COUNT" >> $GITHUB_OUTPUT
7175
7276 echo "## Hypatia Scan Results" >> $GITHUB_STEP_SUMMARY
7377 echo "- Total findings: $FINDING_COUNT" >> $GITHUB_STEP_SUMMARY
7478 echo "- Critical: $CRITICAL" >> $GITHUB_STEP_SUMMARY
7579 echo "- High: $HIGH" >> $GITHUB_STEP_SUMMARY
7680 echo "- Medium: $MEDIUM" >> $GITHUB_STEP_SUMMARY
81+ echo "- Secrets: $SECRET_COUNT" >> $GITHUB_STEP_SUMMARY
82+ echo "- Vulnerabilities: $VULNERABILITY_COUNT" >> $GITHUB_STEP_SUMMARY
83+ echo "- Incident findings (secret + vulnerability): $INCIDENT_COUNT" >> $GITHUB_STEP_SUMMARY
84+
85+ - name : Immediate dispatch to gitbot-fleet (incident findings)
86+ if : steps.scan.outputs.incident_count > 0
87+ env :
88+ DISPATCH_TOKEN : ${{ secrets.FARM_DISPATCH_TOKEN }}
89+ REPO : ${{ github.repository }}
90+ REF : ${{ github.ref }}
91+ SHA : ${{ github.sha }}
92+ RUN_ID : ${{ github.run_id }}
93+ INCIDENT_COUNT : ${{ steps.scan.outputs.incident_count }}
94+ SECRET_COUNT : ${{ steps.scan.outputs.secret_count }}
95+ VULNERABILITY_COUNT : ${{ steps.scan.outputs.vulnerability_count }}
96+ run : |
97+ set -euo pipefail
98+ if [ -z "${DISPATCH_TOKEN:-}" ]; then
99+ echo "::warning::FARM_DISPATCH_TOKEN not configured; skipping immediate cross-repo dispatch."
100+ exit 0
101+ fi
102+
103+ cat > dispatch-payload.json <<EOF
104+ {
105+ "event_type": "hypatia-security-alert",
106+ "client_payload": {
107+ "source_repo": "${REPO}",
108+ "ref": "${REF}",
109+ "sha": "${SHA}",
110+ "run_id": "${RUN_ID}",
111+ "incident_count": "${INCIDENT_COUNT}",
112+ "secret_count": "${SECRET_COUNT}",
113+ "vulnerability_count": "${VULNERABILITY_COUNT}",
114+ "artifact": "hypatia-findings"
115+ }
116+ }
117+ EOF
118+
119+ curl -fsSL \
120+ -X POST \
121+ -H "Authorization: token ${DISPATCH_TOKEN}" \
122+ -H "Accept: application/vnd.github+json" \
123+ https://api.github.com/repos/hyperpolymath/gitbot-fleet/dispatches \
124+ -d @dispatch-payload.json
77125
78126 - name : Upload findings artifact
127+ if : always()
79128 uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
80129 with :
81130 name : hypatia-findings
82131 path : hypatia-findings.json
83132 retention-days : 90
84133
85- - name : Submit findings to gitbot-fleet (Phase 2)
86- if : steps.scan.outputs.findings_count > 0
134+ - name : Publish non-incident findings to gitbot-fleet shared-context
135+ if : steps.scan.outputs.findings_count > 0 && steps.scan.outputs.incident_count == 0
87136 env :
88- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
89- GITHUB_REPOSITORY : ${{ github.repository }}
90- GITHUB_SHA : ${{ github.sha }}
137+ DISPATCH_TOKEN : ${{ secrets.FARM_DISPATCH_TOKEN }}
138+ REPO : ${{ github.repository }}
139+ SHA : ${{ github.sha }}
91140 run : |
92- echo "📤 Submitting ${{ steps.scan.outputs.findings_count }} findings to gitbot-fleet..."
141+ set -euo pipefail
142+ if [ -z "${DISPATCH_TOKEN:-}" ]; then
143+ echo "::warning::FARM_DISPATCH_TOKEN not configured; skipping non-incident publication."
144+ exit 0
145+ fi
146+
147+ jq empty hypatia-findings.json
148+
149+ TIMESTAMP="$(date -u +%Y%m%d-%H%M%S)"
150+ REPO_SLUG="$(echo "$REPO" | tr '/' '-' | tr -cd 'a-zA-Z0-9._-')"
151+ TARGET_FILE="shared-context/findings/${REPO_SLUG}/${TIMESTAMP}.json"
152+ FLEET_DIR="/tmp/gitbot-fleet-${TIMESTAMP}-$$"
153+
154+ trap 'rm -rf "$FLEET_DIR"' EXIT
155+ git clone "https://x-access-token:${DISPATCH_TOKEN}@github.com/hyperpolymath/gitbot-fleet.git" "$FLEET_DIR"
156+ cd "$FLEET_DIR"
157+
158+ git checkout findings-submissions 2>/dev/null || git checkout -b findings-submissions
159+ mkdir -p "$(dirname "$TARGET_FILE")"
160+
161+ jq --arg repo "$REPO" --arg commit "$SHA" --arg submitted_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '
162+ def submission_meta: {
163+ repo: $repo,
164+ commit: $commit,
165+ submitted_at: $submitted_at,
166+ scanner_version: "hypatia-v2"
167+ };
168+ if type == "array" then
169+ {findings: ., submission_metadata: submission_meta}
170+ elif type == "object" and (has("findings")) and (.findings | type == "array") then
171+ . + {submission_metadata: submission_meta}
172+ elif type == "object" then
173+ {findings: [.], submission_metadata: submission_meta}
174+ else
175+ error("Unsupported findings JSON shape")
176+ end
177+ ' "$GITHUB_WORKSPACE/hypatia-findings.json" > "$TARGET_FILE"
178+
179+ ln -sf "$(basename "$TARGET_FILE")" "shared-context/findings/${REPO_SLUG}/latest.json"
180+ FINDING_COUNT="$(jq '.findings | length' "$TARGET_FILE")"
181+
182+ git add "$TARGET_FILE" "shared-context/findings/${REPO_SLUG}/latest.json"
183+ git config user.name "Hypatia Finding Submitter"
184+ git config user.email "hypatia@reposystem.dev"
185+
186+ if git diff --cached --quiet; then
187+ echo "No non-incident finding changes to publish."
188+ exit 0
189+ fi
93190
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"
191+ git commit -m "findings: ${REPO} @ $(date +%Y-%m-%d)
97192
98- # Run submission script
99- bash "$FLEET_DIR/scripts/submit-finding.sh" hypatia-findings.json
193+ Submitted: ${FINDING_COUNT} findings
194+ Commit: ${SHA}
195+ Scanner: hypatia-v2
100196
101- # Cleanup
102- rm -rf "$FLEET_DIR"
197+ Automated submission from GitHub Actions."
103198
104- echo "✅ Finding submission complete"
199+ git push origin findings-submissions
105200
106201 - name : Check for critical issues
107- if : steps.scan.outputs.critical > 0
202+ if : steps.scan.outputs.incident_count > 0
108203 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
204+ echo "::error::Security incident findings detected (secrets/vulnerabilities)."
205+ echo "::error::Review hypatia-findings.json for details."
206+ exit 1
113207
114208 - name : Generate scan report
115209 run : |
0 commit comments