@sunaiva/gate 1.0.0 → 1.1.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 (76) hide show
  1. package/BUSINESS_LICENSE.md +70 -0
  2. package/CHANGELOG.md +148 -0
  3. package/LICENSE +0 -0
  4. package/README.md +411 -27
  5. package/dist/config/defaults.d.ts +22 -1
  6. package/dist/config/defaults.d.ts.map +1 -1
  7. package/dist/config/defaults.js +56 -8
  8. package/dist/config/defaults.js.map +1 -1
  9. package/dist/config/loader.d.ts +0 -0
  10. package/dist/config/loader.d.ts.map +1 -1
  11. package/dist/config/loader.js +24 -6
  12. package/dist/config/loader.js.map +1 -1
  13. package/dist/engine/backend-client.d.ts +58 -0
  14. package/dist/engine/backend-client.d.ts.map +1 -0
  15. package/dist/engine/backend-client.js +287 -0
  16. package/dist/engine/backend-client.js.map +1 -0
  17. package/dist/engine/hmac-verifier.d.ts +33 -0
  18. package/dist/engine/hmac-verifier.d.ts.map +1 -0
  19. package/dist/engine/hmac-verifier.js +161 -0
  20. package/dist/engine/hmac-verifier.js.map +1 -0
  21. package/dist/engine/immutability.d.ts +59 -0
  22. package/dist/engine/immutability.d.ts.map +1 -0
  23. package/dist/engine/immutability.js +129 -0
  24. package/dist/engine/immutability.js.map +1 -0
  25. package/dist/engine/pattern-matcher.d.ts +13 -0
  26. package/dist/engine/pattern-matcher.d.ts.map +1 -1
  27. package/dist/engine/pattern-matcher.js +85 -17
  28. package/dist/engine/pattern-matcher.js.map +1 -1
  29. package/dist/engine/rule-engine.d.ts +62 -1
  30. package/dist/engine/rule-engine.d.ts.map +1 -1
  31. package/dist/engine/rule-engine.js +222 -12
  32. package/dist/engine/rule-engine.js.map +1 -1
  33. package/dist/engine/session-state.d.ts +0 -0
  34. package/dist/engine/session-state.d.ts.map +1 -1
  35. package/dist/engine/session-state.js +8 -2
  36. package/dist/engine/session-state.js.map +1 -1
  37. package/dist/engine/ship-confidence-gate.d.ts +184 -0
  38. package/dist/engine/ship-confidence-gate.d.ts.map +1 -0
  39. package/dist/engine/ship-confidence-gate.js +768 -0
  40. package/dist/engine/ship-confidence-gate.js.map +1 -0
  41. package/dist/index.d.ts +0 -0
  42. package/dist/index.d.ts.map +0 -0
  43. package/dist/index.js +289 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/rules/categories.json +0 -0
  46. package/dist/rules/presets.json +0 -0
  47. package/dist/rules/rules.json +200 -100
  48. package/dist/tools/audit.d.ts +6 -0
  49. package/dist/tools/audit.d.ts.map +1 -1
  50. package/dist/tools/audit.js +43 -6
  51. package/dist/tools/audit.js.map +1 -1
  52. package/dist/tools/bypass.d.ts +0 -0
  53. package/dist/tools/bypass.d.ts.map +1 -1
  54. package/dist/tools/bypass.js +50 -6
  55. package/dist/tools/bypass.js.map +1 -1
  56. package/dist/tools/rules.d.ts +0 -0
  57. package/dist/tools/rules.d.ts.map +0 -0
  58. package/dist/tools/rules.js +0 -0
  59. package/dist/tools/rules.js.map +0 -0
  60. package/dist/tools/ship-confidence.d.ts +11 -0
  61. package/dist/tools/ship-confidence.d.ts.map +1 -0
  62. package/dist/tools/ship-confidence.js +42 -0
  63. package/dist/tools/ship-confidence.js.map +1 -0
  64. package/dist/tools/update.d.ts +0 -0
  65. package/dist/tools/update.d.ts.map +1 -1
  66. package/dist/tools/update.js +45 -9
  67. package/dist/tools/update.js.map +1 -1
  68. package/dist/tools/validate.d.ts +0 -0
  69. package/dist/tools/validate.d.ts.map +1 -1
  70. package/dist/tools/validate.js +56 -4
  71. package/dist/tools/validate.js.map +1 -1
  72. package/dist/types/backend.d.ts +69 -0
  73. package/dist/types/backend.d.ts.map +1 -0
  74. package/dist/types/backend.js +18 -0
  75. package/dist/types/backend.js.map +1 -0
  76. package/package.json +11 -3
@@ -1,56 +1,266 @@
1
1
  /**
2
2
  * Rule Engine — loads rules.json, filters active rules, evaluates actions.
3
+ *
4
+ * Severity model (v1.0.1):
5
+ * - HARD = constitutional rules (always block on match, no enforcement_mode escape)
6
+ * - MEDIUM = standard rule with severity=block (warn-then-block)
7
+ * - SOFT = standard rule with severity=warn (warn only, never block)
8
+ *
9
+ * Premium rules: rules with `backend_required: true` and stub detection_pattern
10
+ * are skipped locally unless a backend URL is configured. Future versions will
11
+ * call the backend over HTTP for these.
3
12
  */
4
- import { readFileSync } from "fs";
13
+ import { readFileSync, existsSync } from "fs";
5
14
  import { join, dirname } from "path";
6
15
  import { fileURLToPath } from "url";
7
16
  import { matchAction } from "./pattern-matcher.js";
17
+ import { BackendClient } from "./backend-client.js";
8
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
- // In dist, rules are in ../rules/ (relative to dist/engine/). In dev, ../../rules/.
10
- const RULES_PATH = join(__dirname, "../rules/rules.json");
19
+ // Try dist layout first (../rules from dist/engine/), then source layout
20
+ // (../../rules from src/engine/). This lets the same code run under tsc-built
21
+ // dist AND under ts-jest from source without a build step.
22
+ function resolveRulesPath() {
23
+ const candidates = [
24
+ join(__dirname, "../rules/rules.json"), // dist: dist/engine -> dist/rules (preferred)
25
+ join(__dirname, "../../dist/rules/rules.json"), // src: src/engine -> dist/rules (test runs from src after build)
26
+ join(__dirname, "../../rules/rules.json"), // src: src/engine -> rules (raw fallback, no backend_required flags)
27
+ ];
28
+ for (const c of candidates) {
29
+ if (existsSync(c))
30
+ return c;
31
+ }
32
+ return candidates[0]; // fall back; loadAllRules will fail-open
33
+ }
34
+ const RULES_PATH = resolveRulesPath();
11
35
  let _rules = null;
36
+ // ----------------------------------------------------------------------
37
+ // Backend client wiring (B4 closes the orphan B3 left behind)
38
+ // ----------------------------------------------------------------------
39
+ // A single process-wide BackendClient. Lazy-constructed on first use so
40
+ // the no-backend path stays cheap. When SUNAIVA_GATE_API_TOKEN is unset
41
+ // the client still works — it returns `skipped_no_token` for every rule
42
+ // and writes the once-per-process stderr notice.
43
+ let _backendClient = null;
44
+ /** Lazy singleton. Tests can override via setBackendClient(). */
45
+ function getBackendClient() {
46
+ if (!_backendClient)
47
+ _backendClient = new BackendClient();
48
+ return _backendClient;
49
+ }
50
+ /** Test-only injection point. */
51
+ export function setBackendClient(client) {
52
+ _backendClient = client;
53
+ }
54
+ /** True iff the premium backend is fully configured (token present). */
55
+ function isBackendConfigured() {
56
+ return getBackendClient().isConfigured();
57
+ }
12
58
  export function loadAllRules() {
13
59
  if (_rules)
14
60
  return _rules;
15
- const raw = readFileSync(RULES_PATH, "utf-8");
16
- _rules = JSON.parse(raw);
61
+ try {
62
+ const raw = readFileSync(RULES_PATH, "utf-8");
63
+ _rules = JSON.parse(raw);
64
+ }
65
+ catch (err) {
66
+ // FAIL-OPEN: never crash the MCP server on bad rules file.
67
+ // Stderr log so operator sees the problem; serve no rules.
68
+ console.error(`[sunaiva-gate] WARN: could not load rules.json at ${RULES_PATH}: ` +
69
+ (err instanceof Error ? err.message : String(err)));
70
+ _rules = [];
71
+ }
17
72
  return _rules;
18
73
  }
74
+ /**
75
+ * Returns ONLY the rules whose `enforcement === "constitutional"`.
76
+ *
77
+ * This is the canonical "what is constitutional" function used by
78
+ * B4's immutability guard. It reads from the package-bundled rules
79
+ * (dist/rules/rules.json), never from the user-editable on-disk
80
+ * copy at ~/.sunaiva/rules.json — so a user cannot circumvent the
81
+ * guard by hand-editing their config.
82
+ *
83
+ * Cached via loadAllRules().
84
+ */
85
+ export function loadConstitutionalRulesOnly() {
86
+ return loadAllRules().filter((r) => r &&
87
+ (r.enforcement === "constitutional" || r.constitutional === true));
88
+ }
89
+ /**
90
+ * Resolved path that loadAllRules() reads from. Exported for tests
91
+ * and diagnostic tooling (e.g. verify-bundle / smoke-test reporting).
92
+ */
93
+ export function getResolvedRulesPath() {
94
+ return RULES_PATH;
95
+ }
19
96
  export function getActiveRules(config) {
20
97
  const all = loadAllRules();
21
98
  return all.filter((r) => config.active_rules.includes(r.id));
22
99
  }
100
+ /** Returns true if the rule should be enforced locally. */
101
+ function isLocalRule(rule, backendConfigured) {
102
+ if (!rule.backend_required)
103
+ return true;
104
+ // Premium rule + backend configured => future HTTP path. Until that lands,
105
+ // we still skip locally and log it so the caller can see what was deferred.
106
+ return backendConfigured;
107
+ }
108
+ /** Map a rule + enforcement_mode to the severity tier label. */
109
+ function deriveSeverity(rule) {
110
+ if (rule.enforcement === "constitutional")
111
+ return "HARD";
112
+ if (rule.severity === "warn")
113
+ return "SOFT";
114
+ // standard + block or warn-then-block
115
+ return "MEDIUM";
116
+ }
23
117
  export function evaluateAction(action, config, warningCounts, context) {
24
118
  const activeRules = getActiveRules(config);
25
119
  const combined = context ? `${action} ${context}` : action;
26
120
  const violations = [];
27
121
  const warnings = [];
122
+ const wouldHaveBlocked = [];
123
+ const skippedPremium = [];
124
+ // B4: sync evaluateAction always skips premium rules locally — the
125
+ // BackendClient lives behind the async wrapper `evaluateActionAsync`.
126
+ // This keeps the smoke test + legacy sync callers synchronous. Premium
127
+ // rules show up in skipped_premium; the async wrapper then enriches the
128
+ // result with backend_results when SUNAIVA_GATE_API_TOKEN is set.
129
+ const backendConfigured = false;
130
+ let maxSeverity = null;
131
+ const bumpSeverity = (s) => {
132
+ if (maxSeverity === null)
133
+ maxSeverity = s;
134
+ else if (s === "HARD")
135
+ maxSeverity = "HARD";
136
+ else if (s === "MEDIUM" && maxSeverity === "SOFT")
137
+ maxSeverity = "MEDIUM";
138
+ };
28
139
  for (const rule of activeRules) {
140
+ if (!isLocalRule(rule, backendConfigured)) {
141
+ skippedPremium.push(rule.id);
142
+ continue;
143
+ }
29
144
  const result = matchAction(combined, rule.detection_pattern);
30
145
  if (!result.matched)
31
146
  continue;
147
+ const tier = deriveSeverity(rule);
148
+ bumpSeverity(tier);
32
149
  if (rule.enforcement === "constitutional") {
33
- // Constitutional rules always block
150
+ // HARD: always block, regardless of enforcement_mode.
34
151
  violations.push(rule);
152
+ wouldHaveBlocked.push(rule.id);
153
+ }
154
+ else if (tier === "SOFT") {
155
+ // SOFT (warn severity): warning only, never block.
156
+ warnings.push(rule);
35
157
  }
36
158
  else {
37
- // Standard rules: warn first time, block on repeat
159
+ // MEDIUM (standard + block): warn-then-block ladder.
38
160
  const count = warningCounts.get(rule.id) ?? 0;
39
- if (config.enforcement_mode === "warn-only") {
40
- warnings.push(rule);
41
- }
42
- else if (config.enforcement_mode === "audit") {
161
+ if (config.enforcement_mode === "warn-only" || config.enforcement_mode === "audit") {
43
162
  warnings.push(rule);
163
+ wouldHaveBlocked.push(rule.id);
44
164
  }
45
165
  else if (count === 0) {
46
166
  warnings.push(rule);
47
167
  }
48
168
  else {
49
169
  violations.push(rule);
170
+ wouldHaveBlocked.push(rule.id);
50
171
  }
51
172
  }
52
173
  }
53
174
  const allowed = violations.length === 0;
54
- return { allowed, violations, warnings };
175
+ return {
176
+ allowed,
177
+ violations,
178
+ warnings,
179
+ severity_tier: maxSeverity,
180
+ would_have_blocked: wouldHaveBlocked,
181
+ skipped_premium: skippedPremium,
182
+ };
183
+ }
184
+ /**
185
+ * Async wrapper around evaluateAction that ALSO delegates premium
186
+ * (`backend_required: true`) rules to the BackendClient. Used by
187
+ * `handleValidateAction` when SUNAIVA_GATE_API_TOKEN is set so premium
188
+ * rules actually get evaluated server-side instead of silently skipped.
189
+ *
190
+ * Failure mode: any backend error (network, 5xx, missing token) becomes
191
+ * a `skipped_*` status on the per-rule result. The BackendClient itself
192
+ * is fail-OPEN for the customer — a Sunaiva outage never blocks the user.
193
+ *
194
+ * Premium-rule semantics:
195
+ * - rule_id in skipped_premium → backend was NOT consulted (sync path)
196
+ * - rule_id in backend_results → backend WAS consulted; check status field
197
+ * - status === "matched" → backend wants to block; promoted to violation
198
+ * - status === "no_match" → backend evaluated clean
199
+ * - status === "skipped_*" → fail-OPEN (rule deferred, see error field)
200
+ *
201
+ * Tests #7 (token unset → skipped_no_token) lives here.
202
+ */
203
+ export async function evaluateActionAsync(action, config, warningCounts, context) {
204
+ const sync = evaluateAction(action, config, warningCounts, context);
205
+ // Premium rule IDs that the sync pass deferred to the backend.
206
+ const activeRules = getActiveRules(config);
207
+ const premiumRules = activeRules.filter((r) => r.backend_required === true && sync.skipped_premium.includes(r.id));
208
+ if (premiumRules.length === 0)
209
+ return sync;
210
+ const combined = context ? `${action} ${context}` : action;
211
+ const client = getBackendClient();
212
+ const backendEval = await client.evaluate(premiumRules.map((r) => r.id), combined, { action_preview: action.slice(0, 200) });
213
+ // Promote backend-matched premium rules into violations / warnings
214
+ // following the same severity-tier ladder used by the local engine.
215
+ const violations = [...sync.violations];
216
+ const warnings = [...sync.warnings];
217
+ const wouldHaveBlocked = [...sync.would_have_blocked];
218
+ let maxSeverity = sync.severity_tier;
219
+ const bump = (s) => {
220
+ if (maxSeverity === null)
221
+ maxSeverity = s;
222
+ else if (s === "HARD")
223
+ maxSeverity = "HARD";
224
+ else if (s === "MEDIUM" && maxSeverity === "SOFT")
225
+ maxSeverity = "MEDIUM";
226
+ };
227
+ for (const r of backendEval.results) {
228
+ if (!r.matched)
229
+ continue;
230
+ const rule = premiumRules.find((p) => p.id === r.rule_id);
231
+ if (!rule)
232
+ continue;
233
+ // Backend severity overrides local; default to MEDIUM when unspecified.
234
+ const tier = rule.enforcement === "constitutional"
235
+ ? "HARD"
236
+ : r.severity === "warn"
237
+ ? "SOFT"
238
+ : "MEDIUM";
239
+ bump(tier);
240
+ if (tier === "SOFT") {
241
+ warnings.push(rule);
242
+ }
243
+ else {
244
+ violations.push(rule);
245
+ wouldHaveBlocked.push(rule.id);
246
+ }
247
+ }
248
+ // Premium rules that the backend handled are no longer "skipped".
249
+ const skippedPremium = sync.skipped_premium.filter((id) => !backendEval.results.some((r) => r.rule_id === id && r.status !== "skipped_no_token" && r.status !== "skipped_disabled" && !r.status.startsWith("skipped_")));
250
+ // Inverse: keep the rules that ARE still skipped (token absent or backend error).
251
+ const stillSkipped = backendEval.results
252
+ .filter((r) => r.status.startsWith("skipped_"))
253
+ .map((r) => r.rule_id);
254
+ // Union local-deferred + still-skipped (de-dup).
255
+ const finalSkipped = Array.from(new Set([...skippedPremium, ...stillSkipped]));
256
+ return {
257
+ allowed: violations.length === 0,
258
+ violations,
259
+ warnings,
260
+ severity_tier: maxSeverity,
261
+ would_have_blocked: wouldHaveBlocked,
262
+ skipped_premium: finalSkipped,
263
+ backend_results: backendEval.results,
264
+ };
55
265
  }
56
266
  //# sourceMappingURL=rule-engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rule-engine.js","sourceRoot":"","sources":["../../src/engine/rule-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,oFAAoF;AACpF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;AAqB1D,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,MAAM,UAAU,YAAY;IAC1B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAW,CAAC;IACnC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,MAAkB,EAClB,aAAkC,EAClC,OAAgB;IAEhB,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAE3D,MAAM,UAAU,GAAW,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAW,EAAE,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,SAAS;QAE9B,IAAI,IAAI,CAAC,WAAW,KAAK,gBAAgB,EAAE,CAAC;YAC1C,oCAAoC;YACpC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,MAAM,CAAC,gBAAgB,KAAK,WAAW,EAAE,CAAC;gBAC5C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;iBAAM,IAAI,MAAM,CAAC,gBAAgB,KAAK,OAAO,EAAE,CAAC;gBAC/C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;iBAAM,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACvB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC;IACxC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"rule-engine.js","sourceRoot":"","sources":["../../src/engine/rule-engine.ts"],"names":[],"mappings":"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"}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../src/engine/session-state.ts"],"names":[],"mappings":"AAIA,UAAU,YAAY;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAMD,wBAAgB,QAAQ,IAAI,YAAY,CAGvC;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAE/C;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAGtD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
1
+ {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../src/engine/session-state.ts"],"names":[],"mappings":"AAOA,UAAU,YAAY;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAMD,wBAAgB,QAAQ,IAAI,YAAY,CAGvC;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAG/C;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAGtD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
@@ -1,5 +1,8 @@
1
1
  import { readFileSync, writeFileSync } from "node:fs";
2
- const STATE_FILE = "/tmp/sunaiva_gate_session.json";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ // Cross-platform tempdir (Windows: %LOCALAPPDATA%\Temp, Unix: /tmp)
5
+ const STATE_FILE = join(tmpdir(), "sunaiva_gate_session.json");
3
6
  function defaultState() {
4
7
  return { session_start: new Date().toISOString(), action_count: 0, warnings_issued: {} };
5
8
  }
@@ -12,7 +15,10 @@ export function getState() {
12
15
  }
13
16
  }
14
17
  export function saveState(s) {
15
- writeFileSync(STATE_FILE, JSON.stringify(s, null, 2));
18
+ try {
19
+ writeFileSync(STATE_FILE, JSON.stringify(s, null, 2));
20
+ }
21
+ catch { /* fail-OPEN: never crash because session state is unwritable */ }
16
22
  }
17
23
  export function recordWarning(ruleId) {
18
24
  const s = getState();
@@ -1 +1 @@
1
- {"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/engine/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEtD,MAAM,UAAU,GAAG,gCAAgC,CAAC;AAQpD,SAAS,YAAY;IACnB,OAAO,EAAE,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAAC,CAAC;IAC7D,MAAM,CAAC;QAAC,OAAO,YAAY,EAAE,CAAC;IAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAe;IACvC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACjE,SAAS,CAAC,CAAC,CAAC,CAAC;IACb,OAAO,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,QAAQ,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,YAAY,EAAE,CAAC;IACjB,SAAS,CAAC,CAAC,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/engine/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,oEAAoE;AACpE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC;AAQ/D,SAAS,YAAY;IACnB,OAAO,EAAE,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAAC,CAAC;IAC7D,MAAM,CAAC;QAAC,OAAO,YAAY,EAAE,CAAC;IAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAe;IACvC,IAAI,CAAC;QAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAC9D,MAAM,CAAC,CAAC,gEAAgE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACjE,SAAS,CAAC,CAAC,CAAC,CAAC;IACb,OAAO,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,QAAQ,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,YAAY,EAAE,CAAC;IACjB,SAAS,CAAC,CAAC,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,184 @@
1
+ export declare const HOOK_NAME = "ship_confidence_gate";
2
+ export declare const HOOK_VERSION = "1.2.0";
3
+ export declare const RULE_NAME = "Rule 42 \u2014 Ship Confidence Gate";
4
+ export declare const RULE_VERSION = "1.0";
5
+ export type GateDecision = "allow" | "block" | "absent" | "skip_key";
6
+ export interface GateEvidence {
7
+ verdict_path?: string;
8
+ verdict_id?: string;
9
+ level?: string;
10
+ signed_at?: string;
11
+ signature_algorithm?: string;
12
+ age_minutes?: number;
13
+ token_path?: string;
14
+ paid_fallthrough_reason?: string;
15
+ }
16
+ export interface GateResult {
17
+ /** Final policy decision after BOTH tiers are evaluated. */
18
+ decision: "allow" | "block";
19
+ /** Which tier produced the result (paid > free; null on block/error). */
20
+ tier: "paid" | "free" | null;
21
+ /** Reason string (human-readable). */
22
+ reason: string;
23
+ /** Structured evidence for the audit ledger. */
24
+ evidence: GateEvidence;
25
+ /** Verdict id if a verdict file was inspected. */
26
+ verdict_id?: string;
27
+ /** Verdict level if checked. */
28
+ level?: string;
29
+ /** signed_at ISO if checked. */
30
+ signed_at?: string;
31
+ /** Age in minutes if checked. */
32
+ age_minutes?: number;
33
+ /** Self-stamp block (matching the Python _stamp field). */
34
+ stamp: GateStamp;
35
+ /** When dry-run is active, the would-have-been decision is preserved here. */
36
+ would_have_been?: "allow" | "block";
37
+ /** When kill-switch active. */
38
+ bypassed?: boolean;
39
+ }
40
+ export interface GateStamp {
41
+ hook_name: string;
42
+ hook_version: string;
43
+ rule_name: string;
44
+ rule_version: string;
45
+ why: string;
46
+ suggested_fix: string;
47
+ artifact_id: string;
48
+ command_preview: string;
49
+ timestamp: string;
50
+ label?: string;
51
+ tier?: "paid" | "free" | null;
52
+ }
53
+ export interface PaidCheckResult {
54
+ decision: GateDecision;
55
+ reason: string;
56
+ evidence: GateEvidence | null;
57
+ }
58
+ export interface GateOptions {
59
+ /** Override the verdict directory. Default: <genesisRoot>/data/ship_confidence_verdicts */
60
+ verdictDir?: string;
61
+ /** Override the approval token directory. Default: <genesisRoot>/data/deploy_queue/APPROVAL_TOKENS */
62
+ approvalDir?: string;
63
+ /** Max age of a signed verdict before it's considered stale (minutes). Default 60. */
64
+ maxAgeMinutes?: number;
65
+ /** Env var name holding the HMAC signing key. Default SHIP_CONFIDENCE_SIGNING_KEY. */
66
+ signingKeyEnv?: string;
67
+ /** Verdict levels that grant allow. Default ["GREEN"]. */
68
+ allowedLevels?: string[];
69
+ /** Token TTL in seconds. Default 3600. */
70
+ tokenTtlSeconds?: number;
71
+ /** Override the genesis root for path resolution. */
72
+ genesisRoot?: string;
73
+ /** Override the audit log path. */
74
+ auditLogPath?: string;
75
+ /** Override env (for tests). Defaults to process.env. */
76
+ env?: NodeJS.ProcessEnv;
77
+ }
78
+ /** Match the Python _sanitize: non-[A-Za-z0-9._-] → '-', strip dashes, max 128. */
79
+ export declare function sanitizeArtifactId(artifactId: string): string;
80
+ /**
81
+ * Detect the genesis-system root, matching the Python _detect_genesis_root logic.
82
+ * Priority: env override → WSL path → Windows path → fall back to a path that
83
+ * may not exist (so log paths stay consistent).
84
+ */
85
+ declare function detectGenesisRoot(env: NodeJS.ProcessEnv): string;
86
+ /** Parse signed_at ISO timestamps tolerantly (accepts 'Z' suffix). */
87
+ declare function parseSignedAt(raw: unknown): Date | null;
88
+ export declare class ShipConfidenceGate {
89
+ private readonly verdictDir;
90
+ private readonly approvalDir;
91
+ private readonly maxAgeMinutes;
92
+ private readonly signingKeyEnv;
93
+ private readonly allowedLevels;
94
+ private readonly tokenTtlSeconds;
95
+ private readonly genesisRoot;
96
+ private readonly auditLogPath;
97
+ private readonly env;
98
+ constructor(opts?: GateOptions);
99
+ /**
100
+ * Look up and verify the signed Verdict for an artifact.
101
+ *
102
+ * Return-value semantics mirror the Python _check_signed_verdict:
103
+ * - "allow" : valid signature, allowed level, fresh → grant
104
+ * - "block" : verdict present but fails policy → HARD block
105
+ * - "absent" : no verdict file → caller tries free-tier fallback
106
+ * - "skip_key" : verdict present but signing key env unset → fall through
107
+ *
108
+ * NEVER throws. Any unexpected error → "absent" (the outer fail-open handler
109
+ * in check() preserves overall fail-OPEN semantics).
110
+ */
111
+ checkSignedVerdict(artifactId: string): Promise<PaidCheckResult>;
112
+ /**
113
+ * Find a fresh approval token matching the artifact_id.
114
+ * Token must be JSON with at minimum {artifact_id, timestamp}.
115
+ */
116
+ findApprovalToken(artifactId: string): Promise<string | null>;
117
+ /** Single-use token consumption. Never throws. */
118
+ consumeToken(tokenPath: string): Promise<void>;
119
+ /** Self-stamped allow payload (matches Python format_allow + _stamp). */
120
+ formatAllow(opts: {
121
+ artifactId: string;
122
+ tier: "paid" | "free" | null;
123
+ why: string;
124
+ commandPreview?: string;
125
+ label?: string;
126
+ extraContext?: string;
127
+ }): {
128
+ continue: true;
129
+ additionalContext: string;
130
+ _stamp: GateStamp;
131
+ };
132
+ /** Self-stamped block payload (matches Python format_block + _stamp). */
133
+ formatBlock(opts: {
134
+ label: string;
135
+ reason: string;
136
+ artifactId: string;
137
+ commandPreview?: string;
138
+ suggestedFix: string;
139
+ }): {
140
+ continue: false;
141
+ decision: "block";
142
+ reason: string;
143
+ stopReason: string;
144
+ message: string;
145
+ _stamp: GateStamp;
146
+ };
147
+ /**
148
+ * Write an entry to the unified audit ledger. Matches the schema in §6.2 of
149
+ * BUILD_PLAN_1_1_0_WAVE2_BRIEFS.md and tags it with event_type so a single
150
+ * file is queryable (Opus orchestrator decision on [VERIFY] item 5).
151
+ */
152
+ writeAudit(entry: Record<string, unknown>): void;
153
+ /** Expose the audit log path for tests and tooling. */
154
+ getAuditLogPath(): string;
155
+ /**
156
+ * Run the full gate logic for a given artifact_id + optional command preview.
157
+ * Returns a GateResult with a final allow/block decision and a self-stamped
158
+ * payload. Audit entries are written to the unified ledger.
159
+ *
160
+ * Behaviour order (matching Python main()):
161
+ * 0. Kill-switch (DISABLE_SUNAIVA_GATE=1) → allow, log bypass.
162
+ * 1. Dry-run (SUNAIVA_GATE_DRY_RUN=1) → probe both tiers, log dry-run, allow.
163
+ * 2. PAID tier → if allow, return allow tier=paid.
164
+ * If block, hard-block (never fall through).
165
+ * If absent/skip_key, continue to free tier.
166
+ * 3. FREE tier → token present and fresh → allow tier=free.
167
+ * Token missing → block with dual-path hint.
168
+ *
169
+ * FAIL-OPEN: any uncaught exception → allow with audit event_type=ship_confidence_error.
170
+ */
171
+ check(artifactId: string, options?: {
172
+ commandPreview?: string;
173
+ label?: string;
174
+ }): Promise<GateResult>;
175
+ }
176
+ export declare const __test: {
177
+ detectGenesisRoot: typeof detectGenesisRoot;
178
+ parseSignedAt: typeof parseSignedAt;
179
+ DEFAULT_AUDIT_PATH: string;
180
+ DEFAULT_AUDIT_DIR: string;
181
+ };
182
+ export declare function defaultAuditLogPath(): string;
183
+ export {};
184
+ //# sourceMappingURL=ship-confidence-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship-confidence-gate.d.ts","sourceRoot":"","sources":["../../src/engine/ship-confidence-gate.ts"],"names":[],"mappings":"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"}