@mneme-ai/core 2.70.0 → 2.72.0

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.
Files changed (33) hide show
  1. package/dist/protoplasm/super_quan/cull.d.ts +70 -0
  2. package/dist/protoplasm/super_quan/cull.d.ts.map +1 -0
  3. package/dist/protoplasm/super_quan/cull.js +218 -0
  4. package/dist/protoplasm/super_quan/cull.js.map +1 -0
  5. package/dist/protoplasm/super_quan/guards.test.d.ts +7 -0
  6. package/dist/protoplasm/super_quan/guards.test.d.ts.map +1 -0
  7. package/dist/protoplasm/super_quan/guards.test.js +142 -0
  8. package/dist/protoplasm/super_quan/guards.test.js.map +1 -0
  9. package/dist/protoplasm/super_quan/homograph_guard.d.ts +47 -0
  10. package/dist/protoplasm/super_quan/homograph_guard.d.ts.map +1 -0
  11. package/dist/protoplasm/super_quan/homograph_guard.js +210 -0
  12. package/dist/protoplasm/super_quan/homograph_guard.js.map +1 -0
  13. package/dist/protoplasm/super_quan/index.d.ts +10 -0
  14. package/dist/protoplasm/super_quan/index.d.ts.map +1 -1
  15. package/dist/protoplasm/super_quan/index.js +10 -0
  16. package/dist/protoplasm/super_quan/index.js.map +1 -1
  17. package/dist/protoplasm/super_quan/input_size_guard.d.ts +58 -0
  18. package/dist/protoplasm/super_quan/input_size_guard.d.ts.map +1 -0
  19. package/dist/protoplasm/super_quan/input_size_guard.js +102 -0
  20. package/dist/protoplasm/super_quan/input_size_guard.js.map +1 -0
  21. package/dist/protoplasm/super_quan/prism.d.ts +50 -0
  22. package/dist/protoplasm/super_quan/prism.d.ts.map +1 -0
  23. package/dist/protoplasm/super_quan/prism.js +231 -0
  24. package/dist/protoplasm/super_quan/prism.js.map +1 -0
  25. package/dist/protoplasm/super_quan/tide_guard.d.ts +71 -0
  26. package/dist/protoplasm/super_quan/tide_guard.d.ts.map +1 -0
  27. package/dist/protoplasm/super_quan/tide_guard.js +135 -0
  28. package/dist/protoplasm/super_quan/tide_guard.js.map +1 -0
  29. package/dist/protoplasm/super_quan/vulns2.test.d.ts +6 -0
  30. package/dist/protoplasm/super_quan/vulns2.test.d.ts.map +1 -0
  31. package/dist/protoplasm/super_quan/vulns2.test.js +164 -0
  32. package/dist/protoplasm/super_quan/vulns2.test.js.map +1 -0
  33. package/package.json +1 -1
@@ -0,0 +1,70 @@
1
+ /**
2
+ * 💀 CULL — Process Reaper via Antibody Pattern + Quorum
3
+ *
4
+ * Closes v2.70 Vuln #4: 6 mneme node processes still alive after single
5
+ * test session → resource exhaustion over time.
6
+ *
7
+ * STRATEGY: every Mneme process writes an antibody to .mneme/cull/<pid>.beat
8
+ * containing { startedAt, processType, antibody }. On startup, every
9
+ * Mneme process runs CULL phase:
10
+ *
11
+ * 1. Scan .mneme/cull/ for all heartbeats
12
+ * 2. Filter to processes with same processType as me
13
+ * 3. Verify each is actually alive (process.kill(pid, 0))
14
+ * 4. Remove dead heartbeats (cleanup)
15
+ * 5. Apply policy: if alive count > maxPerType, cull oldest siblings
16
+ * until count == maxPerType
17
+ *
18
+ * Policy modes:
19
+ * - "youngest-wins" newer process kills older siblings (default)
20
+ * - "oldest-wins" new process refuses to start if maxPerType reached
21
+ * - "quorum" requires majority of siblings to vote out a peer
22
+ *
23
+ * Wild twist: MITOSIS BUDGET — process can split (spawn child) but the
24
+ * child inherits parent's antibody. CULL never kills siblings with
25
+ * matching parent-antibody chain.
26
+ */
27
+ export type CullPolicy = "youngest-wins" | "oldest-wins" | "quorum";
28
+ export interface CullHeartbeat {
29
+ pid: number;
30
+ ppid: number;
31
+ startedAt: string;
32
+ processType: string;
33
+ antibody: string;
34
+ parentAntibody?: string;
35
+ lastBeatAt: string;
36
+ }
37
+ export interface CullConfig {
38
+ cullDir: string;
39
+ policy: CullPolicy;
40
+ maxPerType: Record<string, number>;
41
+ staleAfterMs: number;
42
+ }
43
+ export declare const DEFAULT_CULL: CullConfig;
44
+ export interface CullReport {
45
+ scanned: number;
46
+ removedStale: number;
47
+ killedSiblings: number;
48
+ refusedToKill: number;
49
+ myPid: number;
50
+ myAntibody: string;
51
+ finalAlive: number;
52
+ policy: CullPolicy;
53
+ reasoning: string[];
54
+ hmac: string;
55
+ }
56
+ export declare class Cull {
57
+ readonly cfg: CullConfig;
58
+ constructor(cfg?: CullConfig);
59
+ /** Generate a stable per-process antibody. */
60
+ static makeAntibody(): string;
61
+ /** Write our heartbeat — call on startup + every N seconds. */
62
+ beat(processType: string, antibody: string, parentAntibody?: string): void;
63
+ /** Update lastBeatAt timestamp only. */
64
+ refresh(antibody: string): void;
65
+ /** Run CULL phase: scan, clean dead, enforce maxPerType. */
66
+ enforce(myProcessType: string, myAntibody: string): CullReport;
67
+ /** Count of alive processes by type (for monitoring). */
68
+ censusAlive(): Record<string, number>;
69
+ }
70
+ //# sourceMappingURL=cull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cull.d.ts","sourceRoot":"","sources":["../../../src/protoplasm/super_quan/cull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,UAK1B,CAAC;AAYF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,IAAI;aACa,GAAG,EAAE,UAAU;gBAAf,GAAG,GAAE,UAAyB;IAE1D,8CAA8C;IAC9C,MAAM,CAAC,YAAY,IAAI,MAAM;IAI7B,+DAA+D;IAC/D,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI;IAc1E,wCAAwC;IACxC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU/B,4DAA4D;IAC5D,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU;IAgF9D,yDAAyD;IACzD,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAWtC"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * 💀 CULL — Process Reaper via Antibody Pattern + Quorum
3
+ *
4
+ * Closes v2.70 Vuln #4: 6 mneme node processes still alive after single
5
+ * test session → resource exhaustion over time.
6
+ *
7
+ * STRATEGY: every Mneme process writes an antibody to .mneme/cull/<pid>.beat
8
+ * containing { startedAt, processType, antibody }. On startup, every
9
+ * Mneme process runs CULL phase:
10
+ *
11
+ * 1. Scan .mneme/cull/ for all heartbeats
12
+ * 2. Filter to processes with same processType as me
13
+ * 3. Verify each is actually alive (process.kill(pid, 0))
14
+ * 4. Remove dead heartbeats (cleanup)
15
+ * 5. Apply policy: if alive count > maxPerType, cull oldest siblings
16
+ * until count == maxPerType
17
+ *
18
+ * Policy modes:
19
+ * - "youngest-wins" newer process kills older siblings (default)
20
+ * - "oldest-wins" new process refuses to start if maxPerType reached
21
+ * - "quorum" requires majority of siblings to vote out a peer
22
+ *
23
+ * Wild twist: MITOSIS BUDGET — process can split (spawn child) but the
24
+ * child inherits parent's antibody. CULL never kills siblings with
25
+ * matching parent-antibody chain.
26
+ */
27
+ import { existsSync, readFileSync, writeFileSync, readdirSync, unlinkSync, mkdirSync } from "node:fs";
28
+ import { join } from "node:path";
29
+ import { createHmac } from "node:crypto";
30
+ export const DEFAULT_CULL = {
31
+ cullDir: ".mneme/cull",
32
+ policy: "youngest-wins",
33
+ maxPerType: { daemon: 1, "nucleus-daemon": 1, mcp: 2, bridge: 1, cli: 10 },
34
+ staleAfterMs: 60_000,
35
+ };
36
+ function aliveSafe(pid) {
37
+ if (pid === process.pid)
38
+ return true;
39
+ try {
40
+ process.kill(pid, 0);
41
+ return true;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ function killSafe(pid) {
48
+ if (pid === process.pid)
49
+ return false;
50
+ try {
51
+ process.kill(pid, "SIGTERM");
52
+ return true;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ export class Cull {
59
+ cfg;
60
+ constructor(cfg = DEFAULT_CULL) {
61
+ this.cfg = cfg;
62
+ }
63
+ /** Generate a stable per-process antibody. */
64
+ static makeAntibody() {
65
+ return createHmac("sha256", "mneme-cull").update(`${process.pid}::${process.hrtime.bigint()}::${Math.random()}`).digest("hex").slice(0, 12);
66
+ }
67
+ /** Write our heartbeat — call on startup + every N seconds. */
68
+ beat(processType, antibody, parentAntibody) {
69
+ mkdirSync(this.cfg.cullDir, { recursive: true });
70
+ const hb = {
71
+ pid: process.pid,
72
+ ppid: process.ppid,
73
+ startedAt: new Date().toISOString(),
74
+ processType,
75
+ antibody,
76
+ parentAntibody,
77
+ lastBeatAt: new Date().toISOString(),
78
+ };
79
+ writeFileSync(join(this.cfg.cullDir, `${process.pid}.beat`), JSON.stringify(hb), { encoding: "utf8" });
80
+ }
81
+ /** Update lastBeatAt timestamp only. */
82
+ refresh(antibody) {
83
+ const path = join(this.cfg.cullDir, `${process.pid}.beat`);
84
+ if (!existsSync(path))
85
+ return;
86
+ try {
87
+ const hb = JSON.parse(readFileSync(path, "utf8"));
88
+ hb.lastBeatAt = new Date().toISOString();
89
+ writeFileSync(path, JSON.stringify(hb), "utf8");
90
+ }
91
+ catch { /* */ }
92
+ }
93
+ /** Run CULL phase: scan, clean dead, enforce maxPerType. */
94
+ enforce(myProcessType, myAntibody) {
95
+ const reasoning = [];
96
+ if (!existsSync(this.cfg.cullDir)) {
97
+ mkdirSync(this.cfg.cullDir, { recursive: true });
98
+ }
99
+ const files = readdirSync(this.cfg.cullDir).filter((f) => f.endsWith(".beat"));
100
+ let scanned = 0, removedStale = 0, killedSiblings = 0, refusedToKill = 0;
101
+ const aliveOfMyType = [];
102
+ for (const f of files) {
103
+ scanned++;
104
+ const p = join(this.cfg.cullDir, f);
105
+ let hb;
106
+ try {
107
+ hb = JSON.parse(readFileSync(p, "utf8"));
108
+ }
109
+ catch {
110
+ try {
111
+ unlinkSync(p);
112
+ }
113
+ catch { /* */ }
114
+ removedStale++;
115
+ continue;
116
+ }
117
+ const ageMs = Date.now() - new Date(hb.lastBeatAt).getTime();
118
+ const stillAlive = aliveSafe(hb.pid);
119
+ if (!stillAlive || ageMs > this.cfg.staleAfterMs) {
120
+ try {
121
+ unlinkSync(p);
122
+ removedStale++;
123
+ reasoning.push(`removed stale heartbeat pid=${hb.pid} age=${ageMs}ms alive=${stillAlive}`);
124
+ }
125
+ catch { /* */ }
126
+ continue;
127
+ }
128
+ if (hb.processType === myProcessType)
129
+ aliveOfMyType.push(hb);
130
+ }
131
+ const limit = this.cfg.maxPerType[myProcessType] ?? 1;
132
+ if (aliveOfMyType.length > limit) {
133
+ // Sort by startedAt ASC — oldest first
134
+ aliveOfMyType.sort((a, b) => a.startedAt.localeCompare(b.startedAt));
135
+ const excess = aliveOfMyType.length - limit;
136
+ if (this.cfg.policy === "oldest-wins") {
137
+ // Refuse: don't kill anyone; report so caller can self-exit
138
+ refusedToKill = excess;
139
+ reasoning.push(`oldest-wins policy: ${excess} excess sibling(s) — caller should exit (suicide)`);
140
+ }
141
+ else if (this.cfg.policy === "quorum") {
142
+ // Need majority vote — for now, conservative: kill only if alone is "newest"
143
+ const myStartTime = aliveOfMyType.find((h) => h.pid === process.pid)?.startedAt ?? new Date().toISOString();
144
+ const olderThanMe = aliveOfMyType.filter((h) => h.startedAt < myStartTime).length;
145
+ if (olderThanMe > (aliveOfMyType.length / 2)) {
146
+ refusedToKill = excess;
147
+ reasoning.push(`quorum policy: I am newer than majority — refusing to kill`);
148
+ }
149
+ else {
150
+ // I am the elder; cull oldest excess
151
+ for (let i = 0; i < excess; i++) {
152
+ const victim = aliveOfMyType[i];
153
+ if (victim.pid === process.pid)
154
+ continue;
155
+ // Don't kill mitosis siblings (matching parent_antibody chain)
156
+ if (victim.parentAntibody && victim.parentAntibody === myAntibody) {
157
+ refusedToKill++;
158
+ reasoning.push(`refused to kill mitosis child pid=${victim.pid}`);
159
+ continue;
160
+ }
161
+ if (killSafe(victim.pid)) {
162
+ killedSiblings++;
163
+ reasoning.push(`killed sibling pid=${victim.pid} (started ${victim.startedAt})`);
164
+ }
165
+ else {
166
+ refusedToKill++;
167
+ reasoning.push(`could not kill pid=${victim.pid} (permission?)`);
168
+ }
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ // "youngest-wins" (default) — newer process (likely me) kills older siblings
174
+ for (let i = 0; i < excess; i++) {
175
+ const victim = aliveOfMyType[i];
176
+ if (victim.pid === process.pid)
177
+ continue;
178
+ if (victim.parentAntibody && victim.parentAntibody === myAntibody) {
179
+ refusedToKill++;
180
+ reasoning.push(`refused to kill mitosis child pid=${victim.pid}`);
181
+ continue;
182
+ }
183
+ if (killSafe(victim.pid)) {
184
+ killedSiblings++;
185
+ reasoning.push(`culled older sibling pid=${victim.pid}`);
186
+ }
187
+ else {
188
+ refusedToKill++;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ const finalAlive = aliveOfMyType.length - killedSiblings;
194
+ const body = { scanned, removedStale, killedSiblings, refusedToKill, finalAlive, processType: myProcessType, myAntibody };
195
+ const hmac = createHmac("sha256", "cull-report").update(JSON.stringify(body)).digest("hex").slice(0, 16);
196
+ return {
197
+ scanned, removedStale, killedSiblings, refusedToKill,
198
+ myPid: process.pid, myAntibody, finalAlive,
199
+ policy: this.cfg.policy, reasoning, hmac,
200
+ };
201
+ }
202
+ /** Count of alive processes by type (for monitoring). */
203
+ censusAlive() {
204
+ if (!existsSync(this.cfg.cullDir))
205
+ return {};
206
+ const counts = {};
207
+ for (const f of readdirSync(this.cfg.cullDir).filter((f) => f.endsWith(".beat"))) {
208
+ try {
209
+ const hb = JSON.parse(readFileSync(join(this.cfg.cullDir, f), "utf8"));
210
+ if (aliveSafe(hb.pid))
211
+ counts[hb.processType] = (counts[hb.processType] ?? 0) + 1;
212
+ }
213
+ catch { /* */ }
214
+ }
215
+ return counts;
216
+ }
217
+ }
218
+ //# sourceMappingURL=cull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cull.js","sourceRoot":"","sources":["../../../src/protoplasm/super_quan/cull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 🛡 Tests for HOMOGRAPH GUARD + INPUT SIZE GUARD
3
+ *
4
+ * Direct regression pin for the 2 v2.70 vulns user reported.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=guards.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.test.d.ts","sourceRoot":"","sources":["../../../src/protoplasm/super_quan/guards.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * 🛡 Tests for HOMOGRAPH GUARD + INPUT SIZE GUARD
3
+ *
4
+ * Direct regression pin for the 2 v2.70 vulns user reported.
5
+ */
6
+ import { describe, it, expect } from "vitest";
7
+ import { canonicalize, shouldReVerify } from "./homograph_guard.js";
8
+ import { checkInputSize, emitEnvelope, detectInputSource } from "./input_size_guard.js";
9
+ describe("🛡 HOMOGRAPH GUARD — Vuln #1 closure", () => {
10
+ it("REGRESSION: 'Ųĸ.70.0' (Arabic-Indic Ųĸ) canonicalizes to '2.70.0'", () => {
11
+ const r = canonicalize("Mneme is Ųĸ.70.0");
12
+ expect(r.canonical).toContain("2.70.0");
13
+ expect(r.flags).toContain("homograph_detected");
14
+ expect(r.digitsTransliterated).toBeGreaterThanOrEqual(1);
15
+ expect(shouldReVerify(r)).toBe(true);
16
+ });
17
+ it("Thai digits āš’.āš—āš.āš → 2.70.0", () => {
18
+ const r = canonicalize("version āš’.āš—āš.āš");
19
+ expect(r.canonical).toContain("2.70.0");
20
+ expect(r.flags).toContain("homograph_detected");
21
+ });
22
+ it("Fullwidth digits īŧ’.īŧ—īŧ.īŧ → 2.70.0", () => {
23
+ const r = canonicalize("see īŧ’.īŧ—īŧ.īŧ here");
24
+ expect(r.canonical).toContain("2.70.0");
25
+ expect(r.digitsTransliterated).toBeGreaterThanOrEqual(4);
26
+ });
27
+ it("Bengali digits ⧍.ā§­ā§Ļ.ā§Ļ → 2.70.0", () => {
28
+ const r = canonicalize("v ⧍.ā§­ā§Ļ.ā§Ļ");
29
+ expect(r.canonical).toContain("2.70.0");
30
+ });
31
+ it("Math bold digits 𝟐.𝟕𝟎.𝟎 → 2.70.0", () => {
32
+ const r = canonicalize("𝟐.𝟕𝟎.𝟎");
33
+ expect(r.canonical).toContain("2.70.0");
34
+ });
35
+ it("Cyrillic 'а' (U+0430) → Latin 'a'", () => {
36
+ const r = canonicalize("аpple"); // first char is Cyrillic
37
+ expect(r.canonical).toBe("apple");
38
+ expect(r.flags).toContain("homograph_detected");
39
+ expect(r.confusablesReplaced).toBeGreaterThanOrEqual(1);
40
+ });
41
+ it("BIDI override (U+202E) detected and stripped", () => {
42
+ const r = canonicalize("hello‮world");
43
+ expect(r.flags).toContain("rtl_override");
44
+ expect(r.canonical).toBe("helloworld");
45
+ });
46
+ it("Zero-width space stripped", () => {
47
+ const r = canonicalize("hello​world");
48
+ expect(r.flags).toContain("zwsp_injected");
49
+ expect(r.canonical).toBe("helloworld");
50
+ });
51
+ it("Control chars stripped", () => {
52
+ const r = canonicalize("hello\x00world\x07");
53
+ expect(r.flags).toContain("control_char_injected");
54
+ expect(r.canonical).toBe("helloworld");
55
+ });
56
+ it("Pure ASCII input passes unchanged (no flags)", () => {
57
+ const r = canonicalize("Mneme is 2.70.0");
58
+ expect(r.canonical).toBe("Mneme is 2.70.0");
59
+ expect(r.flags.length).toBe(0);
60
+ expect(shouldReVerify(r)).toBe(false);
61
+ });
62
+ it("Mixed-script Latin+Cyrillic flagged", () => {
63
+ // Use a Cyrillic letter that's NOT in our confusable map so canonicalize
64
+ // keeps it as Cyrillic → mixed script remains
65
+ const r = canonicalize("hello Đ–ĐžŅ€Đļ");
66
+ expect(r.flags).toContain("mixed_script");
67
+ });
68
+ it("All homograph defenses compose: BIDI + zwsp + Arabic-Indic together", () => {
69
+ const r = canonicalize("‮v​Ųĸ.Ų§Ų .Ų \x00");
70
+ expect(r.flags).toContain("rtl_override");
71
+ expect(r.flags).toContain("zwsp_injected");
72
+ expect(r.flags).toContain("control_char_injected");
73
+ expect(r.flags).toContain("homograph_detected");
74
+ expect(r.canonical).toContain("v2.70.0");
75
+ });
76
+ });
77
+ describe("🛡 INPUT SIZE GUARD — Vuln #2 closure", () => {
78
+ it("REGRESSION: 28K char argv input → rejected with JSON envelope (NOT silent)", () => {
79
+ const big = "a".repeat(28_000);
80
+ const r = checkInputSize(big, { source: "argv" });
81
+ expect(r.ok).toBe(false);
82
+ expect(r.envelope.error).toBe("INPUT_TOO_LARGE");
83
+ expect(r.envelope.sizeReceived).toBe(28_000);
84
+ expect(r.envelope.hint).toContain("stdin");
85
+ expect(r.receipt).toContain("28000B");
86
+ });
87
+ it("Same 28K input via stdin → accepted (10MB limit)", () => {
88
+ const big = "a".repeat(28_000);
89
+ const r = checkInputSize(big, { source: "stdin" });
90
+ expect(r.ok).toBe(true);
91
+ expect(r.envelope.error).toBeUndefined();
92
+ });
93
+ it("--allow-truncate accepts oversized input + flags truncation", () => {
94
+ const big = "x".repeat(50_000);
95
+ const r = checkInputSize(big, { source: "argv", allowTruncate: true });
96
+ expect(r.ok).toBe(true);
97
+ expect(r.truncated).toBe(true);
98
+ expect(r.truncatedAt).toBe(24_000);
99
+ expect(r.envelope.hint).toContain("first");
100
+ });
101
+ it("emitEnvelope always writes JSON, returns appropriate exit code", () => {
102
+ const collected = [];
103
+ const big = "a".repeat(30_000);
104
+ const r = checkInputSize(big, { source: "argv" });
105
+ const exitCode = emitEnvelope(r, (s) => collected.push(s));
106
+ expect(collected.length).toBe(1);
107
+ const parsed = JSON.parse(collected[0]);
108
+ expect(parsed.ok).toBe(false);
109
+ expect(exitCode).toBe(2); // distinct from generic crash exit 1
110
+ });
111
+ it("Small input via argv passes through", () => {
112
+ const r = checkInputSize("hello world", { source: "argv" });
113
+ expect(r.ok).toBe(true);
114
+ expect(r.truncated).toBe(false);
115
+ expect(r.envelope.ok).toBe(true);
116
+ });
117
+ it("Custom limit honored", () => {
118
+ const r = checkInputSize("12345", { source: "argv", customLimit: 3 });
119
+ expect(r.ok).toBe(false);
120
+ expect(r.limit).toBe(3);
121
+ });
122
+ it("Receipt includes head + tail for tamper-evident size proof", () => {
123
+ const r = checkInputSize("hello world this is a test input", { source: "argv" });
124
+ expect(r.receipt).toContain("hello");
125
+ expect(r.receipt).toMatch(/B head=/);
126
+ });
127
+ it("Envelope is a single-line JSON (safe for shell consumers)", () => {
128
+ const big = "x".repeat(40_000);
129
+ const r = checkInputSize(big, { source: "argv" });
130
+ const lines = [];
131
+ emitEnvelope(r, (s) => lines.push(s));
132
+ expect(lines.length).toBe(1);
133
+ expect(lines[0].endsWith("\n")).toBe(true);
134
+ // No newlines inside JSON body
135
+ expect(lines[0].slice(0, -1).split("\n").length).toBe(1);
136
+ });
137
+ it("detectInputSource returns a valid source", () => {
138
+ const s = detectInputSource();
139
+ expect(["argv", "stdin", "file", "unknown"]).toContain(s);
140
+ });
141
+ });
142
+ //# sourceMappingURL=guards.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.test.js","sourceRoot":"","sources":["../../../src/protoplasm/super_quan/guards.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 🛡 HOMOGRAPH GUARD — Unicode normalization + confusable detection
3
+ *
4
+ * Closes the v2.70 vuln: "Ųĸ.70.0" (Arabic-Indic digit) passed as MIXED
5
+ * instead of REFUTED → attacker bypassed version check by spelling the
6
+ * digit in a non-ASCII script.
7
+ *
8
+ * Solution stacks 4 lenses:
9
+ * 1. NFKC normalize → canonicalizes compatibility forms
10
+ * 2. Digit transliterate → maps all Unicode digits → ASCII 0-9
11
+ * 3. Confusable scan → flags homoglyph attempts (UTS #39 subset)
12
+ * 4. Pipeline annotation → caller knows input was canonicalized
13
+ *
14
+ * API:
15
+ * canonicalize(input) → { canonical, original, flags, transformations }
16
+ *
17
+ * Output flags drive verdict:
18
+ * "homograph_detected" → version claim has non-ASCII digits
19
+ * "mixed_script" → claim mixes script families (suspicious)
20
+ * "rtl_override" → contains BIDI override (U+202E)
21
+ * "control_char_injected" → contains null / BEL / BS / etc.
22
+ * "zwsp_injected" → zero-width space / joiner
23
+ *
24
+ * No external Unicode tables — uses Node's built-in normalize() + a
25
+ * small curated confusable map.
26
+ */
27
+ export interface CanonicalizeResult {
28
+ original: string;
29
+ canonical: string;
30
+ flags: string[];
31
+ transformations: string[];
32
+ confusablesReplaced: number;
33
+ digitsTransliterated: number;
34
+ }
35
+ export declare function canonicalize(input: string): CanonicalizeResult;
36
+ /**
37
+ * Convenience: given a claim, return whether it's safe to verify as-is
38
+ * or needs caller to re-verify on the canonical form.
39
+ *
40
+ * Caller should:
41
+ * const c = canonicalize(input);
42
+ * if (c.flags.includes("homograph_detected")) {
43
+ * // verify on c.canonical instead — annotate verdict with c.flags
44
+ * }
45
+ */
46
+ export declare function shouldReVerify(result: CanonicalizeResult): boolean;
47
+ //# sourceMappingURL=homograph_guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"homograph_guard.d.ts","sourceRoot":"","sources":["../../../src/protoplasm/super_quan/homograph_guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAsEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CAsE9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAElE"}