candor-ts 0.5.9 → 0.5.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "candor-ts",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "description": "candor for TypeScript — per-function side effects, transitively, with a policy gate (candor-spec 0.5)",
5
5
  "type": "module",
6
6
  "dependencies": {
package/scan-core.mjs CHANGED
@@ -49,6 +49,13 @@ export const KAPPA_RULES = [
49
49
  [/^(node:)?dns(\/promises)?$/,
50
50
  /^(?!(new|getServers|setServers|getDefaultResultOrder|setDefaultResultOrder)$)/, "Net"],
51
51
  [/^(node:)?child_process$/, null, "Exec"],
52
+ // node:worker_threads — `postMessage` crosses a thread boundary (the canonical Node worker IPC);
53
+ // `receiveMessageOnPort` reads it. Covers `worker.postMessage`, `parentPort.postMessage`, and a
54
+ // `MessagePort`'s `.postMessage` (all typed from this module). `new Worker(...)` spawns the thread but
55
+ // construction is inert here (like the net-cluster ctors) — the message verbs are the IPC boundary.
56
+ [/^(node:)?worker_threads$/, /^(postMessage|receiveMessageOnPort)$/, "Ipc"],
57
+ // node:cluster — `fork()` spawns a worker PROCESS and wires its IPC channel.
58
+ [/^(node:)?cluster$/, /^fork$/, "Ipc"],
52
59
  [/^(node:)?sqlite$/, null, "Db"],
53
60
  // the curated npm tier
54
61
  [/^(axios|got|node-fetch|undici|ws|socket\.io(-client)?|nodemailer)$/, null, "Net"],
package/scan.mjs CHANGED
@@ -917,6 +917,16 @@ function visitCalls(node) {
917
917
  // entropy were invisible).
918
918
  const name = decl.name ? decl.name.getText() : "";
919
919
  const parent = decl.parent && decl.parent.name ? decl.parent.name.getText() : "";
920
+ // `eval(code)` executes an arbitrary code string — it can perform ANY effect, so it is genuinely
921
+ // Unknown (the same posture as `new Function(s)`, which already reads Unknown via the no-decl
922
+ // path). The es-lib declares `eval` as a top-level ambient function (parent is the global/source
923
+ // file, no type name), and `globalThis.eval`/`window.eval`/`self.eval` all resolve to the same
924
+ // `eval` declaration — so keying on the resolved name catches every access form. Without this it
925
+ // resolved to a benign es-lib member and read SILENT-PURE (a code-execution sink reported pure).
926
+ if (name === "eval" && parent !== "Math" && parent !== "JSON") {
927
+ rec.direct.add("Unknown");
928
+ rec.why.add("call:eval");
929
+ }
920
930
  if ((parent === "DateConstructor" && name === "now") || (parent === "Performance" && name === "now"))
921
931
  rec.direct.add("Clock");
922
932
  if (parent === "Math" && name === "random") rec.direct.add("Rand");