@guilz-dev/belay 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude/runtime-entry.js +5 -18
- package/dist/adapters/codex/runtime-entry.js +10 -11
- package/dist/adapters/cursor/hook-router.d.ts +1 -0
- package/dist/adapters/cursor/hook-router.js +26 -3
- package/dist/adapters/cursor/hook-routing-health.d.ts +1 -0
- package/dist/adapters/cursor/hook-routing-health.js +53 -0
- package/dist/adapters/shared/gate-runtime.d.ts +0 -2
- package/dist/adapters/shared/gate-runtime.js +2 -53
- package/dist/bundle/claude-runtime.mjs +446 -196
- package/dist/bundle/codex-runtime.mjs +449 -219
- package/dist/bundle/cursor-dispatcher.mjs +20 -3
- package/dist/bundle/cursor-runtime.mjs +441 -178
- package/dist/commands/doctor.js +4 -0
- package/dist/core/capability/index.d.ts +1 -1
- package/dist/core/capability/index.js +1 -1
- package/dist/core/capability/policy-engine.d.ts +19 -0
- package/dist/core/capability/policy-engine.js +31 -0
- package/dist/core/classify-tool.js +372 -148
- package/dist/core/config.js +2 -2
- package/dist/core/gate-engine.js +2 -9
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -2155,7 +2155,7 @@ function normalizeConfig(config) {
|
|
|
2155
2155
|
policy: {
|
|
2156
2156
|
unknownLocalEffect: v4.policy?.unknownLocalEffect === "deny" ? "deny" : v4.policy?.unknownLocalEffect === "allow_flagged" ? "allow_flagged" : DEFAULT_POLICY_V3.unknownLocalEffect,
|
|
2157
2157
|
unparseableShell: v4.policy?.unparseableShell === "deny" ? "deny" : v4.policy?.unparseableShell === "allow_flagged" ? "allow_flagged" : DEFAULT_POLICY_V3.unparseableShell,
|
|
2158
|
-
codexUnmappedTool:
|
|
2158
|
+
codexUnmappedTool: "allow",
|
|
2159
2159
|
fenceWarnThreshold: typeof v4.policy?.fenceWarnThreshold === "number" && v4.policy.fenceWarnThreshold > 0 && v4.policy.fenceWarnThreshold <= 1 ? v4.policy.fenceWarnThreshold : DEFAULT_FENCE_WARN_THRESHOLD,
|
|
2160
2160
|
confidenceThresholds: {
|
|
2161
2161
|
allow: typeof v4.policy?.confidenceThresholds?.allow === "number" ? v4.policy.confidenceThresholds.allow : DEFAULT_CONFIDENCE_THRESHOLDS.allow,
|
|
@@ -2457,7 +2457,7 @@ var init_config = __esm({
|
|
|
2457
2457
|
DEFAULT_POLICY_V3 = {
|
|
2458
2458
|
unknownLocalEffect: "allow_flagged",
|
|
2459
2459
|
unparseableShell: "deny",
|
|
2460
|
-
codexUnmappedTool: "
|
|
2460
|
+
codexUnmappedTool: "allow",
|
|
2461
2461
|
confidenceThresholds: { ...DEFAULT_CONFIDENCE_THRESHOLDS },
|
|
2462
2462
|
modelAssist: { ...DEFAULT_MODEL_ASSIST },
|
|
2463
2463
|
transactional: { ...DEFAULT_TRANSACTIONAL_V3 },
|
|
@@ -10866,6 +10866,40 @@ function evaluateFileMutationPolicy(analysis, config, auth) {
|
|
|
10866
10866
|
);
|
|
10867
10867
|
return { request, decision };
|
|
10868
10868
|
}
|
|
10869
|
+
function buildFileReadCapabilityRequest(analysis) {
|
|
10870
|
+
return {
|
|
10871
|
+
version: CAPABILITY_REQUEST_VERSION,
|
|
10872
|
+
principal: {
|
|
10873
|
+
adapter: analysis.adapter,
|
|
10874
|
+
repoRoot: analysis.repoRoot,
|
|
10875
|
+
sessionHash: hashSession(`${analysis.repoRoot}:${analysis.cwd}`)
|
|
10876
|
+
},
|
|
10877
|
+
action: "fs.read",
|
|
10878
|
+
resource: { kind: "path", path: analysis.resolvedPath },
|
|
10879
|
+
context: {
|
|
10880
|
+
cwd: analysis.cwd,
|
|
10881
|
+
inputFingerprint: analysis.inputFingerprint,
|
|
10882
|
+
hookKind: analysis.hookKind,
|
|
10883
|
+
analysisBasis: [`tool:${analysis.toolKind}`, `location:${analysis.locationLabel}`, "read"]
|
|
10884
|
+
},
|
|
10885
|
+
evidence: {
|
|
10886
|
+
level: analysis.locationLabel === "repo_local" ? "certain" : "possible",
|
|
10887
|
+
signals: [...analysis.signals, "effect.fs_read"]
|
|
10888
|
+
}
|
|
10889
|
+
};
|
|
10890
|
+
}
|
|
10891
|
+
function evaluateFileReadPolicy(analysis, config, auth) {
|
|
10892
|
+
const request = buildFileReadCapabilityRequest(analysis);
|
|
10893
|
+
const enriched = enrichAuthWithMaterializedGrants(request, config, {
|
|
10894
|
+
...auth,
|
|
10895
|
+
sensitivePaths: auth?.sensitivePaths ?? analysis.sensitivePaths
|
|
10896
|
+
});
|
|
10897
|
+
const decision = getDefaultPolicyEngine().evaluate(
|
|
10898
|
+
request,
|
|
10899
|
+
buildAuthorizationContext(config, analysis.trustedWorkspaceRoots, enriched)
|
|
10900
|
+
);
|
|
10901
|
+
return { request, decision };
|
|
10902
|
+
}
|
|
10869
10903
|
|
|
10870
10904
|
// src/core/capability/reasons.ts
|
|
10871
10905
|
var FS_SCOPE_REASONS = /* @__PURE__ */ new Set(["outside_repo_mutation", "outside_repo_redirect"]);
|
|
@@ -17087,17 +17121,41 @@ function verdictToClassifyResult(result, config, options = {}) {
|
|
|
17087
17121
|
|
|
17088
17122
|
// src/core/classify-tool.ts
|
|
17089
17123
|
var DEFAULT_SENSITIVE_PATHS = [".env", ".env.*", "**/credentials/**"];
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
"
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17124
|
+
function toolInputRecord(payload) {
|
|
17125
|
+
const toolInput = payload.tool_input;
|
|
17126
|
+
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) {
|
|
17127
|
+
return null;
|
|
17128
|
+
}
|
|
17129
|
+
return toolInput;
|
|
17130
|
+
}
|
|
17131
|
+
function hasMutationFields(input) {
|
|
17132
|
+
return typeof input.contents === "string" || typeof input.old_string === "string" || typeof input.new_string === "string" || typeof input.newContents === "string";
|
|
17133
|
+
}
|
|
17134
|
+
function inferToolPayloadEffect(payload, toolName) {
|
|
17135
|
+
if (extractShellCommand(payload)) {
|
|
17136
|
+
return "shell";
|
|
17137
|
+
}
|
|
17138
|
+
const input = toolInputRecord(payload);
|
|
17139
|
+
if (!input) {
|
|
17140
|
+
return "indeterminate";
|
|
17141
|
+
}
|
|
17142
|
+
if (hasMutationFields(input)) {
|
|
17143
|
+
return "file_mutation";
|
|
17144
|
+
}
|
|
17145
|
+
if (extractPatch(payload)) {
|
|
17146
|
+
return "apply_patch";
|
|
17147
|
+
}
|
|
17148
|
+
if (typeof input.pattern === "string" || typeof input.glob_pattern === "string") {
|
|
17149
|
+
return "search_read";
|
|
17150
|
+
}
|
|
17151
|
+
if (typeof input.file_path === "string") {
|
|
17152
|
+
return "file_read";
|
|
17153
|
+
}
|
|
17154
|
+
if (typeof input.path === "string" || typeof input.target_file === "string") {
|
|
17155
|
+
return normalizedToolName(toolName) === "delete" ? "file_delete" : "indeterminate";
|
|
17156
|
+
}
|
|
17157
|
+
return "indeterminate";
|
|
17158
|
+
}
|
|
17101
17159
|
function policyAuth(options) {
|
|
17102
17160
|
if (!options.grants && options.attestation === void 0 && options.egressProxyActive === void 0) {
|
|
17103
17161
|
return void 0;
|
|
@@ -17277,6 +17335,314 @@ function classifyFileMutationWithPolicy(params) {
|
|
|
17277
17335
|
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY
|
|
17278
17336
|
};
|
|
17279
17337
|
}
|
|
17338
|
+
function classifyFileReadWithPolicy(params) {
|
|
17339
|
+
const fingerprint = toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot);
|
|
17340
|
+
const { request, decision } = evaluateFileReadPolicy(
|
|
17341
|
+
{
|
|
17342
|
+
hookKind: "tool",
|
|
17343
|
+
toolKind: params.toolKind,
|
|
17344
|
+
filePath: params.filePath,
|
|
17345
|
+
resolvedPath: params.resolvedPath,
|
|
17346
|
+
repoRoot: params.repoRoot,
|
|
17347
|
+
cwd: params.cwd,
|
|
17348
|
+
inputFingerprint: fingerprint,
|
|
17349
|
+
signals: params.signals,
|
|
17350
|
+
locationLabel: params.locationLabel,
|
|
17351
|
+
trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
|
|
17352
|
+
sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths
|
|
17353
|
+
},
|
|
17354
|
+
params.config,
|
|
17355
|
+
policyAuth(params.options)
|
|
17356
|
+
);
|
|
17357
|
+
if (policyDecisionRequiresAsk(decision)) {
|
|
17358
|
+
return {
|
|
17359
|
+
verdict: "deny_pending_approval",
|
|
17360
|
+
reason: policyReasonToLegacyReason(decision),
|
|
17361
|
+
summary: params.filePath,
|
|
17362
|
+
fingerprint,
|
|
17363
|
+
assessment: {
|
|
17364
|
+
reversibility: "reversible",
|
|
17365
|
+
external: params.locationLabel === "outside_repo",
|
|
17366
|
+
blastRadius: params.locationLabel === "outside_repo" ? "outside the repository" : "sensitive repository file",
|
|
17367
|
+
confidence: 0.85,
|
|
17368
|
+
signals: [...params.signals, ...decision.signals]
|
|
17369
|
+
},
|
|
17370
|
+
capabilityRequests: [request],
|
|
17371
|
+
authorizationDecision: decision,
|
|
17372
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY
|
|
17373
|
+
};
|
|
17374
|
+
}
|
|
17375
|
+
return {
|
|
17376
|
+
verdict: "allow",
|
|
17377
|
+
reason: "effect.fs_read",
|
|
17378
|
+
summary: params.filePath,
|
|
17379
|
+
fingerprint,
|
|
17380
|
+
assessment: {
|
|
17381
|
+
reversibility: "reversible",
|
|
17382
|
+
external: false,
|
|
17383
|
+
blastRadius: "tool scope",
|
|
17384
|
+
confidence: 0.88,
|
|
17385
|
+
signals: [...params.signals, ...decision.signals]
|
|
17386
|
+
},
|
|
17387
|
+
capabilityRequests: [request],
|
|
17388
|
+
authorizationDecision: decision,
|
|
17389
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY
|
|
17390
|
+
};
|
|
17391
|
+
}
|
|
17392
|
+
function classifyFilePathMutation(params) {
|
|
17393
|
+
const {
|
|
17394
|
+
toolName,
|
|
17395
|
+
toolKind,
|
|
17396
|
+
filePath,
|
|
17397
|
+
repoRoot,
|
|
17398
|
+
cwd,
|
|
17399
|
+
config,
|
|
17400
|
+
options,
|
|
17401
|
+
sensitivePaths,
|
|
17402
|
+
protectedRoots,
|
|
17403
|
+
isDelete
|
|
17404
|
+
} = params;
|
|
17405
|
+
const signals = [];
|
|
17406
|
+
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17407
|
+
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17408
|
+
if (hitsProtectedRoot) {
|
|
17409
|
+
signals.push("control_plane_path");
|
|
17410
|
+
return classifyFileMutationWithPolicy({
|
|
17411
|
+
toolName,
|
|
17412
|
+
toolKind,
|
|
17413
|
+
filePath,
|
|
17414
|
+
resolvedPath,
|
|
17415
|
+
repoRoot,
|
|
17416
|
+
cwd,
|
|
17417
|
+
config,
|
|
17418
|
+
options,
|
|
17419
|
+
signals,
|
|
17420
|
+
isDelete,
|
|
17421
|
+
locationLabel: "control_plane"
|
|
17422
|
+
});
|
|
17423
|
+
}
|
|
17424
|
+
const workspaceMatch = resolveWorkspaceRootMatch(
|
|
17425
|
+
repoRoot,
|
|
17426
|
+
options.trustedWorkspaceRoots,
|
|
17427
|
+
resolvedPath
|
|
17428
|
+
);
|
|
17429
|
+
if (workspaceMatch === null) {
|
|
17430
|
+
signals.push("outside_repo_path");
|
|
17431
|
+
return classifyFileMutationWithPolicy({
|
|
17432
|
+
toolName,
|
|
17433
|
+
toolKind,
|
|
17434
|
+
filePath,
|
|
17435
|
+
resolvedPath,
|
|
17436
|
+
repoRoot,
|
|
17437
|
+
cwd,
|
|
17438
|
+
config,
|
|
17439
|
+
options,
|
|
17440
|
+
signals,
|
|
17441
|
+
isDelete,
|
|
17442
|
+
locationLabel: "outside_repo"
|
|
17443
|
+
});
|
|
17444
|
+
}
|
|
17445
|
+
if (workspaceMatch.kind === "trusted") {
|
|
17446
|
+
signals.push("trusted_workspace_root");
|
|
17447
|
+
}
|
|
17448
|
+
const trustedCwd = resolveClassifierTrustedCwd(cwd, options);
|
|
17449
|
+
const workspacePrescan = mutationPrescanRequiresAsk({
|
|
17450
|
+
targets: [filePath],
|
|
17451
|
+
cwd,
|
|
17452
|
+
repoRoot,
|
|
17453
|
+
trustedCwd,
|
|
17454
|
+
trustedWorkspaceRoots: options.trustedWorkspaceRoots,
|
|
17455
|
+
sensitivePaths
|
|
17456
|
+
});
|
|
17457
|
+
if (workspacePrescan) {
|
|
17458
|
+
return classifyFileMutationWithPolicy({
|
|
17459
|
+
toolName,
|
|
17460
|
+
toolKind,
|
|
17461
|
+
filePath,
|
|
17462
|
+
resolvedPath,
|
|
17463
|
+
repoRoot,
|
|
17464
|
+
cwd,
|
|
17465
|
+
config,
|
|
17466
|
+
options,
|
|
17467
|
+
signals,
|
|
17468
|
+
isDelete,
|
|
17469
|
+
locationLabel: "sensitive_path"
|
|
17470
|
+
});
|
|
17471
|
+
}
|
|
17472
|
+
const relativePath = workspaceMatch.relativePath;
|
|
17473
|
+
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
17474
|
+
signals.push("sensitive_path");
|
|
17475
|
+
return classifyFileMutationWithPolicy({
|
|
17476
|
+
toolName,
|
|
17477
|
+
toolKind,
|
|
17478
|
+
filePath,
|
|
17479
|
+
resolvedPath,
|
|
17480
|
+
repoRoot,
|
|
17481
|
+
cwd,
|
|
17482
|
+
config,
|
|
17483
|
+
options,
|
|
17484
|
+
signals,
|
|
17485
|
+
isDelete,
|
|
17486
|
+
locationLabel: "sensitive_path"
|
|
17487
|
+
});
|
|
17488
|
+
}
|
|
17489
|
+
if (isDelete) {
|
|
17490
|
+
if (isGitPath(resolvedPath, repoRoot)) {
|
|
17491
|
+
signals.push("protected_artifact");
|
|
17492
|
+
return classifyFileMutationWithPolicy({
|
|
17493
|
+
toolName,
|
|
17494
|
+
toolKind,
|
|
17495
|
+
filePath,
|
|
17496
|
+
resolvedPath,
|
|
17497
|
+
repoRoot,
|
|
17498
|
+
cwd,
|
|
17499
|
+
config,
|
|
17500
|
+
options,
|
|
17501
|
+
signals,
|
|
17502
|
+
isDelete: true,
|
|
17503
|
+
locationLabel: "sensitive_path"
|
|
17504
|
+
});
|
|
17505
|
+
}
|
|
17506
|
+
signals.push("file_delete");
|
|
17507
|
+
return classifyFileMutationWithPolicy({
|
|
17508
|
+
toolName,
|
|
17509
|
+
toolKind,
|
|
17510
|
+
filePath,
|
|
17511
|
+
resolvedPath,
|
|
17512
|
+
repoRoot,
|
|
17513
|
+
cwd,
|
|
17514
|
+
config,
|
|
17515
|
+
options,
|
|
17516
|
+
signals,
|
|
17517
|
+
isDelete: true,
|
|
17518
|
+
locationLabel: "repo_local"
|
|
17519
|
+
});
|
|
17520
|
+
}
|
|
17521
|
+
signals.push("file_mutation");
|
|
17522
|
+
return classifyFileMutationWithPolicy({
|
|
17523
|
+
toolName,
|
|
17524
|
+
toolKind,
|
|
17525
|
+
filePath,
|
|
17526
|
+
resolvedPath,
|
|
17527
|
+
repoRoot,
|
|
17528
|
+
cwd,
|
|
17529
|
+
config,
|
|
17530
|
+
options,
|
|
17531
|
+
signals,
|
|
17532
|
+
isDelete: false,
|
|
17533
|
+
locationLabel: "repo_local"
|
|
17534
|
+
});
|
|
17535
|
+
}
|
|
17536
|
+
function classifyFilePathRead(params) {
|
|
17537
|
+
const {
|
|
17538
|
+
toolName,
|
|
17539
|
+
toolKind,
|
|
17540
|
+
filePath,
|
|
17541
|
+
repoRoot,
|
|
17542
|
+
cwd,
|
|
17543
|
+
config,
|
|
17544
|
+
options,
|
|
17545
|
+
sensitivePaths,
|
|
17546
|
+
protectedRoots
|
|
17547
|
+
} = params;
|
|
17548
|
+
const signals = ["effect.fs_read"];
|
|
17549
|
+
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17550
|
+
if (protectedRoots.some((root) => pathWithinRoot(root, resolvedPath))) {
|
|
17551
|
+
signals.push("control_plane_path");
|
|
17552
|
+
return classifyFileReadWithPolicy({
|
|
17553
|
+
toolName,
|
|
17554
|
+
toolKind,
|
|
17555
|
+
filePath,
|
|
17556
|
+
resolvedPath,
|
|
17557
|
+
repoRoot,
|
|
17558
|
+
cwd,
|
|
17559
|
+
config,
|
|
17560
|
+
options,
|
|
17561
|
+
signals,
|
|
17562
|
+
locationLabel: "control_plane"
|
|
17563
|
+
});
|
|
17564
|
+
}
|
|
17565
|
+
const workspaceMatch = resolveWorkspaceRootMatch(
|
|
17566
|
+
repoRoot,
|
|
17567
|
+
options.trustedWorkspaceRoots,
|
|
17568
|
+
resolvedPath
|
|
17569
|
+
);
|
|
17570
|
+
if (workspaceMatch === null) {
|
|
17571
|
+
signals.push("outside_repo_path");
|
|
17572
|
+
return classifyFileReadWithPolicy({
|
|
17573
|
+
toolName,
|
|
17574
|
+
toolKind,
|
|
17575
|
+
filePath,
|
|
17576
|
+
resolvedPath,
|
|
17577
|
+
repoRoot,
|
|
17578
|
+
cwd,
|
|
17579
|
+
config,
|
|
17580
|
+
options,
|
|
17581
|
+
signals,
|
|
17582
|
+
locationLabel: "outside_repo"
|
|
17583
|
+
});
|
|
17584
|
+
}
|
|
17585
|
+
const relativePath = workspaceMatch.relativePath;
|
|
17586
|
+
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
17587
|
+
signals.push("sensitive_path");
|
|
17588
|
+
return classifyFileReadWithPolicy({
|
|
17589
|
+
toolName,
|
|
17590
|
+
toolKind,
|
|
17591
|
+
filePath,
|
|
17592
|
+
resolvedPath,
|
|
17593
|
+
repoRoot,
|
|
17594
|
+
cwd,
|
|
17595
|
+
config,
|
|
17596
|
+
options,
|
|
17597
|
+
signals,
|
|
17598
|
+
locationLabel: "sensitive_path"
|
|
17599
|
+
});
|
|
17600
|
+
}
|
|
17601
|
+
return classifyFileReadWithPolicy({
|
|
17602
|
+
toolName,
|
|
17603
|
+
toolKind,
|
|
17604
|
+
filePath,
|
|
17605
|
+
resolvedPath,
|
|
17606
|
+
repoRoot,
|
|
17607
|
+
cwd,
|
|
17608
|
+
config,
|
|
17609
|
+
options,
|
|
17610
|
+
signals,
|
|
17611
|
+
locationLabel: "repo_local"
|
|
17612
|
+
});
|
|
17613
|
+
}
|
|
17614
|
+
function indeterminateToolResult(toolName, payload, repoRoot, options) {
|
|
17615
|
+
const summary = canonicalStringify(scrubPayload(payload.tool_input ?? {}, options));
|
|
17616
|
+
const fingerprint = toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot);
|
|
17617
|
+
if (options.unknownLocalEffect === "deny") {
|
|
17618
|
+
return {
|
|
17619
|
+
verdict: "deny_pending_approval",
|
|
17620
|
+
reason: "indeterminate_tool_effect",
|
|
17621
|
+
summary,
|
|
17622
|
+
fingerprint,
|
|
17623
|
+
assessment: {
|
|
17624
|
+
reversibility: "irreversible",
|
|
17625
|
+
external: false,
|
|
17626
|
+
blastRadius: "unknown tool action",
|
|
17627
|
+
confidence: 0.5,
|
|
17628
|
+
signals: ["indeterminate_tool_effect"]
|
|
17629
|
+
}
|
|
17630
|
+
};
|
|
17631
|
+
}
|
|
17632
|
+
return {
|
|
17633
|
+
verdict: "allow_flagged",
|
|
17634
|
+
reason: "indeterminate_tool_effect",
|
|
17635
|
+
summary,
|
|
17636
|
+
fingerprint,
|
|
17637
|
+
assessment: {
|
|
17638
|
+
reversibility: "recoverable_with_cost",
|
|
17639
|
+
external: false,
|
|
17640
|
+
blastRadius: "tool scope",
|
|
17641
|
+
confidence: 0.5,
|
|
17642
|
+
signals: ["indeterminate_tool_effect"]
|
|
17643
|
+
}
|
|
17644
|
+
};
|
|
17645
|
+
}
|
|
17280
17646
|
async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
17281
17647
|
const toolName = String(payload.tool_name ?? "");
|
|
17282
17648
|
const toolKind = normalizedToolName(toolName);
|
|
@@ -17323,9 +17689,10 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17323
17689
|
summary: command
|
|
17324
17690
|
};
|
|
17325
17691
|
}
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
17692
|
+
const effect = inferToolPayloadEffect(payload, toolName);
|
|
17693
|
+
if (effect === "file_mutation" || effect === "file_delete") {
|
|
17694
|
+
const filePath2 = extractFilePath(payload);
|
|
17695
|
+
if (!filePath2) {
|
|
17329
17696
|
if (options.unknownLocalEffect === "deny") {
|
|
17330
17697
|
return {
|
|
17331
17698
|
verdict: "deny_pending_approval",
|
|
@@ -17355,138 +17722,20 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17355
17722
|
}
|
|
17356
17723
|
};
|
|
17357
17724
|
}
|
|
17358
|
-
|
|
17359
|
-
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17360
|
-
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17361
|
-
if (hitsProtectedRoot) {
|
|
17362
|
-
signals.push("control_plane_path");
|
|
17363
|
-
return classifyFileMutationWithPolicy({
|
|
17364
|
-
toolName,
|
|
17365
|
-
toolKind,
|
|
17366
|
-
filePath,
|
|
17367
|
-
resolvedPath,
|
|
17368
|
-
repoRoot,
|
|
17369
|
-
cwd,
|
|
17370
|
-
config,
|
|
17371
|
-
options,
|
|
17372
|
-
signals,
|
|
17373
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17374
|
-
locationLabel: "control_plane"
|
|
17375
|
-
});
|
|
17376
|
-
}
|
|
17377
|
-
const workspaceMatch = resolveWorkspaceRootMatch(
|
|
17378
|
-
repoRoot,
|
|
17379
|
-
options.trustedWorkspaceRoots,
|
|
17380
|
-
resolvedPath
|
|
17381
|
-
);
|
|
17382
|
-
if (workspaceMatch === null) {
|
|
17383
|
-
signals.push("outside_repo_path");
|
|
17384
|
-
return classifyFileMutationWithPolicy({
|
|
17385
|
-
toolName,
|
|
17386
|
-
toolKind,
|
|
17387
|
-
filePath,
|
|
17388
|
-
resolvedPath,
|
|
17389
|
-
repoRoot,
|
|
17390
|
-
cwd,
|
|
17391
|
-
config,
|
|
17392
|
-
options,
|
|
17393
|
-
signals,
|
|
17394
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17395
|
-
locationLabel: "outside_repo"
|
|
17396
|
-
});
|
|
17397
|
-
}
|
|
17398
|
-
if (workspaceMatch.kind === "trusted") {
|
|
17399
|
-
signals.push("trusted_workspace_root");
|
|
17400
|
-
}
|
|
17401
|
-
const trustedCwd = resolveClassifierTrustedCwd(cwd, options);
|
|
17402
|
-
const workspacePrescan = mutationPrescanRequiresAsk({
|
|
17403
|
-
targets: [filePath],
|
|
17404
|
-
cwd,
|
|
17405
|
-
repoRoot,
|
|
17406
|
-
trustedCwd,
|
|
17407
|
-
trustedWorkspaceRoots: options.trustedWorkspaceRoots,
|
|
17408
|
-
sensitivePaths
|
|
17409
|
-
});
|
|
17410
|
-
if (workspacePrescan) {
|
|
17411
|
-
return classifyFileMutationWithPolicy({
|
|
17412
|
-
toolName,
|
|
17413
|
-
toolKind,
|
|
17414
|
-
filePath,
|
|
17415
|
-
resolvedPath,
|
|
17416
|
-
repoRoot,
|
|
17417
|
-
cwd,
|
|
17418
|
-
config,
|
|
17419
|
-
options,
|
|
17420
|
-
signals,
|
|
17421
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17422
|
-
locationLabel: "sensitive_path"
|
|
17423
|
-
});
|
|
17424
|
-
}
|
|
17425
|
-
const relativePath = workspaceMatch.relativePath;
|
|
17426
|
-
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
17427
|
-
signals.push("sensitive_path");
|
|
17428
|
-
return classifyFileMutationWithPolicy({
|
|
17429
|
-
toolName,
|
|
17430
|
-
toolKind,
|
|
17431
|
-
filePath,
|
|
17432
|
-
resolvedPath,
|
|
17433
|
-
repoRoot,
|
|
17434
|
-
cwd,
|
|
17435
|
-
config,
|
|
17436
|
-
options,
|
|
17437
|
-
signals,
|
|
17438
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17439
|
-
locationLabel: "sensitive_path"
|
|
17440
|
-
});
|
|
17441
|
-
}
|
|
17442
|
-
if (FILE_DELETE_TOOL_NAMES.has(toolKind)) {
|
|
17443
|
-
if (isGitPath(resolvedPath, repoRoot)) {
|
|
17444
|
-
signals.push("protected_artifact");
|
|
17445
|
-
return classifyFileMutationWithPolicy({
|
|
17446
|
-
toolName,
|
|
17447
|
-
toolKind,
|
|
17448
|
-
filePath,
|
|
17449
|
-
resolvedPath,
|
|
17450
|
-
repoRoot,
|
|
17451
|
-
cwd,
|
|
17452
|
-
config,
|
|
17453
|
-
options,
|
|
17454
|
-
signals,
|
|
17455
|
-
isDelete: true,
|
|
17456
|
-
locationLabel: "sensitive_path"
|
|
17457
|
-
});
|
|
17458
|
-
}
|
|
17459
|
-
signals.push("file_delete");
|
|
17460
|
-
return classifyFileMutationWithPolicy({
|
|
17461
|
-
toolName,
|
|
17462
|
-
toolKind,
|
|
17463
|
-
filePath,
|
|
17464
|
-
resolvedPath,
|
|
17465
|
-
repoRoot,
|
|
17466
|
-
cwd,
|
|
17467
|
-
config,
|
|
17468
|
-
options,
|
|
17469
|
-
signals,
|
|
17470
|
-
isDelete: true,
|
|
17471
|
-
locationLabel: "repo_local"
|
|
17472
|
-
});
|
|
17473
|
-
}
|
|
17474
|
-
signals.push("file_mutation");
|
|
17475
|
-
return classifyFileMutationWithPolicy({
|
|
17725
|
+
return classifyFilePathMutation({
|
|
17476
17726
|
toolName,
|
|
17477
17727
|
toolKind,
|
|
17478
|
-
filePath,
|
|
17479
|
-
resolvedPath,
|
|
17728
|
+
filePath: filePath2,
|
|
17480
17729
|
repoRoot,
|
|
17481
17730
|
cwd,
|
|
17482
17731
|
config,
|
|
17483
17732
|
options,
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
|
|
17733
|
+
sensitivePaths,
|
|
17734
|
+
protectedRoots,
|
|
17735
|
+
isDelete: effect === "file_delete"
|
|
17487
17736
|
});
|
|
17488
17737
|
}
|
|
17489
|
-
if (
|
|
17738
|
+
if (effect === "apply_patch") {
|
|
17490
17739
|
const patch = extractPatch(payload);
|
|
17491
17740
|
const targets = patch ? applyPatchTargets2(patch) : [];
|
|
17492
17741
|
if (targets.length === 0) {
|
|
@@ -17524,7 +17773,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17524
17773
|
const result = await classifyToolUse(
|
|
17525
17774
|
{
|
|
17526
17775
|
tool_name: target.delete ? "Delete" : "Write",
|
|
17527
|
-
tool_input: { path: target.path }
|
|
17776
|
+
tool_input: target.delete ? { path: target.path } : { path: target.path, contents: " " }
|
|
17528
17777
|
},
|
|
17529
17778
|
repoRoot,
|
|
17530
17779
|
cwd,
|
|
@@ -17550,19 +17799,54 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17550
17799
|
}
|
|
17551
17800
|
};
|
|
17552
17801
|
}
|
|
17553
|
-
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17558
|
-
assessment: {
|
|
17559
|
-
reversibility: "reversible",
|
|
17560
|
-
external: false,
|
|
17561
|
-
blastRadius: "tool scope",
|
|
17562
|
-
confidence: 0.5,
|
|
17563
|
-
signals: ["unclassified_tool"]
|
|
17802
|
+
if (effect === "file_read") {
|
|
17803
|
+
const filePath2 = extractFilePath(payload);
|
|
17804
|
+
if (!filePath2) {
|
|
17805
|
+
return indeterminateToolResult(toolName, payload, repoRoot, options);
|
|
17564
17806
|
}
|
|
17565
|
-
|
|
17807
|
+
return classifyFilePathRead({
|
|
17808
|
+
toolName,
|
|
17809
|
+
toolKind,
|
|
17810
|
+
filePath: filePath2,
|
|
17811
|
+
repoRoot,
|
|
17812
|
+
cwd,
|
|
17813
|
+
config,
|
|
17814
|
+
options,
|
|
17815
|
+
sensitivePaths,
|
|
17816
|
+
protectedRoots
|
|
17817
|
+
});
|
|
17818
|
+
}
|
|
17819
|
+
if (effect === "search_read") {
|
|
17820
|
+
return {
|
|
17821
|
+
verdict: "allow",
|
|
17822
|
+
reason: "effect.search_read",
|
|
17823
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17824
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17825
|
+
assessment: {
|
|
17826
|
+
reversibility: "reversible",
|
|
17827
|
+
external: false,
|
|
17828
|
+
blastRadius: "tool scope",
|
|
17829
|
+
confidence: 0.88,
|
|
17830
|
+
signals: ["effect.search_read"]
|
|
17831
|
+
}
|
|
17832
|
+
};
|
|
17833
|
+
}
|
|
17834
|
+
const filePath = extractFilePath(payload);
|
|
17835
|
+
if (filePath) {
|
|
17836
|
+
return classifyFilePathMutation({
|
|
17837
|
+
toolName,
|
|
17838
|
+
toolKind,
|
|
17839
|
+
filePath,
|
|
17840
|
+
repoRoot,
|
|
17841
|
+
cwd,
|
|
17842
|
+
config,
|
|
17843
|
+
options,
|
|
17844
|
+
sensitivePaths,
|
|
17845
|
+
protectedRoots,
|
|
17846
|
+
isDelete: toolKind === "delete"
|
|
17847
|
+
});
|
|
17848
|
+
}
|
|
17849
|
+
return indeterminateToolResult(toolName, payload, repoRoot, options);
|
|
17566
17850
|
}
|
|
17567
17851
|
|
|
17568
17852
|
// src/core/gate-engine.ts
|
|
@@ -17897,15 +18181,8 @@ function gateEnabledForAction(config, action) {
|
|
|
17897
18181
|
if (action.kind === "subagent") {
|
|
17898
18182
|
return config.gates.subagent;
|
|
17899
18183
|
}
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
return config.gates.toolShell;
|
|
17903
|
-
}
|
|
17904
|
-
if (toolName === "Write" || toolName === "StrReplace" || toolName === "Delete") {
|
|
17905
|
-
return config.gates.fileMutation;
|
|
17906
|
-
}
|
|
17907
|
-
if (toolName === "Task") {
|
|
17908
|
-
return config.gates.subagent;
|
|
18184
|
+
if (action.kind === "tool") {
|
|
18185
|
+
return config.gates.fileMutation || config.gates.toolShell;
|
|
17909
18186
|
}
|
|
17910
18187
|
return true;
|
|
17911
18188
|
}
|
|
@@ -17942,7 +18219,7 @@ function hashDecisionConfig(config) {
|
|
|
17942
18219
|
init_fingerprint2();
|
|
17943
18220
|
|
|
17944
18221
|
// src/version.ts
|
|
17945
|
-
var PACKAGE_VERSION = "0.10.
|
|
18222
|
+
var PACKAGE_VERSION = "0.10.1";
|
|
17946
18223
|
|
|
17947
18224
|
// src/runtime-provenance.ts
|
|
17948
18225
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -21243,21 +21520,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
21243
21520
|
...authorization,
|
|
21244
21521
|
egressProxyActive
|
|
21245
21522
|
};
|
|
21246
|
-
|
|
21247
|
-
if (action.kind === "tool" && predicted.reason === "unclassified_tool" && (ctx.config.policy.codexUnmappedTool ?? "deny") === "deny") {
|
|
21248
|
-
predicted = {
|
|
21249
|
-
...predicted,
|
|
21250
|
-
verdict: "deny_pending_approval",
|
|
21251
|
-
reason: "unmapped_tool",
|
|
21252
|
-
assessment: {
|
|
21253
|
-
reversibility: "irreversible",
|
|
21254
|
-
external: false,
|
|
21255
|
-
blastRadius: "unknown tool action",
|
|
21256
|
-
confidence: 0.5,
|
|
21257
|
-
signals: ["unmapped_tool"]
|
|
21258
|
-
}
|
|
21259
|
-
};
|
|
21260
|
-
}
|
|
21523
|
+
const predicted = await classifyGatedActionAsync(action, ctx.config, enrichedClassifierOptions);
|
|
21261
21524
|
if (action.kind === "shell" && action.command && isContainedUnknownExecutionEligible(ctx.config, action, predicted)) {
|
|
21262
21525
|
const mediated = await mediateContainedUnknownExecution({
|
|
21263
21526
|
ctx,
|
|
@@ -22121,25 +22384,12 @@ async function runToolGateHook(_eventName) {
|
|
|
22121
22384
|
return;
|
|
22122
22385
|
}
|
|
22123
22386
|
if (!mappedKind) {
|
|
22124
|
-
const verdict3 =
|
|
22125
|
-
toolName,
|
|
22126
|
-
payload,
|
|
22127
|
-
repoRoot: ctx.repoRoot,
|
|
22128
|
-
reason: "unmapped_tool",
|
|
22129
|
-
mode: ctx.config.mode,
|
|
22130
|
-
userMessage: "belay does not recognize this tool action. Run belay doctor, then retry.",
|
|
22131
|
-
agentMessage: "Belay denied this action because the tool could not be normalized."
|
|
22132
|
-
});
|
|
22133
|
-
await deps.appendAudit(ctx, {
|
|
22134
|
-
event: "preToolUse",
|
|
22387
|
+
const verdict3 = await evaluateGatedAction(ctx, deps, {
|
|
22135
22388
|
kind: "tool",
|
|
22136
|
-
|
|
22137
|
-
|
|
22138
|
-
|
|
22139
|
-
|
|
22140
|
-
permission: "deny",
|
|
22141
|
-
summary: toolName,
|
|
22142
|
-
...effectPlanAuditFields(verdict3.effectPlan)
|
|
22389
|
+
cwd,
|
|
22390
|
+
payload,
|
|
22391
|
+
toolName,
|
|
22392
|
+
sourceEvent: "PreToolUse"
|
|
22143
22393
|
});
|
|
22144
22394
|
jsonResponse(gateVerdictToClaudePreToolUseResponse(verdict3));
|
|
22145
22395
|
return;
|