openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
2,037 lines • 74 kB
JavaScript
import { c as normalizeOptionalLowercaseString, l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { y as uniqueStrings } from "./string-normalization-DsCfAx8q.js";
import { t as parseInlineOptionToken } from "./inline-option-token-Dqt7rKG4.js";
import { t as expandHomePrefix } from "./home-dir-BPhrG-aM.js";
import { a as validateSafeBinArgv, c as DEFAULT_SAFE_BINS, l as SAFE_BIN_PROFILES, n as isTrustedSafeBinPath } from "./exec-safe-bin-trust-BL7TeFlZ.js";
import { _ as resolvePolicyTargetResolution, d as resolveExecutableTrustPath, f as resolveExecutionTargetCandidatePath, g as resolvePolicyTargetCandidatePath, i as matchAllowlist, m as resolveExecutionTargetTrustPath, p as resolveExecutionTargetResolution, t as buildCwdBoundHashedArgPattern, u as resolveCommandResolutionFromArgv, v as resolvePolicyTargetTrustPath, y as resolveExecWrapperTrustPlan } from "./exec-command-resolution-B6e6Gzk8.js";
import { E as unwrapDispatchWrappersForResolution, N as normalizeExecutableToken, S as resolvePowerShellInlineCommandMatch, T as resolveDispatchWrapperTrustPlan, _ as hasPosixLoginStartupBeforeInlineCommand, g as hasPosixInteractiveStartupBeforeInlineCommand, h as advancePosixInlineOptionScan, i as extractBindableShellWrapperInlineCommand, l as isShellWrapperExecutable, m as POSIX_INLINE_COMMAND_FLAGS, n as POSIX_SHELL_WRAPPERS, r as POWERSHELL_WRAPPERS, t as POSIX_PARSEABLE_SHELL_WRAPPERS, v as isDirectShellPositionalCarrierCommand, w as isDispatchWrapperExecutable, x as resolveInlineCommandMatch, y as isPowerShellInlineFileCommandFlag } from "./shell-wrapper-resolution-CIQIf-gP.js";
import { a as isWindowsPlatform, i as analyzeWindowsShellCommand } from "./exec-approvals-analysis-CaqIBAfQ.js";
import "./exec-wrapper-resolution-eTidWVtU.js";
import { o as detectInlineEvalArgv, u as isInterpreterLikeAllowlistPattern } from "./risks-CTJz9z0K.js";
import { n as explainShellCommand } from "./extract-rgReYDDg.js";
import path from "node:path";
//#region src/infra/exec-authorization-plan.ts
const POSIX_SHELL_NAMES = new Set(POSIX_PARSEABLE_SHELL_WRAPPERS);
const PROMPT_ONLY_RISKS = /* @__PURE__ */ new Set([
"eval",
"source",
"alias",
"shell-wrapper-through-carrier",
"command-carrier"
]);
const NON_REUSABLE_RISKS = /* @__PURE__ */ new Set(["inline-eval"]);
const UNANALYZABLE_RISKS = /* @__PURE__ */ new Set([
"command-substitution",
"dynamic-executable",
"line-continuation",
"heredoc",
"here-string",
"process-substitution",
"redirect",
"syntax-error",
"function-definition"
]);
const POWERSHELL_NAMES = /* @__PURE__ */ new Set(["powershell", "pwsh"]);
const WINDOWS_CMD_NAMES = /* @__PURE__ */ new Set(["cmd", "cmd.exe"]);
const POSITIONAL_CARRIER_BLOCKED_EXECUTABLES = /* @__PURE__ */ new Set(["find", "xargs"]);
const SHELL_WRAPPER_PRELUDE_REASON = "shell-env-assignment";
const UNSUPPORTED_DIRECT_SHELL_TOPOLOGY_SHAPES = /* @__PURE__ */ new Set([
"background",
"if",
"for",
"while",
"case",
"subshell",
"group"
]);
function normalizePlanningPlatform(platform) {
switch (platform) {
case "aix":
case "android":
case "cygwin":
case "darwin":
case "freebsd":
case "haiku":
case "linux":
case "netbsd":
case "openbsd":
case "sunos":
case "win32": return platform;
default: return;
}
}
function commandSegmentFromStep(step, context) {
return {
raw: step.text,
argv: step.argv,
resolution: resolveCommandResolutionFromArgv(step.argv, context.cwd, context.env, context.platform)
};
}
function commandSegmentFromArgv(argv, context, sourceArgv) {
return {
raw: argv.join(" "),
argv,
sourceArgv,
resolution: resolveCommandResolutionFromArgv(argv, context.cwd, context.env, context.platform)
};
}
function authorizationOperatorForTopology(operator) {
switch (operator.kind) {
case "and": return "&&";
case "or": return "||";
case "pipe":
case "stderr-pipe": return "pipe";
case "sequence":
case "newline-sequence": return ";";
case "background": return "&";
default: return operator.kind;
}
}
function riskInsideStep(risk, step) {
return risk.span.startIndex >= step.span.startIndex && risk.span.endIndex <= step.span.endIndex;
}
function riskBeforeStepExecutable(risk, step) {
return riskInsideStep(risk, step) && risk.span.endIndex <= step.executableSpan.startIndex;
}
function stepReasons(step, risks) {
const reasons = [];
for (const risk of risks) if (PROMPT_ONLY_RISKS.has(risk.kind) && riskInsideStep(risk, step)) reasons.push(risk.kind);
return uniqueStrings(reasons);
}
function nonReusableStepReasons(step, risks) {
const reasons = [];
for (const risk of risks) if (NON_REUSABLE_RISKS.has(risk.kind) && riskInsideStep(risk, step)) reasons.push(risk.kind);
return uniqueStrings(reasons);
}
function isShellExpansionDynamicArgument(risk) {
return risk.kind === "dynamic-argument" && /(?:\$[A-Za-z0-9_@*?#$!-]|\$\{|`|\$\(|[<>]\()/u.test(risk.text);
}
function riskInsidePromptOnlyStep(risk, explanation) {
return [...explanation.topLevelCommands, ...explanation.nestedCommands].some((step) => riskInsideStep(risk, step) && stepReasons(step, explanation.risks).length > 0);
}
function findUnanalyzableRisk(explanation) {
return explanation.risks.find((entry) => UNANALYZABLE_RISKS.has(entry.kind)) ?? null;
}
function hasBlockingRisk(explanation) {
const risk = findUnanalyzableRisk(explanation);
if (risk) return risk.kind;
const unsupportedShape = explanation.shapes.find((shape) => UNSUPPORTED_DIRECT_SHELL_TOPOLOGY_SHAPES.has(shape));
if (unsupportedShape) return unsupportedShape;
const dynamicArgument = explanation.risks.find((entry) => isShellExpansionDynamicArgument(entry) && !riskInsidePromptOnlyStep(entry, explanation));
if (dynamicArgument) return dynamicArgument.kind;
return null;
}
function shellWrapperPreludeReasons(params) {
const reasons = params.risks.filter((risk) => UNANALYZABLE_RISKS.has(risk.kind) && riskBeforeStepExecutable(risk, params.step)).map((risk) => risk.kind);
return uniqueStrings(reasons);
}
function isPathScopedExecutableToken$1(token) {
return token.includes("/") || token.includes("\\");
}
function hasResolvedExecutionPath(segment) {
const execution = segment.resolution?.execution;
return Boolean(execution?.resolvedPath?.trim() || execution?.resolvedRealPath?.trim());
}
function isUnresolvedPathScopedExecutable(segment) {
return isPathScopedExecutableToken$1(segment.argv[0]?.trim() ?? "") && !hasResolvedExecutionPath(segment);
}
function canUseReusableWrapperPayloadCandidates(segments) {
if (!(segments[0]?.argv[0]?.trim() ?? "")) return false;
if (segments.some((segment) => isPathScopedExecutableToken$1(segment.argv[0]?.trim() ?? ""))) return false;
return !segments.some((segment) => normalizeExecutableToken(segment.argv[0] ?? "").endsWith("-wrapper"));
}
function isShellExecutable(argv) {
const executable = normalizeExecutableToken(argv[0] ?? "");
return POSIX_SHELL_NAMES.has(executable);
}
function canUseWrapperShellInvocation(segment) {
const argv = segment.argv;
if (isPathScopedExecutableToken$1(argv[0]?.trim() ?? "")) return false;
return isShellExecutable(argv) && !hasPosixInteractiveStartupBeforeInlineCommand(argv, POSIX_INLINE_COMMAND_FLAGS) && !hasPosixLoginStartupBeforeInlineCommand(argv, POSIX_INLINE_COMMAND_FLAGS);
}
function wrapperPrefixForStep(step) {
const executableStart = Math.max(0, step.executableSpan.startIndex - step.span.startIndex);
return step.text.slice(0, executableStart);
}
function hasCommandPrelude(step) {
return /^[A-Za-z_][A-Za-z0-9_]*=/u.test(wrapperPrefixForStep(step).trimStart());
}
function positionalCarrierSteps(params) {
const inlineMatch = resolveInlineCommandMatch(params.wrapper.segment.argv, POSIX_INLINE_COMMAND_FLAGS, { allowCombinedC: true });
if (inlineMatch.valueTokenIndex === null || !inlineMatch.command) return null;
if (!canUseWrapperShellInvocation(params.wrapper.segment)) return null;
if (!isDirectShellPositionalCarrierCommand(inlineMatch.command)) return null;
const carriedArgv = params.wrapper.segment.argv.slice(inlineMatch.valueTokenIndex + 1).filter((token) => token.trim().length > 0);
if (carriedArgv.length === 0) return null;
const carriedName = normalizeExecutableToken(carriedArgv[0] ?? "");
if (isDispatchWrapperExecutable(carriedName) || POSITIONAL_CARRIER_BLOCKED_EXECUTABLES.has(carriedName) || POSIX_SHELL_NAMES.has(carriedName) || carriedName.endsWith("-wrapper")) return null;
const raw = carriedArgv.join(" ");
const carriedSpan = {
startIndex: params.wrapper.step.span.endIndex,
endIndex: params.wrapper.step.span.endIndex,
startPosition: params.wrapper.step.span.endPosition,
endPosition: params.wrapper.step.span.endPosition
};
return [{
step: {
context: "wrapper-payload",
executable: carriedArgv[0] ?? "",
argv: carriedArgv,
text: raw,
span: carriedSpan,
executableSpan: carriedSpan
},
segment: commandSegmentFromArgv(carriedArgv, params.context, params.wrapper.segment.sourceArgv)
}];
}
function shouldPersistCandidate(params) {
if (params.trustMode !== "executable") return false;
if (params.relationship === "pipeline" && isShellExecutable(params.segment.argv)) return false;
return params.segment.resolution?.policyBlocked !== true;
}
function createCandidate(params) {
const isDirectShellWrapper = params.transport.kind === "direct" && extractBindableShellWrapperInlineCommand(params.segment.argv);
const stepPromptReasons = stepReasons(params.step, params.risks);
const stepNonReusableReasons = nonReusableStepReasons(params.step, params.risks);
const preludeReasons = hasCommandPrelude(params.step) ? shellWrapperPreludeReasons({
step: params.step,
risks: params.risks
}) : [];
if (hasCommandPrelude(params.step) && preludeReasons.length === 0) preludeReasons.push(SHELL_WRAPPER_PRELUDE_REASON);
const reasons = uniqueStrings([
...stepPromptReasons,
...stepNonReusableReasons,
...preludeReasons
]);
const trustMode = params.segment.resolution?.policyBlocked === true ? "prompt-only" : preludeReasons.length > 0 ? "prompt-only" : isDirectShellWrapper ? "exact-command" : stepPromptReasons.length > 0 ? "prompt-only" : "executable";
return {
sourceSegment: params.segment,
sourceStep: params.step,
...params.step.id ? { sourceStepId: params.step.id } : {},
transport: params.transport,
trustMode,
allowAlways: stepNonReusableReasons.length === 0 && shouldPersistCandidate({
segment: params.segment,
relationship: params.relationship,
trustMode
}),
reasons
};
}
function finalizeGroup(params) {
const relationship = params.steps.length > 1 ? "pipeline" : params.relationship;
return {
opToNext: params.opToNext,
candidates: params.steps.map((entry) => createCandidate({
step: entry.step,
segment: entry.segment,
relationship,
transport: params.transport,
risks: params.risks
}))
};
}
function groupsFromSteps(params) {
const sorted = params.steps.toSorted((left, right) => left.step.span.startIndex - right.step.span.startIndex);
const groups = [];
let current = [];
const operatorByFromCommandId = /* @__PURE__ */ new Map();
for (const operator of params.operators ?? []) operatorByFromCommandId.set(operator.fromCommandId, authorizationOperatorForTopology(operator));
if (sorted.length > 1 && operatorByFromCommandId.size === 0) return [finalizeGroup({
steps: sorted,
relationship: "pipeline",
opToNext: null,
transport: params.transport,
risks: params.risks
})];
for (const entry of sorted) {
if (current.length === 0) {
current = [entry];
continue;
}
const previous = current[current.length - 1];
if (!previous) {
current = [entry];
continue;
}
const previousCommandId = previous.step.id;
const operator = previousCommandId ? operatorByFromCommandId.get(previousCommandId) : void 0;
if (operator === "pipe") {
current.push(entry);
continue;
}
const opToNext = operator === "&&" || operator === "||" || operator === ";" || operator === "&" ? operator : ";";
groups.push(finalizeGroup({
steps: current,
relationship: "simple",
opToNext,
transport: params.transport,
risks: params.risks
}));
current = [entry];
}
if (current.length > 0) groups.push(finalizeGroup({
steps: current,
relationship: "simple",
opToNext: null,
transport: params.transport,
risks: params.risks
}));
return groups;
}
function shellWrapperRiskForStep(step, risks) {
return risks.find((entry) => entry.kind === "shell-wrapper" && riskInsideStep(entry, step)) ?? null;
}
function shouldUseWrapperPayload(params) {
if (params.topLevelSteps.length !== 1 || params.nestedSteps.length === 0) return false;
const wrapperStep = params.topLevelSteps[0]?.step;
if (!wrapperStep || !shellWrapperRiskForStep(wrapperStep, params.risks)) return false;
return canUseReusableWrapperPayloadCandidates((params.wrapperCommandId ? params.nestedSteps.filter((entry) => entry.step.parentCommandId === params.wrapperCommandId) : params.nestedSteps).map((entry) => entry.segment));
}
function applyWrapperPayloadPersistenceBoundary(params) {
if (!isUnresolvedPathScopedExecutable(params.wrapper.segment)) return params.groups;
return params.groups.map((group) => ({
...group,
candidates: group.candidates.map((candidate) => ({
...candidate,
allowAlways: false
}))
}));
}
function wrapperPayloadPlan(params) {
const wrapper = params.topLevelSteps[0];
if (!wrapper) return null;
const wrapperRisk = shellWrapperRiskForStep(wrapper.step, params.risks);
if (!wrapperRisk) return null;
if (hasCommandPrelude(wrapper.step)) return null;
if (!canUseWrapperShellInvocation(wrapper.segment)) return null;
if (!params.allowNestedPayload) return null;
const carriedSteps = positionalCarrierSteps({
wrapper,
context: params.context
});
if (carriedSteps) {
const groups = groupsFromSteps({
steps: carriedSteps,
transport: {
kind: "shell-wrapper",
wrapperSegment: wrapper.segment,
wrapperArgv: wrapper.segment.argv,
wrapperPrefix: wrapperPrefixForStep(wrapper.step),
inlineCommand: wrapperRisk.payload
},
risks: params.risks
});
return groups.length > 0 ? applyWrapperPayloadPersistenceBoundary({
wrapper,
groups
}) : null;
}
if (!shouldUseWrapperPayload({
wrapperCommandId: wrapper.step.id,
topLevelSteps: params.topLevelSteps,
nestedSteps: params.nestedSteps,
risks: params.risks
})) return null;
const transport = {
kind: "shell-wrapper",
wrapperSegment: wrapper.segment,
wrapperArgv: wrapper.segment.argv,
wrapperPrefix: wrapperPrefixForStep(wrapper.step),
inlineCommand: wrapperRisk.payload
};
const groups = groupsFromSteps({
steps: wrapper.step.id ? params.nestedSteps.filter((entry) => entry.step.parentCommandId === wrapper.step.id) : params.nestedSteps,
operators: wrapper.step.id ? params.operators.filter((operator) => operator.parentCommandId === wrapper.step.id) : params.operators,
transport,
risks: params.risks
});
return groups.length > 0 ? applyWrapperPayloadPersistenceBoundary({
wrapper,
groups
}) : null;
}
function dialectForArgv(argv) {
const executable = normalizeExecutableToken(argv[0] ?? "");
if (POWERSHELL_NAMES.has(executable)) return "powershell";
if (WINDOWS_CMD_NAMES.has(executable)) return "windows-cmd";
return "argv";
}
function unanalyzablePlan(params) {
return {
ok: false,
dialect: params.dialect,
originalCommand: params.command,
reason: params.reason,
groups: [],
operators: []
};
}
function planFromExplanation(params) {
const topLevelSteps = params.explanation.topLevelCommands.map((step) => ({
step,
segment: commandSegmentFromStep(step, params.context)
}));
const nestedSteps = params.explanation.nestedCommands.filter((step) => step.context === "wrapper-payload").map((step) => ({
step,
segment: commandSegmentFromStep(step, params.context)
}));
const blockingRisk = hasBlockingRisk(params.explanation);
const unanalyzableRisk = findUnanalyzableRisk(params.explanation);
const topLevelStep = topLevelSteps[0]?.step;
const canFallBackToExactWrapper = topLevelSteps.length === 1 && Boolean(topLevelStep && shellWrapperRiskForStep(topLevelStep, params.explanation.risks) && (!unanalyzableRisk || riskInsideStep(unanalyzableRisk, topLevelStep)));
if (!params.explanation.ok || blockingRisk && !canFallBackToExactWrapper) return unanalyzablePlan({
dialect: "posix-shell",
command: params.command,
reason: blockingRisk ?? "unable to parse command"
});
const groups = wrapperPayloadPlan({
context: params.context,
allowNestedPayload: !blockingRisk && !params.explanation.shapes.some((shape) => UNSUPPORTED_DIRECT_SHELL_TOPOLOGY_SHAPES.has(shape)),
topLevelSteps,
nestedSteps,
operators: params.explanation.operators ?? [],
risks: params.explanation.risks
}) ?? groupsFromSteps({
steps: topLevelSteps,
operators: (params.explanation.operators ?? []).filter((operator) => operator.parentCommandId === void 0),
transport: { kind: "direct" },
risks: params.explanation.risks
});
if (groups.length === 0) return unanalyzablePlan({
dialect: "posix-shell",
command: params.command,
reason: "no commands to authorize"
});
return {
ok: true,
dialect: "posix-shell",
originalCommand: params.command,
groups,
operators: params.explanation.operators ?? []
};
}
async function planShellAuthorization(params) {
if (params.platform === "win32") return unanalyzablePlan({
dialect: "windows-cmd",
command: params.command,
reason: "non-POSIX shell command"
});
try {
const explanation = await explainShellCommand(params.command);
return planFromExplanation({
command: params.command,
explanation,
context: {
cwd: params.cwd,
env: params.env,
platform: normalizePlanningPlatform(params.platform)
}
});
} catch (error) {
return unanalyzablePlan({
dialect: "posix-shell",
command: params.command,
reason: error instanceof Error ? error.message : "unable to parse command"
});
}
}
async function planExecAuthorization(params) {
const command = params.command ?? params.analysis.segments.map((segment) => segment.raw).join(params.analysis.chains ? " && " : " | ");
if (!params.analysis.ok) return unanalyzablePlan({
dialect: "argv",
command,
reason: params.analysis.reason ?? "unable to parse command"
});
const argv = params.analysis.segments[0]?.argv ?? [];
const dialect = dialectForArgv(argv);
if (dialect !== "argv") return unanalyzablePlan({
dialect,
command,
reason: "non-POSIX command wrapper"
});
if (params.analysis.segments.length === 1) {
const wrapperSegment = params.analysis.segments[0];
const inlineCommand = extractBindableShellWrapperInlineCommand(argv);
if (inlineCommand && wrapperSegment && canUseWrapperShellInvocation(wrapperSegment)) {
const shellPlan = await planShellAuthorization({
command: inlineCommand,
cwd: params.cwd,
env: params.env,
platform: params.platform
});
if (shellPlan.ok) {
const nestedSegments = shellPlan.groups.flatMap((group) => group.candidates.map((candidate) => candidate.sourceSegment));
if (wrapperSegment && canUseReusableWrapperPayloadCandidates(nestedSegments)) {
const persistNestedPayloads = !isUnresolvedPathScopedExecutable(wrapperSegment);
return {
ok: true,
dialect: "argv",
originalCommand: command,
groups: shellPlan.groups.map((group) => ({
...group,
candidates: group.candidates.map((candidate) => {
const transport = {
kind: "shell-wrapper",
wrapperSegment,
wrapperArgv: wrapperSegment.argv,
wrapperPrefix: "",
inlineCommand
};
return {
...candidate,
transport,
allowAlways: persistNestedPayloads ? candidate.allowAlways : false
};
})
})),
operators: shellPlan.operators
};
}
}
}
}
return {
ok: true,
dialect: "argv",
originalCommand: command,
groups: groupsFromSteps({
steps: params.analysis.segments.map((segment, index) => ({
step: {
context: "top-level",
executable: segment.argv[0] ?? "",
argv: segment.argv,
text: segment.raw,
span: {
startIndex: index,
endIndex: index + segment.raw.length,
startPosition: {
row: 0,
column: index
},
endPosition: {
row: 0,
column: index + segment.raw.length
}
},
executableSpan: {
startIndex: index,
endIndex: index + (segment.argv[0]?.length ?? 0),
startPosition: {
row: 0,
column: index
},
endPosition: {
row: 0,
column: index + (segment.argv[0]?.length ?? 0)
}
}
},
segment: segment.resolution === null ? commandSegmentFromArgv(segment.argv, {
cwd: params.cwd,
env: params.env,
platform: normalizePlanningPlatform(params.platform)
}, segment.sourceArgv) : segment
})),
transport: { kind: "direct" },
risks: []
}),
operators: []
};
}
//#endregion
//#region src/infra/exec-safe-builtins.ts
const DEFAULT_SAFE_BUILTINS = /* @__PURE__ */ new Set([
":",
"cd",
"false",
"pwd",
"test",
"true"
]);
/** Returns true when a parsed POSIX shell segment is one of the closed safe builtin forms. */
function isSafeBuiltinSegment(params) {
if (isWindowsPlatform(params.platform ?? process.platform)) return false;
const head = params.segment.argv[0]?.trim().toLowerCase();
if (!head) return false;
if (head === "[") return params.segment.argv.at(-1) === "]" || params.segment.raw.trim().endsWith("]");
return DEFAULT_SAFE_BUILTINS.has(head);
}
//#endregion
//#region src/infra/package-manager-exec-wrapper.ts
const NPM_EXEC_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
"--cache",
"--loglevel",
"--package",
"--prefix",
"--script-shell",
"--userconfig",
"--workspace",
"-p",
"-w"
]);
const NPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
"--cache",
"--package",
"--prefix",
"--script-shell",
"--userconfig",
"--workspace",
"-p",
"-w"
]);
const NPM_EXEC_FLAG_OPTIONS = /* @__PURE__ */ new Set([
"--no",
"--quiet",
"--ws",
"--workspaces",
"--yes",
"-q",
"-y"
]);
const NPM_EXEC_SUBCOMMANDS = /* @__PURE__ */ new Set(["exec", "x"]);
const PNPM_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
"--config",
"--dir",
"--filter",
"--reporter",
"--stream",
"--test-pattern",
"--workspace-concurrency"
]);
const PNPM_CASE_SENSITIVE_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set(["-C"]);
const PNPM_FLAG_OPTIONS = /* @__PURE__ */ new Set([
"--aggregate-output",
"--color",
"--parallel",
"--recursive",
"--silent",
"--workspace-root",
"-r",
"-s",
"-w"
]);
const PNPM_DLX_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
"--allow-build",
"--package",
"-p"
]);
const PNPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
"--allow-build",
"--config",
"--dir",
"--filter",
"--package",
"-p"
]);
const PNPM_EXEC_SUBCOMMANDS = /* @__PURE__ */ new Set([
"exec",
"dlx",
"node"
]);
const PNPM_SCRIPT_RUN_SUBCOMMANDS = /* @__PURE__ */ new Set([
"restart",
"run",
"start",
"stop",
"test"
]);
const PNPM_BUILTIN_NON_EXEC_SUBCOMMANDS = /* @__PURE__ */ new Set([
"add",
"audit",
"bin",
"config",
"dedupe",
"deploy",
"help",
"import",
"init",
"install",
"licenses",
"link",
"list",
"outdated",
"patch",
"prune",
"publish",
"rebuild",
"remove",
"root",
"server",
"store",
"unlink",
"update",
"view",
"why"
]);
const YARN_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set(["--cwd"]);
const YARN_FLAG_OPTIONS = /* @__PURE__ */ new Set([
"--immutable",
"--silent",
"-s"
]);
const YARN_DLX_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set(["--package", "-p"]);
const YARN_DLX_FLAG_OPTIONS = /* @__PURE__ */ new Set(["--quiet", "-q"]);
const YARN_EXEC_SUBCOMMANDS = /* @__PURE__ */ new Set(["exec", "dlx"]);
const YARN_BUILTIN_NON_EXEC_SUBCOMMANDS = /* @__PURE__ */ new Set([
"add",
"audit",
"autoclean",
"bin",
"cache",
"check",
"config",
"create",
"dedupe",
"generate-lock-entry",
"global",
"help",
"import",
"info",
"init",
"install",
"licenses",
"link",
"list",
"login",
"logout",
"outdated",
"owner",
"pack",
"policies",
"prune",
"publish",
"remove",
"self-update",
"tag",
"team",
"unlink",
"upgrade",
"upgrade-interactive",
"version",
"versions",
"why",
"workspace"
]);
function normalizeOptionFlag(token) {
return normalizeLowercaseStringOrEmpty(parseInlineOptionToken(token).name);
}
function findFirstNonOptionIndex(argv, startIdx, params) {
let idx = startIdx;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
idx += 1;
continue;
}
if (!token.startsWith("-")) return idx;
const parsedOption = parseInlineOptionToken(token);
if (params.caseSensitiveOptionsWithValue?.has(parsedOption.name)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
const flag = normalizeLowercaseStringOrEmpty(parsedOption.name);
if (params.optionsWithValue.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (params.flagOptions.has(flag)) {
idx += 1;
continue;
}
return null;
}
return null;
}
function hasLeadingContextOption(argv, startIdx, params) {
let idx = startIdx;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
idx += 1;
continue;
}
if (!token.startsWith("-")) return false;
const parsedOption = parseInlineOptionToken(token);
const flag = normalizeLowercaseStringOrEmpty(parsedOption.name);
if (params.contextCaseSensitiveOptionsWithValue?.has(parsedOption.name) || params.contextOptionsWithValue.has(flag) || params.contextFlagOptions?.has(flag)) return true;
if (params.caseSensitiveOptionsWithValue?.has(parsedOption.name)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (params.optionsWithValue.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (params.flagOptions.has(flag)) {
idx += 1;
continue;
}
return false;
}
return false;
}
function hasContextOptionBeforeTerminator(argv, startIdx, params) {
let idx = startIdx;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") return false;
if (!token.startsWith("-")) {
idx += 1;
continue;
}
const parsedOption = parseInlineOptionToken(token);
const flag = normalizeLowercaseStringOrEmpty(parsedOption.name);
if (params.contextCaseSensitiveOptionsWithValue?.has(parsedOption.name) || params.contextOptionsWithValue.has(flag) || params.contextFlagOptions?.has(flag)) return true;
if (params.caseSensitiveOptionsWithValue?.has(parsedOption.name)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (params.optionsWithValue.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (params.flagOptions.has(flag)) {
idx += 1;
continue;
}
idx += 1;
}
return false;
}
function hasKnownPackageManagerExecContextOptions(argv) {
switch (normalizePackageManagerExecToken(argv[0] ?? "")) {
case "npm": {
const leadingOptions = {
optionsWithValue: NPM_EXEC_OPTIONS_WITH_VALUE,
caseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
flagOptions: NPM_EXEC_FLAG_OPTIONS
};
if (hasLeadingContextOption(argv, 1, {
...leadingOptions,
contextOptionsWithValue: NPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE,
contextCaseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
contextFlagOptions: /* @__PURE__ */ new Set(["--ws", "--workspaces"])
})) return true;
const subcommandIdx = findFirstNonOptionIndex(argv, 1, leadingOptions);
return subcommandIdx !== null && NPM_EXEC_SUBCOMMANDS.has(argv[subcommandIdx] ?? "") ? hasContextOptionBeforeTerminator(argv, subcommandIdx + 1, {
optionsWithValue: NPM_EXEC_OPTIONS_WITH_VALUE,
caseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
flagOptions: NPM_EXEC_FLAG_OPTIONS,
contextOptionsWithValue: NPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE,
contextCaseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
contextFlagOptions: /* @__PURE__ */ new Set(["--ws", "--workspaces"])
}) : false;
}
case "npx":
case "bunx": return hasLeadingContextOption(argv, 1, {
optionsWithValue: NPM_EXEC_OPTIONS_WITH_VALUE,
caseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
flagOptions: NPM_EXEC_FLAG_OPTIONS,
contextOptionsWithValue: NPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE,
contextCaseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
contextFlagOptions: /* @__PURE__ */ new Set(["--ws", "--workspaces"])
});
case "pnpm": {
const leadingOptions = {
optionsWithValue: /* @__PURE__ */ new Set([...PNPM_OPTIONS_WITH_VALUE, ...PNPM_DLX_OPTIONS_WITH_VALUE]),
caseSensitiveOptionsWithValue: PNPM_CASE_SENSITIVE_OPTIONS_WITH_VALUE,
flagOptions: PNPM_FLAG_OPTIONS
};
if (hasLeadingContextOption(argv, 1, {
...leadingOptions,
contextOptionsWithValue: PNPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE,
contextCaseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
contextFlagOptions: /* @__PURE__ */ new Set([
"--recursive",
"--workspace-root",
"-r",
"-w"
])
})) return true;
const subcommandIdx = findFirstNonOptionIndex(argv, 1, leadingOptions);
return argv[subcommandIdx ?? -1] === "dlx" ? hasLeadingContextOption(argv, (subcommandIdx ?? 0) + 1, {
...leadingOptions,
contextOptionsWithValue: PNPM_EXEC_CONTEXT_OPTIONS_WITH_VALUE,
contextCaseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
contextFlagOptions: /* @__PURE__ */ new Set([
"--recursive",
"--workspace-root",
"-r",
"-w"
])
}) : false;
}
case "yarn": {
const leadingOptions = {
optionsWithValue: /* @__PURE__ */ new Set([...YARN_OPTIONS_WITH_VALUE, ...YARN_DLX_OPTIONS_WITH_VALUE]),
flagOptions: /* @__PURE__ */ new Set([...YARN_FLAG_OPTIONS, ...YARN_DLX_FLAG_OPTIONS])
};
if (hasLeadingContextOption(argv, 1, {
...leadingOptions,
contextOptionsWithValue: /* @__PURE__ */ new Set(["--cwd"])
})) return true;
const subcommandIdx = findFirstNonOptionIndex(argv, 1, leadingOptions);
return argv[subcommandIdx ?? -1] === "dlx" ? hasLeadingContextOption(argv, (subcommandIdx ?? 0) + 1, {
optionsWithValue: YARN_DLX_OPTIONS_WITH_VALUE,
flagOptions: YARN_DLX_FLAG_OPTIONS,
contextOptionsWithValue: /* @__PURE__ */ new Set(["--package", "-p"])
}) : false;
}
default: return false;
}
}
function containsSubcommandToken(argv, subcommands) {
return argv.some((token) => subcommands.has(normalizeLowercaseStringOrEmpty(token)));
}
function normalizePackageManagerExecToken(token) {
return normalizeExecutableToken(token).replace(/\.(?:c|m)?js$/i, "");
}
function firstSubcommandAfterOptions(argv, params) {
const idx = findFirstNonOptionIndex(argv, 1, params);
return idx === null ? null : normalizeLowercaseStringOrEmpty(argv[idx] ?? "");
}
function unwrapPnpmExecInvocation(argv) {
let idx = 1;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
idx += 1;
continue;
}
if (!token.startsWith("-")) {
if (token === "exec") {
if (idx + 1 >= argv.length) return null;
const tail = argv.slice(idx + 1);
const normalizedTail = tail[0] === "--" ? tail.slice(1) : tail;
const firstExecArg = normalizeOptionFlag(normalizedTail[0] ?? "");
if (firstExecArg === "-c" || firstExecArg === "--shell-mode") return null;
return normalizedTail.length > 0 ? normalizedTail : null;
}
if (token === "dlx") return unwrapPnpmDlxInvocation(argv.slice(idx + 1));
if (token === "node") {
const tail = argv.slice(idx + 1);
return ["node", ...tail[0] === "--" ? tail.slice(1) : tail];
}
return null;
}
const parsedOption = parseInlineOptionToken(token);
const flag = normalizeLowercaseStringOrEmpty(parsedOption.name);
if (PNPM_OPTIONS_WITH_VALUE.has(flag) || PNPM_DLX_OPTIONS_WITH_VALUE.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (PNPM_CASE_SENSITIVE_OPTIONS_WITH_VALUE.has(parsedOption.name)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (PNPM_FLAG_OPTIONS.has(flag)) {
idx += 1;
continue;
}
return null;
}
return null;
}
function unwrapPnpmDlxInvocation(argv) {
let idx = 0;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
const tail = argv.slice(idx + 1);
return tail.length > 0 ? tail : null;
}
if (!token.startsWith("-")) return argv.slice(idx);
const parsedOption = parseInlineOptionToken(token);
const flag = normalizeLowercaseStringOrEmpty(parsedOption.name);
if (flag === "-c" || flag === "--shell-mode") return null;
if (PNPM_OPTIONS_WITH_VALUE.has(flag) || PNPM_DLX_OPTIONS_WITH_VALUE.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (PNPM_CASE_SENSITIVE_OPTIONS_WITH_VALUE.has(parsedOption.name)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (PNPM_FLAG_OPTIONS.has(flag)) {
idx += 1;
continue;
}
return null;
}
return null;
}
function unwrapDirectPackageExecInvocation(argv) {
let idx = 1;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (!token.startsWith("-")) return argv.slice(idx);
const flag = normalizeOptionFlag(token);
if (flag === "-c" || flag === "--call") return null;
if (NPM_EXEC_OPTIONS_WITH_VALUE.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (NPM_EXEC_FLAG_OPTIONS.has(flag)) {
idx += 1;
continue;
}
return null;
}
return null;
}
function unwrapNpmExecInvocation(argv) {
let idx = 1;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (!token.startsWith("-")) {
if (!NPM_EXEC_SUBCOMMANDS.has(token)) return null;
idx += 1;
break;
}
const parsedOption = parseInlineOptionToken(token);
const flag = normalizeLowercaseStringOrEmpty(parsedOption.name);
if (NPM_EXEC_OPTIONS_WITH_VALUE.has(flag) || parsedOption.name === "-C") {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (NPM_EXEC_FLAG_OPTIONS.has(flag)) {
idx += 1;
continue;
}
return null;
}
if (idx >= argv.length) return null;
const tail = argv.slice(idx);
if (tail[0] === "--") return tail.length > 1 ? tail.slice(1) : null;
return unwrapDirectPackageExecInvocation(["npx", ...tail]);
}
function unwrapYarnDlxInvocation(argv) {
let idx = 0;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
const tail = argv.slice(idx + 1);
return tail.length > 0 ? tail : null;
}
if (!token.startsWith("-")) return argv.slice(idx);
const flag = normalizeOptionFlag(token);
if (YARN_DLX_OPTIONS_WITH_VALUE.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (YARN_DLX_FLAG_OPTIONS.has(flag)) {
idx += 1;
continue;
}
return null;
}
return null;
}
function unwrapYarnExecInvocation(argv) {
let idx = 1;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
idx += 1;
continue;
}
if (!token.startsWith("-")) {
if (token === "exec") {
const tail = argv.slice(idx + 1);
const normalizedTail = tail[0] === "--" ? tail.slice(1) : tail;
return normalizedTail.length > 0 ? normalizedTail : null;
}
if (token === "dlx") return unwrapYarnDlxInvocation(argv.slice(idx + 1));
return null;
}
const flag = normalizeOptionFlag(token);
if (YARN_OPTIONS_WITH_VALUE.has(flag)) {
idx += token.includes("=") ? 1 : 2;
continue;
}
if (YARN_FLAG_OPTIONS.has(flag)) {
idx += 1;
continue;
}
return null;
}
return null;
}
function unwrapKnownPackageManagerExecInvocation(argv) {
const resolution = resolveKnownPackageManagerExecInvocation(argv);
return resolution.kind === "unwrapped" ? resolution.argv : null;
}
function resolveKnownPackageManagerExecInvocation(argv) {
switch (normalizePackageManagerExecToken(argv[0] ?? "")) {
case "npm": {
const unwrapped = unwrapNpmExecInvocation(argv);
if (unwrapped) return {
kind: "unwrapped",
argv: unwrapped
};
const firstSubcommand = firstSubcommandAfterOptions(argv, {
optionsWithValue: NPM_EXEC_OPTIONS_WITH_VALUE,
caseSensitiveOptionsWithValue: /* @__PURE__ */ new Set(["-C"]),
flagOptions: NPM_EXEC_FLAG_OPTIONS
});
return NPM_EXEC_SUBCOMMANDS.has(firstSubcommand ?? "") ? { kind: "unsafe-exec" } : firstSubcommand === null && containsSubcommandToken(argv.slice(1), NPM_EXEC_SUBCOMMANDS) ? { kind: "unsafe-exec" } : { kind: "not-exec" };
}
case "npx":
case "bunx": {
const unwrapped = unwrapDirectPackageExecInvocation(argv);
return unwrapped ? {
kind: "unwrapped",
argv: unwrapped
} : { kind: "unsafe-exec" };
}
case "pnpm": {
const unwrapped = unwrapPnpmExecInvocation(argv);
if (unwrapped) return {
kind: "unwrapped",
argv: unwrapped
};
const firstSubcommand = firstSubcommandAfterOptions(argv, {
optionsWithValue: /* @__PURE__ */ new Set([...PNPM_OPTIONS_WITH_VALUE, ...PNPM_DLX_OPTIONS_WITH_VALUE]),
caseSensitiveOptionsWithValue: PNPM_CASE_SENSITIVE_OPTIONS_WITH_VALUE,
flagOptions: PNPM_FLAG_OPTIONS
});
const detectedKnownExec = PNPM_EXEC_SUBCOMMANDS.has(firstSubcommand ?? "");
const hiddenKnownExec = firstSubcommand === null && containsSubcommandToken(argv.slice(1), PNPM_EXEC_SUBCOMMANDS);
const implicitExecShorthand = firstSubcommand !== null && !PNPM_SCRIPT_RUN_SUBCOMMANDS.has(firstSubcommand) && !PNPM_BUILTIN_NON_EXEC_SUBCOMMANDS.has(firstSubcommand);
return detectedKnownExec || hiddenKnownExec || implicitExecShorthand ? { kind: "unsafe-exec" } : { kind: "not-exec" };
}
case "yarn": {
const unwrapped = unwrapYarnExecInvocation(argv);
if (unwrapped) return {
kind: "unwrapped",
argv: unwrapped
};
const firstSubcommand = firstSubcommandAfterOptions(argv, {
optionsWithValue: /* @__PURE__ */ new Set([...YARN_OPTIONS_WITH_VALUE, ...YARN_DLX_OPTIONS_WITH_VALUE]),
flagOptions: /* @__PURE__ */ new Set([...YARN_FLAG_OPTIONS, ...YARN_DLX_FLAG_OPTIONS])
});
const detectedKnownExec = YARN_EXEC_SUBCOMMANDS.has(firstSubcommand ?? "");
const hiddenKnownExec = firstSubcommand === null && containsSubcommandToken(argv.slice(1), YARN_EXEC_SUBCOMMANDS);
const implicitRunOrBin = firstSubcommand !== null && (firstSubcommand === "run" || !YARN_BUILTIN_NON_EXEC_SUBCOMMANDS.has(firstSubcommand));
return detectedKnownExec || hiddenKnownExec || implicitRunOrBin ? { kind: "unsafe-exec" } : { kind: "not-exec" };
}
default: return { kind: "not-package-manager" };
}
}
//#endregion
//#region src/infra/exec-approvals-allowlist.ts
function hasShellLineContinuation(command) {
return /\\(?:\r\n|\n|\r)/.test(command);
}
function commandStepToPolicySegment(step, params) {
return {
raw: step.text,
argv: step.argv,
resolution: resolveCommandResolutionFromArgv(step.argv, params.cwd, params.env, params.platform ?? void 0)
};
}
async function explainShellPolicySegments(params) {
try {
const explanation = await explainShellCommand(params.command);
return [...explanation.topLevelCommands, ...explanation.nestedCommands].map((step) => commandStepToPolicySegment(step, params));
} catch {
return [];
}
}
function normalizeSafeBins(entries) {
if (!Array.isArray(entries)) return /* @__PURE__ */ new Set();
const normalized = entries.map((entry) => normalizeLowercaseStringOrEmpty(entry)).filter((entry) => entry.length > 0);
return new Set(normalized);
}
function resolveSafeBins(entries) {
if (entries === void 0) return normalizeSafeBins(DEFAULT_SAFE_BINS);
return normalizeSafeBins(entries ?? []);
}
function isSafeBinUsage(params) {
if (isWindowsPlatform(params.platform ?? process.platform)) return false;
if (params.safeBins.size === 0) return false;
const resolution = params.resolution;
const execName = normalizeOptionalLowercaseString(resolution?.executableName);
if (!execName) return false;
if (!params.safeBins.has(execName)) return false;
const trustPath = resolveExecutableTrustPath(resolution);
if (!trustPath) return false;
if (!(params.isTrustedSafeBinPathFn ?? isTrustedSafeBinPath)({
resolvedPath: trustPath,
trustedDirs: params.trustedSafeBinDirs
})) return false;
const argv = params.argv.slice(1);
const profile = (params.safeBinProfiles ?? SAFE_BIN_PROFILES)[execName];
if (!profile) return false;
return validateSafeBinArgv(argv, profile, { binName: execName });
}
function isPathScopedExecutableToken(token) {
return token.includes("/") || token.includes("\\");
}
function pickExecAllowlistContext(params) {
return {
allowlist: params.allowlist,
safeBins: params.safeBins,
safeBinProfiles: params.safeBinProfiles,
cwd: params.cwd,
env: params.env,
platform: params.platform,
trustedSafeBinDirs: params.trustedSafeBinDirs,
skillBins: params.skillBins,
autoAllowSkills: params.autoAllowSkills,
allowShellBuiltins: params.allowShellBuiltins
};
}
function normalizeSkillBinName(value) {
const trimmed = normalizeOptionalLowercaseString(value);
return trimmed && trimmed.length > 0 ? trimmed : null;
}
function normalizeSkillBinResolvedPath(value) {
const trimmed = normalizeOptionalString(value);
if (!trimmed) return null;
const resolved = path.resolve(trimmed);
if (process.platform === "win32") return normalizeLowercaseStringOrEmpty(resolved.replace(/\\/g, "/"));
return resolved;
}
function buildSkillBinTrustIndex(entries) {
const trustByName = /* @__PURE__ */ new Map();
if (!entries || entries.length === 0) return trustByName;
for (const entry of entries) {
const name = normalizeSkillBinName(entry.name);
const resolvedPath = normalizeSkillBinResolvedPath(entry.resolvedPath);
if (!name || !resolvedPath) continue;
const paths = trustByName.get(name) ?? /* @__PURE__ */ new Set();
paths.add(resolvedPath);
trustByName.set(name, paths);
}
return trustByName;
}
function isSkillAutoAllowedSegment(params) {
if (!params.allowSkills) return false;
const resolution = params.segment.resolution;
const execution = resolveExecutionTargetResolution(resolution);
const trustPath = resolveExecutionTargetTrustPath(resolution);
if (!execution?.resolvedPath || !trustPath) return false;
const rawExecutable = execution.rawExecutable?.trim() ?? "";
if (!rawExecutable || isPathScopedExecutableToken(rawExecutable)) return false;
const executableName = normalizeSkillBinName(execution.executableName);
const resolvedPath = normalizeSkillBinResolvedPath(trustPath);
if (!executableName || !resolvedPath) return false;
return Boolean(params.skillBinTrust.get(executableName)?.has(resolvedPath));
}
const MAX_SHELL_WRAPPER_INLINE_EVAL_DEPTH = 3;
const MAX_PACKAGE_MANAGER_EXEC_UNWRAP_DEPTH = 6;
function resolvePackageManagerTrustTargetArgv(argv, platform = process.platform) {
let current = argv;
let sawPackageManagerExec = false;
for (let depth = 0; depth < MAX_PACKAGE_MANAGER_EXEC_UNWRAP_DEPTH; depth += 1) {
const dispatchPlan = resolveDispatchWrapperTrustPlan(current, void 0, platform);
if (dispatchPlan.policyBlocked) return { kind: "blocked" };
current = dispatchPlan.argv;
const packageManagerExec = resolveKnownPackageManagerExecInvocation(current);
if (packageManagerExec.kind === "unwrapped" && hasKnownPackageManagerExecContextOptions(current)) return { kind: "blocked" };
if (packageManagerExec.kind === "unsafe-exec") return { kind: "blocked" };
if (packageManagerExec.kind !== "unwrapped") return sawPackageManagerExec ? {
kind: "package-manager",
argv: current
} : {
kind: "not-package-manager",
argv: current
};
sawPackageManagerExec = true;
current = packageManagerExec.argv;
}
return { kind: "blocked" };
}
function resolvePackageManagerAllowlistTargetArgv(argv, platform = process.platform) {
const packageManagerTarget = resolvePackageManagerTrustTargetArgv(argv, platform);
if (packageManagerTarget.kind === "blocked") return null;
if (packageManagerTarget.kind !== "package-manager") return;
const trustPlan = resolveExecWrapperTrustPlan(packageManagerTarget.argv, void 0, platform);
if (trustPlan.policyBlocked || trustPlan.shellWrapperExecutable && trustPlan.shellInlineCommand) return null;
return trustPlan.argv;
}
function matchExecutableAllowlistForSegment(params) {
if (params.isPositionalCarrierInvocation) return null;
const match = matchAllowlist(params.allowlist, params.candidateResolution, params.effectiveArgv, params.platform, params.cwd);
const hasBoundArgPattern = typeof match?.argPattern === "string" && match.argPattern.trim().length > 0;
const isBareWildcardMatch = match?.pattern?.trim() === "*" && !hasBoundArgPattern;
if (params.allowlistTargetIsExecutionTarget && (params.inlineCommand !== null || params.isShellWrapperInvocation && params.effectiveArgv.length > 1) && !hasBoundArgPattern && !isBareWildcardMatch) return null;
return match;
}
function executableResolutionsReferToSameTarget(left, right) {
if (!left || !right) return false;
return left.rawExecutable === right.rawExecutable && left.resolvedPath === right.resolvedPath && left.resolvedRealPath === right.resolvedRealPath && left.executableName === right.executableName;
}
function resolveShellWrapperScriptArgv(params) {
const scriptBase = normalizeLowercaseStringOrEmpty(path.basename(params.shellScriptCandidatePath));
const cwdBase = params.cwd && params.cwd.trim() ? params.cwd.trim() : process.cwd();
const resolveArgPath = (a) => path.isAbsolute(a) ? a : path.resolve(cwdBase, a);
let idx = params.effectiveArgv.findIndex((a) => resolveArgPath(a) === params.shellScriptCandidatePath);
if (idx === -1) idx = params.effectiveArgv.findIndex((a) => normalizeLowercaseStringOrEmpty(path.basename(a)) === scriptBase);
const scriptArgs = idx !== -1 ? params.effectiveArgv.slice(idx + 1) : [];
return [params.shellScriptCandidatePath, ...scriptArgs];
}
function resolvePowerShellFileScriptArgv(params) {
const argv = resolveSegmentSourceArgv(params.segment);
if (!Array.isArray(argv) || argv.length < 3) return null;
const wrapperName = normalizeExecutableToken(argv[0] ?? "");
if (!POWERSHELL_WRAPPERS.has(wrapperName)) return null;
const match = resolvePowerShellInlineCommandMatch(argv);
if (match.valueTokenIndex === null || !match.command) return null;
if (!isPowerShellInlineFileCommandFlag(argv[match.valueTokenIndex - 1] ?? "")) return null;
const scriptToken = argv[match.valueTokenIndex]?.trim();
if (!scriptToken) return null;
const expanded = scriptToken.startsWith("~") ? expandHomePrefix(scriptToken) : scriptToken;
const base = params.cwd && params.cwd.trim().length > 0 ? params.cwd : process.cwd();
return [path.isAbsolute(expanded) ? expanded : path.resolve(base, expanded), ...argv.slice(match.valueTokenIndex + 1)];
}
function resolveSegmentSourceArgv(segment) {
const sourceArgv = segment.sourceArgv;
if (!Array.isArray(sourceArgv) || sourceArgv.length === 0) return segment.argv;
const segmentExecutable = normalizeExecutableToken(segment.argv[0] ?? "");
if (!segmentExecutable) return segment.argv;
if (normalizeExecutableToken(sourceArgv[0] ?? "") === segmentExecutable) return sourceArgv;
const unwrappedSourceArgv = unwrapDispatchWrappersForResolution(sourceArgv);
return normalizeExecutableToken(unwrappedSourceArgv[0] ?? "") === segmentExecutable ? unwrappedSourceArgv : segment.argv;
}
function resolveSegmentAllowlistMatch(params) {
const effectiveArgv = params.segment.resolution?.effectiveArgv && params.segment.resolution.effectiveArgv.length > 0 ? params.segment.resolution.effectiveArgv : params.segment.argv;
const packageManagerTargetArgv = resolvePackageManagerAllowlistTargetArgv(effectiveArgv, params.context.platform ?? void 0);
if (packageManagerTargetArgv === null) return {
effectiveArgv,
inlineCommand: null,
match: null
};
const matchArgv = packageManagerTargetArgv ?? effectiveArgv;
const matchResolution = matchArgv === effectiveArgv ? params.segment.resolution : resolveCommandResolutionFromArgv(matchArgv, params.context.cwd, params.context.env, params.context.platform ?? void 0);
const allowlistSegment = matchArgv === params.segment.argv ? params.segment : {
...params.segment,
argv: matchArgv,
resolution: matchResolution
};
const executableResolution = resolvePolicyTargetResolution(matchResolution);
const executionResolution = resolveExecutionTargetResolution(params.segment.resolution);
const candidatePath = resolvePolicyTargetCandidatePath(matchResolution, params.context.cwd);
const trustPath = resolvePolicyTargetTrustPath(matchResolution, params.context.cwd);
const candidateResolution = candidatePath && executableResolution ? {
...executableResolution,
resolvedPath: candidatePath,
resolvedRealPath: trustPath
} : executableResolution;
const matchExecutionResolution = resolveExecutionTargetResolution(matchResolution);
const inlineCommand = extractBindableShellWrapperInlineCommand(allowlistSegment.argv);
const opaquePosixShellWrapper = isOpaquePosixShellWrapperSegment(allowlistSegment);
const powerShellFileScriptArgv = resolvePowerShellFileScriptArgv({
segment: allowlistSegment,
cwd: params.context.cwd
});
const isShellWrapperInvocation = isShellWrapperSegment(allowlistSegment);
const isPositionalCarrierInvocation = inlineCommand !== null && isDirectShellPositionalCarrierCommand(inlineCommand);
const executableMatch = matchExecutableAllowlistForSegment({
allowlist: params.context.allowlist,
candidateResolution,
effectiveArgv: matchArgv,
platform: params.context.platform,
cwd: params.context.cwd,
inlineCommand,
isShellWrapperInvocation,
isPositionalCarrierInvocation,
allowlistTargetIsExecutionTarget: executableResolutionsReferToSameTarget(executableResolution, matchExecutionResolution ?? executionResolution)
});
const shellPositionalArgvCandidate = inlineCommand !== null ? resolveShellWrapperPositionalArgvCandidate({
segment: allowlistSegment,
cwd: params.context.cwd,
env: params.context.env,
platform: params.context.platform
}) : void 0;
const shellPositionalArgvMatch = shellPositionalArgvCandidate ? matchAllowlist(shellPositionalArgvCandidate.durable ? params.context.allowlist : params.context.allowlist.filter((entry) => entry.argPattern === void 0), {
kind: "executable",
rawExecutable: shellPositionalArgvCandidate.path,
resolvedPath: shellPositionalArgvCandidate.path,
resolvedRealPath: resolveCandidateTrustPath(shellPositionalArgvCandidate.path),
executableName: path.basename(shellPositionalArgvCandidate.path)
}, shellPositionalArgvCandidate.argv, params.context.platform, params.context.cwd) : null;
const shellScriptCandidatePath = powerShellFileScriptArgv?.[0] ?? (inlineCommand === null ? resolveShellWrapperScriptCandidatePath({
segment: allowlistSegment,
cwd: params.context.cwd
}) : void 0);
const shellScriptArgv = shellScriptCandidatePath ? powerShellFileScriptArgv ?? resolveShellWrapperScriptArgv({
shellScriptCandidatePath,
effectiveArgv: matchArgv,
cwd: params.context.cwd
}) : null;
const shellScriptMatch = shellScriptCandidatePath && shellScriptArgv ? matchAllowlist(params.context.allowlist, {
kind: "executable",
rawExecutable: shellScriptCandidatePath,
resolvedPath: shellScriptCandidatePath,
resolvedRealPath: resolveCandidateTrustPath(shellScriptCandidatePath),
executableName: path.basename(shellScriptCandidatePath)
}, shellScriptArgv, params.context.platform, params.context.cwd) : null;
return {
effectiveArgv,
inlineCommand: powerShellFileScriptArgv || opaquePosixShellWrapper ? null : inlineCommand,
match: executableMatch ?? shellPositionalArgvMatch ?? shellScriptMatch
};
}
function resolveSegmentSatisfaction(params) {
if (params.match) return "allowlist";
if (isSafeBinUsage({
argv: params.effectiveArgv,
resolution: resolveExecutionTargetResolution(params.segment.resolution),
safeBins: params.context.safeBins,
safeBinProfiles: params.context.safeBinProfiles,
platform: params.context.platform,
trustedSafeBinDirs: params.context.trustedSafeBinDirs
})) return "safeBins";
if (params.context.allowShellBuiltins === true && isSafeBuiltinSegment({
segment: params.segment,
platform: params.context.platform
})) return "safeBuiltins";
return isSkillAutoAllowedSegment({
segment: params.segment,
allowSkills: params.allowSkills,
skillBinTrust: params.skillBinTrust
}) ? "skills" : null;
}
function resolveInlineCommandFallback(params) {
if (params.by !== null || !params.inlineCommand) return null;
if (!isWindowsPlatform(params.context.platform)) return null;
return evaluateShellWrapperInlineCommand({
inlineCommand: params.inlineCommand,
context: params.context,
inlineDepth: params.inlineDepth + 1
});
}
function evaluateShellWrapperInlineCommand(params) {
if (params.inlineDepth >= MAX_SHELL_WRAPPER_INLINE_EVAL_DEPTH) return null;
if (hasShellLineContinuation(params.inlineCommand)) return null;
const analysis = analyzeWindowsShellCommand({
command: params.inlineCommand,
cwd: params.context.cwd,
env: params.context.env,
platform: params.context.platform
});
if (!analysis.ok || analysis.segments.length === 0) return null;
const matches = [];
for (const group of resolveAnalysisSegmentGroups(analysis)) {
const result = evaluateSegments(group, params.context, params.inlineDepth);
if (!result.satisfied) return null;
matches.push(...result.matches);
}
return {
matches,
satisfiedBy: "allowlist"
};
}
function evaluateSegments(segments, params, inlineDepth = 0) {
const matches = [];
const skillBinTrust = buildSkillBinTrustIndex(params.skillBins);
const allowSkills = params.autoAllowSkills === true && skillBinTrust.size > 0;
const segmentAllowlistEntries = [];
const segmentSatisfiedBy = [];
return {
satisfied: segments.every((segment) => {
if (segment.resolution?.policyBlocked === true) {
segmentAllowlistEntries.push(null);
segmentSatisfiedBy.push(null);
return false;
}
const { effectiveArgv, inlineCommand, match } = resolveSegmentAllowlistMatch({
segment,
context: params
});
if (match) matches.push(match);
segmentAllowlistEntries.push(match ?? null);
const by = resolveSegmentSatisfaction({
match,
segment,
effectiveArgv,
context: params,
allowSkills,
skillBinTrust
});
const inlineResult = resolveInlineCommandFallback({
by,
inlineCommand,
context: params,
inlineDepth
});
if (inlineResult) {
matches.push(...inlineResult.matches);
segmentSatisfiedBy.push(inlineResult.satisfiedBy);
return true;
}
segmentSatisfiedBy.push(by);
return Boolean(by);
}),
matches,
segmentAllowlistEntries,
segmentSatisfiedBy
};
}
function resolveAnalysisSegmentGroups(analysis) {
if (analysis.chains) return analysis.chains;
return [analysis.segments];
}
function evaluateAuthorizationCandidate(params) {
if (params.candidate.trustMode === "prompt-only") return {
match: null,
satisfiedBy: null
};
const { effectiveArgv, match } = resolveSegmentAllowlistMatch({
segment: params.candidate.sourceSegment,
context: params.context
});
if (match) return {
match,
satisfiedBy: "allowlist"
};
return {
match,
satisfiedBy: resolveSegmentSatisfaction({
match,
segment: params.candidate.sourceSegment,
effectiveArgv,
context: params.context,
allowSkills: params.allowSkills,
skillBinTrust: params.skillBinTrust
})
};
}
function evaluateAuthorizationPlanGroup(params) {
const matches = [];
const segmentAllowlistEntries = [];
const segmentSatisfiedBy = [];
const segments = [];
let allowlistSatisfied = true;
for (const candidate of params.group.candidates) {
const result = evaluateAuthorizationCandidate({
candidate,
context: params.context,
allowSkills: params.allowSkills,
skillBinTrust: params.skillBinTrust
});
if (result.match) matches.push(result.match);
segments.push(candidate.sourceSegment);
segmentAllowlistEntries.push(result.match);
segmentSatisfiedBy.push(result.satisfiedBy);
if (!result.satisfiedBy) allowlistSatisfied = false;
}
return {
evaluation: {
allowlistSatisfied,
allowlistMatches: matches,
segmentAllowlistEntries,
segmentSatisfiedBy
},
segments
};
}
function finalizeShellAllowlistEvaluations(params) {
const allowlistMatches = [];
const segments = [];
const segmentAllowlistEntries = [];
const segmentSatisfiedBy = [];
let allowlistSatisfied = true;
for (const { analysis, evaluation } of params.evaluations) {
segments.push(...analysis.segments);
allowlistMatches.push(...evaluation.allowlistMatches);
segmentAllowlistEntries.push(...evaluation.segmentAllowlistEntries);
segmentSatisfiedBy.push(...evaluation.segmentSatisfiedBy);
if (!evaluation.allowlistSatisfied) allowlistSatisfied = false;
}
return {
analysisOk: true,
allowlistSatisfied,
allowlistMatches,
segments,
segmentAllowlistEntries,
segmentSatisfiedBy,
...params.authorizationPlan ? { authorizationPlan: params.authorizationPlan } : {}
};
}
function evaluateAuthorizationPlan(params) {
const analysisFailure = () => ({
analysisOk: false,
allowlistSatisfied: false,
allowlistMatches: [],
segments: [],
segmentAllowlistEntries: [],
segmentSatisfiedBy: [],
authorizationPlan: params.plan
});
if (!params.plan.ok) return analysisFailure();
const skillBins = params.context.skillBins ?? [];
const allowSkills = params.context.autoAllowSkills === true && skillBins.length > 0;
const skillBinTrust = buildSkillBinTrustIndex(skillBins);
return finalizeShellAllowlistEvaluations({
evaluations: params.plan.groups.map((group) => {
const { evaluation, segments } = evaluateAuthorizationPlanGroup({
group,
context: params.context,
allowSkills,
skillBinTrust
});
return {
analysis: {
ok: true,
segments
},
evaluation,
opToNext: group.opToNext ?? null
};
}),
authorizationPlan: params.plan
});
}
function evaluateExecAllowlist(params) {
const allowlistMatches = [];
const segmentAllowlistEntries = [];
const segmentSatisfiedBy = [];
if (!params.analysis.ok || params.analysis.segments.length === 0) return {
allowlistSatisfied: false,
allowlistMatches,
segmentAllowlistEntries,
segmentSatisfiedBy
};
const allowlistContext = pickExecAllowlistContext(params);
const hasChains = Boolean(params.analysis.chains);
for (const group of resolveAnalysisSegmentGroups(params.analysis)) {
const result = evaluateSegments(group, allowlistContext);
if (!result.satisfied) {
if (!hasChains) return {
allowlistSatisfied: false,
allowlistMatches: result.matches,
segmentAllowlistEntries: result.segmentAllowlistEntries,
segmentSatisfiedBy: result.segmentSatisfiedBy
};
return {
allowlistSatisfied: false,
allowlistMatches: [],
segmentAllowlistEntries: [],
segmentSatisfiedBy: []
};
}
allowlistMatches.push(...result.matches);
segmentAllowlistEntries.push(...result.segmentAllowlistEntries);
segmentSatisfiedBy.push(...result.segmentSatisfiedBy);
}
return {
allowlistSatisfied: true,
allowlistMatches,
segmentAllowlistEntries,
segmentSatisfiedBy
};
}
function hasSegmentExecutableMatch(segment, predicate) {
const execution = resolveExecutionTargetResolution(segment.resolution);
const candidates = [
execution?.executableName,
execution?.rawExecutable,
segment.argv[0]
];
for (const candidate of candidates) {
if (typeof candidate !== "string") continue;
const trimmed = candidate.trim();
if (!trimmed) continue;
if (predicate(trimmed)) return true;
}
return false;
}
function isShellWrapperSegment(segment) {
return hasSegmentExecutableMatch(segment, isShellWrapperExecutable);
}
function isOpaquePosixShellWrapperSegment(segment) {
return hasSegmentExecutableMatch(segment, (token) => {
const wrapper = normalizeExecutableToken(token);
return POSIX_SHELL_WRAPPERS.has(wrapper) && !POSIX_PARSEABLE_SHELL_WRAPPERS.has(wrapper);
});
}
const SHELL_WRAPPER_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
"-c",
"--command",
"-o",
"-O",
"+O",
"+o"
]);
const POSIX_SHELLS_WITH_PLUS_OPTIONS = /* @__PURE__ */ new Set([
"ash",
"bash",
"dash",
"ksh",
"mksh",
"osh",
"sh",
"yash",
"zsh"
]);
const SHELL_WRAPPER_DISQUALIFYING_SCRIPT_OPTIONS = [
"--rcfile",
"--init-file",
"--startup-file"
];
function hasDisqualifyingShellWrapperScriptOption(token) {
return SHELL_WRAPPER_DISQUALIFYING_SCRIPT_OPTIONS.some((option) => token === option || token.startsWith(`${option}=`));
}
const POWERSHELL_OPTIONS_WITH_VALUE_RE = /^-(?:executionpolicy|ep|windowstyle|w|workingdirectory|wd|inputformat|outputformat|settingsfile|configurationfile|version|v|psconsolefile|pscf|encodedcommand|en|enc|encodedarguments|ea)$/i;
function resolveShellWrapperScriptCandidatePath(params) {
if (!isShellWrapperSegment(params.segment)) return;
if (isOpaquePosixShellWrapperSegment(params.segment)) return;
const argv = params.segment.argv;
if (!Array.isArray(argv) || argv.length < 2) return;
const wrapperName = normalizeExecutableToken(argv[0] ?? "");
const isPowerShell = POWERSHELL_WRAPPERS.has(wrapperName);
const supportsPosixPlusOptions = POSIX_SHELLS_WITH_PLUS_OPTIONS.has(wrapperName);
let idx = 1;
while (idx < argv.length) {
const token = argv[idx]?.trim() ?? "";
if (!token) {
idx += 1;
continue;
}
if (token === "--") {
idx += 1;
break;
}
if (!isPowerShell && POSIX_INLINE_COMMAND_FLAGS.has(token)) return;
if (!isPowerShell && /^-[^-]*c[^-]*$/i.test(token)) return;
if (token === "-s" || !isPowerShell && /^-[^-]*s[^-]*$/i.test(token)) return;
if (hasDisqualifyingShellWrapperScriptOption(token)) return;
if (SHELL_WRAPPER_OPTIONS_WITH_VALUE.has(token)) {
idx += 2;
continue;
}
if (isPowerShell && POWERSHELL_OPTIONS_WITH_VALUE_RE.test(token)) {
idx += 2;
continue;
}
if (!isPowerShell && (token.startsWith("-") || supportsPosixPlusOptions && token.startsWith("+"))) {
idx += advancePosixInlineOptionScan(token);
continue;
}
if (token.startsWith("-") || token.startsWith("+")) {
idx += 1;
continue;
}
break;
}
const scriptToken = argv[idx]?.trim();
if (!scriptToken) return;
if (path.isAbsolute(scriptToken)) return scriptToken;
const expanded = scriptToken.startsWith("~") ? expandHomePrefix(scriptToken) : scriptToken;
const base = params.cwd && params.cwd.trim().length > 0 ? params.cwd : process.cwd();
return path.resolve(base, expanded);
}
function isDurableShellPositionalCarrierCommand(command, tailArgv) {
const trimmed = command.trim();
if (trimmed.length === 0) return false;
const shellWhitespace = String.raw`[^\S\r\n]+`;
const positionalZero = String.raw`(?:\$(?:0|\{0\})|"\$(?:0|\{0\})")`;
if (tailArgv.length === 0) return new RegExp(`^(?:exec${shellWhitespace}(?:--${shellWhitespace})?)?${positionalZero}$`, "u").test(trimmed);
const positionalAll = String.raw`(?:\$(?:@|\{@\})|"\$(?:@|\{@\})")`;
return new RegExp(`^(?:exec${shellWhitespace}(?:--${shellWhitespace})?)?${positionalZero}${shellWhitespace}${positionalAll}$`, "u").test(trimmed);
}
function resolveShellWrapperPositionalArgvCandidate(params) {
if (!isShellWrapperSegment(params.segment)) return;
const argv = params.segment.argv;
if (!Array.isArray(argv) || argv.length < 4) return;
const wrapper = normalizeExecutableToken(argv[0] ?? "");
if (![
"ash",
"bash",
"dash",
"fish",
"ksh",
"sh",
"zsh"
].includes(wrapper)) return;
const inlineMatch = resolveInlineCommandMatch(argv, POSIX_INLINE_COMMAND_FLAGS, { allowCombinedC: true });
if (inlineMatch.valueTokenIndex === null || !inlineMatch.command) return;
if (!isDirectShellPositionalCarrierCommand(inlineMatch.command)) return;
const carriedOffset = argv.slice(inlineMatch.valueTokenIndex + 1).findIndex((token) => token.trim().length > 0);
if (carriedOffset === -1) return;
const carriedIndex = inlineMatch.valueTokenIndex + 1 + carriedOffset;
const carriedExecutable = argv[carriedIndex]?.trim() ?? "";
if (!carriedExecutable) return;
const carriedTailArgv = argv.slice(carriedIndex + 1);
const durable = isDurableShellPositionalCarrierCommand(inlineMatch.command, carriedTailArgv);
const carriedName = normalizeExecutableToken(carriedExecutable);
if (isDispatchWrapperExecutable(carriedName) || isShellWrapperExecutable(carriedName)) return;
const resolution = resolveCommandResolutionFromArgv([carriedExecutable], params.cwd, params.env, params.platform ?? void 0);
const candidatePath = resolveExecutionTargetCandidatePath(resolution, params.cwd);
if (!candidatePath) return;
return {
path: candidatePath,
argv: [resolveCandidateTrustPath(candidatePath) ?? candidatePath, ...carriedTailArgv],
durable
};
}
function buildScriptArgPatternFromArgv(argv, scriptPath, cwd, platform) {
const scriptBase = normalizeLowercaseStringOrEmpty(path.basename(scriptPath));
const base = cwd && cwd.trim() ? cwd.trim() : process.cwd();
const resolveArgPath = (arg) => path.isAbsolute(arg) ? arg : path.resolve(base, arg);
let scriptIdx = argv.findIndex((arg) => resolveArgPath(arg) === scriptPath);
if (scriptIdx === -1) scriptIdx = argv.findIndex((arg) => normalizeLowercaseStringOrEmpty(path.basename(arg)) === scriptBase);
const scriptArgs = scriptIdx !== -1 ? argv.slice(scriptIdx + 1) : [];
return buildCwdBoundHashedArgPattern([scriptPath, ...scriptArgs], base, platform);
}
function buildArgPatternFromArgv(argv, cwd, platform) {
return buildCwdBoundHashedArgPattern(argv, cwd, platform);
}
function addAllowAlwaysPattern(out, pattern, argPattern) {
if (!out.some((p) => p.pattern === pattern && (p.argPattern ?? void 0) === (argPattern ?? void 0))) out.push({
pattern,
argPattern
});
}
function resolveCandidateTrustPath(candidatePath) {
if (!candidatePath) return;
return resolveExecutableTrustPath({
kind: "executable",
rawExecutable: candidatePath,
resolvedPath: candidatePath,
executableName: path.basename(candidatePath)
});
}
function resolveAllowAlwaysPatternArgv(argv, platform = process.platform) {
const packageManagerTarget = resolvePackageManagerTrustTargetArgv(argv, platform);
if (packageManagerTarget.kind === "blocked") return null;
return packageManagerTarget.argv;
}
function collectAllowAlwaysPatterns(params) {
if (params.depth >= 3) return;
const patternArgv = resolveAllowAlwaysPatternArgv(params.segment.argv, params.platform ?? void 0);
if (!patternArgv) return;
const trustPlan = resolveExecWrapperTrustPlan(patternArgv, void 0, params.platform ?? void 0);
if (trustPlan.policyBlocked) return;
const segment = trustPlan.argv === params.segment.argv ? params.segment : {
raw: trustPlan.argv.join(" "),
argv: trustPlan.argv,
sourceArgv: params.segment.sourceArgv,
resolution: resolveCommandResolutionFromArgv(trustPlan.argv, params.cwd, params.env, params.platform ?? void 0)
};
const candidatePath = resolveExecutionTargetTrustPath(segment.resolution, params.cwd);
if (!candidatePath) return;
if (isInterpreterLikeAllowlistPattern(candidatePath)) {
const effectiveArgv = segment.resolution?.effectiveArgv ?? segment.argv;
if (params.strictInlineEval !== true || detectInlineEvalArgv(effectiveArgv) !== null) return;
}
if (!trustPlan.shellWrapperExecutable) {
const argPattern = buildArgPatternFromArgv(segment.argv, params.cwd ?? process.cwd(), params.platform);
addAllowAlwaysPattern(params.out, candidatePath, argPattern);
return;
}
const powerShellFileScriptArgv = resolvePowerShellFileScriptArgv({
segment,
cwd: params.cwd
});
const inlineCommand = powerShellFileScriptArgv ? null : trustPlan.shellInlineCommand;
if (inlineCommand && isOpaquePosixShellWrapperSegment(segment)) return;
const positionalArgvCandidate = inlineCommand !== null ? resolveShellWrapperPositionalArgvCandidate({
segment,
cwd: params.cwd,
env: params.env,
platform: params.platform
}) : void 0;
if (positionalArgvCandidate) {
if (!positionalArgvCandidate.durable) return;
const positionalTrustPath = resolveCandidateTrustPath(positionalArgvCandidate.path) ?? positionalArgvCandidate.path;
const argPattern = buildArgPatternFromArgv(positionalArgvCandidate.argv, params.cwd ?? process.cwd(), params.platform);
addAllowAlwaysPattern(params.out, positionalTrustPath, argPattern);
return;
}
if (!inlineCommand) {
const scriptPath = powerShellFileScriptArgv?.[0] ?? resolveShellWrapperScriptCandidatePath({
segment,
cwd: params.cwd
});
if (scriptPath) {
const scriptTrustPath = resolveCandidateTrustPath(scriptPath) ?? scriptPath;
const argPattern = buildScriptArgPatternFromArgv(powerShellFileScriptArgv ?? segment.argv, scriptPath, params.cwd, params.platform);
addAllowAlwaysPattern(params.out, scriptTrustPath, argPattern);
}
return;
}
if (!isWindowsPlatform(params.platform)) return;
const nested = analyzeWindowsShellCommand({
command: inlineCommand,
cwd: params.cwd,
env: params.env,
platform: params.platform
});
if (!nested.ok || !canUseReusableWrapperPayloadCandidates(nested.segments)) return;
for (const nestedSegment of nested.segments) collectAllowAlwaysPatterns({
segment: nestedSegment,
cwd: params.cwd,
env: params.env,
platform: params.platform,
strictInlineEval: params.strictInlineEval,
depth: params.depth + 1,
out: params.out
});
}
/**
* Derive persisted allowlist patterns for an "allow always" decision.
* When a command is wrapped in a shell (for example `zsh -lc "<cmd>"`),
* persist the inner executable(s) rather than the shell binary.
*/
function resolveAllowAlwaysPatternEntries(params) {
const patterns = [];
for (const segment of params.segments) collectAllowAlwaysPatterns({
segment,
cwd: params.cwd,
env: params.env,
platform: params.platform,
strictInlineEval: params.strictInlineEval,
depth: 0,
out: patterns
});
return patterns;
}
function resolveAllowAlwaysPatterns(params) {
return resolveAllowAlwaysPatternEntries(params).map((pattern) => pattern.pattern);
}
/**
* Evaluates allowlist for shell commands (including &&, ||, ;) and returns analysis metadata.
*/
function evaluateShellAllowlist(params) {
const allowlistContext = {
...pickExecAllowlistContext(params),
allowShellBuiltins: true
};
const analysisFailure = () => ({
analysisOk: false,
allowlistSatisfied: false,
allowlistMatches: [],
segments: [],
segmentAllowlistEntries: [],
segmentSatisfiedBy: []
});
if (hasShellLineContinuation(params.command)) return analysisFailure();
if (!isWindowsPlatform(params.platform)) return analysisFailure();
const analysis = analyzeWindowsShellCommand({
command: params.command,
cwd: params.cwd,
env: params.env,
platform: params.platform
});
if (!analysis.ok) return analysisFailure();
const evaluation = evaluateExecAllowlist({
analysis,
...allowlistContext
});
return {
analysisOk: true,
allowlistSatisfied: evaluation.allowlistSatisfied,
allowlistMatches: evaluation.allowlistMatches,
segments: analysis.segments,
segmentAllowlistEntries: evaluation.segmentAllowlistEntries,
segmentSatisfiedBy: evaluation.segmentSatisfiedBy
};
}
async function evaluateShellAllowlistWithAuthorization(params) {
const allowlistContext = {
...pickExecAllowlistContext(params),
allowShellBuiltins: true
};
const analysisFailure = (segments = [], authorizationPlan) => ({
analysisOk: false,
allowlistSatisfied: false,
allowlistMatches: [],
segments,
segmentAllowlistEntries: [],
segmentSatisfiedBy: [],
...authorizationPlan ? { authorizationPlan } : {}
});
if (!isWindowsPlatform(params.platform)) {
const authorizationPlan = await planShellAuthorization({
command: params.command,
cwd: params.cwd,
env: params.env,
platform: params.platform
});
if (!authorizationPlan.ok) return analysisFailure(await explainShellPolicySegments({
command: params.command,
cwd: params.cwd,
env: params.env,
platform: params.platform
}), authorizationPlan);
return evaluateAuthorizationPlan({
plan: authorizationPlan,
context: allowlistContext
});
}
return evaluateShellAllowlist(params);
}
async function evaluateExecAllowlistWithAuthorization(params) {
if (isWindowsPlatform(params.platform)) return evaluateExecAllowlist(params);
const authorizationPlan = await planExecAuthorization({
analysis: params.analysis,
command: params.command,
cwd: params.cwd,
env: params.env,
platform: params.platform
});
if (!authorizationPlan.ok) return {
allowlistSatisfied: false,
allowlistMatches: [],
segmentAllowlistEntries: [],
segmentSatisfiedBy: [],
segments: params.analysis.segments,
authorizationPlan
};
const result = evaluateAuthorizationPlan({
plan: authorizationPlan,
context: pickExecAllowlistContext(params)
});
return {
allowlistSatisfied: result.allowlistSatisfied,
allowlistMatches: result.allowlistMatches,
segmentAllowlistEntries: result.segmentAllowlistEntries,
segmentSatisfiedBy: result.segmentSatisfiedBy,
segments: result.segments,
authorizationPlan
};
}
//#endregion
export { isSafeBinUsage as a, resolveAllowAlwaysPatterns as c, PNPM_DLX_OPTIONS_WITH_VALUE as d, PNPM_FLAG_OPTIONS as f, planShellAuthorization as g, unwrapKnownPackageManagerExecInvocation as h, evaluateShellAllowlistWithAuthorization as i, resolveSafeBins as l, normalizePackageManagerExecToken as m, evaluateExecAllowlistWithAuthorization as n, normalizeSafeBins as o, PNPM_OPTIONS_WITH_VALUE as p, evaluateShellAllowlist as r, resolveAllowAlwaysPatternEntries as s, evaluateExecAllowlist as t, PNPM_CASE_SENSITIVE_OPTIONS_WITH_VALUE as u };