@cello-protocol/gateway 0.0.1

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 (105) hide show
  1. package/dist/bin/cello-gateway.d.ts +3 -0
  2. package/dist/bin/cello-gateway.d.ts.map +1 -0
  3. package/dist/bin/cello-gateway.js +174 -0
  4. package/dist/bin/cello-gateway.js.map +1 -0
  5. package/dist/client.d.ts +16 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +182 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/config/config-store.d.ts +42 -0
  10. package/dist/config/config-store.d.ts.map +1 -0
  11. package/dist/config/config-store.js +198 -0
  12. package/dist/config/config-store.js.map +1 -0
  13. package/dist/detect/deberta-model-manifest.d.ts +54 -0
  14. package/dist/detect/deberta-model-manifest.d.ts.map +1 -0
  15. package/dist/detect/deberta-model-manifest.js +17 -0
  16. package/dist/detect/deberta-model-manifest.js.map +1 -0
  17. package/dist/detect/exfil.d.ts +14 -0
  18. package/dist/detect/exfil.d.ts.map +1 -0
  19. package/dist/detect/exfil.js +69 -0
  20. package/dist/detect/exfil.js.map +1 -0
  21. package/dist/detect/gitleaks-rules.d.ts +18 -0
  22. package/dist/detect/gitleaks-rules.d.ts.map +1 -0
  23. package/dist/detect/gitleaks-rules.js +229 -0
  24. package/dist/detect/gitleaks-rules.js.map +1 -0
  25. package/dist/detect/injection-patterns.d.ts +10 -0
  26. package/dist/detect/injection-patterns.d.ts.map +1 -0
  27. package/dist/detect/injection-patterns.js +53 -0
  28. package/dist/detect/injection-patterns.js.map +1 -0
  29. package/dist/detect/injection-scanner.d.ts +44 -0
  30. package/dist/detect/injection-scanner.d.ts.map +1 -0
  31. package/dist/detect/injection-scanner.js +45 -0
  32. package/dist/detect/injection-scanner.js.map +1 -0
  33. package/dist/detect/language.d.ts +37 -0
  34. package/dist/detect/language.d.ts.map +1 -0
  35. package/dist/detect/language.js +85 -0
  36. package/dist/detect/language.js.map +1 -0
  37. package/dist/detect/linear-regex.d.ts +20 -0
  38. package/dist/detect/linear-regex.d.ts.map +1 -0
  39. package/dist/detect/linear-regex.js +70 -0
  40. package/dist/detect/linear-regex.js.map +1 -0
  41. package/dist/detect/model-installer.d.ts +32 -0
  42. package/dist/detect/model-installer.d.ts.map +1 -0
  43. package/dist/detect/model-installer.js +94 -0
  44. package/dist/detect/model-installer.js.map +1 -0
  45. package/dist/detect/pii.d.ts +27 -0
  46. package/dist/detect/pii.d.ts.map +1 -0
  47. package/dist/detect/pii.js +119 -0
  48. package/dist/detect/pii.js.map +1 -0
  49. package/dist/detect/rate-limit.d.ts +44 -0
  50. package/dist/detect/rate-limit.d.ts.map +1 -0
  51. package/dist/detect/rate-limit.js +56 -0
  52. package/dist/detect/rate-limit.js.map +1 -0
  53. package/dist/detect/sanitize.d.ts +50 -0
  54. package/dist/detect/sanitize.d.ts.map +1 -0
  55. package/dist/detect/sanitize.js +211 -0
  56. package/dist/detect/sanitize.js.map +1 -0
  57. package/dist/detect/secrets.d.ts +20 -0
  58. package/dist/detect/secrets.d.ts.map +1 -0
  59. package/dist/detect/secrets.js +104 -0
  60. package/dist/detect/secrets.js.map +1 -0
  61. package/dist/index.d.ts +38 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +25 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/passthrough.d.ts +18 -0
  66. package/dist/passthrough.d.ts.map +1 -0
  67. package/dist/passthrough.js +21 -0
  68. package/dist/passthrough.js.map +1 -0
  69. package/dist/protocol.d.ts +53 -0
  70. package/dist/protocol.d.ts.map +1 -0
  71. package/dist/protocol.js +52 -0
  72. package/dist/protocol.js.map +1 -0
  73. package/dist/records/record-store.d.ts +28 -0
  74. package/dist/records/record-store.d.ts.map +1 -0
  75. package/dist/records/record-store.js +134 -0
  76. package/dist/records/record-store.js.map +1 -0
  77. package/dist/screen/inbound.d.ts +29 -0
  78. package/dist/screen/inbound.d.ts.map +1 -0
  79. package/dist/screen/inbound.js +127 -0
  80. package/dist/screen/inbound.js.map +1 -0
  81. package/dist/screen/inbound.test.d.ts +2 -0
  82. package/dist/screen/inbound.test.d.ts.map +1 -0
  83. package/dist/screen/inbound.test.js +49 -0
  84. package/dist/screen/inbound.test.js.map +1 -0
  85. package/dist/screen/outbound.d.ts +57 -0
  86. package/dist/screen/outbound.d.ts.map +1 -0
  87. package/dist/screen/outbound.js +183 -0
  88. package/dist/screen/outbound.js.map +1 -0
  89. package/dist/screen/outbound.test.d.ts +2 -0
  90. package/dist/screen/outbound.test.d.ts.map +1 -0
  91. package/dist/screen/outbound.test.js +62 -0
  92. package/dist/screen/outbound.test.js.map +1 -0
  93. package/dist/server.d.ts +34 -0
  94. package/dist/server.d.ts.map +1 -0
  95. package/dist/server.js +129 -0
  96. package/dist/server.js.map +1 -0
  97. package/dist/spawn.d.ts +32 -0
  98. package/dist/spawn.d.ts.map +1 -0
  99. package/dist/spawn.js +84 -0
  100. package/dist/spawn.js.map +1 -0
  101. package/dist/types.d.ts +121 -0
  102. package/dist/types.d.ts.map +1 -0
  103. package/dist/types.js +39 -0
  104. package/dist/types.js.map +1 -0
  105. package/package.json +42 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cello-gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cello-gateway.d.ts","sourceRoot":"","sources":["../../src/bin/cello-gateway.ts"],"names":[],"mappings":""}
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cello-gateway — the gateway program entry point.
4
+ *
5
+ * Reads its socket path (and optional request-log path) from the environment, starts the
6
+ * gateway server, and prints a READY line so a parent (spawnGatewaySidecar) knows it is
7
+ * listening. M9-CORE-001 runs the pass-through screen; later stories wire the detection
8
+ * pipeline into createGatewayServer's `screen` option here.
9
+ *
10
+ * This is the gateway's composition root — the one place a startup banner goes to stdout. The
11
+ * server itself stays logger-injected (no console.* in library code, INV-7).
12
+ */
13
+ import { createGatewayServer } from "../server.js";
14
+ import { GATEWAY_READY_TOKEN } from "../spawn.js";
15
+ import { OutboundScreener } from "../screen/outbound.js";
16
+ import { InboundScreener } from "../screen/inbound.js";
17
+ import { initLinearRegex } from "../detect/linear-regex.js";
18
+ import { compileInjectionPatterns } from "../detect/injection-patterns.js";
19
+ import { compileSecretRules } from "../detect/secrets.js";
20
+ import { GatewayConfigStore } from "../config/config-store.js";
21
+ import { GatewayRecordStore } from "../records/record-store.js";
22
+ import { createHash } from "node:crypto";
23
+ async function main() {
24
+ const socketPath = process.env["CELLO_GATEWAY_SOCKET"];
25
+ if (!socketPath) {
26
+ process.stderr.write("cello-gateway: CELLO_GATEWAY_SOCKET is required\n");
27
+ process.exit(2);
28
+ return;
29
+ }
30
+ const requestLogPath = process.env["CELLO_GATEWAY_REQUEST_LOG"];
31
+ // The real screen compositions. Config (PII whitelist, rate limit) is M9-CFG-001; defaults here
32
+ // (no whitelist, no rate cap) until that lands. Secret detection (M9-OUT-001) slots into the
33
+ // outbound screener once its RE2/gitleaks binding is chosen.
34
+ // Resolve the RE2 engine (native preferred, WASM fallback) and compile the injection-pattern set
35
+ // BEFORE accepting traffic — so the ReDoS-safe Step-9 scan is live from the first message.
36
+ const engine = await initLinearRegex();
37
+ compileInjectionPatterns();
38
+ compileSecretRules();
39
+ // M9-CFG-001 (INV-4): the gateway owns its config. When CELLO_GATEWAY_CONFIG_DB is set, the versioned
40
+ // config store is the SOURCE OF TRUTH (with its tighten-free / loosen-confirmed governance); env vars
41
+ // are the bootstrap fallback for any key the store has not set. Each setting defaults to its TIGHTEST
42
+ // value (empty whitelist, override off, no rate cap) so an absent/empty config never silently loosens.
43
+ const configDbPath = process.env["CELLO_GATEWAY_CONFIG_DB"];
44
+ const config = configDbPath ? new GatewayConfigStore(configDbPath) : undefined;
45
+ const cfg = (key, envFallback) => {
46
+ const v = config?.get(key);
47
+ return v !== undefined ? v : envFallback;
48
+ };
49
+ const piiWhitelist = cfg("pii_whitelist", (process.env["CELLO_GATEWAY_PII_WHITELIST"] ?? "").split(",").map((s) => s.trim()).filter(Boolean));
50
+ // autonomous_override defaults OFF — the agent's only autonomous lever over a PII warn is `redact`;
51
+ // allowing a value out is a human action (loosening the store requires confirmation).
52
+ const autonomousOverride = cfg("autonomous_override", process.env["CELLO_GATEWAY_AUTONOMOUS_OVERRIDE"] === "1");
53
+ // OUT-004 per-agent outbound rate cap. A positive cap enables it. NOTE: "no cap" is the LOOSEST state,
54
+ // not the tightest — so rate-limiting is OFF by default (the operator opts in to a cap). If a cap IS
55
+ // set but the window is missing/invalid, do NOT silently disable the cap (code-review M1) — fall back
56
+ // to a sane default window so a configured limit is never lost.
57
+ const DEFAULT_RATE_WINDOW_MS = 60_000;
58
+ const rateMax = Number(cfg("rate_max_per_window", Number(process.env["CELLO_GATEWAY_RATE_MAX_PER_WINDOW"])));
59
+ const rawWindow = Number(cfg("rate_window_ms", Number(process.env["CELLO_GATEWAY_RATE_WINDOW_MS"])));
60
+ const rateWindowMs = Number.isFinite(rawWindow) && rawWindow > 0 ? rawWindow : DEFAULT_RATE_WINDOW_MS;
61
+ const rateLimit = Number.isFinite(rateMax) && rateMax > 0
62
+ ? { maxPerWindow: rateMax, windowMs: rateWindowMs }
63
+ : undefined;
64
+ const outbound = new OutboundScreener({ piiWhitelist, autonomousOverride, ...(rateLimit ? { rateLimit } : {}) });
65
+ const inbound = new InboundScreener();
66
+ // M9-REC-001 (INV-4): the gateway records what it did to EVERY message in its own local store,
67
+ // hash-chained for tamper-evidence. Enabled when CELLO_GATEWAY_RECORD_DB is set. The verdict's
68
+ // disposition maps to the record: allow → clean (a clean pass IS recorded — an absent record is
69
+ // itself evidence of suppression), redact/block/warn verbatim.
70
+ const recordDbPath = process.env["CELLO_GATEWAY_RECORD_DB"];
71
+ const records = recordDbPath ? new GatewayRecordStore(recordDbPath) : undefined;
72
+ const recordOutcome = (direction, v, content, correlationId) => {
73
+ if (!records)
74
+ return;
75
+ const disposition = v.disposition === "allow" ? "clean" : v.disposition;
76
+ // A clean pass has no driving reason. For block/redact/warn the top-level reason wins, else the
77
+ // category of the event that drove the disposition — the two disposition enums (ScreenDisposition /
78
+ // GovernanceDisposition) share spelling for block/redact/warn, so this match is exact for those.
79
+ const reason = disposition === "clean"
80
+ ? undefined
81
+ : v.reason ?? v.events?.find((e) => e.disposition === v.disposition)?.category ?? v.events?.[0]?.category;
82
+ records.record({
83
+ direction,
84
+ disposition,
85
+ contentHash: createHash("sha256").update(content).digest("hex"),
86
+ ...(reason !== undefined ? { reason } : {}),
87
+ ...(correlationId !== undefined ? { correlationId } : {}), // INV-7: bind the flow id into the record (code-review HIGH)
88
+ });
89
+ };
90
+ /** Best-effort record on the error path — a record-write failure must not mask the screen_error block. */
91
+ const recordOutcomeBestEffort = (direction, v, content, correlationId) => {
92
+ try {
93
+ recordOutcome(direction, v, content, correlationId);
94
+ }
95
+ catch (err) {
96
+ process.stderr.write(`cello-gateway: record write failed on screen_error: ${err instanceof Error ? err.message : String(err)}\n`);
97
+ }
98
+ };
99
+ const handle = await createGatewayServer({
100
+ socketPath,
101
+ ...(requestLogPath ? { requestLogPath } : {}),
102
+ screen: async (req) => {
103
+ // Catch a screener fault HERE (not in the server's outer catch) so the screen_error block is
104
+ // RECORDED — otherwise a screened-and-blocked message would leave no audit row (code-review MED).
105
+ try {
106
+ if (req.direction === "outbound") {
107
+ const v = outbound.screen(req.content, {
108
+ agentName: req.agentName,
109
+ sessionId: req.sessionId,
110
+ ...(req.governanceDecisions !== undefined ? { governanceDecisions: req.governanceDecisions } : {}),
111
+ });
112
+ const verdict = {
113
+ disposition: v.disposition,
114
+ content: v.content,
115
+ events: v.events,
116
+ ...(v.reason !== undefined ? { reason: v.reason } : {}),
117
+ ...(v.guidance !== undefined ? { guidance: v.guidance } : {}),
118
+ };
119
+ recordOutcome("outbound", verdict, req.content, req.correlationId);
120
+ return verdict;
121
+ }
122
+ const v = await inbound.screen(req.content);
123
+ // On a block, nothing is delivered — omit the (original) content so a block doesn't ship the
124
+ // whole payload back over the socket (the daemon uses its own content hash). Only allow/redact
125
+ // carry content (redact's sanitized bytes; allow is reconstructed from the original by the client).
126
+ const verdict = {
127
+ disposition: v.disposition,
128
+ ...(v.disposition !== "block" ? { content: v.content } : {}),
129
+ events: v.events,
130
+ ...(v.terminal !== undefined ? { terminal: v.terminal } : {}),
131
+ ...(v.reason !== undefined ? { reason: v.reason } : {}),
132
+ ...(v.guidance !== undefined ? { guidance: v.guidance } : {}),
133
+ };
134
+ recordOutcome("inbound", verdict, req.content, req.correlationId);
135
+ return verdict;
136
+ }
137
+ catch (err) {
138
+ // A screener fault (or a record-write throw above) → fail-closed screen_error, recorded so the
139
+ // blocked message still leaves an audit row. The record is best-effort: a persistent DB failure
140
+ // still returns the block (fail-closed), logged, never silently swallowed.
141
+ process.stderr.write(`cello-gateway: screen error (${req.direction}): ${err instanceof Error ? err.message : String(err)}\n`);
142
+ const verdict = {
143
+ disposition: "block",
144
+ reason: "screen_error",
145
+ guidance: "The security gateway hit an internal error while screening this message. " +
146
+ "Nothing was delivered or sent. Check the gateway logs.",
147
+ };
148
+ recordOutcomeBestEffort(req.direction, verdict, req.content, req.correlationId);
149
+ return verdict;
150
+ }
151
+ },
152
+ });
153
+ // Signal readiness to the parent (spawnGatewaySidecar waits for this).
154
+ process.stdout.write(`${GATEWAY_READY_TOKEN} ${socketPath} regex-engine=${engine}\n`);
155
+ let stopping = false;
156
+ const shutdown = (signal) => {
157
+ if (stopping)
158
+ return;
159
+ stopping = true;
160
+ void handle.stop().then(() => {
161
+ config?.close();
162
+ records?.close();
163
+ process.stderr.write(`cello-gateway: stopped (${signal})\n`);
164
+ process.exit(0);
165
+ });
166
+ };
167
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
168
+ process.on("SIGINT", () => shutdown("SIGINT"));
169
+ }
170
+ main().catch((err) => {
171
+ process.stderr.write(`cello-gateway: fatal ${err instanceof Error ? err.message : String(err)}\n`);
172
+ process.exit(1);
173
+ });
174
+ //# sourceMappingURL=cello-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cello-gateway.js","sourceRoot":"","sources":["../../src/bin/cello-gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type ScreenContext, type ScreenVerdict, type SecurityGatewayClient } from "./types.js";
2
+ import type { GatewayLogger } from "./server.js";
3
+ export interface LocalSidecarGatewayClientOptions {
4
+ socketPath: string;
5
+ /** Per-call deadline. A call that does not get a verdict within this window fails closed. */
6
+ deadlineMs?: number;
7
+ logger?: GatewayLogger;
8
+ }
9
+ export declare class LocalSidecarGatewayClient implements SecurityGatewayClient {
10
+ #private;
11
+ constructor(opts: LocalSidecarGatewayClientOptions);
12
+ screenOutbound(content: Uint8Array, ctx: ScreenContext): Promise<ScreenVerdict>;
13
+ screenInbound(content: Uint8Array, ctx: ScreenContext): Promise<ScreenVerdict>;
14
+ close(): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAyC,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACvI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAYjD,MAAM,WAAW,gCAAgC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,qBAAa,yBAA0B,YAAW,qBAAqB;;gBAUzD,IAAI,EAAE,gCAAgC;IAMlD,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAI/E,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAIxE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CA6I7B"}
package/dist/client.js ADDED
@@ -0,0 +1,182 @@
1
+ /**
2
+ * LocalSidecarGatewayClient — the daemon's adapter to a gateway running as a local sidecar.
3
+ *
4
+ * Connects to the gateway's Unix domain socket and screens over the length-prefixed JSON
5
+ * protocol. Every call resolves to a terminal verdict within a deadline: a connect failure, a
6
+ * socket error, or a timeout all resolve to a fail-closed `block` (gateway_unavailable) — never
7
+ * a hang and never a silent allow (INV-6 / SI-001 / DB-001).
8
+ *
9
+ * Phase 2's remote gateway is a sibling implementation of SecurityGatewayClient that swaps this
10
+ * Unix socket for an mTLS connection; the daemon code and the message shapes are unchanged.
11
+ */
12
+ import { connect } from "node:net";
13
+ import { FrameDecoder, encodeFrame, SCREEN_OUTBOUND, SCREEN_INBOUND, } from "./protocol.js";
14
+ import { failClosedVerdict, GOVERNANCE_TIMEOUT } from "./types.js";
15
+ const NOOP_LOGGER = { info() { }, warn() { }, error() { } };
16
+ const DEFAULT_DEADLINE_MS = 5_000;
17
+ export class LocalSidecarGatewayClient {
18
+ #socketPath;
19
+ #deadlineMs;
20
+ #logger;
21
+ #socket = null;
22
+ #connecting = null;
23
+ #pending = new Map();
24
+ #nextId = 1;
25
+ #closed = false;
26
+ constructor(opts) {
27
+ this.#socketPath = opts.socketPath;
28
+ this.#deadlineMs = opts.deadlineMs ?? DEFAULT_DEADLINE_MS;
29
+ this.#logger = opts.logger ?? NOOP_LOGGER;
30
+ }
31
+ screenOutbound(content, ctx) {
32
+ return this.#screen(SCREEN_OUTBOUND, content, ctx);
33
+ }
34
+ screenInbound(content, ctx) {
35
+ return this.#screen(SCREEN_INBOUND, content, ctx);
36
+ }
37
+ async close() {
38
+ this.#closed = true;
39
+ const sock = this.#socket;
40
+ this.#socket = null;
41
+ if (sock)
42
+ await new Promise((resolve) => { sock.end(() => resolve()); });
43
+ // Any still-pending calls fail closed rather than hang on a closing client.
44
+ for (const [, p] of this.#pending) {
45
+ clearTimeout(p.timer);
46
+ p.resolve(failClosedVerdict(p.direction));
47
+ }
48
+ this.#pending.clear();
49
+ }
50
+ async #screen(method, content, ctx) {
51
+ const direction = method === SCREEN_OUTBOUND ? "outbound" : "inbound";
52
+ if (this.#closed)
53
+ return failClosedVerdict(direction);
54
+ let socket;
55
+ try {
56
+ socket = await this.#ensureConnected();
57
+ }
58
+ catch (err) {
59
+ this.#logger.warn("gateway.connect.failed", {
60
+ direction,
61
+ error: err instanceof Error ? err.message : String(err),
62
+ });
63
+ return failClosedVerdict(direction);
64
+ }
65
+ const id = this.#nextId++;
66
+ const request = {
67
+ id,
68
+ method,
69
+ content: Buffer.from(content).toString("base64"),
70
+ ctx: {
71
+ direction,
72
+ agentName: ctx.agentName,
73
+ sessionId: ctx.sessionId,
74
+ ...(ctx.correlationId !== undefined ? { correlationId: ctx.correlationId } : {}),
75
+ ...(ctx.governanceDecisions !== undefined ? { governanceDecisions: ctx.governanceDecisions } : {}),
76
+ },
77
+ };
78
+ return new Promise((resolve) => {
79
+ const timer = setTimeout(() => {
80
+ if (this.#pending.delete(id)) {
81
+ this.#logger.warn("gateway.screen.timeout", { direction, deadlineMs: this.#deadlineMs });
82
+ // Connected but no verdict within the deadline → governance_timeout (distinct from the
83
+ // unreachable case). A timeout is a verdict, not a hang (INV-6 / AC-005).
84
+ resolve(failClosedVerdict(direction, GOVERNANCE_TIMEOUT));
85
+ }
86
+ }, this.#deadlineMs);
87
+ if (typeof timer.unref === "function")
88
+ timer.unref();
89
+ this.#pending.set(id, { resolve, timer, direction, original: content });
90
+ try {
91
+ socket.write(encodeFrame(request));
92
+ }
93
+ catch (err) {
94
+ if (this.#pending.delete(id)) {
95
+ clearTimeout(timer);
96
+ this.#logger.warn("gateway.write.failed", {
97
+ direction,
98
+ error: err instanceof Error ? err.message : String(err),
99
+ });
100
+ resolve(failClosedVerdict(direction));
101
+ }
102
+ }
103
+ });
104
+ }
105
+ #ensureConnected() {
106
+ if (this.#socket && !this.#socket.destroyed)
107
+ return Promise.resolve(this.#socket);
108
+ if (this.#connecting)
109
+ return this.#connecting;
110
+ this.#connecting = new Promise((resolve, reject) => {
111
+ const sock = connect(this.#socketPath);
112
+ // L2: bound the CONNECT too — a stalled connect must fail closed, not hang (INV-6 is
113
+ // unconditional). A UDS connect normally settles immediately; this guards the pathological case.
114
+ const connectTimer = setTimeout(() => {
115
+ sock.destroy();
116
+ this.#connecting = null;
117
+ reject(new Error(`gateway connect timed out after ${this.#deadlineMs}ms`));
118
+ }, this.#deadlineMs);
119
+ if (typeof connectTimer.unref === "function")
120
+ connectTimer.unref();
121
+ const onError = (err) => {
122
+ clearTimeout(connectTimer);
123
+ sock.destroy();
124
+ this.#connecting = null;
125
+ reject(err);
126
+ };
127
+ sock.once("error", onError);
128
+ sock.once("connect", () => {
129
+ clearTimeout(connectTimer);
130
+ sock.off("error", onError);
131
+ this.#connecting = null;
132
+ this.#socket = sock;
133
+ const decoder = new FrameDecoder((obj) => this.#onResponse(obj), (err) => {
134
+ this.#logger.warn("gateway.response.decode.failed", { error: err.message });
135
+ sock.destroy();
136
+ });
137
+ sock.on("data", (chunk) => decoder.push(chunk));
138
+ // A dropped connection resolves every in-flight call fail-closed — never a hang.
139
+ const onClose = () => {
140
+ if (this.#socket === sock)
141
+ this.#socket = null;
142
+ for (const [, p] of this.#pending) {
143
+ clearTimeout(p.timer);
144
+ p.resolve(failClosedVerdict(p.direction));
145
+ }
146
+ this.#pending.clear();
147
+ };
148
+ sock.once("close", onClose);
149
+ sock.on("error", (err) => this.#logger.warn("gateway.socket.error", { error: err.message }));
150
+ resolve(sock);
151
+ });
152
+ });
153
+ return this.#connecting;
154
+ }
155
+ #onResponse(res) {
156
+ const pending = this.#pending.get(res.id);
157
+ if (!pending)
158
+ return; // already timed out / unknown id
159
+ this.#pending.delete(res.id);
160
+ clearTimeout(pending.timer);
161
+ const wire = res.verdict;
162
+ const verdict = { disposition: wire.disposition };
163
+ if (wire.disposition === "allow") {
164
+ // On allow the gateway omits content to keep the wire small; the daemon acts on the
165
+ // original bytes it submitted.
166
+ verdict.content = wire.content !== undefined ? Buffer.from(wire.content, "base64") : pending.original;
167
+ }
168
+ else if (wire.content !== undefined) {
169
+ verdict.content = Buffer.from(wire.content, "base64");
170
+ }
171
+ if (wire.reason !== undefined)
172
+ verdict.reason = wire.reason;
173
+ if (wire.guidance !== undefined)
174
+ verdict.guidance = wire.guidance;
175
+ if (wire.events !== undefined)
176
+ verdict.events = wire.events;
177
+ if (wire.terminal !== undefined)
178
+ verdict.terminal = wire.terminal;
179
+ pending.resolve(verdict);
180
+ }
181
+ }
182
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /** Whether a config change makes the gateway more restrictive (tighten), less (loosen), or neither. */
2
+ export type ConfigDirection = "tighten" | "loosen" | "neutral";
3
+ export type SetResult = {
4
+ ok: true;
5
+ version: number;
6
+ direction: ConfigDirection;
7
+ fingerprint: string;
8
+ } | {
9
+ ok: false;
10
+ reason: "needs_confirmation";
11
+ direction: "loosen";
12
+ };
13
+ export interface ConfigVersionRow {
14
+ version: number;
15
+ value: unknown;
16
+ direction: ConfigDirection;
17
+ confirmed: boolean;
18
+ fingerprint: string;
19
+ }
20
+ export declare class GatewayConfigStore {
21
+ #private;
22
+ constructor(dbPath: string);
23
+ /** Set `key` to `value`. Loosening requires `opts.confirmed`; tightening/neutral is free. The FIRST
24
+ * set of a key is classified against the per-key TIGHTEST baseline, not treated as free (B1). */
25
+ set(key: string, value: unknown, opts?: {
26
+ confirmed?: boolean;
27
+ }): SetResult;
28
+ /** The current (latest-version) value for `key`, or undefined if never set. */
29
+ get(key: string): unknown;
30
+ /** The full append-only version history for `key`, oldest first. */
31
+ history(key: string): ConfigVersionRow[];
32
+ /**
33
+ * Recompute the hash chain for `key` and confirm every stored fingerprint + prev-link matches
34
+ * (catches an edited value, a flipped `confirmed`, a relabelled `direction`, a deleted/reordered row).
35
+ * NOT resistant to a full consistent rewrite or tail truncation by an actor with DB write access +
36
+ * the (unkeyed) hash — that needs the Phase-2 attested head on the directory (M9-ATTEST-001); this is
37
+ * the local half (code-review M3, recorded).
38
+ */
39
+ verifyChain(key: string): boolean;
40
+ close(): void;
41
+ }
42
+ //# sourceMappingURL=config-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/config/config-store.ts"],"names":[],"mappings":"AAuBA,uGAAuG;AACvG,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE/D,MAAM,MAAM,SAAS,GACjB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,eAAe,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,QAAQ,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AA4FD,qBAAa,kBAAkB;;gBAIjB,MAAM,EAAE,MAAM;IAM1B;sGACkG;IAClG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,SAAS;IA2C/E,+EAA+E;IAC/E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAKzB,oEAAoE;IACpE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAaxC;;;;;;OAMG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAcjC,KAAK,IAAI,IAAI;CAWd"}