@sunaiva/gate 1.0.0 → 1.1.2

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 (83) hide show
  1. package/BUSINESS_LICENSE.md +70 -0
  2. package/CHANGELOG.md +254 -0
  3. package/LICENSE +0 -0
  4. package/README.md +451 -67
  5. package/README.md.bak-v1.0.0-stale-MIT +59 -0
  6. package/SUPPORT.md +75 -0
  7. package/TIER_DEFINITIONS.md +161 -0
  8. package/dist/config/defaults.d.ts +22 -1
  9. package/dist/config/defaults.d.ts.map +1 -1
  10. package/dist/config/defaults.js +56 -8
  11. package/dist/config/defaults.js.map +1 -1
  12. package/dist/config/loader.d.ts +0 -0
  13. package/dist/config/loader.d.ts.map +1 -1
  14. package/dist/config/loader.js +23 -5
  15. package/dist/config/loader.js.map +1 -1
  16. package/dist/engine/backend-client.d.ts +58 -0
  17. package/dist/engine/backend-client.d.ts.map +1 -0
  18. package/dist/engine/backend-client.js +287 -0
  19. package/dist/engine/backend-client.js.map +1 -0
  20. package/dist/engine/hmac-verifier.d.ts +52 -0
  21. package/dist/engine/hmac-verifier.d.ts.map +1 -0
  22. package/dist/engine/hmac-verifier.js +159 -0
  23. package/dist/engine/hmac-verifier.js.map +1 -0
  24. package/dist/engine/immutability.d.ts +59 -0
  25. package/dist/engine/immutability.d.ts.map +1 -0
  26. package/dist/engine/immutability.js +129 -0
  27. package/dist/engine/immutability.js.map +1 -0
  28. package/dist/engine/pattern-matcher.d.ts +13 -0
  29. package/dist/engine/pattern-matcher.d.ts.map +1 -1
  30. package/dist/engine/pattern-matcher.js +85 -17
  31. package/dist/engine/pattern-matcher.js.map +1 -1
  32. package/dist/engine/rule-engine.d.ts +62 -1
  33. package/dist/engine/rule-engine.d.ts.map +1 -1
  34. package/dist/engine/rule-engine.js +224 -12
  35. package/dist/engine/rule-engine.js.map +1 -1
  36. package/dist/engine/session-state.d.ts +0 -0
  37. package/dist/engine/session-state.d.ts.map +1 -1
  38. package/dist/engine/session-state.js +8 -2
  39. package/dist/engine/session-state.js.map +1 -1
  40. package/dist/engine/ship-confidence-gate.d.ts +232 -0
  41. package/dist/engine/ship-confidence-gate.d.ts.map +1 -0
  42. package/dist/engine/ship-confidence-gate.js +768 -0
  43. package/dist/engine/ship-confidence-gate.js.map +1 -0
  44. package/dist/index.d.ts +0 -0
  45. package/dist/index.js +293 -2
  46. package/dist/rules/categories.json +0 -0
  47. package/dist/rules/presets.json +0 -0
  48. package/dist/rules/rules.json +132 -64
  49. package/dist/tools/audit.d.ts +6 -0
  50. package/dist/tools/audit.d.ts.map +1 -1
  51. package/dist/tools/audit.js +43 -6
  52. package/dist/tools/audit.js.map +1 -1
  53. package/dist/tools/bypass.d.ts +0 -0
  54. package/dist/tools/bypass.d.ts.map +1 -1
  55. package/dist/tools/bypass.js +50 -6
  56. package/dist/tools/bypass.js.map +1 -1
  57. package/dist/tools/export-attestation.d.ts +45 -0
  58. package/dist/tools/export-attestation.d.ts.map +1 -0
  59. package/dist/tools/export-attestation.js +152 -0
  60. package/dist/tools/export-attestation.js.map +1 -0
  61. package/dist/tools/rules.d.ts +0 -0
  62. package/dist/tools/rules.d.ts.map +0 -0
  63. package/dist/tools/rules.js +0 -0
  64. package/dist/tools/rules.js.map +0 -0
  65. package/dist/tools/ship-confidence.d.ts +17 -0
  66. package/dist/tools/ship-confidence.d.ts.map +1 -0
  67. package/dist/tools/ship-confidence.js +42 -0
  68. package/dist/tools/ship-confidence.js.map +1 -0
  69. package/dist/tools/update.d.ts +0 -0
  70. package/dist/tools/update.d.ts.map +1 -1
  71. package/dist/tools/update.js +45 -9
  72. package/dist/tools/update.js.map +1 -1
  73. package/dist/tools/validate.d.ts +0 -0
  74. package/dist/tools/validate.d.ts.map +1 -1
  75. package/dist/tools/validate.js +56 -4
  76. package/dist/tools/validate.js.map +1 -1
  77. package/dist/types/backend.d.ts +69 -0
  78. package/dist/types/backend.d.ts.map +1 -0
  79. package/dist/types/backend.js +18 -0
  80. package/dist/types/backend.js.map +1 -0
  81. package/package.json +83 -65
  82. package/dist/index.d.ts.map +0 -1
  83. package/dist/index.js.map +0 -1
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Async-style audit write. The file I/O is deferred to setImmediate so the hot
3
+ * path (the validate_action response) returns before the syscall. Errors are
4
+ * swallowed because the audit log is informational and must never break
5
+ * enforcement.
6
+ */
1
7
  export declare function appendAudit(entry: Record<string, unknown>): void;
2
8
  export declare function handleGetAuditLog(args: {
3
9
  limit?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAQA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GAejF"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAYhE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GAejF"}
@@ -1,16 +1,53 @@
1
- import { readFileSync, appendFileSync, existsSync, mkdirSync } from "node:fs";
1
+ import { readFileSync, appendFileSync, existsSync, mkdirSync, statSync, renameSync } from "node:fs";
2
2
  import { dirname } from "node:path";
3
3
  import { getConfig } from "../config/loader.js";
4
+ // Rotate audit log when it crosses this size (bytes).
5
+ const AUDIT_ROTATE_BYTES = 10 * 1024 * 1024; // 10 MB
6
+ // Throttle rotation checks: only stat the file at most every 60s.
7
+ const ROTATE_CHECK_MS = 60_000;
8
+ let _lastRotateCheck = 0;
4
9
  function getLogPath() {
5
10
  return getConfig().audit_log_path;
6
11
  }
7
- export function appendAudit(entry) {
12
+ function maybeRotate(logPath) {
13
+ const now = Date.now();
14
+ if (now - _lastRotateCheck < ROTATE_CHECK_MS)
15
+ return;
16
+ _lastRotateCheck = now;
8
17
  try {
9
- const logPath = getLogPath();
10
- mkdirSync(dirname(logPath), { recursive: true });
11
- appendFileSync(logPath, JSON.stringify(entry) + "\n");
18
+ if (!existsSync(logPath))
19
+ return;
20
+ const size = statSync(logPath).size;
21
+ if (size < AUDIT_ROTATE_BYTES)
22
+ return;
23
+ // Rotate: audit.jsonl -> audit.jsonl.1 (best-effort). Single-slot rotation
24
+ // is acceptable for an informational audit ledger.
25
+ const rotated = `${logPath}.1`;
26
+ renameSync(logPath, rotated);
27
+ }
28
+ catch {
29
+ // Fail-OPEN: never let rotation block writes.
12
30
  }
13
- catch { }
31
+ }
32
+ /**
33
+ * Async-style audit write. The file I/O is deferred to setImmediate so the hot
34
+ * path (the validate_action response) returns before the syscall. Errors are
35
+ * swallowed because the audit log is informational and must never break
36
+ * enforcement.
37
+ */
38
+ export function appendAudit(entry) {
39
+ const stamped = { ...entry };
40
+ setImmediate(() => {
41
+ try {
42
+ const logPath = getLogPath();
43
+ mkdirSync(dirname(logPath), { recursive: true });
44
+ maybeRotate(logPath);
45
+ appendFileSync(logPath, JSON.stringify(stamped) + "\n");
46
+ }
47
+ catch {
48
+ // Fail-OPEN
49
+ }
50
+ });
14
51
  }
15
52
  export async function handleGetAuditLog(args) {
16
53
  const logPath = getLogPath();
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,SAAS,UAAU;IACjB,OAAO,SAAS,EAAE,CAAC,cAAc,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAA8B;IACxD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA0C;IAChF,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACnG,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChF,IAAI,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEvG,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvG,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAEhC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACrH,CAAC"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"bypass.d.ts","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAGA,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;;GAe9E"}
1
+ {"version":3,"file":"bypass.d.ts","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAaA,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;;GAiD9E"}
@@ -1,16 +1,60 @@
1
+ /**
2
+ * log_bypass MCP tool — record an intentional, justified rule bypass.
3
+ *
4
+ * Constitutional rules CANNOT be bypassed (Builder B4 — Finding C3).
5
+ * Backed by `src/engine/immutability.ts`. A rejected bypass writes
6
+ * NOTHING to the audit log (per B4 brief test #8) — the entire call
7
+ * fails before audit is touched. This is intentional: a constitutional
8
+ * bypass attempt is a misuse signal, not a logged business event.
9
+ */
1
10
  import { loadAllRules } from "../engine/rule-engine.js";
11
+ import { assertCanBypass, ConstitutionalImmutableError } from "../engine/immutability.js";
2
12
  import { appendAudit } from "./audit.js";
3
13
  export async function handleLogBypass(args) {
4
14
  const rules = loadAllRules();
5
- const rule = rules.find(r => r.id === args.rule_id);
15
+ const rule = rules.find((r) => r.id === args.rule_id);
6
16
  if (!rule) {
7
- return { content: [{ type: "text", text: JSON.stringify({ error: `Rule not found: ${args.rule_id}` }) }] };
17
+ return {
18
+ content: [{
19
+ type: "text",
20
+ text: JSON.stringify({ error: `Rule not found: ${args.rule_id}` }),
21
+ }],
22
+ };
8
23
  }
9
- if (rule.enforcement === "constitutional") {
10
- return { content: [{ type: "text", text: JSON.stringify({ error: `Cannot bypass constitutional rule: ${args.rule_id}` }) }] };
24
+ try {
25
+ assertCanBypass(args.rule_id);
11
26
  }
12
- const entry = { timestamp: new Date().toISOString(), type: "bypass", rule_id: args.rule_id, reason: args.reason };
27
+ catch (err) {
28
+ if (err instanceof ConstitutionalImmutableError) {
29
+ return {
30
+ content: [{
31
+ type: "text",
32
+ text: JSON.stringify({
33
+ error: "CONSTITUTIONAL_RULE_CANNOT_BE_BYPASSED",
34
+ rule_id: err.rule_id,
35
+ message: "Constitutional rules cannot be bypassed via log_bypass",
36
+ }),
37
+ }],
38
+ };
39
+ }
40
+ throw err;
41
+ }
42
+ const entry = {
43
+ timestamp: new Date().toISOString(),
44
+ type: "bypass",
45
+ rule_id: args.rule_id,
46
+ reason: args.reason,
47
+ };
13
48
  appendAudit(entry);
14
- return { content: [{ type: "text", text: JSON.stringify({ logged: true, bypass_id: `byp_${Date.now()}`, rule_id: args.rule_id }) }] };
49
+ return {
50
+ content: [{
51
+ type: "text",
52
+ text: JSON.stringify({
53
+ logged: true,
54
+ bypass_id: `byp_${Date.now()}`,
55
+ rule_id: args.rule_id,
56
+ }),
57
+ }],
58
+ };
15
59
  }
16
60
  //# sourceMappingURL=bypass.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bypass.js","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;IAEpD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACtH,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,KAAK,gBAAgB,EAAE,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sCAAsC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACzI,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAClH,WAAW,CAAC,KAAK,CAAC,CAAC;IAEnB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACjJ,CAAC"}
1
+ {"version":3,"file":"bypass.js","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;iBACnE,CAAC;SACH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;YAChD,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,wCAAwC;4BAC/C,OAAO,EAAE,GAAG,CAAC,OAAO;4BACpB,OAAO,EAAE,wDAAwD;yBAClE,CAAC;qBACH,CAAC;aACH,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;IACF,WAAW,CAAC,KAAK,CAAC,CAAC;IAEnB,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,MAAM,EAAE,IAAI;oBACZ,SAAS,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE;oBAC9B,OAAO,EAAE,IAAI,CAAC,OAAO;iBACtB,CAAC;aACH,CAAC;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,45 @@
1
+ export interface ExportAttestationArgs {
2
+ /** The verdict_id (preferred) OR an artifact_id we can resolve to a verdict file. */
3
+ verdict_id: string;
4
+ /** Optional artifact name override (defaults to verdict.artifact_id). */
5
+ artifact_name?: string;
6
+ /** Optional artifact sha256 override (defaults to deterministic-derived). */
7
+ artifact_sha256?: string;
8
+ /** Optional output path. If omitted, the envelope is returned in-band only. */
9
+ output_path?: string;
10
+ /** Optional keyid label. Defaults to "sunaiva-gate-hmac-v1.2". */
11
+ keyid?: string;
12
+ /** Optional verdict directory override (test fixtures). */
13
+ verdict_dir?: string;
14
+ /** Optional env override (test fixtures). */
15
+ env?: NodeJS.ProcessEnv;
16
+ }
17
+ export interface ExportAttestationResult {
18
+ /** True iff the envelope was successfully produced. */
19
+ ok: boolean;
20
+ /** Path on disk if output_path was provided. */
21
+ output_path?: string;
22
+ /** The JSONL envelope content (one line). */
23
+ envelope_jsonl?: string;
24
+ /** Reason on failure. */
25
+ reason?: string;
26
+ /** Verdict id resolved during lookup. */
27
+ verdict_id?: string;
28
+ /** The keyid used to sign. */
29
+ keyid?: string;
30
+ }
31
+ /**
32
+ * Programmatic entry point (used by the MCP handler + CLI flag).
33
+ */
34
+ export declare function exportAttestation(args: ExportAttestationArgs): Promise<ExportAttestationResult>;
35
+ /**
36
+ * MCP tool handler — wraps {@link exportAttestation} in the
37
+ * {content:[{type:'text', text}]} response shape.
38
+ */
39
+ export declare function handleExportAttestation(args: ExportAttestationArgs): Promise<{
40
+ content: {
41
+ type: "text";
42
+ text: string;
43
+ }[];
44
+ }>;
45
+ //# sourceMappingURL=export-attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-attestation.d.ts","sourceRoot":"","sources":["../../src/tools/export-attestation.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,EAAE,EAAE,OAAO,CAAC;IACZ,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmFD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CA6ClC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAUxD"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * MCP tool + CLI handler: export_attestation (W2-B3 / T03).
3
+ *
4
+ * Given a verdict_id (or path to a `.signed.json`), build a SLSA
5
+ * Provenance v1.0 in-toto Statement, sign with HMAC-SHA256 over the
6
+ * canonical JSON, and emit the JSONL envelope.
7
+ *
8
+ * Default behaviour:
9
+ * - Look up the verdict by sanitized verdict_id in
10
+ * <genesisRoot>/data/ship_confidence_verdicts/<id>.signed.json.
11
+ * - Sign with $SHIP_CONFIDENCE_SIGNING_KEY (same key the verdict was
12
+ * signed with — symmetry keeps the bundle a single key surface).
13
+ * - Subject artifact name defaults to verdict.artifact_id; sha256
14
+ * defaults to a deterministic placeholder derived from the verdict
15
+ * id (caller can override with --artifact-sha256).
16
+ *
17
+ * Strict shape per §5.3 of SPRINT_1_2_0_PLAN.md.
18
+ */
19
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
20
+ import { join, resolve } from "node:path";
21
+ import { createHash } from "node:crypto";
22
+ import { buildInTotoStatement, envelopeToJsonl, signStatementHmac, } from "../installer/attestation/intoto.js";
23
+ import { sanitizeArtifactId } from "../engine/ship-confidence-gate.js";
24
+ const SIGNING_KEY_ENV = "SHIP_CONFIDENCE_SIGNING_KEY";
25
+ // ---------------------------------------------------------------------------
26
+ // Internals
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Resolve a verdict file by id-or-artifact-id. Returns the parsed
30
+ * verdict payload or null if no matching file is found.
31
+ */
32
+ function resolveVerdictFile(idOrArtifact, verdictDir) {
33
+ if (!existsSync(verdictDir))
34
+ return null;
35
+ const sanitized = sanitizeArtifactId(idOrArtifact);
36
+ const direct = join(verdictDir, `${sanitized}.signed.json`);
37
+ if (existsSync(direct)) {
38
+ try {
39
+ const v = JSON.parse(readFileSync(direct, "utf-8"));
40
+ return { path: direct, verdict: v };
41
+ }
42
+ catch {
43
+ /* fall through to scan */
44
+ }
45
+ }
46
+ // Scan for matching verdict_id OR artifact_id.
47
+ try {
48
+ const files = readdirSync(verdictDir).filter((f) => f.endsWith(".signed.json"));
49
+ for (const f of files) {
50
+ const p = join(verdictDir, f);
51
+ try {
52
+ const v = JSON.parse(readFileSync(p, "utf-8"));
53
+ if (v.verdict_id === idOrArtifact || v.artifact_id === idOrArtifact) {
54
+ return { path: p, verdict: v };
55
+ }
56
+ }
57
+ catch {
58
+ /* skip malformed files */
59
+ }
60
+ }
61
+ }
62
+ catch {
63
+ /* dir read failure */
64
+ }
65
+ return null;
66
+ }
67
+ /** Deterministic sha256 hex derived from verdict_id — placeholder when caller
68
+ * has no real artifact bytes available. The output is byte-stable so audit
69
+ * consumers can verify the same verdict produces the same subject digest. */
70
+ function deterministicSubjectSha(verdictId) {
71
+ return createHash("sha256")
72
+ .update(`sunaiva-subject-${verdictId}`, "utf-8")
73
+ .digest("hex");
74
+ }
75
+ /** Detect the genesis-system root, matching the Python convention. */
76
+ function detectGenesisRoot(env) {
77
+ for (const k of ["GENESIS_ROOT", "CLAUDE_PROJECT_DIR"]) {
78
+ const v = (env[k] ?? "").trim();
79
+ if (v && existsSync(v))
80
+ return v;
81
+ }
82
+ if (existsSync("E:/genesis-system"))
83
+ return "E:/genesis-system";
84
+ if (existsSync("/mnt/e/genesis-system"))
85
+ return "/mnt/e/genesis-system";
86
+ return "E:/genesis-system";
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Public API
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * Programmatic entry point (used by the MCP handler + CLI flag).
93
+ */
94
+ export async function exportAttestation(args) {
95
+ const env = args.env ?? process.env;
96
+ const verdictDir = args.verdict_dir ??
97
+ join(detectGenesisRoot(env), "data", "ship_confidence_verdicts");
98
+ const resolved = resolveVerdictFile(args.verdict_id, verdictDir);
99
+ if (!resolved) {
100
+ return {
101
+ ok: false,
102
+ reason: `no verdict found for '${args.verdict_id}' in ${verdictDir}`,
103
+ };
104
+ }
105
+ const { verdict } = resolved;
106
+ const signingKey = env[SIGNING_KEY_ENV];
107
+ if (!signingKey) {
108
+ return {
109
+ ok: false,
110
+ reason: `${SIGNING_KEY_ENV} env var not set — cannot sign attestation`,
111
+ verdict_id: verdict.verdict_id,
112
+ };
113
+ }
114
+ const artifact = {
115
+ name: args.artifact_name ?? verdict.artifact_id,
116
+ sha256: (args.artifact_sha256 ??
117
+ deterministicSubjectSha(verdict.verdict_id)).toLowerCase(),
118
+ };
119
+ const statement = buildInTotoStatement(verdict, artifact);
120
+ const keyBuffer = Buffer.from(signingKey, "utf-8");
121
+ const signature = signStatementHmac(statement, keyBuffer);
122
+ const keyid = args.keyid ?? "sunaiva-gate-hmac-v1.2";
123
+ const envelopeLine = envelopeToJsonl(statement, signature, keyid);
124
+ let outputPath;
125
+ if (args.output_path) {
126
+ outputPath = resolve(args.output_path);
127
+ writeFileSync(outputPath, envelopeLine, "utf-8");
128
+ }
129
+ return {
130
+ ok: true,
131
+ output_path: outputPath,
132
+ envelope_jsonl: envelopeLine,
133
+ verdict_id: verdict.verdict_id,
134
+ keyid,
135
+ };
136
+ }
137
+ /**
138
+ * MCP tool handler — wraps {@link exportAttestation} in the
139
+ * {content:[{type:'text', text}]} response shape.
140
+ */
141
+ export async function handleExportAttestation(args) {
142
+ const result = await exportAttestation(args);
143
+ return {
144
+ content: [
145
+ {
146
+ type: "text",
147
+ text: JSON.stringify(result, null, 2),
148
+ },
149
+ ],
150
+ };
151
+ }
152
+ //# sourceMappingURL=export-attestation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-attestation.js","sourceRoot":"","sources":["../../src/tools/export-attestation.ts"],"names":[],"mappings":"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"}
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,17 @@
1
+ /**
2
+ * MCP tool: ship_confidence_check
3
+ *
4
+ * Invokes the ShipConfidenceGate for a given artifact_id and returns a
5
+ * structured result. The audit ledger is written by the gate itself.
6
+ */
7
+ export declare function handleShipConfidenceCheck(args: {
8
+ artifact_id: string;
9
+ command_preview?: string;
10
+ label?: string;
11
+ }): Promise<{
12
+ content: {
13
+ type: "text";
14
+ text: string;
15
+ }[];
16
+ }>;
17
+ //# sourceMappingURL=ship-confidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship-confidence.d.ts","sourceRoot":"","sources":["../../src/tools/ship-confidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAmCzD"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * MCP tool: ship_confidence_check
3
+ *
4
+ * Invokes the ShipConfidenceGate for a given artifact_id and returns a
5
+ * structured result. The audit ledger is written by the gate itself.
6
+ */
7
+ import { ShipConfidenceGate } from "../engine/ship-confidence-gate.js";
8
+ export async function handleShipConfidenceCheck(args) {
9
+ // Lazy single-instance — picks up env at call time (test-friendly).
10
+ const gate = new ShipConfidenceGate();
11
+ const result = await gate.check(args.artifact_id, {
12
+ commandPreview: args.command_preview,
13
+ label: args.label,
14
+ });
15
+ const responseBody = {
16
+ allowed: result.decision === "allow",
17
+ decision: result.decision,
18
+ tier: result.tier,
19
+ reason: result.reason,
20
+ evidence: result.evidence,
21
+ verdict_id: result.verdict_id,
22
+ level: result.level,
23
+ signed_at: result.signed_at,
24
+ age_minutes: result.age_minutes,
25
+ would_have_been: result.would_have_been,
26
+ bypassed: result.bypassed ?? false,
27
+ stamp: result.stamp,
28
+ hook_name: result.stamp.hook_name,
29
+ hook_version: result.stamp.hook_version,
30
+ rule_name: result.stamp.rule_name,
31
+ rule_version: result.stamp.rule_version,
32
+ };
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: JSON.stringify(responseBody, null, 2),
38
+ },
39
+ ],
40
+ };
41
+ }
42
+ //# sourceMappingURL=ship-confidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship-confidence.js","sourceRoot":"","sources":["../../src/tools/ship-confidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAI/C;IACC,oEAAoE;IACpE,MAAM,IAAI,GAAG,IAAI,kBAAkB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;QAChD,cAAc,EAAE,IAAI,CAAC,eAAe;QACpC,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG;QACnB,OAAO,EAAE,MAAM,CAAC,QAAQ,KAAK,OAAO;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK;QAClC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;QACvC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;KACxC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;aAC5C;SACF;KACF,CAAC;AACJ,CAAC"}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAGA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;GAqBtF"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAgBA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;GA2CtF"}
@@ -1,24 +1,60 @@
1
+ /**
2
+ * update_rules MCP tool — enable/disable rules.
3
+ *
4
+ * Constitutional rules CANNOT be disabled (Builder B4 — Finding C2).
5
+ * Backed by `src/engine/immutability.ts` whose source of truth is the
6
+ * frozen CONSTITUTIONAL_RULE_IDS array in defaults.ts plus any rule
7
+ * with `enforcement === "constitutional"` in rules.json.
8
+ *
9
+ * Atomicity: if ANY disable target is constitutional, the WHOLE call
10
+ * rejects — no partial commits (per B4 brief test #5). This prevents
11
+ * a caller from sneaking a real disable past the guard by mixing
12
+ * constitutional and non-constitutional IDs.
13
+ */
1
14
  import { getConfig, saveConfig } from "../config/loader.js";
2
- import { loadAllRules } from "../engine/rule-engine.js";
15
+ import { assertCanDisable, ConstitutionalImmutableError } from "../engine/immutability.js";
3
16
  export async function handleUpdateRules(args) {
4
- const cfg = getConfig();
5
- const allRules = loadAllRules();
6
- const constitutional = new Set(allRules.filter(r => r.enforcement === "constitutional").map(r => r.id));
7
- if (args.disable?.some(id => constitutional.has(id))) {
17
+ const blocked = [];
18
+ if (args.disable) {
19
+ for (const id of args.disable) {
20
+ try {
21
+ assertCanDisable(id);
22
+ }
23
+ catch (err) {
24
+ if (err instanceof ConstitutionalImmutableError) {
25
+ blocked.push(err.rule_id);
26
+ }
27
+ else {
28
+ throw err;
29
+ }
30
+ }
31
+ }
32
+ }
33
+ if (blocked.length > 0) {
8
34
  return {
9
35
  content: [{
10
36
  type: "text",
11
- text: JSON.stringify({ error: "Cannot disable constitutional rules", blocked: args.disable.filter(id => constitutional.has(id)) }),
37
+ text: JSON.stringify({
38
+ error: "CONSTITUTIONAL_RULE_IMMUTABLE",
39
+ rule_ids: blocked,
40
+ message: "Constitutional rules cannot be disabled via update_rules",
41
+ }),
12
42
  }],
13
43
  };
14
44
  }
45
+ const cfg = getConfig();
15
46
  const active = new Set(cfg.active_rules);
16
47
  if (args.enable)
17
- args.enable.forEach(id => active.add(id));
48
+ args.enable.forEach((id) => active.add(id));
18
49
  if (args.disable)
19
- args.disable.forEach(id => active.delete(id));
50
+ args.disable.forEach((id) => active.delete(id));
20
51
  cfg.active_rules = [...active];
21
52
  saveConfig(cfg);
22
- return { content: [{ type: "text", text: JSON.stringify({ updated: true, active_count: cfg.active_rules.length }) }] };
53
+ return {
54
+ content: [{
55
+ type: "text",
56
+ text: JSON.stringify({ updated: true, active_count: cfg.active_rules.length }),
57
+ }],
58
+ };
23
59
  }
24
60
  //# sourceMappingURL=update.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA+C;IACrF,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAExG,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACrD,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,qCAAqC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;iBACpI,CAAC;SACH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3D,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AAClI,CAAC"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAE3F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA+C;IACrF,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACvB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;oBAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,KAAK,EAAE,+BAA+B;wBACtC,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,0DAA0D;qBACpE,CAAC;iBACH,CAAC;SACH,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhB,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;aAC/E,CAAC;KACH,CAAC;AACJ,CAAC"}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AAKA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GA0BpF"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AAQA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GA6EpF"}