@wrongstack/plugins 0.306.3 → 0.307.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gitignore-guard.js +1 -1
- package/dist/index.js +385 -346
- package/dist/notify-hub.js +13 -0
- package/dist/path-guard/glob.d.ts +32 -0
- package/dist/path-guard/index.d.ts +2 -44
- package/dist/path-guard/shell-targets.d.ts +40 -0
- package/dist/path-guard/tool-targets.d.ts +34 -0
- package/dist/path-guard.js +377 -373
- package/dist/prompt-firewall.js +23 -1
- package/dist/secret-scanner.js +23 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -9343,7 +9343,7 @@ var DEFAULT_ARTIFACT_PATTERNS = Object.freeze([
|
|
|
9343
9343
|
"*.env.*"
|
|
9344
9344
|
]);
|
|
9345
9345
|
function toForwardSlashes(p) {
|
|
9346
|
-
return
|
|
9346
|
+
return p.split(sep3).join("/").replaceAll("\\", "/");
|
|
9347
9347
|
}
|
|
9348
9348
|
function globToSource(glob) {
|
|
9349
9349
|
return glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
|
|
@@ -13544,6 +13544,19 @@ var plugin38 = {
|
|
|
13544
13544
|
}
|
|
13545
13545
|
}
|
|
13546
13546
|
state35.eventUnsubscribers = [];
|
|
13547
|
+
if (api.tools?.unregister) {
|
|
13548
|
+
try {
|
|
13549
|
+
api.tools.unregister("notify_send");
|
|
13550
|
+
api.tools.unregister("notify_hub_status");
|
|
13551
|
+
} catch {
|
|
13552
|
+
}
|
|
13553
|
+
}
|
|
13554
|
+
if (api.notifier?.unregisterChannel) {
|
|
13555
|
+
try {
|
|
13556
|
+
api.notifier.unregisterChannel("webhook");
|
|
13557
|
+
} catch {
|
|
13558
|
+
}
|
|
13559
|
+
}
|
|
13547
13560
|
const channelCounters = state35.channel?.counters();
|
|
13548
13561
|
state35.channel = null;
|
|
13549
13562
|
state35.lastDelivery = null;
|
|
@@ -13565,40 +13578,7 @@ var plugin38 = {
|
|
|
13565
13578
|
};
|
|
13566
13579
|
var notify_hub_default = plugin38;
|
|
13567
13580
|
|
|
13568
|
-
// src/path-guard/
|
|
13569
|
-
function createState() {
|
|
13570
|
-
return { invocations: 0, blocks: 0, warns: 0, lastBlock: null, hookUnregister: null };
|
|
13571
|
-
}
|
|
13572
|
-
var states = /* @__PURE__ */ new WeakMap();
|
|
13573
|
-
var latestState = createState();
|
|
13574
|
-
var DEFAULT_PROTECT = [
|
|
13575
|
-
"pnpm-lock.yaml",
|
|
13576
|
-
"package-lock.json",
|
|
13577
|
-
"yarn.lock",
|
|
13578
|
-
"bun.lockb",
|
|
13579
|
-
"Cargo.lock",
|
|
13580
|
-
"poetry.lock",
|
|
13581
|
-
".env",
|
|
13582
|
-
".env.*",
|
|
13583
|
-
".git/**",
|
|
13584
|
-
"**/migrations/**"
|
|
13585
|
-
];
|
|
13586
|
-
var DEFAULTS33 = {
|
|
13587
|
-
enabled: true,
|
|
13588
|
-
mode: "block",
|
|
13589
|
-
protect: DEFAULT_PROTECT,
|
|
13590
|
-
allow: []
|
|
13591
|
-
};
|
|
13592
|
-
function readConfig34(raw) {
|
|
13593
|
-
if (!raw || typeof raw !== "object") return { ...DEFAULTS33, protect: [...DEFAULT_PROTECT] };
|
|
13594
|
-
const r = raw;
|
|
13595
|
-
return {
|
|
13596
|
-
enabled: r["enabled"] !== false,
|
|
13597
|
-
mode: r["mode"] === "warn" ? "warn" : "block",
|
|
13598
|
-
protect: Array.isArray(r["protect"]) ? r["protect"].filter((p) => typeof p === "string" && p.length > 0) : [...DEFAULT_PROTECT],
|
|
13599
|
-
allow: Array.isArray(r["allow"]) ? r["allow"].filter((p) => typeof p === "string" && p.length > 0) : []
|
|
13600
|
-
};
|
|
13601
|
-
}
|
|
13581
|
+
// src/path-guard/glob.ts
|
|
13602
13582
|
function compilePathGlob(pattern) {
|
|
13603
13583
|
const normalized = pattern.replace(/\\/g, "/");
|
|
13604
13584
|
let source = "";
|
|
@@ -13764,244 +13744,8 @@ function targetFullyAllowed(target, allowTexts, allowRes) {
|
|
|
13764
13744
|
return allowNormalized.endsWith("/**") && allowRe?.test(`${normalized}/.path-guard-probe`);
|
|
13765
13745
|
});
|
|
13766
13746
|
}
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
var SHELL_CAPABILITIES = /* @__PURE__ */ new Set(["shell.arbitrary", "shell.restricted", "shell.exec"]);
|
|
13770
|
-
var LEGACY_SHELL_TOOLS = /* @__PURE__ */ new Set(["bash", "shell", "exec"]);
|
|
13771
|
-
var LEGACY_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
13772
|
-
"write",
|
|
13773
|
-
"edit",
|
|
13774
|
-
"patch",
|
|
13775
|
-
"scaffold",
|
|
13776
|
-
"format",
|
|
13777
|
-
"replace",
|
|
13778
|
-
"design",
|
|
13779
|
-
"install"
|
|
13780
|
-
]);
|
|
13781
|
-
function writesToDisk(input) {
|
|
13782
|
-
const capabilities = input.toolCapabilities;
|
|
13783
|
-
const capabilitiesUndeclared = !capabilities || capabilities.length === 0;
|
|
13784
|
-
const hasWriteCap = capabilities?.some((capability) => WRITE_CAPABILITIES.has(capability)) ?? false;
|
|
13785
|
-
const hasDiskMutatingCap = capabilities?.some((capability) => DISK_MUTATING_CAPABILITIES.has(capability)) ?? false;
|
|
13786
|
-
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
13787
|
-
if (hasCommandString && executesShell(input) && !hasWriteCap && !hasDiskMutatingCap && !(capabilitiesUndeclared && LEGACY_WRITE_TOOLS.has(input.toolName ?? "")))
|
|
13788
|
-
return false;
|
|
13789
|
-
if (!capabilitiesUndeclared) {
|
|
13790
|
-
if (hasWriteCap || hasDiskMutatingCap) return true;
|
|
13791
|
-
if (capabilities.includes("mcp.proxy")) {
|
|
13792
|
-
const segmentedName = (input.toolName ?? "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9]+/gi, "_").toLowerCase();
|
|
13793
|
-
const filesystemWriter = /(?:^|_)filesystem(?:_|$)/.test(segmentedName) && /(?:^|_)(?:add|append|copy|create|delete|edit|mkdir|move|remove|rename|write)(?:_|$)/.test(
|
|
13794
|
-
segmentedName
|
|
13795
|
-
);
|
|
13796
|
-
const toolInput = input.toolInput ?? {};
|
|
13797
|
-
const hasKnownPath = [...PATH_FIELDS, ...PATH_LIST_FIELDS].some(
|
|
13798
|
-
(field) => toolInput[field] !== void 0
|
|
13799
|
-
);
|
|
13800
|
-
if (filesystemWriter && hasKnownPath) return true;
|
|
13801
|
-
}
|
|
13802
|
-
return false;
|
|
13803
|
-
}
|
|
13804
|
-
if (input.toolMutating !== void 0) return input.toolMutating;
|
|
13805
|
-
return LEGACY_WRITE_TOOLS.has(input.toolName ?? "");
|
|
13806
|
-
}
|
|
13807
|
-
function executesShell(input) {
|
|
13808
|
-
const toolName = input.toolName ?? "";
|
|
13809
|
-
if (LEGACY_SHELL_TOOLS.has(toolName)) return true;
|
|
13810
|
-
if (toolName === "git") return false;
|
|
13811
|
-
const segmentedName = toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
13812
|
-
const isCommandStringRunner = /(?:^|[_.-])(?:command|exec|execute|shell|terminal)(?:$|[_.-])/i.test(segmentedName);
|
|
13813
|
-
const hasShellCapability = input.toolCapabilities?.some((capability) => SHELL_CAPABILITIES.has(capability)) ?? false;
|
|
13814
|
-
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
13815
|
-
return isCommandStringRunner && hasShellCapability || hasCommandString && input.toolMutating === true;
|
|
13816
|
-
}
|
|
13817
|
-
var PATH_FIELDS = [
|
|
13818
|
-
"path",
|
|
13819
|
-
"file_path",
|
|
13820
|
-
"filePath",
|
|
13821
|
-
"target",
|
|
13822
|
-
"target_path",
|
|
13823
|
-
"targetPath",
|
|
13824
|
-
"destination",
|
|
13825
|
-
"dest",
|
|
13826
|
-
"output_path",
|
|
13827
|
-
"outputPath",
|
|
13828
|
-
"out",
|
|
13829
|
-
"file"
|
|
13830
|
-
];
|
|
13831
|
-
var PATH_LIST_FIELDS = ["files", "paths"];
|
|
13832
|
-
var SOURCE_PATH_FIELDS = [
|
|
13833
|
-
"source",
|
|
13834
|
-
"from",
|
|
13835
|
-
"src",
|
|
13836
|
-
"input_path",
|
|
13837
|
-
"inputPath",
|
|
13838
|
-
"old_path",
|
|
13839
|
-
"oldPath"
|
|
13840
|
-
];
|
|
13841
|
-
var MOVE_TOOL_NAME = /(?:^|[_.-])(move|rename)(?:$|[_.-])/i;
|
|
13842
|
-
var DIRECTORY_DELETE_TOOL_NAME = /(?:^|[_.-])(?:rmdir|(?:delete|remove)[_.-](?:dir|directory))(?:$|[_.-])/i;
|
|
13843
|
-
function segmentedToolName(toolName) {
|
|
13844
|
-
return toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
13845
|
-
}
|
|
13846
|
-
function isMoveToolName(toolName) {
|
|
13847
|
-
return MOVE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
13848
|
-
}
|
|
13849
|
-
function isDirectoryDeleteToolName(toolName) {
|
|
13850
|
-
return DIRECTORY_DELETE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
13851
|
-
}
|
|
13852
|
-
function cleanPatchPath(raw) {
|
|
13853
|
-
const trimmed = raw.trim();
|
|
13854
|
-
if (!trimmed || trimmed === "/dev/null") return null;
|
|
13855
|
-
const quoted = /^"([^"]+)"(?:\s|$)/.exec(trimmed)?.[1];
|
|
13856
|
-
const withoutTimestamp = quoted ?? trimmed.replace(/(?:\t|\s+)\d{4}-\d{2}-\d{2}(?:\s.*)?$/, "").trim();
|
|
13857
|
-
if (!withoutTimestamp || withoutTimestamp === "/dev/null") return null;
|
|
13858
|
-
return withoutTimestamp.replace(/^[ab]\//, "");
|
|
13859
|
-
}
|
|
13860
|
-
function pathsFromPatch(patch) {
|
|
13861
|
-
const paths = [];
|
|
13862
|
-
const lines = patch.split(/\r?\n/);
|
|
13863
|
-
for (let index = 0; index + 2 < lines.length; index += 1) {
|
|
13864
|
-
const oldHeader = lines[index];
|
|
13865
|
-
const newHeader = lines[index + 1];
|
|
13866
|
-
const hunkHeader = lines[index + 2];
|
|
13867
|
-
if (!oldHeader?.startsWith("--- ") || !newHeader?.startsWith("+++ ")) continue;
|
|
13868
|
-
if (!hunkHeader?.startsWith("@@ ")) continue;
|
|
13869
|
-
const oldPath = cleanPatchPath(oldHeader.slice(4));
|
|
13870
|
-
const newPath = cleanPatchPath(newHeader.slice(4));
|
|
13871
|
-
if (oldPath) paths.push(oldPath);
|
|
13872
|
-
if (newPath) paths.push(newPath);
|
|
13873
|
-
}
|
|
13874
|
-
return paths;
|
|
13875
|
-
}
|
|
13876
|
-
function appendTarget(targets, value, kind, base) {
|
|
13877
|
-
if (typeof value !== "string" || value.length === 0) return;
|
|
13878
|
-
targets.push({
|
|
13879
|
-
path: resolveTargetPath(value, base),
|
|
13880
|
-
kind
|
|
13881
|
-
});
|
|
13882
|
-
}
|
|
13883
|
-
function appendTargetList(targets, value, directoryCapable, base) {
|
|
13884
|
-
const appendPath = (path) => {
|
|
13885
|
-
targets.push({
|
|
13886
|
-
path: resolveTargetPath(path, base),
|
|
13887
|
-
kind: isUnresolvedPathScope(path) || isRootPathScope(path) || directoryCapable && isDirectoryAmbiguousPath(path) ? "scope" : "file"
|
|
13888
|
-
});
|
|
13889
|
-
};
|
|
13890
|
-
if (typeof value === "string") {
|
|
13891
|
-
const paths = value.split(",").map((item) => item.trim()).filter((path) => path.length > 0);
|
|
13892
|
-
for (const path of paths) appendPath(path);
|
|
13893
|
-
return;
|
|
13894
|
-
}
|
|
13895
|
-
if (!Array.isArray(value)) return;
|
|
13896
|
-
for (const item of value) {
|
|
13897
|
-
if (typeof item !== "string") continue;
|
|
13898
|
-
const path = item.trim();
|
|
13899
|
-
if (path.length > 0) appendPath(path);
|
|
13900
|
-
}
|
|
13901
|
-
}
|
|
13902
|
-
function isReadOnlyInvocation(toolName, toolInput) {
|
|
13903
|
-
if (toolName === "git") {
|
|
13904
|
-
const command = toolInput["command"];
|
|
13905
|
-
if (command === "status" || command === "log" || command === "diff" || command === "fetch" || command === "commit" || command === "branch" || command === "push") {
|
|
13906
|
-
return true;
|
|
13907
|
-
}
|
|
13908
|
-
return command === "worktree" && toolInput["worktreeAction"] === "list";
|
|
13909
|
-
}
|
|
13910
|
-
if (toolName === "design") {
|
|
13911
|
-
const action = toolInput["action"] ?? "list";
|
|
13912
|
-
return action === "list" || action === "foundations" || action === "verify";
|
|
13913
|
-
}
|
|
13914
|
-
if (toolName === "format") return toolInput["check"] === true;
|
|
13915
|
-
if (toolName === "patch" || toolName === "scaffold") return toolInput["dry_run"] === true;
|
|
13916
|
-
if (toolName === "replace") return toolInput["dry_run"] !== false;
|
|
13917
|
-
return false;
|
|
13918
|
-
}
|
|
13919
|
-
function pathsFromToolInput(toolInput, toolName, invocationCwd) {
|
|
13920
|
-
const targets = [];
|
|
13921
|
-
const effectiveCwd = effectiveToolCwd(toolInput["cwd"], invocationCwd);
|
|
13922
|
-
const directoryDelete = isDirectoryDeleteToolName(toolName);
|
|
13923
|
-
for (const field of PATH_FIELDS) {
|
|
13924
|
-
const value = toolInput[field];
|
|
13925
|
-
appendTarget(
|
|
13926
|
-
targets,
|
|
13927
|
-
value,
|
|
13928
|
-
directoryDelete ? "deletion-scope" : typeof value === "string" && isUnresolvedPathScope(value) ? "scope" : "file",
|
|
13929
|
-
effectiveCwd
|
|
13930
|
-
);
|
|
13931
|
-
}
|
|
13932
|
-
const directoryCapableLists = toolName === "format" || toolName === "replace";
|
|
13933
|
-
for (const field of PATH_LIST_FIELDS) {
|
|
13934
|
-
appendTargetList(
|
|
13935
|
-
targets,
|
|
13936
|
-
toolInput[field],
|
|
13937
|
-
directoryCapableLists && field === "files",
|
|
13938
|
-
effectiveCwd
|
|
13939
|
-
);
|
|
13940
|
-
}
|
|
13941
|
-
if (toolName === "install") {
|
|
13942
|
-
appendTarget(targets, effectiveCwd ?? invocationCwd ?? ".", "scope");
|
|
13943
|
-
}
|
|
13944
|
-
if (toolName === "git") {
|
|
13945
|
-
const command = toolInput["command"];
|
|
13946
|
-
if (command === "worktree" && (toolInput["worktreeAction"] === "add" || toolInput["worktreeAction"] === "remove")) {
|
|
13947
|
-
appendTarget(targets, toolInput["worktreePath"] ?? toolInput["worktree_path"], "file");
|
|
13948
|
-
}
|
|
13949
|
-
}
|
|
13950
|
-
if (toolName === "scaffold") {
|
|
13951
|
-
const cwdValue = toolInput["cwd"];
|
|
13952
|
-
const cwd = typeof cwdValue === "string" && cwdValue.length > 0 ? cwdValue : invocationCwd ?? ".";
|
|
13953
|
-
const base = normalizePath2(cwd).replace(/\/$/, "");
|
|
13954
|
-
const name = typeof toolInput["name"] === "string" ? toolInput["name"] : "";
|
|
13955
|
-
const template = toolInput["template"];
|
|
13956
|
-
const filesByTemplate = {
|
|
13957
|
-
"npm-package": ["package.json", "tsconfig.json", "src/index.ts", "src/index.test.ts"],
|
|
13958
|
-
"cli-tool": ["package.json", "src/index.ts"],
|
|
13959
|
-
"react-component": name ? [`${name}.tsx`, `${name}.test.tsx`] : []
|
|
13960
|
-
};
|
|
13961
|
-
for (const file of typeof template === "string" ? filesByTemplate[template] ?? [] : []) {
|
|
13962
|
-
targets.push({ path: `${base}/${file}`, kind: "file" });
|
|
13963
|
-
}
|
|
13964
|
-
targets.push({ path: base, kind: "scope" });
|
|
13965
|
-
}
|
|
13966
|
-
if (isMoveToolName(toolName)) {
|
|
13967
|
-
for (const field of SOURCE_PATH_FIELDS) {
|
|
13968
|
-
appendTarget(targets, toolInput[field], "deletion-scope", effectiveCwd);
|
|
13969
|
-
}
|
|
13970
|
-
}
|
|
13971
|
-
const patch = toolInput["patch"];
|
|
13972
|
-
if (typeof patch === "string") {
|
|
13973
|
-
const patchTargets = pathsFromPatch(patch);
|
|
13974
|
-
const directory = toolInput["directory"];
|
|
13975
|
-
const baseValue = typeof directory === "string" && directory.length > 0 ? directory : invocationCwd;
|
|
13976
|
-
if (baseValue) {
|
|
13977
|
-
const base = normalizePath2(baseValue).replace(/\/$/, "");
|
|
13978
|
-
targets.push(
|
|
13979
|
-
...patchTargets.map((target) => ({ path: `${base}/${target}`, kind: "file" }))
|
|
13980
|
-
);
|
|
13981
|
-
} else {
|
|
13982
|
-
targets.push(...patchTargets.map((path) => ({ path, kind: "file" })));
|
|
13983
|
-
}
|
|
13984
|
-
}
|
|
13985
|
-
if (targets.length === 0) {
|
|
13986
|
-
const cwd = effectiveCwd ?? ".";
|
|
13987
|
-
targets.push({ path: normalizePath2(cwd).replace(/\/$/, "") || ".", kind: "scope" });
|
|
13988
|
-
}
|
|
13989
|
-
const seen = /* @__PURE__ */ new Set();
|
|
13990
|
-
return targets.map((target) => ({
|
|
13991
|
-
...target,
|
|
13992
|
-
path: relativeToInvocationCwd(target.path, invocationCwd)
|
|
13993
|
-
})).filter((target) => {
|
|
13994
|
-
const key = `${target.kind}:${target.path}`;
|
|
13995
|
-
if (seen.has(key)) return false;
|
|
13996
|
-
seen.add(key);
|
|
13997
|
-
return true;
|
|
13998
|
-
});
|
|
13999
|
-
}
|
|
14000
|
-
function operationLabel(toolName) {
|
|
14001
|
-
if (toolName === "write") return "write";
|
|
14002
|
-
if (toolName === "edit") return "edit";
|
|
14003
|
-
return `write via "${toolName}"`;
|
|
14004
|
-
}
|
|
13747
|
+
|
|
13748
|
+
// src/path-guard/shell-targets.ts
|
|
14005
13749
|
var VALUE_TAKING_GIT_OPTIONS = /* @__PURE__ */ new Set([
|
|
14006
13750
|
"-C",
|
|
14007
13751
|
"-c",
|
|
@@ -14165,21 +13909,6 @@ function unwrapEnvSplitStringAtBoundary(command) {
|
|
|
14165
13909
|
}
|
|
14166
13910
|
return command;
|
|
14167
13911
|
}
|
|
14168
|
-
function stripTransparentLaunchers(command) {
|
|
14169
|
-
let stripped = command;
|
|
14170
|
-
let previous;
|
|
14171
|
-
do {
|
|
14172
|
-
previous = stripped;
|
|
14173
|
-
let beforeUnwrap;
|
|
14174
|
-
do {
|
|
14175
|
-
beforeUnwrap = stripped;
|
|
14176
|
-
stripped = unwrapEnvSplitStringAtBoundary(stripped);
|
|
14177
|
-
} while (stripped !== beforeUnwrap);
|
|
14178
|
-
stripped = stripLauncherAtBoundary(stripped, "env", ENV_VALUE_TAKING);
|
|
14179
|
-
stripped = stripLauncherAtBoundary(stripped, "sudo", SUDO_VALUE_TAKING);
|
|
14180
|
-
} while (stripped !== previous);
|
|
14181
|
-
return stripped;
|
|
14182
|
-
}
|
|
14183
13912
|
var SUDO_VALUE_TAKING = /* @__PURE__ */ new Set([
|
|
14184
13913
|
"-u",
|
|
14185
13914
|
"-g",
|
|
@@ -14221,6 +13950,21 @@ var ENV_FLAG_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
14221
13950
|
"--help",
|
|
14222
13951
|
"--version"
|
|
14223
13952
|
]);
|
|
13953
|
+
function stripTransparentLaunchers(command) {
|
|
13954
|
+
let stripped = command;
|
|
13955
|
+
let previous;
|
|
13956
|
+
do {
|
|
13957
|
+
previous = stripped;
|
|
13958
|
+
let beforeUnwrap;
|
|
13959
|
+
do {
|
|
13960
|
+
beforeUnwrap = stripped;
|
|
13961
|
+
stripped = unwrapEnvSplitStringAtBoundary(stripped);
|
|
13962
|
+
} while (stripped !== beforeUnwrap);
|
|
13963
|
+
stripped = stripLauncherAtBoundary(stripped, "env", ENV_VALUE_TAKING);
|
|
13964
|
+
stripped = stripLauncherAtBoundary(stripped, "sudo", SUDO_VALUE_TAKING);
|
|
13965
|
+
} while (stripped !== previous);
|
|
13966
|
+
return stripped;
|
|
13967
|
+
}
|
|
14224
13968
|
function firstUnquotedShellSeparator(raw, start, end) {
|
|
14225
13969
|
let quote = null;
|
|
14226
13970
|
for (let index = start; index < end; index += 1) {
|
|
@@ -14357,9 +14101,7 @@ function executableCommandSubstitutions(command) {
|
|
|
14357
14101
|
}
|
|
14358
14102
|
const commandSubstitution = char === "$" && command[index + 1] === "(";
|
|
14359
14103
|
const processSubstitution = (char === ">" || char === "<") && command[index + 1] === "(";
|
|
14360
|
-
if (!commandSubstitution && !processSubstitution ||
|
|
14361
|
-
// contents as a shell command substitution.
|
|
14362
|
-
commandSubstitution && command[index + 2] === "(")
|
|
14104
|
+
if (!commandSubstitution && !processSubstitution || commandSubstitution && command[index + 2] === "(")
|
|
14363
14105
|
continue;
|
|
14364
14106
|
let depth = 1;
|
|
14365
14107
|
let innerQuote = null;
|
|
@@ -14742,70 +14484,345 @@ function destructiveTargetsAtDepth(command, depth) {
|
|
|
14742
14484
|
targets.push(gitTarget("."));
|
|
14743
14485
|
}
|
|
14744
14486
|
}
|
|
14745
|
-
const findDelete = /(?:^|[;&|\r\n]\s*|\$\(\s*|\(\s*|`\s*)find\b([^;&|)`]*(?:\s-delete(?:\s|$)|\s-exec(?:dir)?\s+(?:[^\s;&|]+[\\/])?(?:rm|rmdir)\b)[^;&|)`]*)/gi;
|
|
14746
|
-
let f = findDelete.exec(normalizedCommand);
|
|
14747
|
-
while (f !== null) {
|
|
14748
|
-
const tokens = shellTokens(f[1] ?? "");
|
|
14749
|
-
const expressionIndex = tokens.findIndex(
|
|
14750
|
-
(token) => token.startsWith("-") || token === "!" || token === "("
|
|
14487
|
+
const findDelete = /(?:^|[;&|\r\n]\s*|\$\(\s*|\(\s*|`\s*)find\b([^;&|)`]*(?:\s-delete(?:\s|$)|\s-exec(?:dir)?\s+(?:[^\s;&|]+[\\/])?(?:rm|rmdir)\b)[^;&|)`]*)/gi;
|
|
14488
|
+
let f = findDelete.exec(normalizedCommand);
|
|
14489
|
+
while (f !== null) {
|
|
14490
|
+
const tokens = shellTokens(f[1] ?? "");
|
|
14491
|
+
const expressionIndex = tokens.findIndex(
|
|
14492
|
+
(token) => token.startsWith("-") || token === "!" || token === "("
|
|
14493
|
+
);
|
|
14494
|
+
const roots = (expressionIndex === -1 ? tokens : tokens.slice(0, expressionIndex)).filter(
|
|
14495
|
+
(token) => token.length > 0
|
|
14496
|
+
);
|
|
14497
|
+
targets.push(...roots.length > 0 ? roots : ["."]);
|
|
14498
|
+
f = findDelete.exec(normalizedCommand);
|
|
14499
|
+
}
|
|
14500
|
+
const shellWrapper = /\b(?:ba|z|k)?sh\s+-c\s+(['"])(.*?)\1/gi;
|
|
14501
|
+
let w = shellWrapper.exec(normalizedCommand);
|
|
14502
|
+
while (w !== null) {
|
|
14503
|
+
if (w[2] && !tokenIsQuoted(w, w[0].split(/\s/)[0] ?? "")) {
|
|
14504
|
+
targets.push(...destructiveTargetsAtDepth(w[2], depth + 1));
|
|
14505
|
+
}
|
|
14506
|
+
w = shellWrapper.exec(normalizedCommand);
|
|
14507
|
+
}
|
|
14508
|
+
let quote = null;
|
|
14509
|
+
for (let index = 0; index < normalizedCommand.length; index += 1) {
|
|
14510
|
+
const char = normalizedCommand[index];
|
|
14511
|
+
if (char === "\n") {
|
|
14512
|
+
quote = null;
|
|
14513
|
+
continue;
|
|
14514
|
+
}
|
|
14515
|
+
if (isQuoteBoundary(normalizedCommand, index, quote)) {
|
|
14516
|
+
quote = quote === char ? null : char === "'" ? "'" : '"';
|
|
14517
|
+
continue;
|
|
14518
|
+
}
|
|
14519
|
+
if (quote !== null || char !== ">") continue;
|
|
14520
|
+
const redirectsBothStreams = normalizedCommand[index + 1] === "&";
|
|
14521
|
+
const overridesNoclobber = normalizedCommand[index + 1] === "|";
|
|
14522
|
+
if (redirectsBothStreams || overridesNoclobber || normalizedCommand[index + 1] === ">") {
|
|
14523
|
+
index += 1;
|
|
14524
|
+
}
|
|
14525
|
+
while (normalizedCommand[index + 1] === " " || normalizedCommand[index + 1] === " ") {
|
|
14526
|
+
index += 1;
|
|
14527
|
+
}
|
|
14528
|
+
const targetQuote = normalizedCommand[index + 1];
|
|
14529
|
+
let end = index + 1;
|
|
14530
|
+
let target;
|
|
14531
|
+
if (targetQuote === "'" || targetQuote === '"') {
|
|
14532
|
+
end = normalizedCommand.indexOf(targetQuote, index + 2);
|
|
14533
|
+
if (end === -1) continue;
|
|
14534
|
+
target = normalizedCommand.slice(index + 2, end);
|
|
14535
|
+
} else {
|
|
14536
|
+
while (end < normalizedCommand.length && !/[\s;&|>()]/.test(normalizedCommand[end] ?? "")) {
|
|
14537
|
+
end += 1;
|
|
14538
|
+
}
|
|
14539
|
+
target = normalizedCommand.slice(index + 1, end);
|
|
14540
|
+
}
|
|
14541
|
+
if (target && !(redirectsBothStreams && (/^\d+$/.test(target) || target === "-"))) {
|
|
14542
|
+
targets.push(target);
|
|
14543
|
+
}
|
|
14544
|
+
index = end;
|
|
14545
|
+
}
|
|
14546
|
+
return [
|
|
14547
|
+
...new Set(
|
|
14548
|
+
targets.map((target) => target.replace(/^['"]|['"]$/g, "")).filter((target) => target !== "/dev/null" && target.toLowerCase() !== "nul")
|
|
14549
|
+
)
|
|
14550
|
+
];
|
|
14551
|
+
}
|
|
14552
|
+
|
|
14553
|
+
// src/path-guard/tool-targets.ts
|
|
14554
|
+
var WRITE_CAPABILITIES = /* @__PURE__ */ new Set(["fs.write", "fs.write.outside-project"]);
|
|
14555
|
+
var DISK_MUTATING_CAPABILITIES = /* @__PURE__ */ new Set(["package.install"]);
|
|
14556
|
+
var SHELL_CAPABILITIES = /* @__PURE__ */ new Set(["shell.arbitrary", "shell.restricted", "shell.exec"]);
|
|
14557
|
+
var LEGACY_SHELL_TOOLS = /* @__PURE__ */ new Set(["bash", "shell", "exec"]);
|
|
14558
|
+
var LEGACY_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
14559
|
+
"write",
|
|
14560
|
+
"edit",
|
|
14561
|
+
"patch",
|
|
14562
|
+
"scaffold",
|
|
14563
|
+
"format",
|
|
14564
|
+
"replace",
|
|
14565
|
+
"design",
|
|
14566
|
+
"install"
|
|
14567
|
+
]);
|
|
14568
|
+
var PATH_FIELDS = [
|
|
14569
|
+
"path",
|
|
14570
|
+
"file_path",
|
|
14571
|
+
"filePath",
|
|
14572
|
+
"target",
|
|
14573
|
+
"target_path",
|
|
14574
|
+
"targetPath",
|
|
14575
|
+
"destination",
|
|
14576
|
+
"dest",
|
|
14577
|
+
"output_path",
|
|
14578
|
+
"outputPath",
|
|
14579
|
+
"out",
|
|
14580
|
+
"file"
|
|
14581
|
+
];
|
|
14582
|
+
var PATH_LIST_FIELDS = ["files", "paths"];
|
|
14583
|
+
var SOURCE_PATH_FIELDS = [
|
|
14584
|
+
"source",
|
|
14585
|
+
"from",
|
|
14586
|
+
"src",
|
|
14587
|
+
"input_path",
|
|
14588
|
+
"inputPath",
|
|
14589
|
+
"old_path",
|
|
14590
|
+
"oldPath"
|
|
14591
|
+
];
|
|
14592
|
+
var MOVE_TOOL_NAME = /(?:^|[_.-])(move|rename)(?:$|[_.-])/i;
|
|
14593
|
+
var DIRECTORY_DELETE_TOOL_NAME = /(?:^|[_.-])(?:rmdir|(?:delete|remove)[_.-](?:dir|directory))(?:$|[_.-])/i;
|
|
14594
|
+
function segmentedToolName(toolName) {
|
|
14595
|
+
return toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
14596
|
+
}
|
|
14597
|
+
function isMoveToolName(toolName) {
|
|
14598
|
+
return MOVE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
14599
|
+
}
|
|
14600
|
+
function isDirectoryDeleteToolName(toolName) {
|
|
14601
|
+
return DIRECTORY_DELETE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
14602
|
+
}
|
|
14603
|
+
function cleanPatchPath(raw) {
|
|
14604
|
+
const trimmed = raw.trim();
|
|
14605
|
+
if (!trimmed || trimmed === "/dev/null") return null;
|
|
14606
|
+
const quoted = /^"([^"]+)"(?:\s|$)/.exec(trimmed)?.[1];
|
|
14607
|
+
const withoutTimestamp = quoted ?? trimmed.replace(/(?:\t|\s+)\d{4}-\d{2}-\d{2}(?:\s.*)?$/, "").trim();
|
|
14608
|
+
if (!withoutTimestamp || withoutTimestamp === "/dev/null") return null;
|
|
14609
|
+
return withoutTimestamp.replace(/^[ab]\//, "");
|
|
14610
|
+
}
|
|
14611
|
+
function pathsFromPatch(patch) {
|
|
14612
|
+
const paths = [];
|
|
14613
|
+
const lines = patch.split(/\r?\n/);
|
|
14614
|
+
for (let index = 0; index + 2 < lines.length; index += 1) {
|
|
14615
|
+
const oldHeader = lines[index];
|
|
14616
|
+
const newHeader = lines[index + 1];
|
|
14617
|
+
const hunkHeader = lines[index + 2];
|
|
14618
|
+
if (!oldHeader?.startsWith("--- ") || !newHeader?.startsWith("+++ ")) continue;
|
|
14619
|
+
if (!hunkHeader?.startsWith("@@ ")) continue;
|
|
14620
|
+
const oldPath = cleanPatchPath(oldHeader.slice(4));
|
|
14621
|
+
const newPath = cleanPatchPath(newHeader.slice(4));
|
|
14622
|
+
if (oldPath) paths.push(oldPath);
|
|
14623
|
+
if (newPath) paths.push(newPath);
|
|
14624
|
+
}
|
|
14625
|
+
return paths;
|
|
14626
|
+
}
|
|
14627
|
+
function appendTarget(targets, value, kind, base) {
|
|
14628
|
+
if (typeof value !== "string" || value.length === 0) return;
|
|
14629
|
+
targets.push({
|
|
14630
|
+
path: resolveTargetPath(value, base),
|
|
14631
|
+
kind
|
|
14632
|
+
});
|
|
14633
|
+
}
|
|
14634
|
+
function appendTargetList(targets, value, directoryCapable, base) {
|
|
14635
|
+
const appendPath = (path) => {
|
|
14636
|
+
targets.push({
|
|
14637
|
+
path: resolveTargetPath(path, base),
|
|
14638
|
+
kind: isUnresolvedPathScope(path) || isRootPathScope(path) || directoryCapable && isDirectoryAmbiguousPath(path) ? "scope" : "file"
|
|
14639
|
+
});
|
|
14640
|
+
};
|
|
14641
|
+
if (typeof value === "string") {
|
|
14642
|
+
const paths = value.split(",").map((item) => item.trim()).filter((path) => path.length > 0);
|
|
14643
|
+
for (const path of paths) appendPath(path);
|
|
14644
|
+
return;
|
|
14645
|
+
}
|
|
14646
|
+
if (!Array.isArray(value)) return;
|
|
14647
|
+
for (const item of value) {
|
|
14648
|
+
if (typeof item !== "string") continue;
|
|
14649
|
+
const path = item.trim();
|
|
14650
|
+
if (path.length > 0) appendPath(path);
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
14653
|
+
function isReadOnlyInvocation(toolName, toolInput) {
|
|
14654
|
+
if (toolName === "git") {
|
|
14655
|
+
const command = toolInput["command"];
|
|
14656
|
+
if (command === "status" || command === "log" || command === "diff" || command === "fetch" || command === "commit" || command === "branch" || command === "push") {
|
|
14657
|
+
return true;
|
|
14658
|
+
}
|
|
14659
|
+
return command === "worktree" && toolInput["worktreeAction"] === "list";
|
|
14660
|
+
}
|
|
14661
|
+
if (toolName === "design") {
|
|
14662
|
+
const action = toolInput["action"] ?? "list";
|
|
14663
|
+
return action === "list" || action === "foundations" || action === "verify";
|
|
14664
|
+
}
|
|
14665
|
+
if (toolName === "format") return toolInput["check"] === true;
|
|
14666
|
+
if (toolName === "patch" || toolName === "scaffold") return toolInput["dry_run"] === true;
|
|
14667
|
+
if (toolName === "replace") return toolInput["dry_run"] !== false;
|
|
14668
|
+
return false;
|
|
14669
|
+
}
|
|
14670
|
+
function writesToDisk(input) {
|
|
14671
|
+
const capabilities = input.toolCapabilities;
|
|
14672
|
+
const capabilitiesUndeclared = !capabilities || capabilities.length === 0;
|
|
14673
|
+
const hasWriteCap = capabilities?.some((capability) => WRITE_CAPABILITIES.has(capability)) ?? false;
|
|
14674
|
+
const hasDiskMutatingCap = capabilities?.some((capability) => DISK_MUTATING_CAPABILITIES.has(capability)) ?? false;
|
|
14675
|
+
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
14676
|
+
if (hasCommandString && executesShell(input) && !hasWriteCap && !hasDiskMutatingCap && !(capabilitiesUndeclared && LEGACY_WRITE_TOOLS.has(input.toolName ?? "")))
|
|
14677
|
+
return false;
|
|
14678
|
+
if (!capabilitiesUndeclared) {
|
|
14679
|
+
if (hasWriteCap || hasDiskMutatingCap) return true;
|
|
14680
|
+
if (capabilities.includes("mcp.proxy")) {
|
|
14681
|
+
const segmentedName = (input.toolName ?? "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9]+/gi, "_").toLowerCase();
|
|
14682
|
+
const filesystemWriter = /(?:^|_)filesystem(?:_|$)/.test(segmentedName) && /(?:^|_)(?:add|append|copy|create|delete|edit|mkdir|move|remove|rename|write)(?:_|$)/.test(
|
|
14683
|
+
segmentedName
|
|
14684
|
+
);
|
|
14685
|
+
const toolInput = input.toolInput ?? {};
|
|
14686
|
+
const hasKnownPath = [...PATH_FIELDS, ...PATH_LIST_FIELDS].some(
|
|
14687
|
+
(field) => toolInput[field] !== void 0
|
|
14688
|
+
);
|
|
14689
|
+
if (filesystemWriter && hasKnownPath) return true;
|
|
14690
|
+
}
|
|
14691
|
+
return false;
|
|
14692
|
+
}
|
|
14693
|
+
if (input.toolMutating !== void 0) return input.toolMutating;
|
|
14694
|
+
return LEGACY_WRITE_TOOLS.has(input.toolName ?? "");
|
|
14695
|
+
}
|
|
14696
|
+
function executesShell(input) {
|
|
14697
|
+
const toolName = input.toolName ?? "";
|
|
14698
|
+
if (LEGACY_SHELL_TOOLS.has(toolName)) return true;
|
|
14699
|
+
if (toolName === "git") return false;
|
|
14700
|
+
const segmentedName = toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
14701
|
+
const isCommandStringRunner = /(?:^|[_.-])(?:command|exec|execute|shell|terminal)(?:$|[_.-])/i.test(segmentedName);
|
|
14702
|
+
const hasShellCapability = input.toolCapabilities?.some((capability) => SHELL_CAPABILITIES.has(capability)) ?? false;
|
|
14703
|
+
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
14704
|
+
return isCommandStringRunner && hasShellCapability || hasCommandString && input.toolMutating === true;
|
|
14705
|
+
}
|
|
14706
|
+
function pathsFromToolInput(toolInput, toolName, invocationCwd) {
|
|
14707
|
+
const targets = [];
|
|
14708
|
+
const effectiveCwd = effectiveToolCwd(toolInput["cwd"], invocationCwd);
|
|
14709
|
+
const directoryDelete = isDirectoryDeleteToolName(toolName);
|
|
14710
|
+
for (const field of PATH_FIELDS) {
|
|
14711
|
+
const value = toolInput[field];
|
|
14712
|
+
appendTarget(
|
|
14713
|
+
targets,
|
|
14714
|
+
value,
|
|
14715
|
+
directoryDelete ? "deletion-scope" : typeof value === "string" && isUnresolvedPathScope(value) ? "scope" : "file",
|
|
14716
|
+
effectiveCwd
|
|
14751
14717
|
);
|
|
14752
|
-
|
|
14753
|
-
|
|
14718
|
+
}
|
|
14719
|
+
const directoryCapableLists = toolName === "format" || toolName === "replace";
|
|
14720
|
+
for (const field of PATH_LIST_FIELDS) {
|
|
14721
|
+
appendTargetList(
|
|
14722
|
+
targets,
|
|
14723
|
+
toolInput[field],
|
|
14724
|
+
directoryCapableLists && field === "files",
|
|
14725
|
+
effectiveCwd
|
|
14754
14726
|
);
|
|
14755
|
-
targets.push(...roots.length > 0 ? roots : ["."]);
|
|
14756
|
-
f = findDelete.exec(normalizedCommand);
|
|
14757
14727
|
}
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
while (w !== null) {
|
|
14761
|
-
if (w[2] && !tokenIsQuoted(w, w[0].split(/\s/)[0] ?? "")) {
|
|
14762
|
-
targets.push(...destructiveTargetsAtDepth(w[2], depth + 1));
|
|
14763
|
-
}
|
|
14764
|
-
w = shellWrapper.exec(normalizedCommand);
|
|
14728
|
+
if (toolName === "install") {
|
|
14729
|
+
appendTarget(targets, effectiveCwd ?? invocationCwd ?? ".", "scope");
|
|
14765
14730
|
}
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
14770
|
-
quote = null;
|
|
14771
|
-
continue;
|
|
14772
|
-
}
|
|
14773
|
-
if (isQuoteBoundary(normalizedCommand, index, quote)) {
|
|
14774
|
-
quote = quote === char ? null : char === "'" ? "'" : '"';
|
|
14775
|
-
continue;
|
|
14731
|
+
if (toolName === "git") {
|
|
14732
|
+
const command = toolInput["command"];
|
|
14733
|
+
if (command === "worktree" && (toolInput["worktreeAction"] === "add" || toolInput["worktreeAction"] === "remove")) {
|
|
14734
|
+
appendTarget(targets, toolInput["worktreePath"] ?? toolInput["worktree_path"], "file");
|
|
14776
14735
|
}
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
const
|
|
14780
|
-
|
|
14781
|
-
|
|
14736
|
+
}
|
|
14737
|
+
if (toolName === "scaffold") {
|
|
14738
|
+
const cwdValue = toolInput["cwd"];
|
|
14739
|
+
const cwd = typeof cwdValue === "string" && cwdValue.length > 0 ? cwdValue : invocationCwd ?? ".";
|
|
14740
|
+
const base = normalizePath2(cwd).replace(/\/$/, "");
|
|
14741
|
+
const name = typeof toolInput["name"] === "string" ? toolInput["name"] : "";
|
|
14742
|
+
const template = toolInput["template"];
|
|
14743
|
+
const filesByTemplate = {
|
|
14744
|
+
"npm-package": ["package.json", "tsconfig.json", "src/index.ts", "src/index.test.ts"],
|
|
14745
|
+
"cli-tool": ["package.json", "src/index.ts"],
|
|
14746
|
+
"react-component": name ? [`${name}.tsx`, `${name}.test.tsx`] : []
|
|
14747
|
+
};
|
|
14748
|
+
for (const file of typeof template === "string" ? filesByTemplate[template] ?? [] : []) {
|
|
14749
|
+
targets.push({ path: `${base}/${file}`, kind: "file" });
|
|
14782
14750
|
}
|
|
14783
|
-
|
|
14784
|
-
|
|
14751
|
+
targets.push({ path: base, kind: "scope" });
|
|
14752
|
+
}
|
|
14753
|
+
if (isMoveToolName(toolName)) {
|
|
14754
|
+
for (const field of SOURCE_PATH_FIELDS) {
|
|
14755
|
+
appendTarget(targets, toolInput[field], "deletion-scope", effectiveCwd);
|
|
14785
14756
|
}
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
14757
|
+
}
|
|
14758
|
+
const patch = toolInput["patch"];
|
|
14759
|
+
if (typeof patch === "string") {
|
|
14760
|
+
const patchTargets = pathsFromPatch(patch);
|
|
14761
|
+
const directory = toolInput["directory"];
|
|
14762
|
+
const baseValue = typeof directory === "string" && directory.length > 0 ? directory : invocationCwd;
|
|
14763
|
+
if (baseValue) {
|
|
14764
|
+
const base = normalizePath2(baseValue).replace(/\/$/, "");
|
|
14765
|
+
targets.push(
|
|
14766
|
+
...patchTargets.map((target) => ({ path: `${base}/${target}`, kind: "file" }))
|
|
14767
|
+
);
|
|
14793
14768
|
} else {
|
|
14794
|
-
|
|
14795
|
-
end += 1;
|
|
14796
|
-
}
|
|
14797
|
-
target = normalizedCommand.slice(index + 1, end);
|
|
14798
|
-
}
|
|
14799
|
-
if (target && !(redirectsBothStreams && (/^\d+$/.test(target) || target === "-"))) {
|
|
14800
|
-
targets.push(target);
|
|
14769
|
+
targets.push(...patchTargets.map((path) => ({ path, kind: "file" })));
|
|
14801
14770
|
}
|
|
14802
|
-
index = end;
|
|
14803
14771
|
}
|
|
14804
|
-
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14772
|
+
if (targets.length === 0) {
|
|
14773
|
+
const cwd = effectiveCwd ?? ".";
|
|
14774
|
+
targets.push({ path: normalizePath2(cwd).replace(/\/$/, "") || ".", kind: "scope" });
|
|
14775
|
+
}
|
|
14776
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14777
|
+
return targets.map((target) => ({
|
|
14778
|
+
...target,
|
|
14779
|
+
path: relativeToInvocationCwd(target.path, invocationCwd)
|
|
14780
|
+
})).filter((target) => {
|
|
14781
|
+
const key = `${target.kind}:${target.path}`;
|
|
14782
|
+
if (seen.has(key)) return false;
|
|
14783
|
+
seen.add(key);
|
|
14784
|
+
return true;
|
|
14785
|
+
});
|
|
14786
|
+
}
|
|
14787
|
+
function operationLabel(toolName) {
|
|
14788
|
+
if (toolName === "write") return "write";
|
|
14789
|
+
if (toolName === "edit") return "edit";
|
|
14790
|
+
return `write via "${toolName}"`;
|
|
14791
|
+
}
|
|
14792
|
+
|
|
14793
|
+
// src/path-guard/index.ts
|
|
14794
|
+
function createState() {
|
|
14795
|
+
return { invocations: 0, blocks: 0, warns: 0, lastBlock: null, hookUnregister: null };
|
|
14796
|
+
}
|
|
14797
|
+
var states = /* @__PURE__ */ new WeakMap();
|
|
14798
|
+
var latestState = createState();
|
|
14799
|
+
var DEFAULT_PROTECT = [
|
|
14800
|
+
"pnpm-lock.yaml",
|
|
14801
|
+
"package-lock.json",
|
|
14802
|
+
"yarn.lock",
|
|
14803
|
+
"bun.lockb",
|
|
14804
|
+
"Cargo.lock",
|
|
14805
|
+
"poetry.lock",
|
|
14806
|
+
".env",
|
|
14807
|
+
".env.*",
|
|
14808
|
+
".git/**",
|
|
14809
|
+
"**/migrations/**"
|
|
14810
|
+
];
|
|
14811
|
+
var DEFAULTS33 = {
|
|
14812
|
+
enabled: true,
|
|
14813
|
+
mode: "block",
|
|
14814
|
+
protect: DEFAULT_PROTECT,
|
|
14815
|
+
allow: []
|
|
14816
|
+
};
|
|
14817
|
+
function readConfig34(raw) {
|
|
14818
|
+
if (!raw || typeof raw !== "object") return { ...DEFAULTS33, protect: [...DEFAULT_PROTECT] };
|
|
14819
|
+
const r = raw;
|
|
14820
|
+
return {
|
|
14821
|
+
enabled: r["enabled"] !== false,
|
|
14822
|
+
mode: r["mode"] === "warn" ? "warn" : "block",
|
|
14823
|
+
protect: Array.isArray(r["protect"]) ? r["protect"].filter((p) => typeof p === "string" && p.length > 0) : [...DEFAULT_PROTECT],
|
|
14824
|
+
allow: Array.isArray(r["allow"]) ? r["allow"].filter((p) => typeof p === "string" && p.length > 0) : []
|
|
14825
|
+
};
|
|
14809
14826
|
}
|
|
14810
14827
|
var plugin39 = {
|
|
14811
14828
|
name: "path-guard",
|
|
@@ -16033,7 +16050,29 @@ var CREDENTIAL_PATTERNS = [
|
|
|
16033
16050
|
regex: /postgres(?:ql)?:\/\/(?:[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+|[^&\s?"'`#]{1,2048}\?(?:(?!(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=)[^&\s#"'`]{1,256}&){0,32}(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=[^&\s#"'`]{1,4096})/g
|
|
16034
16051
|
},
|
|
16035
16052
|
{ type: "mysql_uri", regex: /mysql:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
16036
|
-
{ type: "redis_uri", regex: /redis:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g }
|
|
16053
|
+
{ type: "redis_uri", regex: /redis:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
16054
|
+
{
|
|
16055
|
+
// Credentials serialised as JSON, keyed rather than prefixed. Every other
|
|
16056
|
+
// entry in this table recognises a credential by its SHAPE (`ghp_`, `sk-`,
|
|
16057
|
+
// `eyJ`), which means a key with no distinctive prefix — Azure, a
|
|
16058
|
+
// self-hosted gateway, an Anthropic/Codex OAuth token — was invisible to
|
|
16059
|
+
// both surfaces. `prompt-firewall` guards the outgoing provider request, so
|
|
16060
|
+
// this is what stops a JSON-shaped tool result carrying such a value to a
|
|
16061
|
+
// third party.
|
|
16062
|
+
//
|
|
16063
|
+
// The key is matched in a LOOKBEHIND, so the reported match is the secret
|
|
16064
|
+
// itself and the pattern keeps zero capturing groups — `secret-scanner`
|
|
16065
|
+
// maps a combined-regex group index back to the pattern that fired, and an
|
|
16066
|
+
// inner group would shift that mapping (see the style note above, enforced
|
|
16067
|
+
// by credential-pattern-parity.test.ts).
|
|
16068
|
+
//
|
|
16069
|
+
// Mirrors `json_credential_key` in
|
|
16070
|
+
// `@wrongstack/core` → `src/security/secret-scrubber.ts`. Keep the two key
|
|
16071
|
+
// lists in step; the core side additionally preserves the key name when it
|
|
16072
|
+
// rewrites, which is why it is written with capture groups instead.
|
|
16073
|
+
type: "json_credential_key",
|
|
16074
|
+
regex: /(?<="[A-Za-z0-9_]{0,64}(?:apiKey|api_key|token|secret|password|authorization|bearer|private_key|access_token|refresh_token|client_secret)"\s{0,8}:\s{0,8}")[^"\\]{8,512}(?=")/gi
|
|
16075
|
+
}
|
|
16037
16076
|
];
|
|
16038
16077
|
function cloneCredentialPatterns() {
|
|
16039
16078
|
return CREDENTIAL_PATTERNS.map((p) => ({
|