@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
|
@@ -1504,7 +1504,7 @@ function normalizeConfig(config) {
|
|
|
1504
1504
|
policy: {
|
|
1505
1505
|
unknownLocalEffect: v4.policy?.unknownLocalEffect === "deny" ? "deny" : v4.policy?.unknownLocalEffect === "allow_flagged" ? "allow_flagged" : DEFAULT_POLICY_V3.unknownLocalEffect,
|
|
1506
1506
|
unparseableShell: v4.policy?.unparseableShell === "deny" ? "deny" : v4.policy?.unparseableShell === "allow_flagged" ? "allow_flagged" : DEFAULT_POLICY_V3.unparseableShell,
|
|
1507
|
-
codexUnmappedTool:
|
|
1507
|
+
codexUnmappedTool: "allow",
|
|
1508
1508
|
fenceWarnThreshold: typeof v4.policy?.fenceWarnThreshold === "number" && v4.policy.fenceWarnThreshold > 0 && v4.policy.fenceWarnThreshold <= 1 ? v4.policy.fenceWarnThreshold : DEFAULT_FENCE_WARN_THRESHOLD,
|
|
1509
1509
|
confidenceThresholds: {
|
|
1510
1510
|
allow: typeof v4.policy?.confidenceThresholds?.allow === "number" ? v4.policy.confidenceThresholds.allow : DEFAULT_CONFIDENCE_THRESHOLDS.allow,
|
|
@@ -1806,7 +1806,7 @@ var init_config = __esm({
|
|
|
1806
1806
|
DEFAULT_POLICY_V3 = {
|
|
1807
1807
|
unknownLocalEffect: "allow_flagged",
|
|
1808
1808
|
unparseableShell: "deny",
|
|
1809
|
-
codexUnmappedTool: "
|
|
1809
|
+
codexUnmappedTool: "allow",
|
|
1810
1810
|
confidenceThresholds: { ...DEFAULT_CONFIDENCE_THRESHOLDS },
|
|
1811
1811
|
modelAssist: { ...DEFAULT_MODEL_ASSIST },
|
|
1812
1812
|
transactional: { ...DEFAULT_TRANSACTIONAL_V3 },
|
|
@@ -10813,6 +10813,40 @@ function evaluateFileMutationPolicy(analysis, config, auth) {
|
|
|
10813
10813
|
);
|
|
10814
10814
|
return { request, decision };
|
|
10815
10815
|
}
|
|
10816
|
+
function buildFileReadCapabilityRequest(analysis) {
|
|
10817
|
+
return {
|
|
10818
|
+
version: CAPABILITY_REQUEST_VERSION,
|
|
10819
|
+
principal: {
|
|
10820
|
+
adapter: analysis.adapter,
|
|
10821
|
+
repoRoot: analysis.repoRoot,
|
|
10822
|
+
sessionHash: hashSession(`${analysis.repoRoot}:${analysis.cwd}`)
|
|
10823
|
+
},
|
|
10824
|
+
action: "fs.read",
|
|
10825
|
+
resource: { kind: "path", path: analysis.resolvedPath },
|
|
10826
|
+
context: {
|
|
10827
|
+
cwd: analysis.cwd,
|
|
10828
|
+
inputFingerprint: analysis.inputFingerprint,
|
|
10829
|
+
hookKind: analysis.hookKind,
|
|
10830
|
+
analysisBasis: [`tool:${analysis.toolKind}`, `location:${analysis.locationLabel}`, "read"]
|
|
10831
|
+
},
|
|
10832
|
+
evidence: {
|
|
10833
|
+
level: analysis.locationLabel === "repo_local" ? "certain" : "possible",
|
|
10834
|
+
signals: [...analysis.signals, "effect.fs_read"]
|
|
10835
|
+
}
|
|
10836
|
+
};
|
|
10837
|
+
}
|
|
10838
|
+
function evaluateFileReadPolicy(analysis, config, auth) {
|
|
10839
|
+
const request = buildFileReadCapabilityRequest(analysis);
|
|
10840
|
+
const enriched = enrichAuthWithMaterializedGrants(request, config, {
|
|
10841
|
+
...auth,
|
|
10842
|
+
sensitivePaths: auth?.sensitivePaths ?? analysis.sensitivePaths
|
|
10843
|
+
});
|
|
10844
|
+
const decision = getDefaultPolicyEngine().evaluate(
|
|
10845
|
+
request,
|
|
10846
|
+
buildAuthorizationContext(config, analysis.trustedWorkspaceRoots, enriched)
|
|
10847
|
+
);
|
|
10848
|
+
return { request, decision };
|
|
10849
|
+
}
|
|
10816
10850
|
|
|
10817
10851
|
// src/core/capability/reasons.ts
|
|
10818
10852
|
var FS_SCOPE_REASONS = /* @__PURE__ */ new Set(["outside_repo_mutation", "outside_repo_redirect"]);
|
|
@@ -17083,17 +17117,41 @@ function verdictToClassifyResult(result, config, options = {}) {
|
|
|
17083
17117
|
|
|
17084
17118
|
// src/core/classify-tool.ts
|
|
17085
17119
|
var DEFAULT_SENSITIVE_PATHS = [".env", ".env.*", "**/credentials/**"];
|
|
17086
|
-
|
|
17087
|
-
|
|
17088
|
-
"
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17120
|
+
function toolInputRecord(payload) {
|
|
17121
|
+
const toolInput = payload.tool_input;
|
|
17122
|
+
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) {
|
|
17123
|
+
return null;
|
|
17124
|
+
}
|
|
17125
|
+
return toolInput;
|
|
17126
|
+
}
|
|
17127
|
+
function hasMutationFields(input) {
|
|
17128
|
+
return typeof input.contents === "string" || typeof input.old_string === "string" || typeof input.new_string === "string" || typeof input.newContents === "string";
|
|
17129
|
+
}
|
|
17130
|
+
function inferToolPayloadEffect(payload, toolName) {
|
|
17131
|
+
if (extractShellCommand(payload)) {
|
|
17132
|
+
return "shell";
|
|
17133
|
+
}
|
|
17134
|
+
const input = toolInputRecord(payload);
|
|
17135
|
+
if (!input) {
|
|
17136
|
+
return "indeterminate";
|
|
17137
|
+
}
|
|
17138
|
+
if (hasMutationFields(input)) {
|
|
17139
|
+
return "file_mutation";
|
|
17140
|
+
}
|
|
17141
|
+
if (extractPatch(payload)) {
|
|
17142
|
+
return "apply_patch";
|
|
17143
|
+
}
|
|
17144
|
+
if (typeof input.pattern === "string" || typeof input.glob_pattern === "string") {
|
|
17145
|
+
return "search_read";
|
|
17146
|
+
}
|
|
17147
|
+
if (typeof input.file_path === "string") {
|
|
17148
|
+
return "file_read";
|
|
17149
|
+
}
|
|
17150
|
+
if (typeof input.path === "string" || typeof input.target_file === "string") {
|
|
17151
|
+
return normalizedToolName(toolName) === "delete" ? "file_delete" : "indeterminate";
|
|
17152
|
+
}
|
|
17153
|
+
return "indeterminate";
|
|
17154
|
+
}
|
|
17097
17155
|
function policyAuth(options) {
|
|
17098
17156
|
if (!options.grants && options.attestation === void 0 && options.egressProxyActive === void 0) {
|
|
17099
17157
|
return void 0;
|
|
@@ -17273,6 +17331,314 @@ function classifyFileMutationWithPolicy(params) {
|
|
|
17273
17331
|
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY
|
|
17274
17332
|
};
|
|
17275
17333
|
}
|
|
17334
|
+
function classifyFileReadWithPolicy(params) {
|
|
17335
|
+
const fingerprint = toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot);
|
|
17336
|
+
const { request, decision } = evaluateFileReadPolicy(
|
|
17337
|
+
{
|
|
17338
|
+
hookKind: "tool",
|
|
17339
|
+
toolKind: params.toolKind,
|
|
17340
|
+
filePath: params.filePath,
|
|
17341
|
+
resolvedPath: params.resolvedPath,
|
|
17342
|
+
repoRoot: params.repoRoot,
|
|
17343
|
+
cwd: params.cwd,
|
|
17344
|
+
inputFingerprint: fingerprint,
|
|
17345
|
+
signals: params.signals,
|
|
17346
|
+
locationLabel: params.locationLabel,
|
|
17347
|
+
trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
|
|
17348
|
+
sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths
|
|
17349
|
+
},
|
|
17350
|
+
params.config,
|
|
17351
|
+
policyAuth(params.options)
|
|
17352
|
+
);
|
|
17353
|
+
if (policyDecisionRequiresAsk(decision)) {
|
|
17354
|
+
return {
|
|
17355
|
+
verdict: "deny_pending_approval",
|
|
17356
|
+
reason: policyReasonToLegacyReason(decision),
|
|
17357
|
+
summary: params.filePath,
|
|
17358
|
+
fingerprint,
|
|
17359
|
+
assessment: {
|
|
17360
|
+
reversibility: "reversible",
|
|
17361
|
+
external: params.locationLabel === "outside_repo",
|
|
17362
|
+
blastRadius: params.locationLabel === "outside_repo" ? "outside the repository" : "sensitive repository file",
|
|
17363
|
+
confidence: 0.85,
|
|
17364
|
+
signals: [...params.signals, ...decision.signals]
|
|
17365
|
+
},
|
|
17366
|
+
capabilityRequests: [request],
|
|
17367
|
+
authorizationDecision: decision,
|
|
17368
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY
|
|
17369
|
+
};
|
|
17370
|
+
}
|
|
17371
|
+
return {
|
|
17372
|
+
verdict: "allow",
|
|
17373
|
+
reason: "effect.fs_read",
|
|
17374
|
+
summary: params.filePath,
|
|
17375
|
+
fingerprint,
|
|
17376
|
+
assessment: {
|
|
17377
|
+
reversibility: "reversible",
|
|
17378
|
+
external: false,
|
|
17379
|
+
blastRadius: "tool scope",
|
|
17380
|
+
confidence: 0.88,
|
|
17381
|
+
signals: [...params.signals, ...decision.signals]
|
|
17382
|
+
},
|
|
17383
|
+
capabilityRequests: [request],
|
|
17384
|
+
authorizationDecision: decision,
|
|
17385
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY
|
|
17386
|
+
};
|
|
17387
|
+
}
|
|
17388
|
+
function classifyFilePathMutation(params) {
|
|
17389
|
+
const {
|
|
17390
|
+
toolName,
|
|
17391
|
+
toolKind,
|
|
17392
|
+
filePath,
|
|
17393
|
+
repoRoot,
|
|
17394
|
+
cwd,
|
|
17395
|
+
config,
|
|
17396
|
+
options,
|
|
17397
|
+
sensitivePaths,
|
|
17398
|
+
protectedRoots,
|
|
17399
|
+
isDelete
|
|
17400
|
+
} = params;
|
|
17401
|
+
const signals = [];
|
|
17402
|
+
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17403
|
+
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17404
|
+
if (hitsProtectedRoot) {
|
|
17405
|
+
signals.push("control_plane_path");
|
|
17406
|
+
return classifyFileMutationWithPolicy({
|
|
17407
|
+
toolName,
|
|
17408
|
+
toolKind,
|
|
17409
|
+
filePath,
|
|
17410
|
+
resolvedPath,
|
|
17411
|
+
repoRoot,
|
|
17412
|
+
cwd,
|
|
17413
|
+
config,
|
|
17414
|
+
options,
|
|
17415
|
+
signals,
|
|
17416
|
+
isDelete,
|
|
17417
|
+
locationLabel: "control_plane"
|
|
17418
|
+
});
|
|
17419
|
+
}
|
|
17420
|
+
const workspaceMatch = resolveWorkspaceRootMatch(
|
|
17421
|
+
repoRoot,
|
|
17422
|
+
options.trustedWorkspaceRoots,
|
|
17423
|
+
resolvedPath
|
|
17424
|
+
);
|
|
17425
|
+
if (workspaceMatch === null) {
|
|
17426
|
+
signals.push("outside_repo_path");
|
|
17427
|
+
return classifyFileMutationWithPolicy({
|
|
17428
|
+
toolName,
|
|
17429
|
+
toolKind,
|
|
17430
|
+
filePath,
|
|
17431
|
+
resolvedPath,
|
|
17432
|
+
repoRoot,
|
|
17433
|
+
cwd,
|
|
17434
|
+
config,
|
|
17435
|
+
options,
|
|
17436
|
+
signals,
|
|
17437
|
+
isDelete,
|
|
17438
|
+
locationLabel: "outside_repo"
|
|
17439
|
+
});
|
|
17440
|
+
}
|
|
17441
|
+
if (workspaceMatch.kind === "trusted") {
|
|
17442
|
+
signals.push("trusted_workspace_root");
|
|
17443
|
+
}
|
|
17444
|
+
const trustedCwd = resolveClassifierTrustedCwd(cwd, options);
|
|
17445
|
+
const workspacePrescan = mutationPrescanRequiresAsk({
|
|
17446
|
+
targets: [filePath],
|
|
17447
|
+
cwd,
|
|
17448
|
+
repoRoot,
|
|
17449
|
+
trustedCwd,
|
|
17450
|
+
trustedWorkspaceRoots: options.trustedWorkspaceRoots,
|
|
17451
|
+
sensitivePaths
|
|
17452
|
+
});
|
|
17453
|
+
if (workspacePrescan) {
|
|
17454
|
+
return classifyFileMutationWithPolicy({
|
|
17455
|
+
toolName,
|
|
17456
|
+
toolKind,
|
|
17457
|
+
filePath,
|
|
17458
|
+
resolvedPath,
|
|
17459
|
+
repoRoot,
|
|
17460
|
+
cwd,
|
|
17461
|
+
config,
|
|
17462
|
+
options,
|
|
17463
|
+
signals,
|
|
17464
|
+
isDelete,
|
|
17465
|
+
locationLabel: "sensitive_path"
|
|
17466
|
+
});
|
|
17467
|
+
}
|
|
17468
|
+
const relativePath = workspaceMatch.relativePath;
|
|
17469
|
+
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
17470
|
+
signals.push("sensitive_path");
|
|
17471
|
+
return classifyFileMutationWithPolicy({
|
|
17472
|
+
toolName,
|
|
17473
|
+
toolKind,
|
|
17474
|
+
filePath,
|
|
17475
|
+
resolvedPath,
|
|
17476
|
+
repoRoot,
|
|
17477
|
+
cwd,
|
|
17478
|
+
config,
|
|
17479
|
+
options,
|
|
17480
|
+
signals,
|
|
17481
|
+
isDelete,
|
|
17482
|
+
locationLabel: "sensitive_path"
|
|
17483
|
+
});
|
|
17484
|
+
}
|
|
17485
|
+
if (isDelete) {
|
|
17486
|
+
if (isGitPath(resolvedPath, repoRoot)) {
|
|
17487
|
+
signals.push("protected_artifact");
|
|
17488
|
+
return classifyFileMutationWithPolicy({
|
|
17489
|
+
toolName,
|
|
17490
|
+
toolKind,
|
|
17491
|
+
filePath,
|
|
17492
|
+
resolvedPath,
|
|
17493
|
+
repoRoot,
|
|
17494
|
+
cwd,
|
|
17495
|
+
config,
|
|
17496
|
+
options,
|
|
17497
|
+
signals,
|
|
17498
|
+
isDelete: true,
|
|
17499
|
+
locationLabel: "sensitive_path"
|
|
17500
|
+
});
|
|
17501
|
+
}
|
|
17502
|
+
signals.push("file_delete");
|
|
17503
|
+
return classifyFileMutationWithPolicy({
|
|
17504
|
+
toolName,
|
|
17505
|
+
toolKind,
|
|
17506
|
+
filePath,
|
|
17507
|
+
resolvedPath,
|
|
17508
|
+
repoRoot,
|
|
17509
|
+
cwd,
|
|
17510
|
+
config,
|
|
17511
|
+
options,
|
|
17512
|
+
signals,
|
|
17513
|
+
isDelete: true,
|
|
17514
|
+
locationLabel: "repo_local"
|
|
17515
|
+
});
|
|
17516
|
+
}
|
|
17517
|
+
signals.push("file_mutation");
|
|
17518
|
+
return classifyFileMutationWithPolicy({
|
|
17519
|
+
toolName,
|
|
17520
|
+
toolKind,
|
|
17521
|
+
filePath,
|
|
17522
|
+
resolvedPath,
|
|
17523
|
+
repoRoot,
|
|
17524
|
+
cwd,
|
|
17525
|
+
config,
|
|
17526
|
+
options,
|
|
17527
|
+
signals,
|
|
17528
|
+
isDelete: false,
|
|
17529
|
+
locationLabel: "repo_local"
|
|
17530
|
+
});
|
|
17531
|
+
}
|
|
17532
|
+
function classifyFilePathRead(params) {
|
|
17533
|
+
const {
|
|
17534
|
+
toolName,
|
|
17535
|
+
toolKind,
|
|
17536
|
+
filePath,
|
|
17537
|
+
repoRoot,
|
|
17538
|
+
cwd,
|
|
17539
|
+
config,
|
|
17540
|
+
options,
|
|
17541
|
+
sensitivePaths,
|
|
17542
|
+
protectedRoots
|
|
17543
|
+
} = params;
|
|
17544
|
+
const signals = ["effect.fs_read"];
|
|
17545
|
+
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17546
|
+
if (protectedRoots.some((root) => pathWithinRoot(root, resolvedPath))) {
|
|
17547
|
+
signals.push("control_plane_path");
|
|
17548
|
+
return classifyFileReadWithPolicy({
|
|
17549
|
+
toolName,
|
|
17550
|
+
toolKind,
|
|
17551
|
+
filePath,
|
|
17552
|
+
resolvedPath,
|
|
17553
|
+
repoRoot,
|
|
17554
|
+
cwd,
|
|
17555
|
+
config,
|
|
17556
|
+
options,
|
|
17557
|
+
signals,
|
|
17558
|
+
locationLabel: "control_plane"
|
|
17559
|
+
});
|
|
17560
|
+
}
|
|
17561
|
+
const workspaceMatch = resolveWorkspaceRootMatch(
|
|
17562
|
+
repoRoot,
|
|
17563
|
+
options.trustedWorkspaceRoots,
|
|
17564
|
+
resolvedPath
|
|
17565
|
+
);
|
|
17566
|
+
if (workspaceMatch === null) {
|
|
17567
|
+
signals.push("outside_repo_path");
|
|
17568
|
+
return classifyFileReadWithPolicy({
|
|
17569
|
+
toolName,
|
|
17570
|
+
toolKind,
|
|
17571
|
+
filePath,
|
|
17572
|
+
resolvedPath,
|
|
17573
|
+
repoRoot,
|
|
17574
|
+
cwd,
|
|
17575
|
+
config,
|
|
17576
|
+
options,
|
|
17577
|
+
signals,
|
|
17578
|
+
locationLabel: "outside_repo"
|
|
17579
|
+
});
|
|
17580
|
+
}
|
|
17581
|
+
const relativePath = workspaceMatch.relativePath;
|
|
17582
|
+
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
17583
|
+
signals.push("sensitive_path");
|
|
17584
|
+
return classifyFileReadWithPolicy({
|
|
17585
|
+
toolName,
|
|
17586
|
+
toolKind,
|
|
17587
|
+
filePath,
|
|
17588
|
+
resolvedPath,
|
|
17589
|
+
repoRoot,
|
|
17590
|
+
cwd,
|
|
17591
|
+
config,
|
|
17592
|
+
options,
|
|
17593
|
+
signals,
|
|
17594
|
+
locationLabel: "sensitive_path"
|
|
17595
|
+
});
|
|
17596
|
+
}
|
|
17597
|
+
return classifyFileReadWithPolicy({
|
|
17598
|
+
toolName,
|
|
17599
|
+
toolKind,
|
|
17600
|
+
filePath,
|
|
17601
|
+
resolvedPath,
|
|
17602
|
+
repoRoot,
|
|
17603
|
+
cwd,
|
|
17604
|
+
config,
|
|
17605
|
+
options,
|
|
17606
|
+
signals,
|
|
17607
|
+
locationLabel: "repo_local"
|
|
17608
|
+
});
|
|
17609
|
+
}
|
|
17610
|
+
function indeterminateToolResult(toolName, payload, repoRoot, options) {
|
|
17611
|
+
const summary = canonicalStringify(scrubPayload(payload.tool_input ?? {}, options));
|
|
17612
|
+
const fingerprint = toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot);
|
|
17613
|
+
if (options.unknownLocalEffect === "deny") {
|
|
17614
|
+
return {
|
|
17615
|
+
verdict: "deny_pending_approval",
|
|
17616
|
+
reason: "indeterminate_tool_effect",
|
|
17617
|
+
summary,
|
|
17618
|
+
fingerprint,
|
|
17619
|
+
assessment: {
|
|
17620
|
+
reversibility: "irreversible",
|
|
17621
|
+
external: false,
|
|
17622
|
+
blastRadius: "unknown tool action",
|
|
17623
|
+
confidence: 0.5,
|
|
17624
|
+
signals: ["indeterminate_tool_effect"]
|
|
17625
|
+
}
|
|
17626
|
+
};
|
|
17627
|
+
}
|
|
17628
|
+
return {
|
|
17629
|
+
verdict: "allow_flagged",
|
|
17630
|
+
reason: "indeterminate_tool_effect",
|
|
17631
|
+
summary,
|
|
17632
|
+
fingerprint,
|
|
17633
|
+
assessment: {
|
|
17634
|
+
reversibility: "recoverable_with_cost",
|
|
17635
|
+
external: false,
|
|
17636
|
+
blastRadius: "tool scope",
|
|
17637
|
+
confidence: 0.5,
|
|
17638
|
+
signals: ["indeterminate_tool_effect"]
|
|
17639
|
+
}
|
|
17640
|
+
};
|
|
17641
|
+
}
|
|
17276
17642
|
async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
17277
17643
|
const toolName = String(payload.tool_name ?? "");
|
|
17278
17644
|
const toolKind = normalizedToolName(toolName);
|
|
@@ -17319,9 +17685,10 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17319
17685
|
summary: command
|
|
17320
17686
|
};
|
|
17321
17687
|
}
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17688
|
+
const effect = inferToolPayloadEffect(payload, toolName);
|
|
17689
|
+
if (effect === "file_mutation" || effect === "file_delete") {
|
|
17690
|
+
const filePath2 = extractFilePath(payload);
|
|
17691
|
+
if (!filePath2) {
|
|
17325
17692
|
if (options.unknownLocalEffect === "deny") {
|
|
17326
17693
|
return {
|
|
17327
17694
|
verdict: "deny_pending_approval",
|
|
@@ -17351,138 +17718,20 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17351
17718
|
}
|
|
17352
17719
|
};
|
|
17353
17720
|
}
|
|
17354
|
-
|
|
17355
|
-
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17356
|
-
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17357
|
-
if (hitsProtectedRoot) {
|
|
17358
|
-
signals.push("control_plane_path");
|
|
17359
|
-
return classifyFileMutationWithPolicy({
|
|
17360
|
-
toolName,
|
|
17361
|
-
toolKind,
|
|
17362
|
-
filePath,
|
|
17363
|
-
resolvedPath,
|
|
17364
|
-
repoRoot,
|
|
17365
|
-
cwd,
|
|
17366
|
-
config,
|
|
17367
|
-
options,
|
|
17368
|
-
signals,
|
|
17369
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17370
|
-
locationLabel: "control_plane"
|
|
17371
|
-
});
|
|
17372
|
-
}
|
|
17373
|
-
const workspaceMatch = resolveWorkspaceRootMatch(
|
|
17374
|
-
repoRoot,
|
|
17375
|
-
options.trustedWorkspaceRoots,
|
|
17376
|
-
resolvedPath
|
|
17377
|
-
);
|
|
17378
|
-
if (workspaceMatch === null) {
|
|
17379
|
-
signals.push("outside_repo_path");
|
|
17380
|
-
return classifyFileMutationWithPolicy({
|
|
17381
|
-
toolName,
|
|
17382
|
-
toolKind,
|
|
17383
|
-
filePath,
|
|
17384
|
-
resolvedPath,
|
|
17385
|
-
repoRoot,
|
|
17386
|
-
cwd,
|
|
17387
|
-
config,
|
|
17388
|
-
options,
|
|
17389
|
-
signals,
|
|
17390
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17391
|
-
locationLabel: "outside_repo"
|
|
17392
|
-
});
|
|
17393
|
-
}
|
|
17394
|
-
if (workspaceMatch.kind === "trusted") {
|
|
17395
|
-
signals.push("trusted_workspace_root");
|
|
17396
|
-
}
|
|
17397
|
-
const trustedCwd = resolveClassifierTrustedCwd(cwd, options);
|
|
17398
|
-
const workspacePrescan = mutationPrescanRequiresAsk({
|
|
17399
|
-
targets: [filePath],
|
|
17400
|
-
cwd,
|
|
17401
|
-
repoRoot,
|
|
17402
|
-
trustedCwd,
|
|
17403
|
-
trustedWorkspaceRoots: options.trustedWorkspaceRoots,
|
|
17404
|
-
sensitivePaths
|
|
17405
|
-
});
|
|
17406
|
-
if (workspacePrescan) {
|
|
17407
|
-
return classifyFileMutationWithPolicy({
|
|
17408
|
-
toolName,
|
|
17409
|
-
toolKind,
|
|
17410
|
-
filePath,
|
|
17411
|
-
resolvedPath,
|
|
17412
|
-
repoRoot,
|
|
17413
|
-
cwd,
|
|
17414
|
-
config,
|
|
17415
|
-
options,
|
|
17416
|
-
signals,
|
|
17417
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17418
|
-
locationLabel: "sensitive_path"
|
|
17419
|
-
});
|
|
17420
|
-
}
|
|
17421
|
-
const relativePath = workspaceMatch.relativePath;
|
|
17422
|
-
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
17423
|
-
signals.push("sensitive_path");
|
|
17424
|
-
return classifyFileMutationWithPolicy({
|
|
17425
|
-
toolName,
|
|
17426
|
-
toolKind,
|
|
17427
|
-
filePath,
|
|
17428
|
-
resolvedPath,
|
|
17429
|
-
repoRoot,
|
|
17430
|
-
cwd,
|
|
17431
|
-
config,
|
|
17432
|
-
options,
|
|
17433
|
-
signals,
|
|
17434
|
-
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
17435
|
-
locationLabel: "sensitive_path"
|
|
17436
|
-
});
|
|
17437
|
-
}
|
|
17438
|
-
if (FILE_DELETE_TOOL_NAMES.has(toolKind)) {
|
|
17439
|
-
if (isGitPath(resolvedPath, repoRoot)) {
|
|
17440
|
-
signals.push("protected_artifact");
|
|
17441
|
-
return classifyFileMutationWithPolicy({
|
|
17442
|
-
toolName,
|
|
17443
|
-
toolKind,
|
|
17444
|
-
filePath,
|
|
17445
|
-
resolvedPath,
|
|
17446
|
-
repoRoot,
|
|
17447
|
-
cwd,
|
|
17448
|
-
config,
|
|
17449
|
-
options,
|
|
17450
|
-
signals,
|
|
17451
|
-
isDelete: true,
|
|
17452
|
-
locationLabel: "sensitive_path"
|
|
17453
|
-
});
|
|
17454
|
-
}
|
|
17455
|
-
signals.push("file_delete");
|
|
17456
|
-
return classifyFileMutationWithPolicy({
|
|
17457
|
-
toolName,
|
|
17458
|
-
toolKind,
|
|
17459
|
-
filePath,
|
|
17460
|
-
resolvedPath,
|
|
17461
|
-
repoRoot,
|
|
17462
|
-
cwd,
|
|
17463
|
-
config,
|
|
17464
|
-
options,
|
|
17465
|
-
signals,
|
|
17466
|
-
isDelete: true,
|
|
17467
|
-
locationLabel: "repo_local"
|
|
17468
|
-
});
|
|
17469
|
-
}
|
|
17470
|
-
signals.push("file_mutation");
|
|
17471
|
-
return classifyFileMutationWithPolicy({
|
|
17721
|
+
return classifyFilePathMutation({
|
|
17472
17722
|
toolName,
|
|
17473
17723
|
toolKind,
|
|
17474
|
-
filePath,
|
|
17475
|
-
resolvedPath,
|
|
17724
|
+
filePath: filePath2,
|
|
17476
17725
|
repoRoot,
|
|
17477
17726
|
cwd,
|
|
17478
17727
|
config,
|
|
17479
17728
|
options,
|
|
17480
|
-
|
|
17481
|
-
|
|
17482
|
-
|
|
17729
|
+
sensitivePaths,
|
|
17730
|
+
protectedRoots,
|
|
17731
|
+
isDelete: effect === "file_delete"
|
|
17483
17732
|
});
|
|
17484
17733
|
}
|
|
17485
|
-
if (
|
|
17734
|
+
if (effect === "apply_patch") {
|
|
17486
17735
|
const patch = extractPatch(payload);
|
|
17487
17736
|
const targets = patch ? applyPatchTargets2(patch) : [];
|
|
17488
17737
|
if (targets.length === 0) {
|
|
@@ -17520,7 +17769,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17520
17769
|
const result = await classifyToolUse(
|
|
17521
17770
|
{
|
|
17522
17771
|
tool_name: target.delete ? "Delete" : "Write",
|
|
17523
|
-
tool_input: { path: target.path }
|
|
17772
|
+
tool_input: target.delete ? { path: target.path } : { path: target.path, contents: " " }
|
|
17524
17773
|
},
|
|
17525
17774
|
repoRoot,
|
|
17526
17775
|
cwd,
|
|
@@ -17546,19 +17795,54 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17546
17795
|
}
|
|
17547
17796
|
};
|
|
17548
17797
|
}
|
|
17549
|
-
|
|
17550
|
-
|
|
17551
|
-
|
|
17552
|
-
|
|
17553
|
-
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17554
|
-
assessment: {
|
|
17555
|
-
reversibility: "reversible",
|
|
17556
|
-
external: false,
|
|
17557
|
-
blastRadius: "tool scope",
|
|
17558
|
-
confidence: 0.5,
|
|
17559
|
-
signals: ["unclassified_tool"]
|
|
17798
|
+
if (effect === "file_read") {
|
|
17799
|
+
const filePath2 = extractFilePath(payload);
|
|
17800
|
+
if (!filePath2) {
|
|
17801
|
+
return indeterminateToolResult(toolName, payload, repoRoot, options);
|
|
17560
17802
|
}
|
|
17561
|
-
|
|
17803
|
+
return classifyFilePathRead({
|
|
17804
|
+
toolName,
|
|
17805
|
+
toolKind,
|
|
17806
|
+
filePath: filePath2,
|
|
17807
|
+
repoRoot,
|
|
17808
|
+
cwd,
|
|
17809
|
+
config,
|
|
17810
|
+
options,
|
|
17811
|
+
sensitivePaths,
|
|
17812
|
+
protectedRoots
|
|
17813
|
+
});
|
|
17814
|
+
}
|
|
17815
|
+
if (effect === "search_read") {
|
|
17816
|
+
return {
|
|
17817
|
+
verdict: "allow",
|
|
17818
|
+
reason: "effect.search_read",
|
|
17819
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17820
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17821
|
+
assessment: {
|
|
17822
|
+
reversibility: "reversible",
|
|
17823
|
+
external: false,
|
|
17824
|
+
blastRadius: "tool scope",
|
|
17825
|
+
confidence: 0.88,
|
|
17826
|
+
signals: ["effect.search_read"]
|
|
17827
|
+
}
|
|
17828
|
+
};
|
|
17829
|
+
}
|
|
17830
|
+
const filePath = extractFilePath(payload);
|
|
17831
|
+
if (filePath) {
|
|
17832
|
+
return classifyFilePathMutation({
|
|
17833
|
+
toolName,
|
|
17834
|
+
toolKind,
|
|
17835
|
+
filePath,
|
|
17836
|
+
repoRoot,
|
|
17837
|
+
cwd,
|
|
17838
|
+
config,
|
|
17839
|
+
options,
|
|
17840
|
+
sensitivePaths,
|
|
17841
|
+
protectedRoots,
|
|
17842
|
+
isDelete: toolKind === "delete"
|
|
17843
|
+
});
|
|
17844
|
+
}
|
|
17845
|
+
return indeterminateToolResult(toolName, payload, repoRoot, options);
|
|
17562
17846
|
}
|
|
17563
17847
|
|
|
17564
17848
|
// src/core/gate-engine.ts
|
|
@@ -17893,15 +18177,8 @@ function gateEnabledForAction(config, action) {
|
|
|
17893
18177
|
if (action.kind === "subagent") {
|
|
17894
18178
|
return config.gates.subagent;
|
|
17895
18179
|
}
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
return config.gates.toolShell;
|
|
17899
|
-
}
|
|
17900
|
-
if (toolName === "Write" || toolName === "StrReplace" || toolName === "Delete") {
|
|
17901
|
-
return config.gates.fileMutation;
|
|
17902
|
-
}
|
|
17903
|
-
if (toolName === "Task") {
|
|
17904
|
-
return config.gates.subagent;
|
|
18180
|
+
if (action.kind === "tool") {
|
|
18181
|
+
return config.gates.fileMutation || config.gates.toolShell;
|
|
17905
18182
|
}
|
|
17906
18183
|
return true;
|
|
17907
18184
|
}
|
|
@@ -17938,7 +18215,7 @@ function hashDecisionConfig(config) {
|
|
|
17938
18215
|
init_fingerprint2();
|
|
17939
18216
|
|
|
17940
18217
|
// src/version.ts
|
|
17941
|
-
var PACKAGE_VERSION = "0.10.
|
|
18218
|
+
var PACKAGE_VERSION = "0.10.1";
|
|
17942
18219
|
|
|
17943
18220
|
// src/runtime-provenance.ts
|
|
17944
18221
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -21239,21 +21516,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
21239
21516
|
...authorization,
|
|
21240
21517
|
egressProxyActive
|
|
21241
21518
|
};
|
|
21242
|
-
|
|
21243
|
-
if (action.kind === "tool" && predicted.reason === "unclassified_tool" && (ctx.config.policy.codexUnmappedTool ?? "deny") === "deny") {
|
|
21244
|
-
predicted = {
|
|
21245
|
-
...predicted,
|
|
21246
|
-
verdict: "deny_pending_approval",
|
|
21247
|
-
reason: "unmapped_tool",
|
|
21248
|
-
assessment: {
|
|
21249
|
-
reversibility: "irreversible",
|
|
21250
|
-
external: false,
|
|
21251
|
-
blastRadius: "unknown tool action",
|
|
21252
|
-
confidence: 0.5,
|
|
21253
|
-
signals: ["unmapped_tool"]
|
|
21254
|
-
}
|
|
21255
|
-
};
|
|
21256
|
-
}
|
|
21519
|
+
const predicted = await classifyGatedActionAsync(action, ctx.config, enrichedClassifierOptions);
|
|
21257
21520
|
if (action.kind === "shell" && action.command && isContainedUnknownExecutionEligible(ctx.config, action, predicted)) {
|
|
21258
21521
|
const mediated = await mediateContainedUnknownExecution({
|
|
21259
21522
|
ctx,
|
|
@@ -21382,40 +21645,6 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
21382
21645
|
scopeHintPayload: params.payload
|
|
21383
21646
|
});
|
|
21384
21647
|
}
|
|
21385
|
-
async function gateUnmappedToolVerdict(ctx, deps, toolName, payload) {
|
|
21386
|
-
const scrubOpts = scrubOptionsFromConfig(ctx.config);
|
|
21387
|
-
const replayPayload = fingerprintReplayPayload("tool", payload, scrubOpts) ?? {};
|
|
21388
|
-
const result = {
|
|
21389
|
-
verdict: "deny_pending_approval",
|
|
21390
|
-
reason: "unmapped_tool",
|
|
21391
|
-
summary: toolName,
|
|
21392
|
-
fingerprint: toolFingerprint(toolName, replayPayload, ctx.repoRoot),
|
|
21393
|
-
assessment: {
|
|
21394
|
-
reversibility: "irreversible",
|
|
21395
|
-
external: false,
|
|
21396
|
-
blastRadius: "unknown Codex tool action",
|
|
21397
|
-
confidence: 0.5,
|
|
21398
|
-
signals: ["unmapped_tool"]
|
|
21399
|
-
}
|
|
21400
|
-
};
|
|
21401
|
-
return gateDecisionToVerdict(ctx, deps, "tool", result, {
|
|
21402
|
-
approvalInput: {
|
|
21403
|
-
input: toolName,
|
|
21404
|
-
inputKind: "tool",
|
|
21405
|
-
cwd: ctx.repoRoot,
|
|
21406
|
-
toolName,
|
|
21407
|
-
payload: replayPayload
|
|
21408
|
-
},
|
|
21409
|
-
replayAction: {
|
|
21410
|
-
kind: "tool",
|
|
21411
|
-
cwd: ctx.repoRoot,
|
|
21412
|
-
toolName,
|
|
21413
|
-
payload: replayPayload,
|
|
21414
|
-
fingerprint: result.fingerprint,
|
|
21415
|
-
repoRoot: ctx.repoRoot
|
|
21416
|
-
}
|
|
21417
|
-
});
|
|
21418
|
-
}
|
|
21419
21648
|
async function consumeCapabilityGrantIfUsed(ctx, deps, result) {
|
|
21420
21649
|
if (result.reason !== "capability_grant" && result.authorizationDecision?.matchedRule !== "grant.exact") {
|
|
21421
21650
|
return true;
|
|
@@ -22107,13 +22336,14 @@ async function runToolGateHook(eventName) {
|
|
|
22107
22336
|
const ctx = await loadRuntimeContext(cwd);
|
|
22108
22337
|
const deps = createDefaultGateRuntimeDeps();
|
|
22109
22338
|
if (!kind) {
|
|
22110
|
-
const
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22339
|
+
const normalizedPayload2 = normalizeCodexToolPayload("tool", payload);
|
|
22340
|
+
const verdict3 = await evaluateGatedAction(ctx, deps, {
|
|
22341
|
+
kind: "tool",
|
|
22342
|
+
cwd,
|
|
22343
|
+
payload: normalizedPayload2,
|
|
22344
|
+
toolName,
|
|
22345
|
+
sourceEvent: eventName
|
|
22346
|
+
});
|
|
22117
22347
|
jsonResponse(gateVerdictToCodexPreToolUseResponse(verdict3));
|
|
22118
22348
|
return;
|
|
22119
22349
|
}
|