@intutic/gate 2.2.0 → 2.3.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 (74) hide show
  1. package/README.md +29 -12
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +20 -6
  4. package/dist/actions.js.map +1 -1
  5. package/dist/client.d.ts +19 -1
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +48 -4
  8. package/dist/client.js.map +1 -1
  9. package/dist/dsh.d.ts +1 -1
  10. package/dist/dsh.js +1 -1
  11. package/dist/errors.d.ts +25 -2
  12. package/dist/errors.d.ts.map +1 -1
  13. package/dist/errors.js +53 -0
  14. package/dist/errors.js.map +1 -1
  15. package/dist/eve.d.ts +11 -11
  16. package/dist/eve.d.ts.map +1 -1
  17. package/dist/eve.js +10 -10
  18. package/dist/eve.js.map +1 -1
  19. package/dist/gate.d.ts +33 -1
  20. package/dist/gate.d.ts.map +1 -1
  21. package/dist/gate.js +118 -9
  22. package/dist/gate.js.map +1 -1
  23. package/dist/harness.d.ts +28 -20
  24. package/dist/harness.d.ts.map +1 -1
  25. package/dist/harness.js +165 -26
  26. package/dist/harness.js.map +1 -1
  27. package/dist/hold.d.ts +69 -0
  28. package/dist/hold.d.ts.map +1 -0
  29. package/dist/hold.js +127 -0
  30. package/dist/hold.js.map +1 -0
  31. package/dist/imagecheck.d.ts +14 -7
  32. package/dist/imagecheck.d.ts.map +1 -1
  33. package/dist/imagecheck.js +3 -3
  34. package/dist/imagecheck.js.map +1 -1
  35. package/dist/index.d.ts +7 -3
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +4 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/limits.d.ts +26 -0
  40. package/dist/limits.d.ts.map +1 -0
  41. package/dist/limits.js +45 -0
  42. package/dist/limits.js.map +1 -0
  43. package/dist/managedAgents.d.ts +3 -3
  44. package/dist/managedAgents.d.ts.map +1 -1
  45. package/dist/managedAgents.js +2 -2
  46. package/dist/mcpRegistryRecord.d.ts +143 -0
  47. package/dist/mcpRegistryRecord.d.ts.map +1 -0
  48. package/dist/mcpRegistryRecord.js +217 -0
  49. package/dist/mcpRegistryRecord.js.map +1 -0
  50. package/dist/openai.d.ts +3 -3
  51. package/dist/openai.d.ts.map +1 -1
  52. package/dist/openai.js +9 -8
  53. package/dist/openai.js.map +1 -1
  54. package/dist/phrases.d.ts +87 -0
  55. package/dist/phrases.d.ts.map +1 -0
  56. package/dist/phrases.js +236 -0
  57. package/dist/phrases.js.map +1 -0
  58. package/dist/sequence.d.ts +52 -0
  59. package/dist/sequence.d.ts.map +1 -0
  60. package/dist/sequence.js +121 -0
  61. package/dist/sequence.js.map +1 -0
  62. package/dist/snapshot.d.ts +50 -36
  63. package/dist/snapshot.d.ts.map +1 -1
  64. package/dist/snapshot.js +90 -48
  65. package/dist/snapshot.js.map +1 -1
  66. package/dist/ssoGroups.d.ts +6 -0
  67. package/dist/ssoGroups.d.ts.map +1 -1
  68. package/dist/ssoGroups.js +27 -7
  69. package/dist/ssoGroups.js.map +1 -1
  70. package/dist/workflow.d.ts +5 -3
  71. package/dist/workflow.d.ts.map +1 -1
  72. package/dist/workflow.js +8 -4
  73. package/dist/workflow.js.map +1 -1
  74. package/package.json +1 -1
package/dist/harness.js CHANGED
@@ -47,7 +47,7 @@
47
47
  * existing bypass-permissions behavior unless users opt in." Under
48
48
  * `'allow-all'` nothing pauses. Under the stricter modes the mode decides
49
49
  * WHICH built-ins pause, and each paused call is then a genuine per-call
50
- * approval this gate answers (TD-415, corrected): the
50
+ * approval this gate answers: the
51
51
  * `@ai-sdk/harness-claude-code` bridge (`dist/bridge/index.mjs`,
52
52
  * `createPermissionSettings`/`nativeToolRequiresApproval`) adds `ask` rules
53
53
  * for bash-kind tools (`Bash`, `Monitor`) under `'allow-edits'`, and for
@@ -84,6 +84,10 @@
84
84
  import { createHash } from 'node:crypto';
85
85
  import { active as activeGate } from './gate.js';
86
86
  import { IntuticGateRefusal } from './errors.js';
87
+ import { MCP_ALLOWLIST_JS_SOURCE, MCP_REGISTRY_JS_SOURCE, MCP_SNAPSHOT_UNVERIFIED_JS_SOURCE } from './mcpRegistryRecord.js';
88
+ import { PHRASES_JS_SOURCE } from './phrases.js';
89
+ import { SEQUENCE_JS_SOURCE } from './sequence.js';
90
+ import { ARGUMENTS_SIZE_LIMIT, COMMAND_SIZE_LIMIT, GATE_DEADLINE_MS, HOOK_TIMEOUT_SECONDS } from './limits.js';
87
91
  /**
88
92
  * Render a pending approval's `input` as the `tool_input` object
89
93
  * {@link Gate.guard} evaluates.
@@ -328,11 +332,19 @@ function sandboxJoin(workDir, relative) {
328
332
  return `${base}/${relative}`;
329
333
  }
330
334
  /**
331
- * Self-contained (zero-`require`) hand-port of `snapshot.ts`'s
332
- * `normalise`/`evaluate` — Tier A1 only. See the module-level comment above
333
- * for what this deliberately does and does not cover, and
334
- * `__tests__/harness.test.ts` for the behavioural-parity check against the
335
- * real `snapshot.evaluate()` this port is pinned to.
335
+ * Self-contained (built-ins only, no npm install) hand-port of `snapshot.ts`'s
336
+ * `loadSnapshot`/`normalise`/`evaluate` and of `gate.ts`'s Tier M — the
337
+ * policy-snapshot rules and the MCP server registry and allowlist. See the
338
+ * module-level comment above for what this deliberately does and does not
339
+ * cover, and `__tests__/harness.test.ts` for the behavioural-parity check
340
+ * against the real `snapshot.evaluate()` this port is pinned to and the
341
+ * shared MCP registry vectors.
342
+ *
343
+ * The rules text is checked as every gate checks it: a missing or broken
344
+ * `#digest`, or a `#workspace` other than `workspaceId`, leaves only its
345
+ * SSO-group refusals, and refuses every MCP call (`POLICY_SNAPSHOT_UNVERIFIED`)
346
+ * because neither MCP record can be vouched for. An empty rules text is no
347
+ * snapshot at all, as an absent file is.
336
348
  *
337
349
  * Contract matches the laptop's `claude-code-check.js`
338
350
  * (`services/sync-daemon/src/harness/claudeCodeHooks.ts`) deliberately:
@@ -342,91 +354,218 @@ function sandboxJoin(workDir, relative) {
342
354
  * any parse/read error fails CLOSED (exit `2`), the same posture
343
355
  * `emitJsFailClosedPrelude` documents for the laptop's version.
344
356
  */
345
- function renderSandboxGateScript(rulesFileName) {
357
+ function renderSandboxGateScript(rulesFileName, workspaceId = '') {
346
358
  return `#!/usr/bin/env node
347
359
  'use strict';
348
360
  /**
349
- * Intutic sandbox PreToolUse gate (Tier A1 only — policy-snapshot rules).
361
+ * Intutic sandbox PreToolUse gate (policy-snapshot rules, and the MCP server
362
+ * registry and allowlist the snapshot carries).
350
363
  * Auto-generated by @intutic/gate's intuticSandboxBootstrap(). DO NOT EDIT.
351
364
  *
352
365
  * Unlike the laptop's claude-code-check.js, this script has no live
353
366
  * control-plane connection at call time (the recommended sandbox network
354
367
  * policy is deny-all) and therefore implements NEITHER the SOP tier (A3)
355
- * NOR review-hold parking NOR governance-event draining. See TD-417.
368
+ * NOR review-hold parking NOR governance-event draining.
356
369
  */
357
370
  const fs = require('fs');
358
371
  const path = require('path');
372
+ const crypto = require('crypto');
359
373
 
360
374
  const RULES_PATH = path.join(__dirname, ${JSON.stringify(rulesFileName)});
375
+ const WORKSPACE_ID = ${JSON.stringify(workspaceId)};
361
376
 
362
377
  function normalise(v) {
363
378
  const s = v === null || v === undefined ? '' : String(v);
364
379
  return ' ' + s.replace(/\\s+/g, ' ').trim() + ' ';
365
380
  }
366
381
 
367
- function loadRules() {
382
+ function stringList(v) {
383
+ return Array.isArray(v) ? v.filter(function (x) { return typeof x === 'string'; }) : [];
384
+ }
385
+
386
+ /** The snapshot: its rules, MCP records and whether it verified. */
387
+ function loadSnapshot() {
388
+ const out = { rules: [], state: 'absent', mcpRegistry: null, mcpAllowlist: null };
368
389
  let text;
369
390
  try {
370
391
  text = fs.readFileSync(RULES_PATH, 'utf-8');
371
392
  } catch (e) {
372
- return [];
393
+ return out;
373
394
  }
374
- const rules = [];
395
+ // Written empty when the bootstrap was given no rules: no snapshot, not a
396
+ // damaged one.
397
+ if (!text.trim()) return out;
398
+ out.state = 'ok';
399
+ let digest = '', workspace = '';
400
+ const body = [];
375
401
  for (const line of text.split('\\n')) {
402
+ if (line.indexOf('#digest ') === 0) { digest = line.slice(8).trim(); continue; }
403
+ if (line.indexOf('#workspace ') === 0) { workspace = line.slice(11).trim(); continue; }
376
404
  if (!line || line.charAt(0) === '#') continue;
405
+ body.push(line);
377
406
  const f = line.split('\\t');
407
+ if (f[0] === '@mcp_registry' && f.length === 2) {
408
+ try {
409
+ const r = JSON.parse(Buffer.from(f[1], 'base64').toString('utf8'));
410
+ const disabled = {};
411
+ if (r.disabledTools && typeof r.disabledTools === 'object') {
412
+ for (const k of Object.keys(r.disabledTools)) disabled[k] = stringList(r.disabledTools[k]);
413
+ }
414
+ out.mcpRegistry = { defaultPolicy: r.defaultPolicy === 'deny' ? 'deny' : 'allow',
415
+ approvedServers: stringList(r.approvedServers), blockedServers: stringList(r.blockedServers),
416
+ heldServers: stringList(r.heldServers), disabledTools: disabled };
417
+ } catch (e) { /* a damaged record is no registry */ }
418
+ continue;
419
+ }
420
+ if (f[0] === '@mcp_allowlist' && f.length === 3) {
421
+ out.mcpAllowlist = { severity: f[1] === 'shadow' ? 'shadow' : 'block', servers: f[2].split(',').filter(Boolean) };
422
+ continue;
423
+ }
424
+ // Column order: id, severity, flags, subject, reason, source(regex).
378
425
  if (f.length < 6 || !f[5]) continue;
426
+ // Flags: i = case-insensitive, s = a sequence rule (sequence.ts).
427
+ const ic = f[2].indexOf('i') !== -1;
379
428
  try {
380
- rules.push({
429
+ out.rules.push({
381
430
  id: f[0],
382
431
  severity: f[1],
383
432
  subject: f[3] || 'any',
384
433
  reason: f[4],
385
- pattern: new RegExp(f[5], f[2] === 'i' ? 'i' : ''),
434
+ pattern: new RegExp(f[5], ic ? 'i' : ''),
435
+ steps: f[2].indexOf('s') !== -1 ? compileSequence(f[5], ic) : null,
386
436
  });
387
437
  } catch (e) {
388
438
  // Regex would not compile — dropped, not fatal. Matches snapshot.ts.
389
439
  }
390
440
  }
391
- return rules;
441
+ // Integrity, as snapshot.ts checks it: the digest over the data lines (a
442
+ // missing one fails too), and the workspace the rules were issued to.
443
+ const actual = crypto.createHash('sha256').update(body.join('\\n'), 'utf-8').digest('hex').slice(0, 32);
444
+ if (actual !== digest || (workspace && WORKSPACE_ID && workspace !== WORKSPACE_ID)) {
445
+ out.state = 'invalid';
446
+ // Only the SSO-group refusals survive, and neither MCP record does.
447
+ out.rules = out.rules.filter(function (r) { return r.id.indexOf('sso_group.') === 0 && r.severity === 'block'; });
448
+ out.mcpRegistry = null;
449
+ out.mcpAllowlist = null;
450
+ }
451
+ return out;
392
452
  }
393
453
 
454
+ // The phrase matcher snapshot.ts uses, emitted from phrases.ts: a \`phrase\`
455
+ // rule's source is |-separated phrases matched as words, not a regex.
456
+ ${PHRASES_JS_SOURCE}
457
+
458
+ // The sequence-rule matcher snapshot.ts uses, emitted from sequence.ts: a rule
459
+ // flagged \`s\` has its steps searched for in order, in linear time.
460
+ ${SEQUENCE_JS_SOURCE}
461
+
462
+ // The MCP server registry and allowlist decisions, and the refusal on an
463
+ // unverified snapshot, emitted from mcpRegistryRecord.ts.
464
+ ${MCP_REGISTRY_JS_SOURCE}
465
+
466
+ ${MCP_ALLOWLIST_JS_SOURCE}
467
+
468
+ ${MCP_SNAPSHOT_UNVERIFIED_JS_SOURCE}
469
+
394
470
  function evaluate(toolName, target, command, rules) {
395
471
  const nTool = normalise(toolName);
396
472
  const nCommand = normalise(command);
397
473
  const nTarget = normalise(target);
474
+ let words = null;
398
475
  for (const rule of rules) {
476
+ if (rule.subject === 'phrase') {
477
+ if (words === null) words = phraseText(command);
478
+ const w = words;
479
+ if (!rule.pattern.source.split('|').some(function (p) { return hasPhrase(w, p, true); })) continue;
480
+ return { severity: rule.severity, reason: rule.reason + ' [' + rule.id + ']' };
481
+ }
399
482
  const subjects =
400
483
  rule.subject === 'tool' ? [nTool] :
401
484
  rule.subject === 'command' ? [nCommand] :
402
485
  rule.subject === 'target' ? [nTarget] :
403
486
  [nCommand, nTarget];
404
487
  for (const subject of subjects) {
405
- if (!rule.pattern.test(subject)) continue;
488
+ if (!(rule.steps ? sequenceMatch(rule.steps, subject) : rule.pattern.test(subject))) continue;
406
489
  return { severity: rule.severity, reason: rule.reason + ' [' + rule.id + ']' };
407
490
  }
408
491
  }
409
492
  return null;
410
493
  }
411
494
 
495
+ /**
496
+ * Tier M, for an mcp__<server>__<tool> call: on an unverified snapshot every
497
+ * call is refused; otherwise the registry, then the allowlist, whose refusal
498
+ * under shadow (an observe-only workspace) is reported and allowed.
499
+ */
500
+ function evaluateMcp(toolName, snap) {
501
+ if (toolName.indexOf('mcp__') !== 0) return null;
502
+ const rest = toolName.slice('mcp__'.length);
503
+ const sep = rest.indexOf('__');
504
+ if (sep <= 0) return null;
505
+ const server = rest.slice(0, sep);
506
+ if (snap.state === 'invalid') {
507
+ const u = mcpSnapshotUnverifiedRefusal(server);
508
+ return { severity: 'block', reason: u.reason + ' [' + u.ruleId + ']', code: u.code };
509
+ }
510
+ const r = snap.mcpRegistry ? evaluateMcpRegistry(snap.mcpRegistry, server, rest.slice(sep + 2)) : null;
511
+ if (r) return { severity: 'block', reason: r.reason + ' [' + r.ruleId + ']', code: r.code };
512
+ const a = snap.mcpAllowlist ? evaluateMcpAllowlist(snap.mcpAllowlist, server) : null;
513
+ if (a) return { severity: snap.mcpAllowlist.severity === 'shadow' ? 'shadow' : 'block', reason: a.reason + ' [' + a.ruleId + ']', code: a.code };
514
+ return null;
515
+ }
516
+
412
517
  let inputData = '';
413
518
  process.stdin.on('data', (chunk) => { inputData += chunk; });
414
519
  process.stdin.on('end', () => {
415
520
  try {
416
521
  const ctx = JSON.parse(inputData || '{}');
417
- const toolName = ctx.tool_name || ctx.toolName || '';
522
+ const toolName = String(ctx.tool_name || ctx.toolName || '');
418
523
  const toolInput = ctx.tool_input || ctx.toolInput || {};
419
524
  const target = toolInput.path || toolInput.file_path || toolInput.filePath ||
420
525
  toolInput.new_path || toolInput.target || toolInput.notebook_path || '';
421
526
  const command = String(toolInput.command || toolInput.cmd || toolInput.script || '');
422
- const rules = loadRules();
423
- const decision = evaluate(toolName, target, command, rules);
424
- if (decision && decision.severity === 'block') {
425
- console.error('[Intutic Guardrail] BLOCKED: ' + decision.reason);
527
+ // Too large to evaluate inside the hook timeout: refused before any rule
528
+ // runs (limits.ts). Claude Code reads a hook that times out as an allow.
529
+ const commandBytes = Buffer.byteLength(command, 'utf8');
530
+ const argumentBytes = Buffer.byteLength(JSON.stringify(toolInput) || '', 'utf8');
531
+ if (commandBytes > ${COMMAND_SIZE_LIMIT} || argumentBytes > ${ARGUMENTS_SIZE_LIMIT}) {
532
+ console.error('[Intutic Guardrail] BLOCKED: COMMAND_TOO_LARGE: the ' +
533
+ (commandBytes > ${COMMAND_SIZE_LIMIT} ? 'command is ' + commandBytes : 'tool arguments are ' + argumentBytes) +
534
+ ' bytes, over the ' + (commandBytes > ${COMMAND_SIZE_LIMIT} ? ${COMMAND_SIZE_LIMIT} : ${ARGUMENTS_SIZE_LIMIT}) +
535
+ '-byte limit a gate evaluates; split the work into smaller calls');
536
+ process.exit(2);
537
+ }
538
+ const snap = loadSnapshot();
539
+ // The rules run under a deadline that interrupts even a regex mid-match,
540
+ // measured from process start, and a call still undecided then is refused:
541
+ // a snapshot rule written in a workspace need not be linear.
542
+ let decision;
543
+ globalThis.__intuticEvaluate = function () {
544
+ return evaluate(toolName, target, command, snap.rules) || evaluateMcp(toolName, snap);
545
+ };
546
+ try {
547
+ decision = require('vm').runInThisContext('__intuticEvaluate()', {
548
+ timeout: Math.max(1, ${GATE_DEADLINE_MS} - Math.round(process.uptime() * 1000)),
549
+ });
550
+ } catch (err) {
551
+ if (!err || err.code !== 'ERR_SCRIPT_EXECUTION_TIMEOUT') throw err;
552
+ console.error('[Intutic Guardrail] BLOCKED: GATE_DEADLINE: the policy rules did not finish within ' +
553
+ ${GATE_DEADLINE_MS} + ' ms, so the call is refused rather than left to the hook timeout');
426
554
  process.exit(2);
427
555
  }
428
556
  if (decision && (decision.severity === 'warn' || decision.severity === 'shadow')) {
429
557
  console.error('[Intutic Guardrail] FLAGGED (' + decision.severity + '): ' + decision.reason);
558
+ } else if (decision && decision.severity === 'hold') {
559
+ // A hold asks a person first, and this script cannot reach the control
560
+ // plane to ask: it refuses, as every gate does with a hold it cannot record.
561
+ console.error('[Intutic Guardrail] HELD for approval: ' + decision.reason +
562
+ ' — approval cannot be requested from inside this sandbox, so the call is refused.');
563
+ process.exit(2);
564
+ } else if (decision) {
565
+ // block, or a severity this script does not know: never an allow. An
566
+ // MCP refusal names its code, as the other gates' refusals do.
567
+ console.error('[Intutic Guardrail] BLOCKED: ' + (decision.code ? decision.code + ': ' : '') + decision.reason);
568
+ process.exit(2);
430
569
  }
431
570
  process.exit(0);
432
571
  } catch (err) {
@@ -454,7 +593,7 @@ function sandboxClaudeSettings(hookScriptSandboxPath) {
454
593
  {
455
594
  type: 'command',
456
595
  command: `node ${hookScriptSandboxPath}`,
457
- timeout: 10,
596
+ timeout: HOOK_TIMEOUT_SECONDS,
458
597
  statusMessage: 'Verifying tool execution against Intutic SOP policy...',
459
598
  },
460
599
  ],
@@ -513,8 +652,8 @@ async function writeSandboxUserSettings(session, hookScriptSandboxPath, abortSig
513
652
  }
514
653
  /**
515
654
  * Builds `{ bootstrapHash, onBootstrap }` for
516
- * `HarnessAgentSettings.sandboxConfig` — the channel TD-417 identified as
517
- * existing but unused:
655
+ * `HarnessAgentSettings.sandboxConfig` — a channel the framework provides
656
+ * but nothing used:
518
657
  *
519
658
  * ```ts
520
659
  * import { HarnessAgent } from '@ai-sdk/harness/agent'
@@ -547,7 +686,7 @@ export function intuticSandboxBootstrap(opts = {}) {
547
686
  const rulesRelPath = `${bootstrapDir}/policy-snapshot.rules`;
548
687
  const scriptRelPath = `${bootstrapDir}/claude-code-check.js`;
549
688
  const rulesContent = opts.policySnapshotRules ?? '';
550
- const scriptContent = renderSandboxGateScript('policy-snapshot.rules');
689
+ const scriptContent = renderSandboxGateScript('policy-snapshot.rules', opts.workspaceId ?? '');
551
690
  // Same hashing convention `snapshot.ts` already uses for the policy
552
691
  // digest (`createHash('sha256')` from node:crypto) — not a new mechanism.
553
692
  const bootstrapHash = createHash('sha256')
@@ -574,6 +713,6 @@ export function intuticSandboxBootstrap(opts = {}) {
574
713
  },
575
714
  };
576
715
  }
577
- // Exposed for the behavioural-parity test — not part of the public surface.
716
+ // Exposed for the behavioural-parity tests — not part of the public surface.
578
717
  export const _internal = { renderSandboxGateScript, renderSandboxClaudeSettings, sandboxJoin };
579
718
  //# sourceMappingURL=harness.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"harness.js","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"harness.js","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"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"}
package/dist/hold.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Approval holds — a hold rule refuses the call for now and asks a person.
3
+ *
4
+ * Port of `packages/intutic-clawde/intutic_clawde/gate/hold.py`, and the same
5
+ * mechanism as the MCP proxy's `approvalHold.ts`, through the same
6
+ * control-plane decisions API the harness hook gates use:
7
+ *
8
+ * 1. A call that matches a hold rule (`hold` severity in the policy snapshot,
9
+ * or a `REQUIRE_APPROVAL:` rule in the SOP register) is looked up in the
10
+ * workspace's approved bypasses (`GET /api/v1/decisions/approved-bypasses`).
11
+ * An exact, unexpired match — same rule, same tool, same arguments — lets
12
+ * the call through.
13
+ * 2. Otherwise the call is refused with an {@link IntuticGateHold} and a hold
14
+ * is recorded (`POST /api/v1/decisions`): it joins the review queue, the
15
+ * workspace is notified (`decision.pending`, Slack included), and the
16
+ * refusal carries the hold id.
17
+ * 3. An owner, admin or engineering manager approves it
18
+ * (`intutic decision approve <holdId>` or the Slack card). The identical
19
+ * retry passes only while the workspace's review-hold bypass
20
+ * (`reviewHoldBypassEnabled`) is on, for `reviewHoldBypassTtlMinutes`;
21
+ * with it off, approving records the decision and the retry is held again.
22
+ *
23
+ * "Identical" is the bypass key: the rule id, the tool name trimmed and
24
+ * lower-cased, and a SHA-256 of the arguments serialised with sorted keys, so
25
+ * the same arguments in a different key order still match and any other
26
+ * value does not. `packages/shared-types/fixtures/hold-key-vectors.json` holds
27
+ * this, the Python gate and the MCP proxy to the same hash.
28
+ *
29
+ * A hold needs the control plane both ways, so without one (no client, or an
30
+ * unreachable control plane) the call stays held, whatever `failClosed` says,
31
+ * exactly as a hook gate's hold refuses when it cannot record: a rule that
32
+ * says a person must approve is not satisfied by nobody being reachable.
33
+ */
34
+ import type { GateClient } from './client.js';
35
+ export type HoldOutcome = {
36
+ kind: 'bypassed';
37
+ holdId: string;
38
+ decidedBy: string;
39
+ } | {
40
+ kind: 'held';
41
+ holdId: string;
42
+ recorded: boolean;
43
+ };
44
+ /** JSON with object keys sorted at every level, so key order never changes a hash. */
45
+ export declare function canonicalJson(value: unknown): string;
46
+ /** The bypass key's call half: the tool and a hash of its arguments. */
47
+ export declare function holdKey(toolName: string, toolInput: unknown): {
48
+ toolNameNormalized: string;
49
+ targetHash: string;
50
+ };
51
+ /**
52
+ * What the agent is told, held or not recorded — the one place this package
53
+ * words a hold. Says who can approve, and that a retry passes only with the
54
+ * bypass setting on, because "retry after approval" alone is false under the
55
+ * default settings.
56
+ */
57
+ export declare function holdMessage(ruleReason: string, ruleId: string, outcome: {
58
+ holdId: string;
59
+ recorded: boolean;
60
+ }): string;
61
+ /**
62
+ * Lets the call through on an approved bypass, or records a hold and returns
63
+ * its id. Never throws: every failure leaves the call held.
64
+ */
65
+ export declare function requestHold(client: GateClient | null, rule: {
66
+ id: string;
67
+ reason: string;
68
+ }, toolName: string, toolInput: unknown): Promise<HoldOutcome>;
69
+ //# sourceMappingURL=hold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hold.d.ts","sourceRoot":"","sources":["../src/hold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAK7C,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAA;AAEvD,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASpD;AAED,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG;IAAE,kBAAkB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAKhH;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAetH;AAYD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,WAAW,CAAC,CAoBtB"}
package/dist/hold.js ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Approval holds — a hold rule refuses the call for now and asks a person.
3
+ *
4
+ * Port of `packages/intutic-clawde/intutic_clawde/gate/hold.py`, and the same
5
+ * mechanism as the MCP proxy's `approvalHold.ts`, through the same
6
+ * control-plane decisions API the harness hook gates use:
7
+ *
8
+ * 1. A call that matches a hold rule (`hold` severity in the policy snapshot,
9
+ * or a `REQUIRE_APPROVAL:` rule in the SOP register) is looked up in the
10
+ * workspace's approved bypasses (`GET /api/v1/decisions/approved-bypasses`).
11
+ * An exact, unexpired match — same rule, same tool, same arguments — lets
12
+ * the call through.
13
+ * 2. Otherwise the call is refused with an {@link IntuticGateHold} and a hold
14
+ * is recorded (`POST /api/v1/decisions`): it joins the review queue, the
15
+ * workspace is notified (`decision.pending`, Slack included), and the
16
+ * refusal carries the hold id.
17
+ * 3. An owner, admin or engineering manager approves it
18
+ * (`intutic decision approve <holdId>` or the Slack card). The identical
19
+ * retry passes only while the workspace's review-hold bypass
20
+ * (`reviewHoldBypassEnabled`) is on, for `reviewHoldBypassTtlMinutes`;
21
+ * with it off, approving records the decision and the retry is held again.
22
+ *
23
+ * "Identical" is the bypass key: the rule id, the tool name trimmed and
24
+ * lower-cased, and a SHA-256 of the arguments serialised with sorted keys, so
25
+ * the same arguments in a different key order still match and any other
26
+ * value does not. `packages/shared-types/fixtures/hold-key-vectors.json` holds
27
+ * this, the Python gate and the MCP proxy to the same hash.
28
+ *
29
+ * A hold needs the control plane both ways, so without one (no client, or an
30
+ * unreachable control plane) the call stays held, whatever `failClosed` says,
31
+ * exactly as a hook gate's hold refuses when it cannot record: a rule that
32
+ * says a person must approve is not satisfied by nobody being reachable.
33
+ */
34
+ import { createHash, randomBytes } from 'node:crypto';
35
+ /** The hold-record version the control plane accepts. */
36
+ const HOLD_RECORD_VERSION = 1;
37
+ /** JSON with object keys sorted at every level, so key order never changes a hash. */
38
+ export function canonicalJson(value) {
39
+ if (Array.isArray(value))
40
+ return `[${value.map(canonicalJson).join(',')}]`;
41
+ if (value !== null && typeof value === 'object') {
42
+ const entries = Object.entries(value)
43
+ .filter(([, v]) => v !== undefined)
44
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
45
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(',')}}`;
46
+ }
47
+ return JSON.stringify(value ?? null);
48
+ }
49
+ /** The bypass key's call half: the tool and a hash of its arguments. */
50
+ export function holdKey(toolName, toolInput) {
51
+ return {
52
+ toolNameNormalized: toolName.trim().toLowerCase(),
53
+ targetHash: createHash('sha256').update(canonicalJson(toolInput ?? {})).digest('hex'),
54
+ };
55
+ }
56
+ function newHoldId() {
57
+ return `hold_${Date.now().toString(36)}_${randomBytes(4).toString('hex')}`;
58
+ }
59
+ /**
60
+ * What the agent is told, held or not recorded — the one place this package
61
+ * words a hold. Says who can approve, and that a retry passes only with the
62
+ * bypass setting on, because "retry after approval" alone is false under the
63
+ * default settings.
64
+ */
65
+ export function holdMessage(ruleReason, ruleId, outcome) {
66
+ if (!outcome.recorded) {
67
+ return (`HELD for approval: ${ruleReason} [${ruleId}], but the hold could not be recorded ` +
68
+ `(Intutic control plane unreachable), so there is nothing to approve yet. Do not retry ` +
69
+ `until the control plane is reachable; the retry then asks for approval.`);
70
+ }
71
+ return (`HELD for approval: ${ruleReason} [${ruleId}]. Hold id: ${outcome.holdId}. ` +
72
+ `An owner, admin or engineering manager can approve it with: intutic decision approve ` +
73
+ `${outcome.holdId} (or reject it), or from the Slack card. Retry this exact call after ` +
74
+ `approval only if the workspace's review-hold bypass (reviewHoldBypassEnabled) is on; ` +
75
+ `otherwise approving records the decision and the call stays held.`);
76
+ }
77
+ /**
78
+ * Lets the call through on an approved bypass, or records a hold and returns
79
+ * its id. Never throws: every failure leaves the call held.
80
+ */
81
+ export async function requestHold(client, rule, toolName, toolInput) {
82
+ const holdId = newHoldId();
83
+ if (client === null)
84
+ return { kind: 'held', holdId, recorded: false };
85
+ const { toolNameNormalized, targetHash } = holdKey(toolName, toolInput);
86
+ const bypass = await findBypass(client, rule.id, toolNameNormalized, targetHash);
87
+ if (bypass)
88
+ return bypass;
89
+ const recorded = await client.recordHold({
90
+ v: HOLD_RECORD_VERSION,
91
+ holdId,
92
+ reason: rule.id,
93
+ tool: toolName,
94
+ sessionId: client.sessionId,
95
+ at: new Date().toISOString(),
96
+ toolNameNormalized,
97
+ targetHash,
98
+ context: { source: 'gate_sdk', harness: client.harness, tool: toolName, rule: rule.reason },
99
+ });
100
+ return { kind: 'held', holdId, recorded };
101
+ }
102
+ async function findBypass(client, ruleId, toolNameNormalized, targetHash) {
103
+ const list = (await client.approvedBypasses());
104
+ if (!list)
105
+ return null;
106
+ const now = Date.now();
107
+ for (const raw of list) {
108
+ // The route answers for the key's own workspace; the comparison is a
109
+ // second check, made whenever this client was told its workspace.
110
+ if (client.workspaceId && raw.workspaceId !== client.workspaceId)
111
+ continue;
112
+ if (raw.sopRuleId !== ruleId)
113
+ continue;
114
+ if (raw.toolNameNormalized !== toolNameNormalized || raw.targetHash !== targetHash)
115
+ continue;
116
+ const expires = typeof raw.expiresAt === 'string' ? Date.parse(raw.expiresAt) : NaN;
117
+ if (Number.isNaN(expires) || now >= expires)
118
+ continue;
119
+ return {
120
+ kind: 'bypassed',
121
+ holdId: typeof raw.holdId === 'string' ? raw.holdId : '',
122
+ decidedBy: typeof raw.decidedBy === 'string' ? raw.decidedBy : '',
123
+ };
124
+ }
125
+ return null;
126
+ }
127
+ //# sourceMappingURL=hold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hold.js","sourceRoot":"","sources":["../src/hold.ts"],"names":[],"mappings":"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"}
@@ -9,9 +9,9 @@
9
9
  * no admission webhook — so this check is the argument-level enforcement
10
10
  * point for "deploy only pinned, reviewed images".
11
11
  *
12
- * Fail-closed on anything it cannot read. That is a deliberate departure from
13
- * Intutic's fail-open default (WASM rules, hook-gate, the MCP proxy all fail
14
- * open). The reasoning: a gate that cannot parse what it is being asked to
12
+ * Fail-closed on anything it cannot read. Other tiers follow a
13
+ * fail setting when the control plane cannot be reached; this one never does.
14
+ * The reasoning: a gate that cannot parse what it is being asked to
15
15
  * approve does not know what it is approving, and "I could not read it" is
16
16
  * not evidence of safety.
17
17
  */
@@ -21,6 +21,7 @@ export declare const E_UNKNOWN_REGISTRY = "E_UNKNOWN_REGISTRY";
21
21
  export declare const E_UNKNOWN_IMAGE = "E_UNKNOWN_IMAGE";
22
22
  export declare const E_DIGEST_MISMATCH = "E_DIGEST_MISMATCH";
23
23
  export declare const E_MANIFEST_UNPARSEABLE = "E_MANIFEST_UNPARSEABLE";
24
+ export type ImageRefusalCode = typeof E_UNPINNED_LATEST | typeof E_UNPINNED_TAG | typeof E_UNKNOWN_REGISTRY | typeof E_UNKNOWN_IMAGE | typeof E_DIGEST_MISMATCH | typeof E_MANIFEST_UNPARSEABLE;
24
25
  /** A parsed container image reference. */
25
26
  export interface ImageRef {
26
27
  raw: string;
@@ -40,12 +41,18 @@ export interface ImagePolicy {
40
41
  approved_digests?: string[];
41
42
  }>;
42
43
  }
43
- export interface Verdict {
44
- ok: boolean;
45
- code: string;
44
+ /** `code` is `''` on a pass and names the failure otherwise. */
45
+ export type Verdict = {
46
+ ok: true;
47
+ code: '';
46
48
  detail: string;
47
49
  images: ImageRef[];
48
- }
50
+ } | {
51
+ ok: false;
52
+ code: ImageRefusalCode;
53
+ detail: string;
54
+ images: ImageRef[];
55
+ };
49
56
  /** The single line an operator sees on the dashboard. */
50
57
  export declare function verdictReason(v: Verdict): string;
51
58
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"imagecheck.d.ts","sourceRoot":"","sources":["../src/imagecheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD,eAAO,MAAM,cAAc,mBAAmB,CAAA;AAC9C,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AACtD,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAChD,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD,eAAO,MAAM,sBAAsB,2BAA2B,CAAA;AAE9D,0CAA0C;AAC1C,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAE/C;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CACzD;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,QAAQ,EAAE,CAAA;CACnB;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGhD;AAUD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,QAAQ,CAmBhE;AA+BD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAoChG;AAqBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAqBnE;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAuDrF;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAqC5F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAchG;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAE7E"}
1
+ {"version":3,"file":"imagecheck.d.ts","sourceRoot":"","sources":["../src/imagecheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD,eAAO,MAAM,cAAc,mBAAmB,CAAA;AAC9C,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AACtD,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAChD,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD,eAAO,MAAM,sBAAsB,2BAA2B,CAAA;AAE9D,MAAM,MAAM,gBAAgB,GACxB,OAAO,iBAAiB,GACxB,OAAO,cAAc,GACrB,OAAO,kBAAkB,GACzB,OAAO,eAAe,GACtB,OAAO,iBAAiB,GACxB,OAAO,sBAAsB,CAAA;AAEjC,0CAA0C;AAC1C,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAE/C;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CACzD;AAED,gEAAgE;AAChE,MAAM,MAAM,OAAO,GACf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,EAAE,CAAA;CAAE,GAC1D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAA;AAE7E,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGhD;AAUD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,QAAQ,CAmBhE;AA+BD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAoChG;AAqBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAqBnE;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAuDrF;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAqC5F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAchG;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAE7E"}
@@ -9,9 +9,9 @@
9
9
  * no admission webhook — so this check is the argument-level enforcement
10
10
  * point for "deploy only pinned, reviewed images".
11
11
  *
12
- * Fail-closed on anything it cannot read. That is a deliberate departure from
13
- * Intutic's fail-open default (WASM rules, hook-gate, the MCP proxy all fail
14
- * open). The reasoning: a gate that cannot parse what it is being asked to
12
+ * Fail-closed on anything it cannot read. Other tiers follow a
13
+ * fail setting when the control plane cannot be reached; this one never does.
14
+ * The reasoning: a gate that cannot parse what it is being asked to
15
15
  * approve does not know what it is approving, and "I could not read it" is
16
16
  * not evidence of safety.
17
17
  */