Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ jobs:
fail-fast: false
matrix:
include:
- language: javascript-typescript
# Repo source is not JS/TS; scan workflow files via the
# actions extractor (every repo has those). See hypatia rule
# codeql_language_matrix_mismatch.
- language: actions
build-mode: none

steps:
Expand Down
193 changes: 16 additions & 177 deletions .github/workflows/hypatia-scan.yml
Original file line number Diff line number Diff line change
@@ -1,190 +1,29 @@
# SPDX-License-Identifier: MPL-2.0
# Hypatia Neurosymbolic CI/CD Security Scan
# Thin wrapper around hyperpolymath/standards hypatia-scan-reusable.yml.
# See standards#191 for the reusable's purpose and design.

name: Hypatia Security Scan

on:
push:
branches: [ main, master, develop ]
branches: [main, master, develop]
pull_request:
branches: [ main, master ]
branches: [main, master]
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
- cron: '0 0 * * 0'
workflow_dispatch:

# Estate guardrail: cancel superseded runs so re-pushes don't pile up.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
# security-events: read lets the built-in GITHUB_TOKEN query this
# repo's own Dependabot alerts via the Hypatia DependabotAlerts rule
# (DA001-DA004). Without this, `scan_from_path` gets HTTP 403 and
# the rule silently returns no findings.
# See 007-lang/audits/audit-dependabot-automation-gap-2026-04-17.md.
security-events: read
security-events: write
pull-requests: write

jobs:
scan:
name: Hypatia Neurosymbolic Analysis
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Full history for better pattern analysis

- name: Setup Elixir for Hypatia scanner
uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9 # v1.18.2
with:
elixir-version: '1.19.4'
otp-version: '28.3'

- name: Clone Hypatia
run: |
if [ ! -d "$HOME/hypatia" ]; then
git clone https://github.com/hyperpolymath/hypatia.git "$HOME/hypatia"
fi

- name: Build Hypatia scanner (if needed)
run: |
cd "$HOME/hypatia"
if [ ! -f hypatia ]; then
echo "Building hypatia scanner..."
mix deps.get
mix escript.build
fi

- name: Run Hypatia scan
id: scan
env:
# Pass the built-in Actions token through to Hypatia so the
# DependabotAlerts rule can query this repo's own alerts.
# For cross-repo scanning (fleet-coordinator scan-supervised),
# a PAT with `security_events` scope is required instead.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Scanning repository: ${{ github.repository }}"

# Run scanner (exits non-zero when findings exist — suppress to continue)
HYPATIA_FORMAT=json "$HOME/hypatia/hypatia-cli.sh" scan . > hypatia-findings.json || true

# Count findings
FINDING_COUNT=$(jq '. | length' hypatia-findings.json 2>/dev/null || echo 0)
echo "findings_count=$FINDING_COUNT" >> $GITHUB_OUTPUT

# Extract severity counts
CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' hypatia-findings.json)
HIGH=$(jq '[.[] | select(.severity == "high")] | length' hypatia-findings.json)
MEDIUM=$(jq '[.[] | select(.severity == "medium")] | length' hypatia-findings.json)

echo "critical=$CRITICAL" >> $GITHUB_OUTPUT
echo "high=$HIGH" >> $GITHUB_OUTPUT
echo "medium=$MEDIUM" >> $GITHUB_OUTPUT

echo "## Hypatia Scan Results" >> $GITHUB_STEP_SUMMARY
echo "- Total findings: $FINDING_COUNT" >> $GITHUB_STEP_SUMMARY
echo "- Critical: $CRITICAL" >> $GITHUB_STEP_SUMMARY
echo "- High: $HIGH" >> $GITHUB_STEP_SUMMARY
echo "- Medium: $MEDIUM" >> $GITHUB_STEP_SUMMARY

- name: Upload findings artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: hypatia-findings
path: hypatia-findings.json
retention-days: 90

- name: Submit findings to gitbot-fleet (Phase 2)
if: steps.scan.outputs.findings_count > 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_SHA: ${{ github.sha }}
run: |
echo "📤 Submitting ${{ steps.scan.outputs.findings_count }} findings to gitbot-fleet..."

# Clone gitbot-fleet to temp directory
FLEET_DIR="/tmp/gitbot-fleet-$$"
git clone https://github.com/hyperpolymath/gitbot-fleet.git "$FLEET_DIR"

# Run submission script
bash "$FLEET_DIR/scripts/submit-finding.sh" hypatia-findings.json

# Cleanup
rm -rf "$FLEET_DIR"

echo "✅ Finding submission complete"

- name: Check for critical issues
if: steps.scan.outputs.critical > 0
run: |
echo "⚠️ Critical security issues found!"
echo "Review hypatia-findings.json for details"
# Don't fail the build yet - just warn
# exit 1

- name: Generate scan report
run: |
cat << EOF > hypatia-report.md
# Hypatia Security Scan Report

**Repository:** ${{ github.repository }}
**Scan Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")
**Commit:** ${{ github.sha }}

## Summary

| Severity | Count |
|----------|-------|
| Critical | ${{ steps.scan.outputs.critical }} |
| High | ${{ steps.scan.outputs.high }} |
| Medium | ${{ steps.scan.outputs.medium }} |
| **Total**| ${{ steps.scan.outputs.findings_count }} |

## Next Steps

1. Review findings in the artifact: hypatia-findings.json
2. Auto-fixable issues will be addressed by robot-repo-automaton (Phase 3)
3. Manual review required for complex issues

## Learning

These findings feed Hypatia's learning engine to improve future rules.

---
*Powered by [Hypatia](https://github.com/hyperpolymath/hypatia) - Neurosymbolic CI/CD Intelligence*
EOF

cat hypatia-report.md >> $GITHUB_STEP_SUMMARY

- name: Comment on PR with findings
if: github.event_name == 'pull_request' && steps.scan.outputs.findings_count > 0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v7
with:
script: |
const fs = require('fs');
const findings = JSON.parse(fs.readFileSync('hypatia-findings.json', 'utf8'));

const critical = findings.filter(f => f.severity === 'critical').length;
const high = findings.filter(f => f.severity === 'high').length;

let comment = `## 🔍 Hypatia Security Scan\n\n`;
comment += `**Findings:** ${findings.length} issues detected\n\n`;
comment += `| Severity | Count |\n|----------|-------|\n`;
comment += `| 🔴 Critical | ${critical} |\n`;
comment += `| 🟠 High | ${high} |\n`;
comment += `| 🟡 Medium | ${findings.length - critical - high} |\n\n`;

if (critical > 0) {
comment += `⚠️ **Action Required:** Critical security issues found!\n\n`;
}

comment += `<details><summary>View findings</summary>\n\n`;
comment += `\`\`\`json\n${JSON.stringify(findings.slice(0, 10), null, 2)}\n\`\`\`\n`;
comment += `</details>\n\n`;
comment += `*Powered by Hypatia Neurosymbolic CI/CD Intelligence*`;

github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
hypatia:
uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@97df762107501909f50bb770e9bc200b6c415600
secrets: inherit
Loading