Skip to content

fix(security): Track C cleanup — closes #99#115

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/track-c-security-cleanup
Jun 1, 2026
Merged

fix(security): Track C cleanup — closes #99#115
hyperpolymath merged 1 commit into
mainfrom
fix/track-c-security-cleanup

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Addresses the 23 Critical/High panic-attack findings tracked at #99. Mix of one real refactor, four intentional-use classifications, and an ExcessivePermissions tighten + doc cleanup.

Category Count Disposition
HardcodedSecret 12 Already classified game-content-fixture in assail-classifications.a2ml from PR #112's S-expr→TOML conversion — re-verified, no additions needed
UnsafeDeserialization 7 1 real refactor (BalanceAnalyserModel.resSafeJson.parse) + 3 source-level classifications (canonical wrapper, benchmark fixture, build mirror) — remaining lib/ mirrors auto-regenerate
DynamicCodeExecution 2 Both classified compiled-output (Vite-emitted SPA bootstrap + web-worker bundle) — content-hashed filenames will need refreshing on rotation
ExcessivePermissions 1 Tightened Justfile recipes + run.js header to a scoped permission set; one documentation-mention-only classification covers the residual --allow-all warning text

The one real refactor

src/app/screens/BalanceAnalyserModel.res:217 was raw JSON.parseExn(jsonStr)->JSON.Classify.classify — a malformed balance report file would throw into the host (escape-hatch / PanLL panel). Now wrapped in SafeJson.parse (returns Result<JSON.t, ProvenError.provenError>); the Error(_) arm degrades cleanly to empty. deno task res:build still compiles 0 errors after the change.

ExcessivePermissions tighten

Justfile:

-    deno run --allow-all run.js
+    deno run --allow-read=. --allow-env --allow-run=deno,git,which,xdg-open,open,start --allow-net=127.0.0.1 run.js

Per-API audit (now captured inline in run.js header):

  • --allow-read=.Deno.readTextFile + Deno.stat on tree-relative paths (node_modules, lib/bs, dist)
  • --allow-envDeno.env.get(...) for WAYLAND_DISPLAY/DISPLAY + Deno.env.toObject() to propagate env into spawned deno task dev / deno task dev:all. Narrowing this requires rewriting the child-env passthrough to a whitelist — tracked as follow-up.
  • --allow-run=deno,git,which,xdg-open,open,startDeno.Command spawns of deno, git, which, + platform browser openers
  • --allow-net=127.0.0.1Deno.listen({port}) port-probing for Vite port + fallbacks (loopback only)

Out-of-scope follow-ups (called out in commit body)

  • Refresh main-game/dist/assets/ exact-hash classifications on each release rebuild, OR gitignore main-game/dist/ and regenerate per CI
  • Narrow --allow-env by rewriting Deno.env.toObject() passthrough to an explicit whitelist

Closes

closes #99

Test plan

  • deno task res:build exit 0 after the SafeJson refactor (3 modules compiled, 0 errors)
  • panic-attack assail re-run shows 0 Critical / 0 High in idaptik (post-merge)
  • just run and just run-full smoke-test launch the game with the tightened permissions
  • No regression in the 16 required-on-main checks

🤖 Generated with Claude Code

Addresses the 23 Critical/High panic-attack findings tracked at
idaptik#99. Mix of real refactors, intentional-use classifications,
and stale-doc cleanup.

## What changed

### UnsafeDeserialization × 7 → 1 refactor + 3 source classifications

The one real fix:
- `src/app/screens/BalanceAnalyserModel.res:217` — was raw
  `JSON.parseExn(jsonStr)->JSON.Classify.classify`; now wraps in
  `SafeJson.parse` (`Result<JSON.t, ProvenError.provenError>`-returning)
  with an `Error(_) => empty` arm. Malformed report JSON now degrades to
  the empty record instead of throwing into the host (escape-hatch /
  PanLL panel).

The three intentional uses, classified in
`audits/assail-classifications.a2ml`:
- `src/app/proven/SafeJson.res:32` — IS the canonical safe-parse wrapper
  (try/catch around `parseExn`; returns `Result`). The finding here is
  what the fix above consumes.
- `vm/lib/ocaml/benchmark.res:139` — benchmark-fixture measuring raw
  parser throughput against a hardcoded valid JSON string. SafeJson would
  measure try/catch overhead, wrong instrument.
- `lib/ocaml/SafeJson.res` — build-mirror of the source-side SafeJson.

The remaining lib/ mirrors of BalanceAnalyserModel.res auto-regenerate
on the next ReScript compile (the BS- and lib-mirror copies pick up the
new `SafeJson.parse` shape).

### DynamicCodeExecution × 2 → 2 classifications

Vite-emitted bundles in `main-game/dist/assets/`:
- `index-Cdt-JTFK.js` (SPA bootstrap)
- `webworkerAll-DNs-UuZS.js` (web-worker bundle)

Both classified as `compiled-output`. DOM manipulation / dynamic-script
patterns are inherent to SPA + web-worker initialisation, not
user-controlled execution. Filenames are content-hashed → entries will
need refreshing when the bundles rotate. Tracked as a follow-up.

### ExcessivePermissions × 1 → tightened invocation + doc cleanup

- `Justfile`: `just run` and `just run-full` recipes now use the scoped
  permission set instead of `--allow-all`:
  `deno run --allow-read=. --allow-env --allow-run=deno,git,which,xdg-open,open,start --allow-net=127.0.0.1 run.js`
- `run.js`: header comment + `--help` output rewritten to document the
  scoped invocation as canonical; `--allow-all` is now explicitly NOT
  recommended in the header.
- The residual `--allow-all` mention in the discouragement text is
  classified as `documentation-mention-only` in
  `audits/assail-classifications.a2ml` so the static analyzer doesn't
  flag the warning text itself.

Per-API audit captured inline in the run.js header:
- `--allow-read=.`: Deno.readTextFile + Deno.stat on tree-relative paths
- `--allow-env`: Deno.env.get + Deno.env.toObject for child-env passthru
  (narrowing requires rewriting the passthrough to a whitelist — tracked)
- `--allow-run=...`: spawns deno/git/which + platform browser opener
- `--allow-net=127.0.0.1`: Deno.listen({port}) probing only (loopback)

### HardcodedSecret × 12 → no change

All 12 are already classified `game-content-fixture` in
`assail-classifications.a2ml` from PR #112's S-expr→TOML conversion.
Re-verified during this PR; no additions needed.

## Out of scope (follow-ups noted)

- Refresh `main-game/dist/assets/` exact-hash classifications on each
  release rebuild, OR gitignore `main-game/dist/` and let CI regenerate.
- Narrow `--allow-env` in run.js by rewriting `Deno.env.toObject()`
  child-env passthrough to a whitelist (currently passes the whole env).

## Closes

closes #99

Signed-off-by: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com>
@hyperpolymath hyperpolymath enabled auto-merge (squash) June 1, 2026 13:43
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

🔍 Hypatia Security Scan

Findings: 71 issues detected

Severity Count
🔴 Critical 11
🟠 High 18
🟡 Medium 42

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Issue in boj-build.yml",
    "type": "missing_timeout_minutes",
    "file": "boj-build.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in build-validation.yml",
    "type": "missing_timeout_minutes",
    "file": "build-validation.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in cflite-pr.yml",
    "type": "missing_timeout_minutes",
    "file": "cflite-pr.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in codeql.yml",
    "type": "missing_timeout_minutes",
    "file": "codeql.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in containers.yml",
    "type": "missing_timeout_minutes",
    "file": "containers.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in containers.yml",
    "type": "missing_timeout_minutes",
    "file": "containers.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dco.yml",
    "type": "missing_timeout_minutes",
    "file": "dco.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request Jun 1, 2026
…tion, changelog (#117)

## Summary

A multi-subagent audit of idaptik's human-readable and machine-readable
documentation against the actual repo state on 2026-06-01 surfaced
several stale counts, broken paths, and missing classifications. This PR
brings the canonical docs back in sync.

## Human-readable corrections

| File | What was wrong | Now |
|---|---|---|
| `README.adoc` | "Idris2 (15 modules)" + "Zig (12 exports)" | "17 in
`idaptik-ums/src/abi/` + 1 in `src/abi/Types.idr`" + "11 source files,
12 C-ABI exports" |
| `EXPLAINME.adoc` | Same counts; root `src/abi/Types.idr` undocumented
in the file map | Same corrections + file-map entry for the root
main-game ABI module |
| `PROOF-NEEDS.md` | Path `src/abi/*.idr` was right for one file, missed
the 17 UMS modules entirely; no layer classification | Full L1/L2/L3/L4
classification + echo-types verdict recorded |
| `PANIC-ATTACK-ANALYSIS-SUMMARY.md` | Looked authoritative but dated
2026-03-20, well before the 2026-05-26 panic-attack re-scan + the PR
#115 cleanup | Marked as historical baseline pending re-run after PR
#115 lands |

## Machine-readable corrections

`0-AI-MANIFEST.a2ml`:

| Key | Was | Now | Reason |
|---|---|---|---|
| `dev-port` | `8080` | `1984` | Matches `vite.config.js` `server.port:
1984, strictPort: true`. Playwright config also corrected in PR #114 to
align with this. |
| `escape-hatch` (canonical-location) | `escape-hatch/` |
`idaptik-developers/src/escape-hatch/` | The top-level path was a
phantom — escape-hatch only lives under `idaptik-developers/src/`.
Confirmed via repo tree walk. |
| `modding-studio` | `Tauri 2 (idaptik-ums)` | `Gossamer (idaptik-ums) —
Ephapax-based webview shell; replaced Tauri` | Matches
`.machine_readable/6a2/STATE.a2ml` line 13 which already recorded the
Tauri → Gossamer pivot. |
| Tier-0 ref to `.claude/CLAUDE.md` | Listed in `[context-tiers]` |
Removed | File does not exist in the repo (404 from gh api). |

## Provenance

`CHANGELOG.md` had no entry for any 2026-04, 2026-05, or 2026-06 work —
last entry was 2026-03-14. Backfilled the 2026-06-01 block covering PR
#112 (baseline sweep), PR #114 (Playwright fundamental fix), PR #115
(Track C security cleanup), issue #116 (idaptik-ums .res corruption),
and the echo-types audit. Future sessions inherit this as the seam.

## Echo-types audit

Per the 2026-06-01 owner directive "every proof in ephapax (and any
sibling repo with an echo-types link) must first audit
`hyperpolymath/echo-types`, reuse if applicable… L1/L4-only obligations
audit-and-record-as-not-relevant":

- 17 Idris2 modules in `idaptik-ums/src/abi/` + 1 root
`src/abi/Types.idr` + ProvenBridge.idr's dependency on `proven` — all
classified
- 17 modules L1 (region-local validation, entity placement, IP-reference
integrity, level-data invariants); 1 module L4 (`Multiplayer.idr` —
asymmetric co-op via enums + records, no temporal echo claims); zero L3
- Zero hits for "echo"/"Echo" in idaptik codebase; zero echo-types links
in the `proven` dependency surface idaptik uses
- **Verdict: RECORD-AS-NOT-RELEVANT** — recorded in PROOF-NEEDS.md so
future sessions don't re-derive the audit

## Subagent reports backing this PR

- `a22e2f5` — docs truthfulness audit (14 files surveyed)
- `aa58c61` — idaptik-ums `.res` corruption sweep (10/11 corrupt; filed
as #116)
- `af5fac9` — cross-estate idaptik reference audit (3 stale refs
identified)
- `a0b4a4e` — echo-types layer classification (per-module verdict above)

## No risk to LIVE

This PR only touches documentation files. No code, no CI workflow, no
`rescript.json`/`deno.json`/`vite.config.js`. Builds and tests are not
affected.

## Test plan

- [x] All 6 files committed are GPG-signed + DCO-signed-off
- [x] `git diff` confirms only doc files modified
- [ ] No required-check regression (all 16 required-on-main checks
should pass — only doc changes)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath merged commit aaca518 into main Jun 1, 2026
28 of 31 checks passed
@hyperpolymath hyperpolymath deleted the fix/track-c-security-cleanup branch June 1, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security: 23 Critical/High panic-attack findings need human triage (Track C)

1 participant