pi-crew 0.9.35 → 0.9.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.36] — security audit round 1 (2026-07-14)
4
+
5
+ Three security hardening fixes from the first formal security audit pass (run via `team_20260714045239_bb49d72211b966a2` + verified via `team_20260714062932_638dbb0310cc9f77`, 12/12 targeted tests pass, typecheck clean):
6
+
7
+ - **`writeIntermediate()` path-traversal guard** — `src/workflows/intermediate-store.ts`. `writeIntermediate()` previously had no validation on `phase`/`stepId` before constructing the filename, while the sibling `readIntermediate()` was already hardened (M-2 fix 2026-06-23). An attacker-controlled `phase` or `stepId` could write JSON to arbitrary paths. Fix: added `isSafePathId(phase) && isSafePathId(stepId)` guard at the top of `writeIntermediate()` — throws `Error("Invalid phase or stepId for intermediate store")` on bad input. Closes the write/read asymmetry.
8
+ - **Tests**: `test/unit/intermediate-store-traversal.test.ts` (+3 cases).
9
+ - **`InstinctStore` `projectId` validation** — `src/state/instinct-store.ts`. All 4 public methods that accept `projectId` (`saveInstinct`, `getProjectInstincts`, `promoteInstinct`, `deleteInstinct`) now call `assertSafePathId("projectId", projectId)` before using the value in `path.join()`.
10
+ - **Tests**: `test/unit/instinct-store-projectid-guard.test.ts` (+4 cases).
11
+ - **Verification env sanitization default → opt-out** — `src/runtime/verification-gates.ts`. `isVerificationEnvSanitizeEnabled()` flipped from opt-in (`PI_CREW_VERIFICATION_SANITIZE_ENV=1`) to opt-out (default `true`, explicitly disabled via env var set to `"0"`). Prevents accidental secret leakage to verification commands in untrusted repos — the safe path is now the default. `PI_CREW_VERIFICATION_PRESERVE_ENV=KEY1,KEY2,...` remains the escape hatch for tests/flows that legitimately need specific secrets.
12
+ - **Tests**: `test/unit/verification-gates-env-sanitize.test.ts` (5 cases) + `test/unit/verification-env-sanitize.test.ts` (7 integration cases).
13
+
14
+ **False positives eliminated during the audit** (documented so they don't reappear):
15
+
16
+ - `runtime/run-cache.ts` — cache keys are SHA-256 hex hashes (16 chars) — inherently safe from path injection.
17
+ - `runtime/task-runner/retrieval-orchestrator.ts` — `rg` invocations use `node:child_process.spawn()` with structured args, no shell. No injection vector.
18
+ - `runtime/pi-spawn.ts:159` `execSync("npm root -g")` — hardcoded command, `execSync` is intentional for Windows `PATHEXT` resolution.
19
+
20
+ **Files changed**: 4 src files, 3 test files, 1 comment-only update. +100 / -13 net.
21
+
22
+ ### Audit findings (security survey, see `.gsd/AUDIT-PLAN.md` for full detail)
23
+
24
+ Surveyed 36 process-execution call sites (`execSync`/`spawn`/`execFileSync`), 100+ `import()` sites, 13 `require()` sites, 9 `__proto__` references, path-traversal patterns, env sanitization, and unbounded data structures.
25
+
26
+ - **Path traversal**: 2 real issues fixed (`intermediate-store.ts`, `instinct-store.ts`); 1 false positive (`run-cache.ts`).
27
+ - **Process execution**: 1 critical-pattern (`sh -c` in `verification-gates.ts` — properly guarded by `validateGateCommand()`), 1 `execSync` with hardcoded command (intentional), 34 safe `spawn`/`execFileSync` with args arrays.
28
+ - **Env handling**: 1 real issue fixed (verification env default flipped to opt-out); 2 low/info items (rg inherits full env, `diagnostic-export` writes non-secret env vars — both by design).
29
+ - **Code injection**: 0 `eval`, 0 `new Function`, 0 `vm.*` usage, 0 `prototype[`. 9 `__proto__` references — all prototype-pollution defenses (`POLLUTED_KEYS` deny-lists).
30
+ - **Memory safety**: all major Maps/Sets have MAX_* caps + LRU eviction (workflowCache=32, teamCache=32, asyncAgentReaderCache=128, agentEventSeqCache=1000, liveAgents=5000, NotificationRouter.seen=10000, etc.).
31
+
3
32
  ## [0.9.35] — performance plan Phases 1–3 + 2 wiring fixes (2026-07-13)
4
33
 
5
34
  Shipped the **forward performance optimization plan** in 3 phases (`docs/performance-optimization-execution-plan.md`) plus 2 follow-up wiring fixes for the `pipeline` workflow and `schedule` action. 8 performance optimizations landed + 1 bundle rebuild. End-to-end verified post-restart via `team action='run', workflow='pipeline', team='research'` (`team_20260713102348_529c8e4e79e90e20`, 4/4 tasks, 142,686 tokens, 6.4 min, pipeline-summary.md emitted with "PIPELINE_WORKFLOW_OK" + scheduled job successfully removed via new subAction). Typecheck clean, 63 + 58 + 92 targeted unit tests pass across the modified suites.
@@ -12891,7 +12891,7 @@
12891
12891
  "format": "esm"
12892
12892
  },
12893
12893
  "src/runtime/async-runner.ts": {
12894
- "bytes": 14704,
12894
+ "bytes": 14705,
12895
12895
  "imports": [
12896
12896
  {
12897
12897
  "path": "node:child_process",
@@ -14759,7 +14759,7 @@
14759
14759
  "format": "esm"
14760
14760
  },
14761
14761
  "src/runtime/verification-gates.ts": {
14762
- "bytes": 17042,
14762
+ "bytes": 17191,
14763
14763
  "imports": [
14764
14764
  {
14765
14765
  "path": "node:child_process",
@@ -18415,7 +18415,7 @@
18415
18415
  "imports": [],
18416
18416
  "exports": [],
18417
18417
  "inputs": {},
18418
- "bytes": 6696933
18418
+ "bytes": 6697128
18419
18419
  },
18420
18420
  "dist/index.mjs": {
18421
18421
  "imports": [
@@ -21546,7 +21546,7 @@
21546
21546
  "bytesInOutput": 2699
21547
21547
  },
21548
21548
  "src/runtime/async-runner.ts": {
21549
- "bytesInOutput": 8942
21549
+ "bytesInOutput": 8943
21550
21550
  },
21551
21551
  "src/subagents/async-entry.ts": {
21552
21552
  "bytesInOutput": 119
@@ -21792,7 +21792,7 @@
21792
21792
  "bytesInOutput": 810
21793
21793
  },
21794
21794
  "src/runtime/verification-gates.ts": {
21795
- "bytesInOutput": 7561
21795
+ "bytesInOutput": 7597
21796
21796
  },
21797
21797
  "src/runtime/worker-startup.ts": {
21798
21798
  "bytesInOutput": 2344
@@ -22125,7 +22125,7 @@
22125
22125
  "bytesInOutput": 81
22126
22126
  }
22127
22127
  },
22128
- "bytes": 3172886
22128
+ "bytes": 3172923
22129
22129
  }
22130
22130
  }
22131
22131
  }
package/dist/index.mjs CHANGED
@@ -48581,7 +48581,7 @@ var init_async_runner = __esm({
48581
48581
  // Phase 1.5: worker-thread atomic writer opt-in (RFC 15).
48582
48582
  "PI_CREW_WORKER_ATOMIC_WRITER",
48583
48583
  "PI_TEAMS_WORKER_ATOMIC_WRITER",
48584
- // Phase 1.5 #1: verification env sanitization opt-in (RFC 13 §6).
48584
+ // Phase 1.5 #1: verification env sanitization opt-out (RFC 13 §6).
48585
48585
  "PI_CREW_VERIFICATION_SANITIZE_ENV",
48586
48586
  "PI_TEAMS_VERIFICATION_SANITIZE_ENV",
48587
48587
  "PI_CREW_VERIFICATION_PRESERVE_ENV",
@@ -58026,7 +58026,10 @@ import { spawn as spawn4 } from "node:child_process";
58026
58026
  import * as fs82 from "node:fs";
58027
58027
  import * as path69 from "node:path";
58028
58028
  function isVerificationEnvSanitizeEnabled() {
58029
- return process.env.PI_CREW_VERIFICATION_SANITIZE_ENV === "1" || process.env.PI_TEAMS_VERIFICATION_SANITIZE_ENV === "1";
58029
+ if (process.env.PI_CREW_VERIFICATION_SANITIZE_ENV === "0" || process.env.PI_TEAMS_VERIFICATION_SANITIZE_ENV === "0") {
58030
+ return false;
58031
+ }
58032
+ return true;
58030
58033
  }
58031
58034
  function buildVerificationEnv() {
58032
58035
  if (!isVerificationEnvSanitizeEnabled()) {