Skip to content

Commit 55459d7

Browse files
committed
security: standardize secret scanning on TruffleHog
1 parent 95a0637 commit 55459d7

13 files changed

Lines changed: 2298 additions & 95 deletions

File tree

.github/workflows/hypatia-scan.yml

Lines changed: 12 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
# SPDX-License-Identifier: MPL-2.0
22
# Hypatia Neurosymbolic CI/CD Security Scan
33
name: Hypatia Security Scan
4-
54
on:
65
push:
7-
branches: [ main, master, develop ]
6+
branches: [main, master, develop]
87
pull_request:
9-
branches: [ main, master ]
8+
branches: [main, master]
109
schedule:
11-
- cron: '0 0 * * 0' # Weekly on Sunday
10+
- cron: '0 0 * * 0' # Weekly on Sunday
1211
workflow_dispatch:
1312
# Estate guardrail: cancel superseded runs so re-pushes don't pile up
1413
# queued runs across the estate. Safe here because this workflow only
1514
# performs read-only checks/lint/test/scan with no publish or mutation.
1615
concurrency:
1716
group: ${{ github.workflow }}-${{ github.ref }}
1817
cancel-in-progress: true
19-
2018
permissions:
2119
contents: read
2220
# security-events: write serves two purposes (write implies read):
@@ -38,31 +36,26 @@ permissions:
3836
# "Resource not accessible by integration" and (absent continue-on-error)
3937
# hard-fails the scan — exactly what the gate-decoupling design forbids.
4038
pull-requests: write
41-
4239
jobs:
4340
scan:
4441
name: Hypatia Neurosymbolic Analysis
4542
runs-on: ubuntu-latest
4643
timeout-minutes: 15
47-
4844
steps:
4945
- name: Checkout repository
5046
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
5147
with:
52-
fetch-depth: 0 # Full history for better pattern analysis
53-
48+
fetch-depth: 0 # Full history for better pattern analysis
5449
- name: Setup Elixir for Hypatia scanner
5550
uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.18.2
5651
with:
5752
elixir-version: '1.18'
5853
otp-version: '27'
59-
6054
- name: Clone Hypatia
6155
run: |
6256
if [ ! -d "$HOME/hypatia" ]; then
6357
git clone https://github.com/hyperpolymath/hypatia.git "$HOME/hypatia"
6458
fi
65-
6659
- name: Build Hypatia scanner (if needed)
6760
run: |
6861
cd "$HOME/hypatia"
@@ -71,7 +64,6 @@ jobs:
7164
mix deps.get
7265
mix escript.build
7366
fi
74-
7567
- name: Run Hypatia scan
7668
id: scan
7769
env:
@@ -104,14 +96,12 @@ jobs:
10496
echo "- Critical: $CRITICAL" >> $GITHUB_STEP_SUMMARY
10597
echo "- High: $HIGH" >> $GITHUB_STEP_SUMMARY
10698
echo "- Medium: $MEDIUM" >> $GITHUB_STEP_SUMMARY
107-
10899
- name: Upload findings artifact
109100
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
110101
with:
111102
name: hypatia-findings
112103
path: hypatia-findings.json
113104
retention-days: 90
114-
115105
- name: Convert Hypatia findings to SARIF
116106
# Always runs (no findings_count guard): an EMPTY SARIF run is
117107
# valid and intentional — uploading it clears stale Hypatia
@@ -227,7 +217,6 @@ jobs:
227217
console.log(`hypatia.sarif written: ${results.length} result(s).`);
228218
CJS
229219
node "$RUNNER_TEMP/hypatia-sarif.cjs"
230-
231220
- name: Upload SARIF to GitHub code scanning
232221
# Fork PRs get a read-only GITHUB_TOKEN, so security-events:write
233222
# is unavailable and upload-sarif cannot publish — skip there
@@ -239,16 +228,19 @@ jobs:
239228
# exists to end). The empty-SARIF "clear stale alerts" path is
240229
# handled in the converter above and does not error here.
241230
if: >-
242-
always() &&
243-
(github.event_name != 'pull_request' ||
231+
always() && (github.event_name != 'pull_request' ||
232+
233+
234+
235+
236+
244237
github.event.pull_request.head.repo.fork != true)
245238
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.28.1
246239
with:
247240
sarif_file: hypatia.sarif
248241
# Distinct category so Hypatia results coexist with CodeQL's
249242
# (codeql.yml) instead of overwriting them on the same surface.
250243
category: hypatia
251-
252244
- name: Submit findings to gitbot-fleet (Phase 2)
253245
if: steps.scan.outputs.findings_count > 0
254246
# Phase 2 is the collaborative LEARNING side-channel ("bots share
@@ -272,52 +264,7 @@ jobs:
272264
GITHUB_REPOSITORY: ${{ github.repository }}
273265
GITHUB_SHA: ${{ github.sha }}
274266
FINDINGS_COUNT: ${{ steps.scan.outputs.findings_count }}
275-
run: |
276-
echo "📤 Submitting $FINDINGS_COUNT findings to gitbot-fleet..."
277-
278-
# Clone gitbot-fleet to temp directory. A clone failure (network,
279-
# repo gone) is non-fatal: learning submission is best-effort.
280-
FLEET_DIR="/tmp/gitbot-fleet-$$"
281-
if ! git clone --depth 1 https://github.com/hyperpolymath/gitbot-fleet.git "$FLEET_DIR"; then
282-
echo "::warning::Could not clone gitbot-fleet — skipping Phase 2 learning submission (non-fatal)."
283-
exit 0
284-
fi
285-
286-
# The submission script's location in gitbot-fleet has drifted
287-
# before (it was absent from the default branch, which exit-127'd
288-
# every consuming repo's scan). Probe known locations rather than
289-
# hard-coding one path, and skip gracefully if none is present.
290-
SUBMIT_SCRIPT=""
291-
for cand in \
292-
"$FLEET_DIR/scripts/submit-finding.sh" \
293-
"$FLEET_DIR/scripts/submit_finding.sh" \
294-
"$FLEET_DIR/bin/submit-finding.sh" \
295-
"$FLEET_DIR/submit-finding.sh"; do
296-
if [ -f "$cand" ]; then
297-
SUBMIT_SCRIPT="$cand"
298-
break
299-
fi
300-
done
301-
302-
if [ -z "$SUBMIT_SCRIPT" ]; then
303-
echo "::warning::gitbot-fleet submit-finding script not found at any known path — skipping Phase 2 learning submission (non-fatal). Findings are still uploaded as an artifact and gated below."
304-
rm -rf "$FLEET_DIR"
305-
exit 0
306-
fi
307-
308-
# Run submission script. Pass the findings path as ABSOLUTE —
309-
# the script cd's into its own working dir before reading the
310-
# file, so a relative path would resolve to the wrong place.
311-
# A submission-script failure is logged but non-fatal.
312-
if bash "$SUBMIT_SCRIPT" "$GITHUB_WORKSPACE/hypatia-findings.json"; then
313-
echo "✅ Finding submission complete"
314-
else
315-
echo "::warning::gitbot-fleet submission script exited non-zero — Phase 2 learning submission skipped (non-fatal)."
316-
fi
317-
318-
# Cleanup
319-
rm -rf "$FLEET_DIR"
320-
267+
run: "echo \"\U0001F4E4 Submitting $FINDINGS_COUNT findings to gitbot-fleet...\"\n\n# Clone gitbot-fleet to temp directory. A clone failure (network,\n# repo gone) is non-fatal: learning submission is best-effort.\nFLEET_DIR=\"/tmp/gitbot-fleet-$$\"\nif ! git clone --depth 1 https://github.com/hyperpolymath/gitbot-fleet.git \"$FLEET_DIR\"; then\n echo \"::warning::Could not clone gitbot-fleet — skipping Phase 2 learning submission (non-fatal).\"\n exit 0\nfi\n\n# The submission script's location in gitbot-fleet has drifted\n# before (it was absent from the default branch, which exit-127'd\n# every consuming repo's scan). Probe known locations rather than\n# hard-coding one path, and skip gracefully if none is present.\nSUBMIT_SCRIPT=\"\"\nfor cand in \\\n \"$FLEET_DIR/scripts/submit-finding.sh\" \\\n \"$FLEET_DIR/scripts/submit_finding.sh\" \\\n \"$FLEET_DIR/bin/submit-finding.sh\" \\\n \"$FLEET_DIR/submit-finding.sh\"; do\n if [ -f \"$cand\" ]; then\n SUBMIT_SCRIPT=\"$cand\"\n break\n fi\ndone\n\nif [ -z \"$SUBMIT_SCRIPT\" ]; then\n echo \"::warning::gitbot-fleet submit-finding script not found at any known path — skipping Phase 2 learning submission (non-fatal). Findings are still uploaded as an artifact and gated below.\"\n rm -rf \"$FLEET_DIR\"\n exit 0\nfi\n\n# Run submission script. Pass the findings path as ABSOLUTE —\n# the script cd's into its own working dir before reading the\n# file, so a relative path would resolve to the wrong place.\n# A submission-script failure is logged but non-fatal.\nif bash \"$SUBMIT_SCRIPT\" \"$GITHUB_WORKSPACE/hypatia-findings.json\"; then\n echo \"✅ Finding submission complete\"\nelse\n echo \"::warning::gitbot-fleet submission script exited non-zero — Phase 2 learning submission skipped (non-fatal).\"\nfi\n\n# Cleanup\nrm -rf \"$FLEET_DIR\"\n"
321268
- name: Check for critical issues
322269
if: steps.scan.outputs.critical > 0
323270
# GATING POLICY (explicit, by design — not an oversight):
@@ -335,7 +282,6 @@ jobs:
335282
echo "::warning::Hypatia found critical security issue(s) — advisory."
336283
echo "See the Security → Code scanning page (category: hypatia)"
337284
echo "and the hypatia-findings.json artifact for details."
338-
339285
- name: Generate scan report
340286
run: |
341287
cat << EOF > hypatia-report.md
@@ -374,7 +320,6 @@ jobs:
374320
EOF
375321
376322
cat hypatia-report.md >> $GITHUB_STEP_SUMMARY
377-
378323
- name: Comment on PR with findings
379324
if: github.event_name == 'pull_request' && steps.scan.outputs.findings_count > 0
380325
# Advisory only — posting findings as a PR comment must never gate
@@ -384,32 +329,4 @@ jobs:
384329
continue-on-error: true
385330
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v7
386331
with:
387-
script: |
388-
const fs = require('fs');
389-
const findings = JSON.parse(fs.readFileSync('hypatia-findings.json', 'utf8'));
390-
391-
const critical = findings.filter(f => f.severity === 'critical').length;
392-
const high = findings.filter(f => f.severity === 'high').length;
393-
394-
let comment = `## 🔍 Hypatia Security Scan\n\n`;
395-
comment += `**Findings:** ${findings.length} issues detected\n\n`;
396-
comment += `| Severity | Count |\n|----------|-------|\n`;
397-
comment += `| 🔴 Critical | ${critical} |\n`;
398-
comment += `| 🟠 High | ${high} |\n`;
399-
comment += `| 🟡 Medium | ${findings.length - critical - high} |\n\n`;
400-
401-
if (critical > 0) {
402-
comment += `⚠️ **Action Required:** Critical security issues found!\n\n`;
403-
}
404-
405-
comment += `<details><summary>View findings</summary>\n\n`;
406-
comment += `\`\`\`json\n${JSON.stringify(findings.slice(0, 10), null, 2)}\n\`\`\`\n`;
407-
comment += `</details>\n\n`;
408-
comment += `*Powered by Hypatia Neurosymbolic CI/CD Intelligence*`;
409-
410-
github.rest.issues.createComment({
411-
owner: context.repo.owner,
412-
repo: context.repo.repo,
413-
issue_number: context.issue.number,
414-
body: comment
415-
});
332+
script: "const fs = require('fs');\nconst findings = JSON.parse(fs.readFileSync('hypatia-findings.json', 'utf8'));\n\nconst critical = findings.filter(f => f.severity === 'critical').length;\nconst high = findings.filter(f => f.severity === 'high').length;\n\nlet comment = `## \U0001F50D Hypatia Security Scan\\n\\n`;\ncomment += `**Findings:** ${findings.length} issues detected\\n\\n`;\ncomment += `| Severity | Count |\\n|----------|-------|\\n`;\ncomment += `| \U0001F534 Critical | ${critical} |\\n`;\ncomment += `| \U0001F7E0 High | ${high} |\\n`;\ncomment += `| \U0001F7E1 Medium | ${findings.length - critical - high} |\\n\\n`;\n\nif (critical > 0) {\n comment += `⚠️ **Action Required:** Critical security issues found!\\n\\n`;\n}\n\ncomment += `<details><summary>View findings</summary>\\n\\n`;\ncomment += `\\`\\`\\`json\\n${JSON.stringify(findings.slice(0, 10), null, 2)}\\n\\`\\`\\`\\n`;\ncomment += `</details>\\n\\n`;\ncomment += `*Powered by Hypatia Neurosymbolic CI/CD Intelligence*`;\n\ngithub.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: comment\n});"

.machine_readable/6a2/AGENTIC.a2ml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# AGENTIC.a2ml — AI agent constraints and capabilities
5+
# Defines what AI agents can and cannot do in this repository.
6+
7+
[metadata]
8+
version = "0.1.0"
9+
last-updated = "2026-04-11"
10+
11+
[agent-permissions]
12+
can-edit-source = true
13+
can-edit-tests = true
14+
can-edit-docs = true
15+
can-edit-config = true
16+
can-create-files = true
17+
18+
[agent-constraints]
19+
# What AI agents must NOT do:
20+
# - Never use banned language patterns (believe_me, unsafeCoerce, etc.)
21+
# - Never commit secrets or credentials
22+
# - Never use banned languages (TypeScript, Python, Go, etc.)
23+
# - Never place state files in repository root (must be in .machine_readable/)
24+
# - Never use AGPL license (use MPL-2.0)
25+
26+
[maintenance-integrity]
27+
fail-closed = true
28+
require-evidence-per-step = true
29+
allow-silent-skip = false
30+
require-rerun-after-fix = true
31+
release-claim-requires-hard-pass = true
32+
33+
# ============================================================================
34+
# METHODOLOGY (ADR-002)
35+
# ============================================================================
36+
# Detailed methodology configuration lives in:
37+
# .machine_readable/bot_directives/methodology.a2ml
38+
# .machine_readable/bot_directives/coverage.a2ml
39+
# .machine_readable/bot_directives/debt.a2ml
40+
#
41+
# AGENTIC.a2ml declares WHAT agents can do (permissions, gating).
42+
# bot_directives/ declares HOW agents should work (methodology).
43+
44+
[methodology]
45+
instructions-dir = ".machine_readable/bot_directives/"
46+
default-mode = "hybrid"
47+
48+
[automation-hooks]
49+
# on-enter: Read 0-AI-MANIFEST.a2ml, then STATE.a2ml, then bot_directives/
50+
# on-exit: Update STATE.a2ml, coverage.a2ml, and debt.a2ml with session outcomes
51+
# on-commit: Run just validate-rsr
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# ECOSYSTEM.a2ml — Ecosystem position
3+
# Converted from ECOSYSTEM.scm on 2026-04-14
4+
5+
[metadata]
6+
project = "pseudoscript"
7+
ecosystem = "hyperpolymath"
8+
9+
[position]
10+
type = "programming-language"
11+
purpose = "Pseudocode-syntax AffineScript. Write code that looks like pseudocode. Get affine resource guarantees and typed WASM out."
12+
13+
[pipeline]
14+
position = "co-product"
15+
chain = "katagoria → typell → typed-wasm → PanLL"
16+
notes = "PseudoScript compiles to typed WasmGC. TypeLL grounds its type system. typed-wasm provides the shared binary layout and ABI conventions."
17+
coordination = "nextgen-typing"
18+
19+
[related-projects]
20+
projects = [
21+
{ name = "typell", relationship = "type-theory-foundation", notes = "TypeLL's open-ended progressive framework grounds PseudoScript's type system. typell-pseudoscript bridge crate." },
22+
{ name = "typed-wasm", relationship = "aggregate-library", notes = "Shared binary layout conventions for WasmGC cross-language calls. PseudoScript Option[T]/Result[T,E]/String have agreed layouts here." },
23+
{ name = "nextgen-typing", relationship = "coordination-parent", notes = "Coordination monorepo for the type theory pipeline. Canonical architecture doc." },
24+
{ name = "affinescript", relationship = "foundation", notes = "PseudoScript is a syntactic face of AffineScript." },
25+
{ name = "rattlescript", relationship = "sibling", notes = "Both are syntactic faces of AffineScript." },
26+
{ name = "ephapax", relationship = "sibling-wasm-target", notes = "Both compile to typed WasmGC. Independent designs; converge at binary level via typed-wasm." },
27+
{ name = "katagoria", relationship = "research-upstream", notes = "Type theory research origination. Future PseudoScript type system extensions may originate there." },
28+
{ name = "panll", relationship = "consumer", notes = "PseudoScript is one of PanLL's development language targets." },
29+
]

.machine_readable/6a2/META.a2ml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# META.a2ml — Project meta-level information
5+
# Architecture decisions, design rationale, governance.
6+
7+
[metadata]
8+
version = "0.1.0"
9+
last-updated = "2026-04-11"
10+
11+
[project-info]
12+
type = "library" # TODO: update type (library|binary|service|website|monorepo) # library | binary | monorepo | service | website
13+
languages = [] # e.g. ["rust", "zig", "idris2"]
14+
license = "MPL-2.0"
15+
author = "Jonathan D.A. Jewell (hyperpolymath)"
16+
17+
[architecture-decisions]
18+
# ADR format: status = proposed | accepted | deprecated | superseded | rejected
19+
# - { id = "ADR-001", title = "Use Zig for FFI", status = "accepted", date = "2026-02-14" }
20+
21+
[development-practices]
22+
build-tool = "just"
23+
container-runtime = "podman"
24+
ci-platform = "github-actions"
25+
package-manager = "guix" # guix | nix | cargo | mix
26+
27+
[maintenance-axes]
28+
scoping-first = true
29+
execution-order = "axis-1 > axis-2 > axis-3"
30+
axis-1 = "must > intend > like"
31+
axis-2 = "corrective > adaptive > perfective"
32+
axis-3 = "systems > compliance > effects"
33+
34+
[scoping]
35+
sources = "README, roadmap, status docs, maintenance checklist, CI/security docs"
36+
marker-scan = "TODO/FIXME/XXX/HACK/STUB/PARTIAL"
37+
idris-unsound-scan = "believe_me/assert_total"
38+
39+
[axis-2-maintenance-rules]
40+
corrective-first = true
41+
adaptive-second = true
42+
adaptive-focus = "scope-change reconciliation, stale-reference removal, obsolete-work culling"
43+
perfective-third = true
44+
perfective-source = "axis-1 honest state after corrective/adaptive updates"
45+
46+
[axis-3-audit-rules]
47+
audit-focus = "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed"
48+
compliance-focus = "seams/compromises/exception register, bounded exceptions, anti-drift checks"
49+
drift-risk-example = "single exception broadening into policy violation (e.g. ReScript->TypeScript spread)"
50+
effects-evidence = "benchmark execution/results and maintainer status dialogue/review"
51+
52+
[design-rationale]
53+
# Key design decisions and their reasoning
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# NEUROSYM.a2ml — Neurosymbolic integration metadata
5+
# Configuration for Hypatia scanning and symbolic reasoning.
6+
7+
[metadata]
8+
version = "0.1.0"
9+
last-updated = "2026-04-11"
10+
11+
[hypatia-config]
12+
scan-enabled = true
13+
scan-depth = "standard" # quick | standard | deep
14+
report-format = "logtalk"
15+
16+
[symbolic-rules]
17+
# Custom symbolic rules for this project
18+
# - { name = "no-unsafe-ffi", pattern = "believe_me|unsafeCoerce", severity = "critical" }
19+
20+
[neural-config]
21+
# Neural pattern detection settings
22+
# confidence-threshold = 0.85
23+
# model = "hypatia-v2"

0 commit comments

Comments
 (0)