Skip to content

Wire installer to materialise SecurityValidator runtime artefacts (#160)#161

Merged
virtualian merged 1 commit intomainfrom
160-installer-securityvalidator-materialize
Apr 27, 2026
Merged

Wire installer to materialise SecurityValidator runtime artefacts (#160)#161
virtualian merged 1 commit intomainfrom
160-installer-securityvalidator-materialize

Conversation

@virtualian
Copy link
Copy Markdown
Owner

Summary

Closes #160. Closes the SecurityValidator regression chain #156 → #157 → #158 → #159 → #160:

Changes

File Change
Releases/v4.0.3+/.claude/PAI-Install/engine/pai-runtime-migration.ts NEW — migratePaiRuntime helper
Releases/v4.0.3+/.claude/PAI-Install/engine/actions.ts +9 — invoke from runRepository after migratePerPackCommands
Releases/v4.0.3+/.claude/PAI-Install/engine/exec.ts +25 — add tryExecAt (structured cwd, no shell)
Releases/v4.0.3+/.claude/bun.lock NEW — tracked lockfile, pins yaml@2.8.3

Decisions (recorded in PRD)

  • D1 — Materialisation: copy, not symlink. ~/.pai/ is an independent runtime; user-edited patterns.yaml lives alongside the shipped patterns.example.yaml without crossing the ~/.claude boundary.
  • D2 — bun.lock tracked in repo. Pins yaml@2.8.3 for reproducible installs across machines/dates. ~360 bytes.
  • No new StepId. The helper extends runRepository, mirroring the three existing migrators (memory, skills, commands).

Behaviour

  • Fresh install: copies package.json + bun.lock, runs bun install, copies PAI/PAISECURITYSYSTEM/failed=0, verify-security-validator.sh PASS=8 FAIL=0.
  • Upgrade (idempotent): already-current for manifest, skipped-yaml-present for install, copied for PAISECURITYSYSTEM (cpSync merge semantics — user-edited patterns.yaml preserved).
  • Manifest refreshed (yaml version bump): force-runs bun install even when yaml marker is present, so the new pin actually lands in node_modules/.
  • Soft-fail: failures (missing source, permission denied, bun install timeout) emit a clear message and continue; the install does NOT abort. verify-security-validator.sh is the post-install regression guard.
  • Defensive invariant: if ~/.pai/ exists as a regular file (corrupted state), aborts the module with a clear diagnostic rather than overwriting user data.

Security review (in-PR)

/simplify flagged a shell-injection vector in the first cut — tryExec(\"cd \\\"\${paiHome}\\\" && bun install\") would have failed on paths containing quotes/dollars/backticks and was injection-prone if PAI_DIR were ever attacker-influenced. Fixed by adding tryExecAt to exec.ts (uses execFileSync with structured cwd, no shell concatenation).

Other findings actioned: idempotency hole on yaml major-bump (force install when manifest just changed), missing paiHome-is-directory invariant (clear-diagnostic abort), redundant intermediate mkdirSync (cpSync recursive: true creates intermediates — empirically verified).

Out of scope

  • Triplication refactor (getPaiHomeDir × 3, cpFilter/isIgnored × 3 across migrators) — flagged HIGH severity by /simplify but touches three existing reviewed modules. Tracked separately (issue to be filed).
  • Whatever populates ~/.claude/PAI/ on a fresh upstream clone (this PR tolerates source-absent gracefully via soft-fail; the upstream gap is Investigate: restructure two-root split to simplify absorbing upstream releases #144 territory).

Test plan

  • Run bash Tools/verify-security-validator.sh post-install on a fresh machine — expect PASS=8 FAIL=0.
  • Run installer in upgrade mode on an existing install — expect already-current / skipped-yaml-present summary, no patterns.yaml clobbering.
  • Bump yaml dep version in Releases/v4.0.3+/.claude/package.json, regenerate bun.lock, run installer — confirm bun install re-runs and yaml updates in ~/.pai/node_modules/yaml/.

Closes the regression chain #156#157#158#159#160. New
`migratePaiRuntime` helper copies `~/.claude/{package.json,bun.lock}`
and `~/.claude/PAI/PAISECURITYSYSTEM/` into `~/.pai/`, then runs
`bun install` if `node_modules/yaml/` is absent or the manifest was
just refreshed. Adds `tryExecAt` (structured cwd, no shell) to
`exec.ts`. Tracks `Releases/v4.0.3+/.claude/bun.lock` for reproducible
installs (pins yaml@2.8.3).

Soft-fails per sub-routine — failures surface via
`Tools/verify-security-validator.sh` rather than aborting the install.
After this lands, a fresh-machine install passes the verify script
PASS=8 FAIL=0 with no manual setup.

- New: `Releases/v4.0.3+/.claude/PAI-Install/engine/pai-runtime-migration.ts`
- New: `Releases/v4.0.3+/.claude/bun.lock`
- Edit: `actions.ts` — invoke from `runRepository` after
  `migratePerPackCommands`, both fresh-install and upgrade paths
- Edit: `exec.ts` — add `tryExecAt` for shell-free subprocess calls
@virtualian virtualian merged commit 16e21be into main Apr 27, 2026
@virtualian virtualian deleted the 160-installer-securityvalidator-materialize branch April 27, 2026 15:31
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.

SecurityValidator: wire installer to materialize ~/.pai/package.json + bun install + PAI/PAISECURITYSYSTEM (#158 follow-up)

1 participant