@getmarrow/mcp 3.9.102 → 3.9.103
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.
- package/README.md +49 -23
- package/dist/cli.js +41 -10
- package/dist/cli.js.map +1 -1
- package/dist/codex-plugin-pins.d.ts +19 -0
- package/dist/codex-plugin-pins.d.ts.map +1 -0
- package/dist/codex-plugin-pins.js +43 -0
- package/dist/codex-plugin-pins.js.map +1 -0
- package/dist/codex-plugins.d.ts +34 -0
- package/dist/codex-plugins.d.ts.map +1 -0
- package/dist/codex-plugins.js +240 -0
- package/dist/codex-plugins.js.map +1 -0
- package/dist/hook-contract.d.ts +2 -2
- package/dist/hook-contract.d.ts.map +1 -1
- package/dist/hook-contract.js +8 -3
- package/dist/hook-contract.js.map +1 -1
- package/dist/hook-pre-action.d.ts +48 -2
- package/dist/hook-pre-action.d.ts.map +1 -1
- package/dist/hook-pre-action.js +195 -22
- package/dist/hook-pre-action.js.map +1 -1
- package/dist/hook.d.ts +1 -1
- package/dist/hook.d.ts.map +1 -1
- package/dist/hook.js +12 -6
- package/dist/hook.js.map +1 -1
- package/dist/host-session.d.ts +11 -0
- package/dist/host-session.d.ts.map +1 -1
- package/dist/host-session.js +49 -0
- package/dist/host-session.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -10
- package/dist/index.js.map +1 -1
- package/dist/normalized-action.d.ts +29 -6
- package/dist/normalized-action.d.ts.map +1 -1
- package/dist/normalized-action.js +492 -102
- package/dist/normalized-action.js.map +1 -1
- package/dist/own-server-identity.d.ts +123 -0
- package/dist/own-server-identity.d.ts.map +1 -0
- package/dist/own-server-identity.js +1052 -0
- package/dist/own-server-identity.js.map +1 -0
- package/dist/own-tool.d.ts +7 -3
- package/dist/own-tool.d.ts.map +1 -1
- package/dist/own-tool.js +7 -3
- package/dist/own-tool.js.map +1 -1
- package/dist/redact.d.ts +23 -0
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +181 -8
- package/dist/redact.js.map +1 -1
- package/dist/seatbelt/classifier-pin.d.ts +15 -0
- package/dist/seatbelt/classifier-pin.d.ts.map +1 -0
- package/dist/seatbelt/classifier-pin.js +26 -0
- package/dist/seatbelt/classifier-pin.js.map +1 -0
- package/dist/seatbelt/guards.d.ts +10 -0
- package/dist/seatbelt/guards.d.ts.map +1 -0
- package/dist/seatbelt/guards.js +509 -0
- package/dist/seatbelt/guards.js.map +1 -0
- package/dist/seatbelt/hook.d.ts +72 -0
- package/dist/seatbelt/hook.d.ts.map +1 -0
- package/dist/seatbelt/hook.js +362 -0
- package/dist/seatbelt/hook.js.map +1 -0
- package/dist/seatbelt/longopts.d.ts +68 -0
- package/dist/seatbelt/longopts.d.ts.map +1 -0
- package/dist/seatbelt/longopts.js +377 -0
- package/dist/seatbelt/longopts.js.map +1 -0
- package/dist/seatbelt/mapper.d.ts +83 -0
- package/dist/seatbelt/mapper.d.ts.map +1 -0
- package/dist/seatbelt/mapper.js +10248 -0
- package/dist/seatbelt/mapper.js.map +1 -0
- package/dist/seatbelt/record.d.ts +94 -0
- package/dist/seatbelt/record.d.ts.map +1 -0
- package/dist/seatbelt/record.js +776 -0
- package/dist/seatbelt/record.js.map +1 -0
- package/dist/seatbelt/tables.d.ts +82 -0
- package/dist/seatbelt/tables.d.ts.map +1 -0
- package/dist/seatbelt/tables.js +359 -0
- package/dist/seatbelt/tables.js.map +1 -0
- package/dist/seatbelt-deploy.d.ts +100 -0
- package/dist/seatbelt-deploy.d.ts.map +1 -0
- package/dist/seatbelt-deploy.js +393 -0
- package/dist/seatbelt-deploy.js.map +1 -0
- package/dist/seatbelt-fs.d.ts +30 -0
- package/dist/seatbelt-fs.d.ts.map +1 -0
- package/dist/seatbelt-fs.js +94 -0
- package/dist/seatbelt-fs.js.map +1 -0
- package/dist/seatbelt-git.d.ts +212 -0
- package/dist/seatbelt-git.d.ts.map +1 -0
- package/dist/seatbelt-git.js +844 -0
- package/dist/seatbelt-git.js.map +1 -0
- package/dist/seatbelt-mode.d.ts +77 -0
- package/dist/seatbelt-mode.d.ts.map +1 -0
- package/dist/seatbelt-mode.js +496 -0
- package/dist/seatbelt-mode.js.map +1 -0
- package/dist/seatbelt-path.d.ts +123 -0
- package/dist/seatbelt-path.d.ts.map +1 -0
- package/dist/seatbelt-path.js +482 -0
- package/dist/seatbelt-path.js.map +1 -0
- package/dist/seatbelt-scripts.d.ts +109 -0
- package/dist/seatbelt-scripts.d.ts.map +1 -0
- package/dist/seatbelt-scripts.js +1060 -0
- package/dist/seatbelt-scripts.js.map +1 -0
- package/dist/tool-catalog.js +2 -2
- package/dist/tool-catalog.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/server.json +3 -3
- package/vendor/classifier/MANIFEST.json +25 -0
- package/vendor/classifier/classifier.js +1356 -0
- package/vendor/classifier/policy-baseline.js +187 -0
- package/vendor/classifier/redact.js +59 -0
- package/vendor/classifier/shell-parse.js +455 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-pre-action.d.ts","sourceRoot":"","sources":["../src/hook-pre-action.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAgB,iBAAiB,EAAgC,MAAM,SAAS,CAAC;AAK5G,OAAO,EAsBL,KAAK,QAAQ,EAEd,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"hook-pre-action.d.ts","sourceRoot":"","sources":["../src/hook-pre-action.ts"],"names":[],"mappings":"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"}
|
package/dist/hook-pre-action.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DENIED_DECISION_CLOSE_TIMEOUT_MS = exports.GROK_FIXED_DENIAL = exports.HELD_SLOW_TEXT = exports.HOLD_OWNER_DENIAL = exports.PreActionControlTimeoutError = exports.PRE_ACTION_CONTROL_TIMEOUT_MS = exports.MAX_PRE_ACTION_INPUT_BYTES = exports.MARROW_OUTAGE_WARNING = exports.NO_KEY_TEXT = void 0;
|
|
3
|
+
exports.DENIED_DECISION_CLOSE_TIMEOUT_MS = exports.SEATBELT_CURSOR_ASK_AGENT_TEXT = exports.SEATBELT_CURSOR_ASK_USER_TEXT = exports.SEATBELT_HELD_TEXT = exports.GROK_FIXED_DENIAL = exports.HELD_OFFLINE_TEXT = exports.HELD_SLOW_TEXT = exports.HOLD_OWNER_DENIAL = exports.PreActionControlTimeoutError = exports.PRE_ACTION_CONTROL_TIMEOUT_MS = exports.MAX_PRE_ACTION_INPUT_BYTES = exports.MARROW_OUTAGE_WARNING = exports.SETUP_UNCONFIRMED_TEXT = exports.CLAIMED_NO_KEY_TEXT = exports.NO_KEY_TEXT = void 0;
|
|
4
4
|
exports.isMarrowControlTimeout = isMarrowControlTimeout;
|
|
5
5
|
exports.isMarrowControlOutage = isMarrowControlOutage;
|
|
6
6
|
exports.heldActionHookOutput = heldActionHookOutput;
|
|
@@ -16,6 +16,7 @@ exports.advisoryGateNotice = advisoryGateNotice;
|
|
|
16
16
|
exports.runtimeGateVerdict = runtimeGateVerdict;
|
|
17
17
|
exports.gateDecisionMessage = gateDecisionMessage;
|
|
18
18
|
exports.localControlAllowOutput = localControlAllowOutput;
|
|
19
|
+
exports.seatbeltPassOutput = seatbeltPassOutput;
|
|
19
20
|
exports.localLoopGuardDenyOutput = localLoopGuardDenyOutput;
|
|
20
21
|
exports.classifyTool = classifyTool;
|
|
21
22
|
exports.cursorPreActionHookOutput = cursorPreActionHookOutput;
|
|
@@ -27,6 +28,7 @@ exports.preActionHookOutput = preActionHookOutput;
|
|
|
27
28
|
exports.closeDeniedDecision = closeDeniedDecision;
|
|
28
29
|
exports.localApprovalCategories = localApprovalCategories;
|
|
29
30
|
exports.installPreActionHook = installPreActionHook;
|
|
31
|
+
exports.outageHolds = outageHolds;
|
|
30
32
|
exports.runPreActionHookCommand = runPreActionHookCommand;
|
|
31
33
|
const node_crypto_1 = require("node:crypto");
|
|
32
34
|
const index_1 = require("./index");
|
|
@@ -36,6 +38,7 @@ const control_state_1 = require("./control-state");
|
|
|
36
38
|
const runtime_contract_1 = require("./runtime-contract");
|
|
37
39
|
const host_approval_1 = require("./host-approval");
|
|
38
40
|
const host_session_1 = require("./host-session");
|
|
41
|
+
const own_server_identity_1 = require("./own-server-identity");
|
|
39
42
|
const normalized_action_1 = require("./normalized-action");
|
|
40
43
|
const session_loop_guard_1 = require("./session-loop-guard");
|
|
41
44
|
const hook_tool_policy_1 = require("./hook-tool-policy");
|
|
@@ -43,6 +46,12 @@ const hook_contract_1 = require("./hook-contract");
|
|
|
43
46
|
Object.defineProperty(exports, "MARROW_OUTAGE_WARNING", { enumerable: true, get: function () { return hook_contract_1.MARROW_OUTAGE_WARNING; } });
|
|
44
47
|
/** A protected action with no Marrow key anywhere this machine keeps one (MARROW_API_KEY, ~/.marrow/env.local or ~/.marrow/env, owner-only). */
|
|
45
48
|
exports.NO_KEY_TEXT = 'Marrow has no API key on this machine. Owner: create one at getmarrow.ai/signup, then run the installer activate command in a terminal. Do not retry this action.';
|
|
49
|
+
/** Seatbelt mode `claimed_no_key` (spec §1.1): account evidence on the machine but no usable key. Same text as src/seatbelt/hook.ts. */
|
|
50
|
+
exports.CLAIMED_NO_KEY_TEXT = 'Marrow is linked to an account but has no working key; owner: run `npx -y @getmarrow/install@latest doctor`.';
|
|
51
|
+
/** `claimed_no_key` without account evidence (a mode fallback): the same holds, never an account claim. Same text as src/seatbelt/hook.ts. */
|
|
52
|
+
exports.SETUP_UNCONFIRMED_TEXT = 'Marrow has no working key on this machine and its keyless mode is off here (strict mode, or a home folder it cannot trust); owner: run `npx -y @getmarrow/install@latest doctor`.';
|
|
53
|
+
/** The seatbelt path itself could not run (its modules did not load): a stop (spec §2.1.4). */
|
|
54
|
+
const SEATBELT_FAILED_TEXT = 'MARROW SEATBELT stopped this action: a safety check that could not finish (U5.fail_closed, hook_error). This needs the machine owner. Do not retry it another way or edit Marrow settings.';
|
|
46
55
|
// Claude Code sends the whole tool input, and a Write of a long document grows
|
|
47
56
|
// further once JSON-escaped, so tens of kilobytes of markdown must still parse.
|
|
48
57
|
exports.MAX_PRE_ACTION_INPUT_BYTES = 4 * 1024 * 1024;
|
|
@@ -107,6 +116,8 @@ function isMarrowControlOutage(error) {
|
|
|
107
116
|
exports.HOLD_OWNER_DENIAL = 'Marrow is holding this action for approval. Retry it after approval.';
|
|
108
117
|
/** Marrow did not answer within the hook's time limit: an action that can be held stays held. */
|
|
109
118
|
exports.HELD_SLOW_TEXT = 'Marrow did not answer in time, so this action is held. Retry it in a moment.';
|
|
119
|
+
/** Marrow cannot be reached (a real outage): a high-risk action fails closed; routine actions keep the outage allow. */
|
|
120
|
+
exports.HELD_OFFLINE_TEXT = 'Marrow cannot be reached right now, so this high-risk action is held; routine actions keep running. Retry it when Marrow is back.';
|
|
110
121
|
/** The only denial @getmarrow/install's Grok guard passes through (any other output blocks with a launch failure). */
|
|
111
122
|
exports.GROK_FIXED_DENIAL = 'Marrow blocked this protected action.';
|
|
112
123
|
/**
|
|
@@ -231,7 +242,7 @@ function plainControlFix(error) {
|
|
|
231
242
|
}
|
|
232
243
|
// Names a reached control failure by HTTP status and stable failure code, with a plain
|
|
233
244
|
// fix (see plainControlFix); private service text is never echoed into the agent transcript.
|
|
234
|
-
function controlRejectionMessage(error, agentId) {
|
|
245
|
+
function controlRejectionMessage(error, agentId, kind = controlFailureKind(error)) {
|
|
235
246
|
const detail = [];
|
|
236
247
|
if (error instanceof request_reliability_1.MarrowRequestError) {
|
|
237
248
|
if (typeof error.status === 'number' && Number.isInteger(error.status))
|
|
@@ -241,7 +252,6 @@ function controlRejectionMessage(error, agentId) {
|
|
|
241
252
|
detail.push(code);
|
|
242
253
|
}
|
|
243
254
|
const suffix = detail.length ? ` (${detail.join(' ')})` : '';
|
|
244
|
-
const kind = controlFailureKind(error);
|
|
245
255
|
if (kind === 'credential_scope') {
|
|
246
256
|
const agent = agentId && SAFE_AGENT_ID.test(agentId)
|
|
247
257
|
? `agent "${agentId}"`
|
|
@@ -410,6 +420,46 @@ function localControlAllowOutput(harness) {
|
|
|
410
420
|
return { decision: 'allow' };
|
|
411
421
|
return {};
|
|
412
422
|
}
|
|
423
|
+
/** The Cursor events where Cursor enforces "ask" with its own approval prompt (the installer's execution hooks). */
|
|
424
|
+
const CURSOR_ASK_EVENTS = new Set(['beforeShellExecution', 'beforeMCPExecution']);
|
|
425
|
+
/** Keyless seatbelt: a host that cannot hand this action to its own approval prompt holds it (no account to approve it). */
|
|
426
|
+
exports.SEATBELT_HELD_TEXT = 'MARROW SEATBELT held this action: this host cannot hand it to its own approval prompt here, and no Marrow account is linked to approve it. This needs the machine owner. Do not retry it another way or edit Marrow settings. Tell the owner: run it yourself in your own terminal, or link a Marrow account with "npx -y @getmarrow/install@latest activate" (it needs MARROW_API_KEY set first) so these become approval prompts.';
|
|
427
|
+
exports.SEATBELT_CURSOR_ASK_USER_TEXT = 'Marrow seatbelt (no account linked): approve this action here only if you expected it.';
|
|
428
|
+
exports.SEATBELT_CURSOR_ASK_AGENT_TEXT = 'Cursor is asking the user to approve this action (Marrow seatbelt, no account linked). Wait for the answer; do not retry it another way.';
|
|
429
|
+
/**
|
|
430
|
+
* The keyless seatbelt's answer for an action it does not stop (spec §1.3 "pass": Marrow adds no
|
|
431
|
+
* decision and the host's own permission flow runs). `heldBefore`: the 3.9.103 keyless hook held this
|
|
432
|
+
* action (protected, or not read-only on Windsurf, Gemini or Grok). `null` means exit 0, no output.
|
|
433
|
+
* - Not held before: exactly the answer 3.9.103 gave (its read-only and unprotected passes).
|
|
434
|
+
* - Held before: never an explicit allow that could skip the host's own approval step.
|
|
435
|
+
* Claude Code and Codex `{}` (no permissionDecision), Cline `{cancel:false}`, Windsurf no output:
|
|
436
|
+
* the hosts' neutral answers (see PASS_THROUGH_HOSTS), so their own approval step runs.
|
|
437
|
+
* Gemini CLI `{"decision":"allow"}`: the installed guard passes only that or a fixed denial (no
|
|
438
|
+
* output is a launch failure that blocks), and Gemini applies its own policy and confirmation
|
|
439
|
+
* after the BeforeTool hook whatever an "allow" says, so it is Gemini's neutral answer.
|
|
440
|
+
* Cursor beforeShellExecution / beforeMCPExecution: "ask", so Cursor's own approval prompt decides.
|
|
441
|
+
* Cursor preToolUse (no neutral answer, "ask" not enforced) and Grok (its guard passes only an
|
|
442
|
+
* explicit allow or the fixed denial, and nothing shows an allow keeps Grok's own approval): held,
|
|
443
|
+
* as 3.9.103 did. Any other or missing Cursor event name is treated as preToolUse.
|
|
444
|
+
*/
|
|
445
|
+
function seatbeltPassOutput(harness, hookEventName, heldBefore) {
|
|
446
|
+
if (!heldBefore)
|
|
447
|
+
return localControlAllowOutput(harness);
|
|
448
|
+
if (harness === 'windsurf')
|
|
449
|
+
return null;
|
|
450
|
+
if (harness === 'cline')
|
|
451
|
+
return { cancel: false };
|
|
452
|
+
if (harness === 'gemini')
|
|
453
|
+
return { decision: 'allow' };
|
|
454
|
+
if (harness === 'grok')
|
|
455
|
+
return { decision: 'deny', reason: exports.GROK_FIXED_DENIAL };
|
|
456
|
+
if (harness === 'cursor') {
|
|
457
|
+
return typeof hookEventName === 'string' && CURSOR_ASK_EVENTS.has(hookEventName)
|
|
458
|
+
? { permission: 'ask', user_message: exports.SEATBELT_CURSOR_ASK_USER_TEXT, agent_message: exports.SEATBELT_CURSOR_ASK_AGENT_TEXT }
|
|
459
|
+
: { permission: 'deny', user_message: exports.SEATBELT_HELD_TEXT, agent_message: exports.SEATBELT_HELD_TEXT };
|
|
460
|
+
}
|
|
461
|
+
return {};
|
|
462
|
+
}
|
|
413
463
|
function localLoopGuardDenyOutput(harness, reason) {
|
|
414
464
|
const bounded = reason.replace(/[\u0000-\u001f\u007f]/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 500);
|
|
415
465
|
if (harness === 'windsurf')
|
|
@@ -418,7 +468,10 @@ function localLoopGuardDenyOutput(harness, reason) {
|
|
|
418
468
|
return { permission: 'deny', user_message: bounded, agent_message: bounded };
|
|
419
469
|
if (harness === 'cline')
|
|
420
470
|
return { cancel: true, errorMessage: bounded };
|
|
421
|
-
|
|
471
|
+
// The installed Grok guard passes only an allow or this fixed denial; any other text is its launch failure (audit M1).
|
|
472
|
+
if (harness === 'grok')
|
|
473
|
+
return { decision: 'deny', reason: exports.GROK_FIXED_DENIAL };
|
|
474
|
+
if (harness === 'gemini')
|
|
422
475
|
return { decision: 'deny', reason: bounded };
|
|
423
476
|
return { hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: bounded } };
|
|
424
477
|
}
|
|
@@ -456,7 +509,13 @@ function localControlDisabled() {
|
|
|
456
509
|
return false;
|
|
457
510
|
}
|
|
458
511
|
}
|
|
459
|
-
|
|
512
|
+
/**
|
|
513
|
+
* `ownUnproven`: the label is one of Marrow's own, but the host's server
|
|
514
|
+
* identity check did not prove the official server (Codex, Cursor). Such a
|
|
515
|
+
* call is classified as a protected MCP tool of another server, never
|
|
516
|
+
* read-only (it imitates Marrow's names, so a read verb proves nothing).
|
|
517
|
+
*/
|
|
518
|
+
function classifyTool(event, options = {}) {
|
|
460
519
|
const tool = String(event.tool_name || 'tool').slice(0, 64);
|
|
461
520
|
const normalizedTool = (0, hook_tool_policy_1.normalizeHookToolName)(tool);
|
|
462
521
|
// Editing and task tools are judged by their target; shell-like words in the
|
|
@@ -464,7 +523,8 @@ function classifyTool(event) {
|
|
|
464
523
|
const shellGoverned = (0, hook_tool_policy_1.isShellGovernedTool)(event);
|
|
465
524
|
const command = shellGoverned ? (0, hook_tool_policy_1.hookToolCommand)(event) : '';
|
|
466
525
|
const input = (0, hook_tool_policy_1.toolClassificationText)(event).toLowerCase();
|
|
467
|
-
|
|
526
|
+
// A look-alike of Marrow's own tool is never read-only, whatever its verb.
|
|
527
|
+
const readOnly = options.ownUnproven !== true && (0, hook_tool_policy_1.isReadOnlyToolEvent)(event);
|
|
468
528
|
const secretAccess = (0, hook_tool_policy_1.isSecretMaterialAccess)(event);
|
|
469
529
|
const protectedShellCommand = shellGoverned && (0, hook_tool_policy_1.isProtectedShellMutation)(command);
|
|
470
530
|
const infrastructureDeployment = /\b(?:kubectl|terraform|pulumi|helm)\b/.test(command.toLowerCase())
|
|
@@ -493,7 +553,7 @@ function classifyTool(event) {
|
|
|
493
553
|
const protectedAction = !readOnly && (secretAccess
|
|
494
554
|
|| (shellGoverned && /\b(?:deploy|release|publish|git\s+push|git\s+merge|gh\s+pr\s+merge|migration|migrate|secret|credential|rotate|revoke|payment|refund|charge|invoice|production|prod)\b/.test(input))
|
|
495
555
|
|| protectedShellCommand
|
|
496
|
-
|| ((0, hook_tool_policy_1.isMcpHookTool)(event.tool_name) && !(0, hook_tool_policy_1.isOfficialMarrowMcpTool)(event.tool_name))
|
|
556
|
+
|| ((0, hook_tool_policy_1.isMcpHookTool)(event.tool_name) && (options.ownUnproven === true || !(0, hook_tool_policy_1.isOfficialMarrowMcpTool)(event.tool_name)))
|
|
497
557
|
|| (['use_mcp_tool', 'use_tool'].includes(normalizedTool) && !(0, hook_tool_policy_1.isOfficialMarrowMcpEvent)(event)));
|
|
498
558
|
const risk = readOnly ? 'low' : protectedAction ? 'high' : 'medium';
|
|
499
559
|
const target = surfaces.includes('npm') ? `npm:${type}`
|
|
@@ -548,11 +608,12 @@ function clinePreActionHookOutput(result) {
|
|
|
548
608
|
};
|
|
549
609
|
}
|
|
550
610
|
if (result.protectedRisk && (!result.runtime || !result.permit?.verified)) {
|
|
551
|
-
const credentialsUnavailable = result.enforcementError === exports.NO_KEY_TEXT
|
|
611
|
+
const credentialsUnavailable = result.enforcementError === exports.NO_KEY_TEXT || result.enforcementError === exports.CLAIMED_NO_KEY_TEXT
|
|
612
|
+
|| result.enforcementError === exports.SETUP_UNCONFIRMED_TEXT;
|
|
552
613
|
return {
|
|
553
614
|
cancel: true,
|
|
554
615
|
errorMessage: credentialsUnavailable
|
|
555
|
-
?
|
|
616
|
+
? result.enforcementError
|
|
556
617
|
: result.failure === 'credential_scope'
|
|
557
618
|
? 'This Marrow API key is not authorized to obtain action permits for this agent. Use the API key issued to this agent and retry.'
|
|
558
619
|
: result.failure === 'unavailable'
|
|
@@ -828,11 +889,54 @@ function installPreActionHook(startDir = process.cwd()) {
|
|
|
828
889
|
fs.writeFileSync(path, JSON.stringify(settings, null, 2) + '\n');
|
|
829
890
|
return { settingsPath: path, installed: reconciled.changed };
|
|
830
891
|
}
|
|
892
|
+
/**
|
|
893
|
+
* I3: whether a real outage (the gate never answered) holds this action. Never looser than master,
|
|
894
|
+
* which allowed every action in an outage. A shell command is read by the seatbelt mapper: held for an
|
|
895
|
+
* S0-S5/S-x hit or a program on the outage list (git push, publish, deploy, remote delete), allowed
|
|
896
|
+
* when the mapper read all of it and found neither (words in a message, a path or a comment never hold
|
|
897
|
+
* it). Anything else, or a mapper that could not finish, keeps `classifiedHighRisk` (F2).
|
|
898
|
+
*/
|
|
899
|
+
function outageHolds(classifiedHighRisk, read) {
|
|
900
|
+
let reading = { shell: false, risk: 'unknown' };
|
|
901
|
+
try {
|
|
902
|
+
reading = read();
|
|
903
|
+
}
|
|
904
|
+
catch { /* unknown: the classifier's answer */ }
|
|
905
|
+
if (reading.risk === 'high')
|
|
906
|
+
return true;
|
|
907
|
+
if (reading.shell && reading.risk === 'not_high')
|
|
908
|
+
return false;
|
|
909
|
+
return classifiedHighRisk;
|
|
910
|
+
}
|
|
911
|
+
function seatbeltEvent(source, rawEvent) {
|
|
912
|
+
const raw = asRecord(rawEvent) || {};
|
|
913
|
+
const event = source;
|
|
914
|
+
return {
|
|
915
|
+
tool_name: source.tool_name, tool_input: source.tool_input, cwd: event.cwd ?? raw.cwd, truncated: event.input_truncated === true,
|
|
916
|
+
session: source.session_id || source.conversation_id || source.task_id || undefined,
|
|
917
|
+
};
|
|
918
|
+
}
|
|
831
919
|
async function runPreActionHookCommand(input) {
|
|
920
|
+
// Account mode: the S0-S5 floor in watch runs after the answer is written, for the record only.
|
|
921
|
+
const watch = {};
|
|
922
|
+
try {
|
|
923
|
+
await runPreActionHook(input, watch);
|
|
924
|
+
}
|
|
925
|
+
finally {
|
|
926
|
+
if (watch.harness && watch.event) {
|
|
927
|
+
try {
|
|
928
|
+
require('./seatbelt/hook').accountFloor(watch.harness, watch.event, (0, host_approval_1.preToolDeadline)((0, host_approval_1.approvalHostFor)(watch.harness)));
|
|
929
|
+
}
|
|
930
|
+
catch { /* watch never changes the answer */ }
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
async function runPreActionHook(input, watch) {
|
|
832
935
|
if (process.env.MARROW_AUTO_HOOK === 'false')
|
|
833
936
|
return;
|
|
834
937
|
const identity = (0, hook_contract_1.resolveNativeHookIdentity)(process.argv[2]);
|
|
835
938
|
let event = input;
|
|
939
|
+
let rawEvent = input;
|
|
836
940
|
let inputFailure = null;
|
|
837
941
|
if (event === undefined) {
|
|
838
942
|
try {
|
|
@@ -842,7 +946,8 @@ async function runPreActionHookCommand(input) {
|
|
|
842
946
|
}
|
|
843
947
|
else {
|
|
844
948
|
const raw = stdin.raw.trim();
|
|
845
|
-
|
|
949
|
+
rawEvent = raw ? JSON.parse(raw) : {};
|
|
950
|
+
event = (0, hook_contract_1.normalizeHookEventPayload)(rawEvent);
|
|
846
951
|
}
|
|
847
952
|
}
|
|
848
953
|
catch {
|
|
@@ -865,7 +970,7 @@ async function runPreActionHookCommand(input) {
|
|
|
865
970
|
emitDecision({ runtime: null, permit: null, protectedRisk: true, enforcementError: inputFailure || 'Marrow could not classify this mutation-capable tool request.' }, identity.harness);
|
|
866
971
|
return;
|
|
867
972
|
}
|
|
868
|
-
if ((0,
|
|
973
|
+
if ((0, own_server_identity_1.isOfficialMarrowMcpEventOnHost)(identity.harness, source, rawEvent)) {
|
|
869
974
|
if (identity.harness === 'windsurf') {
|
|
870
975
|
process.exitCode = 0;
|
|
871
976
|
return;
|
|
@@ -876,7 +981,7 @@ async function runPreActionHookCommand(input) {
|
|
|
876
981
|
: {}));
|
|
877
982
|
return;
|
|
878
983
|
}
|
|
879
|
-
const classified = classifyTool(source);
|
|
984
|
+
const classified = classifyTool(source, { ownUnproven: (0, hook_tool_policy_1.isOfficialMarrowMcpEvent)(source) });
|
|
880
985
|
let localControl;
|
|
881
986
|
try {
|
|
882
987
|
localControl = (0, control_state_1.readLocalControlState)();
|
|
@@ -962,6 +1067,55 @@ async function runPreActionHookCommand(input) {
|
|
|
962
1067
|
emitLoopGuardDenial(identity.harness, loopDecision.reason || `Marrow local loop guard blocked this unchanged repeat. Receipt: ${loopDecision.receipt}.`);
|
|
963
1068
|
return;
|
|
964
1069
|
}
|
|
1070
|
+
// No usable key: the seatbelt decides first (spec §1.1), before the read-only pass so S4 reads stop.
|
|
1071
|
+
// `seatbelt` answers here with no network call; `claimed_no_key` stops S0-S5 here and keeps the holds below.
|
|
1072
|
+
// Whether a keyless hold may say "linked to an account" (only with account evidence, never for a mode fallback).
|
|
1073
|
+
let keylessAccountLinked = false;
|
|
1074
|
+
// The keyless hold text when the seatbelt does not answer: master's no-key text in seatbelt mode (a
|
|
1075
|
+
// tool the mapper does not recognise, audit H1), the claimed_no_key texts otherwise.
|
|
1076
|
+
let keylessSeatbeltMode = false;
|
|
1077
|
+
if (!resolved.apiKey) {
|
|
1078
|
+
let keyless;
|
|
1079
|
+
try {
|
|
1080
|
+
keyless = require('./seatbelt/hook').keylessSeatbelt(identity.harness, seatbeltEvent(source, rawEvent));
|
|
1081
|
+
}
|
|
1082
|
+
catch {
|
|
1083
|
+
keyless = { mode: 'claimed_no_key', stopText: SEATBELT_FAILED_TEXT };
|
|
1084
|
+
}
|
|
1085
|
+
keylessAccountLinked = keyless.accountLinked === true;
|
|
1086
|
+
keylessSeatbeltMode = keyless.mode === 'seatbelt';
|
|
1087
|
+
if (keyless.stopText) {
|
|
1088
|
+
emitLoopGuardDenial(identity.harness, keyless.stopText);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
// A tool the mapper does not recognise never gets the seatbelt pass: master's answer below.
|
|
1092
|
+
if (keyless.mode === 'seatbelt' && keyless.recognized === true) {
|
|
1093
|
+
// Never an explicit allow for an action 3.9.103 held: the host's own approval step decides.
|
|
1094
|
+
const answer = seatbeltPassOutput(identity.harness, source.hook_event_name, !classified.readOnly && enforcementRequired);
|
|
1095
|
+
if (answer === null)
|
|
1096
|
+
process.exitCode = 0;
|
|
1097
|
+
else
|
|
1098
|
+
process.stdout.write(JSON.stringify(answer));
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
watch.harness = identity.harness;
|
|
1104
|
+
watch.event = seatbeltEvent(source, rawEvent);
|
|
1105
|
+
let floor = null;
|
|
1106
|
+
try {
|
|
1107
|
+
floor = require('./seatbelt/hook');
|
|
1108
|
+
}
|
|
1109
|
+
catch { /* watch only: a missing module never changes the account flow */ }
|
|
1110
|
+
if (floor && floor.SEATBELT_ROLLOUT.account_floor === 'on') {
|
|
1111
|
+
watch.harness = undefined;
|
|
1112
|
+
const stopText = floor.accountFloor(identity.harness, watch.event, (0, host_approval_1.preToolDeadline)((0, host_approval_1.approvalHostFor)(identity.harness)));
|
|
1113
|
+
if (stopText) {
|
|
1114
|
+
emitLoopGuardDenial(identity.harness, stopText);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
965
1119
|
if (classified.readOnly) {
|
|
966
1120
|
const allow = localControlAllowOutput(identity.harness);
|
|
967
1121
|
if (allow === null)
|
|
@@ -988,7 +1142,7 @@ async function runPreActionHookCommand(input) {
|
|
|
988
1142
|
runtime: null,
|
|
989
1143
|
permit: null,
|
|
990
1144
|
protectedRisk: enforcementRequired,
|
|
991
|
-
enforcementError: exports.NO_KEY_TEXT,
|
|
1145
|
+
enforcementError: keylessSeatbeltMode ? exports.NO_KEY_TEXT : keylessAccountLinked ? exports.CLAIMED_NO_KEY_TEXT : exports.SETUP_UNCONFIRMED_TEXT,
|
|
992
1146
|
}, identity.harness);
|
|
993
1147
|
return;
|
|
994
1148
|
}
|
|
@@ -1058,6 +1212,11 @@ async function runPreActionHookCommand(input) {
|
|
|
1058
1212
|
});
|
|
1059
1213
|
// The decision and gate receipt this control path holds, so a denial can close them.
|
|
1060
1214
|
const held = { decisionId: null, gateReceiptId: null };
|
|
1215
|
+
// Set once the runtime gate has answered. A later network or 5xx failure (decision, permit issue
|
|
1216
|
+
// or verify) on a high-risk action is a reached answer that no permit can be had: a denial, never
|
|
1217
|
+
// "offline, allowed". Routine actions keep the outage policy (failure_mode low_risk_behavior).
|
|
1218
|
+
const reach = { gateAnswered: false };
|
|
1219
|
+
const highRisk = classified.protected || classified.risk === 'high';
|
|
1061
1220
|
const control = async (signal) => {
|
|
1062
1221
|
const runtime = await (0, index_1.marrowAgentRuntime)(resolved.apiKey, baseUrl, {
|
|
1063
1222
|
action: classified.action,
|
|
@@ -1072,6 +1231,7 @@ async function runPreActionHookCommand(input) {
|
|
|
1072
1231
|
// non-durable fast_gate receipt can never back an action permit.
|
|
1073
1232
|
...(enforcementRequired ? { risk_level: classified.risk } : {}),
|
|
1074
1233
|
}, sessionId, agentId, signal);
|
|
1234
|
+
reach.gateAnswered = true;
|
|
1075
1235
|
const heldIds = [...new Set([runtime.decision_id, runtime.completion_contract?.decision_id, runtime.runtime_authorization?.decision_id]
|
|
1076
1236
|
.filter((value) => typeof value === 'string' && SAFE_DECISION_ID.test(value)))];
|
|
1077
1237
|
held.decisionId = heldIds.length === 1 ? heldIds[0] : null;
|
|
@@ -1173,7 +1333,7 @@ async function runPreActionHookCommand(input) {
|
|
|
1173
1333
|
timedOut: true,
|
|
1174
1334
|
enforcementError: hook_contract_1.MARROW_OUTAGE_WARNING,
|
|
1175
1335
|
}
|
|
1176
|
-
: isMarrowControlOutage(error)
|
|
1336
|
+
: isMarrowControlOutage(error) && !(reach.gateAnswered && highRisk)
|
|
1177
1337
|
? {
|
|
1178
1338
|
runtime: null,
|
|
1179
1339
|
permit: null,
|
|
@@ -1181,13 +1341,21 @@ async function runPreActionHookCommand(input) {
|
|
|
1181
1341
|
outage: true,
|
|
1182
1342
|
enforcementError: hook_contract_1.MARROW_OUTAGE_WARNING,
|
|
1183
1343
|
}
|
|
1184
|
-
:
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1344
|
+
: isMarrowControlOutage(error)
|
|
1345
|
+
? {
|
|
1346
|
+
runtime: null,
|
|
1347
|
+
permit: null,
|
|
1348
|
+
protectedRisk: enforcementRequired,
|
|
1349
|
+
enforcementError: controlRejectionMessage(error, agentId, 'unavailable'),
|
|
1350
|
+
failure: 'unavailable',
|
|
1351
|
+
}
|
|
1352
|
+
: {
|
|
1353
|
+
runtime: null,
|
|
1354
|
+
permit: null,
|
|
1355
|
+
protectedRisk: enforcementRequired,
|
|
1356
|
+
enforcementError: controlRejectionMessage(error, agentId),
|
|
1357
|
+
...(controlFailureKind(error) ? { failure: controlFailureKind(error) } : {}),
|
|
1358
|
+
})),
|
|
1191
1359
|
lifecycle,
|
|
1192
1360
|
]);
|
|
1193
1361
|
const claudePrompt = ownerApprovalPrompt(identity.harness, source);
|
|
@@ -1205,12 +1373,17 @@ async function runPreActionHookCommand(input) {
|
|
|
1205
1373
|
}
|
|
1206
1374
|
if (result.outage) {
|
|
1207
1375
|
// Marrow cannot be reached. An action in a category the account owner
|
|
1208
|
-
// protects stays held on every host;
|
|
1376
|
+
// protects stays held on every host; a high-risk action fails closed (high-risk
|
|
1377
|
+
// work needs a fresh gate); routine actions keep the outage policy.
|
|
1209
1378
|
const protectedNow = (0, host_approval_1.protectedAmong)(holdContext, localApprovalCategories(classified));
|
|
1210
1379
|
if (protectedNow.length) {
|
|
1211
1380
|
emitHeldPlan(identity.harness, { kind: 'deny', agentText: host_approval_1.HELD_UNREACHABLE_TEXT, userText: host_approval_1.HELD_UNREACHABLE_TEXT, code: false });
|
|
1212
1381
|
return;
|
|
1213
1382
|
}
|
|
1383
|
+
if (outageHolds(highRisk, () => require('./seatbelt/hook').outageRisk(seatbeltEvent(source, rawEvent), holdContext.deadlineAt ?? Number.POSITIVE_INFINITY))) {
|
|
1384
|
+
emitHeldPlan(identity.harness, { kind: 'deny', agentText: exports.HELD_OFFLINE_TEXT, userText: exports.HELD_OFFLINE_TEXT, code: false });
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1214
1387
|
}
|
|
1215
1388
|
const verdict = result.outage ? null : runtimeGateVerdict(result.runtime);
|
|
1216
1389
|
const guidance = verdict?.kind === 'review' ? (0, runtime_contract_1.ordinaryApprovalGuidance)(result.runtime) : null;
|