@guilz-dev/belay 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/dist/adapters/codex/hooks.d.ts +1 -0
- package/dist/adapters/codex/hooks.js +3 -0
- package/dist/adapters/cursor/dispatcher-generation.d.ts +3 -0
- package/dist/adapters/cursor/dispatcher-generation.js +5 -0
- package/dist/adapters/cursor/hook-dispatch-entry.d.ts +7 -0
- package/dist/adapters/cursor/hook-dispatch-entry.js +126 -0
- package/dist/adapters/cursor/hook-router.d.ts +23 -0
- package/dist/adapters/cursor/hook-router.js +266 -0
- package/dist/adapters/cursor/hooks.d.ts +4 -0
- package/dist/adapters/cursor/hooks.js +99 -8
- package/dist/adapters/cursor/routing-layout.d.ts +5 -0
- package/dist/adapters/cursor/routing-layout.js +29 -0
- package/dist/adapters/cursor/runtime-entry.d.ts +17 -0
- package/dist/adapters/cursor/runtime-entry.js +39 -39
- package/dist/adapters/layouts/scope.d.ts +5 -0
- package/dist/adapters/layouts/scope.js +71 -0
- package/dist/adapters/shared/gate-runtime.js +1 -0
- package/dist/bundle/claude-runtime.mjs +1932 -1740
- package/dist/bundle/codex-runtime.mjs +1934 -1742
- package/dist/bundle/cursor-dispatcher.mjs +443 -0
- package/dist/bundle/cursor-runtime.mjs +2017 -1821
- package/dist/commands/doctor.js +191 -15
- package/dist/commands/health-snapshot.js +9 -4
- package/dist/commands/recovery-checkpoints.d.ts +3 -3
- package/dist/config-io.js +11 -2
- package/dist/core/audit-legacy-archive.js +43 -25
- package/dist/core/classify-tool.js +16 -8
- package/dist/core/effect-ir/argv-delegate.d.ts +9 -0
- package/dist/core/effect-ir/argv-delegate.js +42 -0
- package/dist/core/effect-ir/shell-lower/argv-delegate-gate.d.ts +3 -0
- package/dist/core/effect-ir/shell-lower/argv-delegate-gate.js +40 -0
- package/dist/core/effect-ir/shell-lower/augment.d.ts +4 -0
- package/dist/core/effect-ir/shell-lower/augment.js +97 -0
- package/dist/core/effect-ir/shell-lower/context.d.ts +10 -0
- package/dist/core/effect-ir/shell-lower/context.js +1 -0
- package/dist/core/effect-ir/shell-lower/decode-process.d.ts +9 -0
- package/dist/core/effect-ir/shell-lower/decode-process.js +201 -0
- package/dist/core/effect-ir/shell-lower/decoders/belay.d.ts +2 -0
- package/dist/core/effect-ir/shell-lower/decoders/belay.js +29 -0
- package/dist/core/effect-ir/shell-lower/decoders/builtins.d.ts +7 -0
- package/dist/core/effect-ir/shell-lower/decoders/builtins.js +194 -0
- package/dist/core/effect-ir/shell-lower/decoders/decode-package-exec.d.ts +4 -0
- package/dist/core/effect-ir/shell-lower/decoders/decode-package-exec.js +68 -0
- package/dist/core/effect-ir/shell-lower/decoders/docker.d.ts +3 -0
- package/dist/core/effect-ir/shell-lower/decoders/docker.js +43 -0
- package/dist/core/effect-ir/shell-lower/decoders/filesystem.d.ts +9 -0
- package/dist/core/effect-ir/shell-lower/decoders/filesystem.js +217 -0
- package/dist/core/effect-ir/shell-lower/decoders/prisma.d.ts +2 -0
- package/dist/core/effect-ir/shell-lower/decoders/prisma.js +54 -0
- package/dist/core/effect-ir/shell-lower/decoders/ruby.d.ts +11 -0
- package/dist/core/effect-ir/shell-lower/decoders/ruby.js +147 -0
- package/dist/core/effect-ir/shell-lower/decoders/toolchain.d.ts +7 -0
- package/dist/core/effect-ir/shell-lower/decoders/toolchain.js +155 -0
- package/dist/core/effect-ir/shell-lower/requirement.d.ts +12 -0
- package/dist/core/effect-ir/shell-lower/requirement.js +65 -0
- package/dist/core/effect-ir/shell-lower/segment.d.ts +11 -0
- package/dist/core/effect-ir/shell-lower/segment.js +82 -0
- package/dist/core/effect-ir/shell-lower/tokens.d.ts +26 -0
- package/dist/core/effect-ir/shell-lower/tokens.js +183 -0
- package/dist/core/effect-ir/shell-lower.d.ts +2 -7
- package/dist/core/effect-ir/shell-lower.js +60 -1502
- package/dist/core/glob.js +32 -16
- package/dist/core/integrity.d.ts +2 -2
- package/dist/core/integrity.js +52 -12
- package/dist/core/replay-scrub.d.ts +2 -0
- package/dist/core/replay-scrub.js +8 -0
- package/dist/core/shell-substitution.js +2 -2
- package/dist/core/shell-unparseable.js +3 -1
- package/dist/defaults.d.ts +7 -3
- package/dist/defaults.js +29 -22
- package/dist/installer/bootstrap.d.ts +1 -0
- package/dist/installer/bootstrap.js +2 -2
- package/dist/installer/runtime-artifacts.js +43 -13
- package/dist/installer.js +44 -9
- package/dist/node-resolution.d.ts +1 -0
- package/dist/node-resolution.js +61 -0
- package/dist/templates.d.ts +7 -4
- package/dist/templates.js +42 -4
- package/dist/types.d.ts +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -3580,7 +3580,7 @@ var init_config_io = __esm({
|
|
|
3580
3580
|
|
|
3581
3581
|
// src/adapters/cursor/runtime-entry.ts
|
|
3582
3582
|
init_approval();
|
|
3583
|
-
import
|
|
3583
|
+
import path65 from "node:path";
|
|
3584
3584
|
import process2 from "node:process";
|
|
3585
3585
|
|
|
3586
3586
|
// src/core/approval-repo-lookup.ts
|
|
@@ -3640,7 +3640,7 @@ init_approval_replay();
|
|
|
3640
3640
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
3641
3641
|
import { existsSync as existsSync16 } from "node:fs";
|
|
3642
3642
|
import { mkdir as mkdir14, readFile as readFile16, writeFile as writeFile11 } from "node:fs/promises";
|
|
3643
|
-
import
|
|
3643
|
+
import path62 from "node:path";
|
|
3644
3644
|
|
|
3645
3645
|
// src/core/approval-service.ts
|
|
3646
3646
|
init_config_io();
|
|
@@ -6647,31 +6647,44 @@ import { randomUUID as randomUUID3 } from "node:crypto";
|
|
|
6647
6647
|
import path22 from "node:path";
|
|
6648
6648
|
|
|
6649
6649
|
// src/core/glob.ts
|
|
6650
|
+
init_approval();
|
|
6651
|
+
function globPatternToRegexSource(pattern) {
|
|
6652
|
+
let result = "";
|
|
6653
|
+
let index = 0;
|
|
6654
|
+
while (index < pattern.length) {
|
|
6655
|
+
const char = pattern[index];
|
|
6656
|
+
if (char === "*" && pattern[index + 1] === "*") {
|
|
6657
|
+
index += 2;
|
|
6658
|
+
if (pattern[index] === "/") {
|
|
6659
|
+
result += "(?:.*/)?";
|
|
6660
|
+
index += 1;
|
|
6661
|
+
} else {
|
|
6662
|
+
result += ".*";
|
|
6663
|
+
}
|
|
6664
|
+
continue;
|
|
6665
|
+
}
|
|
6666
|
+
if (char === "*") {
|
|
6667
|
+
result += "[^/]*";
|
|
6668
|
+
index += 1;
|
|
6669
|
+
continue;
|
|
6670
|
+
}
|
|
6671
|
+
result += escapeRegex(char);
|
|
6672
|
+
index += 1;
|
|
6673
|
+
}
|
|
6674
|
+
return result;
|
|
6675
|
+
}
|
|
6676
|
+
function globPatternMatches(pattern, normalized, baseName) {
|
|
6677
|
+
const regex = new RegExp(`^${globPatternToRegexSource(pattern)}$`);
|
|
6678
|
+
return regex.test(normalized) || regex.test(baseName);
|
|
6679
|
+
}
|
|
6650
6680
|
function matchesSensitivePath(filePath, patterns) {
|
|
6651
6681
|
const normalized = filePath.replaceAll("\\", "/");
|
|
6652
6682
|
const segments = normalized.split("/");
|
|
6653
6683
|
const baseName = segments.at(-1) ?? normalized;
|
|
6654
6684
|
for (const pattern of patterns) {
|
|
6655
6685
|
const normalizedPattern = pattern.replaceAll("\\", "/");
|
|
6656
|
-
if (normalizedPattern.includes("**")) {
|
|
6657
|
-
const parts = normalizedPattern.split("**").map((part) => part.replace(/^\/+|\/+$/g, ""));
|
|
6658
|
-
const prefix = parts[0]?.replace(/\/+$/, "") ?? "";
|
|
6659
|
-
const suffix = parts[1]?.replace(/^\/+/, "") ?? "";
|
|
6660
|
-
if (prefix && !normalized.startsWith(prefix)) {
|
|
6661
|
-
continue;
|
|
6662
|
-
}
|
|
6663
|
-
if (suffix && !normalized.includes(suffix)) {
|
|
6664
|
-
continue;
|
|
6665
|
-
}
|
|
6666
|
-
if (prefix || suffix) {
|
|
6667
|
-
return true;
|
|
6668
|
-
}
|
|
6669
|
-
}
|
|
6670
6686
|
if (normalizedPattern.includes("*")) {
|
|
6671
|
-
|
|
6672
|
-
`^${normalizedPattern.replaceAll(".", "\\.").replaceAll("*", ".*")}$`
|
|
6673
|
-
);
|
|
6674
|
-
if (regex.test(normalized) || regex.test(baseName)) {
|
|
6687
|
+
if (globPatternMatches(normalizedPattern, normalized, baseName)) {
|
|
6675
6688
|
return true;
|
|
6676
6689
|
}
|
|
6677
6690
|
continue;
|
|
@@ -11073,6 +11086,16 @@ function subagentFingerprintSource(payload, scrubOptions) {
|
|
|
11073
11086
|
}
|
|
11074
11087
|
return scrubValue(payload, scrubOptions);
|
|
11075
11088
|
}
|
|
11089
|
+
function fingerprintToolInputSource(payload) {
|
|
11090
|
+
const toolInput = payload.tool_input;
|
|
11091
|
+
if (!toolInput || typeof toolInput !== "object") {
|
|
11092
|
+
return {};
|
|
11093
|
+
}
|
|
11094
|
+
return redactToolInvocationId(
|
|
11095
|
+
toolInput,
|
|
11096
|
+
typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0
|
|
11097
|
+
);
|
|
11098
|
+
}
|
|
11076
11099
|
function fingerprintReplayPayload(kind, payload, scrubOptions) {
|
|
11077
11100
|
if (!payload) {
|
|
11078
11101
|
return void 0;
|
|
@@ -11182,7 +11205,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
|
|
|
11182
11205
|
}
|
|
11183
11206
|
|
|
11184
11207
|
// src/core/classify-tool.ts
|
|
11185
|
-
import
|
|
11208
|
+
import path50 from "node:path";
|
|
11186
11209
|
init_fingerprint2();
|
|
11187
11210
|
init_path_utils();
|
|
11188
11211
|
init_scrub();
|
|
@@ -11301,11 +11324,8 @@ function worstEffectDecision(decisions) {
|
|
|
11301
11324
|
}
|
|
11302
11325
|
|
|
11303
11326
|
// src/core/effect-ir/shell-lower.ts
|
|
11304
|
-
init_git_resource_identity();
|
|
11305
|
-
init_path_utils();
|
|
11306
11327
|
init_shell_tokenizer();
|
|
11307
|
-
import
|
|
11308
|
-
import path42 from "node:path";
|
|
11328
|
+
import path49 from "node:path";
|
|
11309
11329
|
|
|
11310
11330
|
// src/core/verdict/docker-compose-run.ts
|
|
11311
11331
|
import path37 from "node:path";
|
|
@@ -11645,6 +11665,17 @@ function decodeDockerComposeRun(tokens) {
|
|
|
11645
11665
|
|
|
11646
11666
|
// src/core/verdict/egress-classify.ts
|
|
11647
11667
|
import path38 from "node:path";
|
|
11668
|
+
var EGRESS_TOOL_HEADS = /* @__PURE__ */ new Set([
|
|
11669
|
+
"aws",
|
|
11670
|
+
"curl",
|
|
11671
|
+
"gh",
|
|
11672
|
+
"gcloud",
|
|
11673
|
+
"heroku",
|
|
11674
|
+
"kubectl",
|
|
11675
|
+
"netlify",
|
|
11676
|
+
"vercel",
|
|
11677
|
+
"wget"
|
|
11678
|
+
]);
|
|
11648
11679
|
var CURL_EFFECT_NEUTRAL_FLAGS = /* @__PURE__ */ new Set([
|
|
11649
11680
|
"-f",
|
|
11650
11681
|
"-L",
|
|
@@ -11678,6 +11709,9 @@ var GH_READ_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11678
11709
|
"workflow list",
|
|
11679
11710
|
"workflow view"
|
|
11680
11711
|
]);
|
|
11712
|
+
function isEgressToolHead(head) {
|
|
11713
|
+
return EGRESS_TOOL_HEADS.has(head);
|
|
11714
|
+
}
|
|
11681
11715
|
function decodeEgressEffects(params) {
|
|
11682
11716
|
const head = path38.basename(params.tokens[0] ?? "");
|
|
11683
11717
|
if (head !== "curl" && head !== "wget" && head !== "gh") {
|
|
@@ -13940,7 +13974,7 @@ function extractBalancedParenContent(command, start) {
|
|
|
13940
13974
|
index += 1;
|
|
13941
13975
|
continue;
|
|
13942
13976
|
}
|
|
13943
|
-
if (char === "\\" &&
|
|
13977
|
+
if (char === "\\" && inDouble) {
|
|
13944
13978
|
escaping = true;
|
|
13945
13979
|
index += 1;
|
|
13946
13980
|
continue;
|
|
@@ -14018,7 +14052,9 @@ function hasUnclosedQuote(command) {
|
|
|
14018
14052
|
continue;
|
|
14019
14053
|
}
|
|
14020
14054
|
if (char === "\\") {
|
|
14021
|
-
|
|
14055
|
+
if (quote !== "'") {
|
|
14056
|
+
escaping = true;
|
|
14057
|
+
}
|
|
14022
14058
|
continue;
|
|
14023
14059
|
}
|
|
14024
14060
|
if (quote) {
|
|
@@ -14535,6 +14571,50 @@ function redactCommand(command) {
|
|
|
14535
14571
|
return command.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]").replace(/sk-[A-Za-z0-9]{8,}/g, "sk-[REDACTED]").trim();
|
|
14536
14572
|
}
|
|
14537
14573
|
|
|
14574
|
+
// src/core/effect-ir/argv-delegate.ts
|
|
14575
|
+
function innerRecipeFromArgvDelegate(peel) {
|
|
14576
|
+
if (peel.opaque || peel.innerTokens.length === 0) {
|
|
14577
|
+
return null;
|
|
14578
|
+
}
|
|
14579
|
+
return peel.innerTokens.join(" ");
|
|
14580
|
+
}
|
|
14581
|
+
function peelArgvDelegateArgv(tokens) {
|
|
14582
|
+
const launcher = tokens[0] ?? "";
|
|
14583
|
+
if (!launcher || tokens.length < 2) {
|
|
14584
|
+
return null;
|
|
14585
|
+
}
|
|
14586
|
+
const signals = ["process.argv_delegate"];
|
|
14587
|
+
let index = 1;
|
|
14588
|
+
while (index < tokens.length) {
|
|
14589
|
+
const token = tokens[index] ?? "";
|
|
14590
|
+
if (token === "--") {
|
|
14591
|
+
index += 1;
|
|
14592
|
+
break;
|
|
14593
|
+
}
|
|
14594
|
+
if (token.startsWith("-")) {
|
|
14595
|
+
return {
|
|
14596
|
+
launcher,
|
|
14597
|
+
innerTokens: [],
|
|
14598
|
+
opaque: true,
|
|
14599
|
+
reason: "argv_delegate_wrapper_options",
|
|
14600
|
+
signals: [...signals, "argv_delegate_wrapper_options"]
|
|
14601
|
+
};
|
|
14602
|
+
}
|
|
14603
|
+
break;
|
|
14604
|
+
}
|
|
14605
|
+
const innerTokens = tokens.slice(index);
|
|
14606
|
+
if (innerTokens.length === 0) {
|
|
14607
|
+
return null;
|
|
14608
|
+
}
|
|
14609
|
+
return {
|
|
14610
|
+
launcher,
|
|
14611
|
+
innerTokens,
|
|
14612
|
+
opaque: false,
|
|
14613
|
+
reason: "argv_delegate_peel",
|
|
14614
|
+
signals
|
|
14615
|
+
};
|
|
14616
|
+
}
|
|
14617
|
+
|
|
14538
14618
|
// src/core/effect-ir/shell-build.ts
|
|
14539
14619
|
function buildShellEffectPlan(params) {
|
|
14540
14620
|
const nodes = params.segments.map(buildSegmentNode);
|
|
@@ -14592,717 +14672,631 @@ function mergeNodes(nodes) {
|
|
|
14592
14672
|
return { kind: "merge", children: nodes };
|
|
14593
14673
|
}
|
|
14594
14674
|
|
|
14595
|
-
// src/core/effect-ir/shell-lower.ts
|
|
14596
|
-
|
|
14597
|
-
var
|
|
14598
|
-
|
|
14675
|
+
// src/core/effect-ir/shell-lower/argv-delegate-gate.ts
|
|
14676
|
+
import path42 from "node:path";
|
|
14677
|
+
var ARGV_DELEGATE_INNER_BLOCKLIST = /* @__PURE__ */ new Set([
|
|
14678
|
+
"sudo",
|
|
14679
|
+
"env",
|
|
14680
|
+
"command",
|
|
14681
|
+
"builtin",
|
|
14682
|
+
"exec",
|
|
14683
|
+
"time",
|
|
14684
|
+
"nice",
|
|
14685
|
+
"nohup",
|
|
14686
|
+
"stdbuf",
|
|
14687
|
+
"setsid",
|
|
14688
|
+
"("
|
|
14689
|
+
]);
|
|
14690
|
+
function shouldApplyArgvDelegate(head, innerTokens, depth) {
|
|
14691
|
+
if (depth > 0 || isEgressToolHead(head) || head === "bundle") {
|
|
14692
|
+
return false;
|
|
14693
|
+
}
|
|
14694
|
+
if (ARGV_DELEGATE_INNER_BLOCKLIST.has(head)) {
|
|
14695
|
+
return false;
|
|
14696
|
+
}
|
|
14697
|
+
const innerHead = path42.basename(innerTokens[0] ?? "");
|
|
14698
|
+
if (ARGV_DELEGATE_INNER_BLOCKLIST.has(innerHead)) {
|
|
14699
|
+
return false;
|
|
14700
|
+
}
|
|
14701
|
+
return innerTokens.length >= 2;
|
|
14702
|
+
}
|
|
14703
|
+
function isGrammarUnknownOnly(requirements, head) {
|
|
14704
|
+
if (requirements.length !== 2) {
|
|
14705
|
+
return false;
|
|
14706
|
+
}
|
|
14707
|
+
const [spawn9, indeterminate] = requirements;
|
|
14708
|
+
return spawn9.action === "process.exec" && spawn9.resource.kind === "executable" && spawn9.resource.command === head && spawn9.resource.operation === "spawn" && indeterminate.action === "indeterminate" && indeterminate.evidence.signals.includes("process.grammar_unknown");
|
|
14709
|
+
}
|
|
14710
|
+
|
|
14711
|
+
// src/core/effect-ir/shell-lower/augment.ts
|
|
14712
|
+
init_shell_tokenizer();
|
|
14713
|
+
|
|
14714
|
+
// src/core/effect-ir/shell-lower/requirement.ts
|
|
14599
14715
|
var SECRET_PATH_PATTERN = /(?:^|[/\\])(?:\.env(?:\..*)?|credentials?|secrets?|id_rsa)(?:$|[/\\])/i;
|
|
14600
14716
|
var CONTROL_PLANE_PATH_PATTERN = /^(?:\/etc(?:\/|$)|\/var\/run(?:\/|$)|.*(?:^|[/\\])\.(?:git|ssh|cursor|claude)(?:[/\\]|$))/;
|
|
14601
|
-
function
|
|
14602
|
-
|
|
14603
|
-
|
|
14604
|
-
|
|
14605
|
-
|
|
14606
|
-
|
|
14607
|
-
|
|
14608
|
-
|
|
14717
|
+
function requirement2(tag, action, resource, segment, signals) {
|
|
14718
|
+
return {
|
|
14719
|
+
tag,
|
|
14720
|
+
action,
|
|
14721
|
+
resource,
|
|
14722
|
+
evidence: {
|
|
14723
|
+
level: tag === "indeterminate" ? "indeterminate" : "certain",
|
|
14724
|
+
signals: [...new Set(signals)].sort(),
|
|
14725
|
+
basis: ["shell_semantic_lowering"]
|
|
14726
|
+
},
|
|
14727
|
+
provenance: { segment }
|
|
14728
|
+
};
|
|
14609
14729
|
}
|
|
14610
|
-
function
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
|
|
14614
|
-
|
|
14615
|
-
|
|
14616
|
-
|
|
14617
|
-
|
|
14618
|
-
|
|
14619
|
-
|
|
14620
|
-
|
|
14621
|
-
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
|
|
14627
|
-
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
"indeterminate",
|
|
14638
|
-
{ kind: "unknown" },
|
|
14639
|
-
result.commandRedacted,
|
|
14640
|
-
["shell.cwd_unknown"]
|
|
14641
|
-
)
|
|
14642
|
-
);
|
|
14643
|
-
}
|
|
14644
|
-
result = {
|
|
14645
|
-
...result,
|
|
14646
|
-
requirements,
|
|
14647
|
-
...requiresCwd ? {
|
|
14648
|
-
completeness: "partial",
|
|
14649
|
-
opacity: joinEffectOpacity(result.opacity, "opaque")
|
|
14650
|
-
} : {},
|
|
14651
|
-
signals: [.../* @__PURE__ */ new Set([...result.signals, "shell.cwd_unknown"])]
|
|
14652
|
-
};
|
|
14653
|
-
}
|
|
14654
|
-
lowered.push(result);
|
|
14655
|
-
if (!inferredEnv.DATABASE_URL && startsLocalPostgresService(segment)) {
|
|
14656
|
-
inferredEnv = {
|
|
14657
|
-
...inferredEnv,
|
|
14658
|
-
DATABASE_URL: "postgresql://127.0.0.1:5432/local"
|
|
14659
|
-
};
|
|
14660
|
-
}
|
|
14661
|
-
const nextCwd = resolveCdTransition(segment, cwd);
|
|
14662
|
-
if (nextCwd) {
|
|
14663
|
-
cwd = nextCwd.cwd;
|
|
14664
|
-
cwdKnown = nextCwd.known;
|
|
14665
|
-
}
|
|
14666
|
-
}
|
|
14667
|
-
if (commands.length > 1 && /[\r\n]/.test(command) && lowered.some(
|
|
14668
|
-
(segment) => segment.requirements.some((entry) => entry.action === "network.connect")
|
|
14669
|
-
)) {
|
|
14670
|
-
lowered.push(
|
|
14671
|
-
shellSegment(
|
|
14672
|
-
"[multiline network boundary]",
|
|
14673
|
-
"shell-boundary",
|
|
14674
|
-
[
|
|
14675
|
-
requirement2(
|
|
14676
|
-
"indeterminate",
|
|
14677
|
-
"indeterminate",
|
|
14678
|
-
{ kind: "unknown" },
|
|
14679
|
-
"[multiline network boundary]",
|
|
14680
|
-
["shell.multiline_network_boundary"]
|
|
14681
|
-
)
|
|
14682
|
-
],
|
|
14683
|
-
"opaque",
|
|
14684
|
-
/* @__PURE__ */ new Set(["shell.multiline_network_boundary"])
|
|
14730
|
+
function processRequirement(command, operation, segment, signals) {
|
|
14731
|
+
return requirement2(
|
|
14732
|
+
"process.exec",
|
|
14733
|
+
"process.exec",
|
|
14734
|
+
{ kind: "executable", command, operation },
|
|
14735
|
+
segment,
|
|
14736
|
+
signals
|
|
14737
|
+
);
|
|
14738
|
+
}
|
|
14739
|
+
function unsupportedProcess(command, segment, signal) {
|
|
14740
|
+
return [
|
|
14741
|
+
processRequirement(command, "spawn", segment, [signal]),
|
|
14742
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [signal])
|
|
14743
|
+
];
|
|
14744
|
+
}
|
|
14745
|
+
function addWriteEffects(requirements, resolved, segment, signals) {
|
|
14746
|
+
requirements.push(
|
|
14747
|
+
requirement2("fs.write", "fs.write", { kind: "path", path: resolved }, segment, signals)
|
|
14748
|
+
);
|
|
14749
|
+
if (CONTROL_PLANE_PATH_PATTERN.test(resolved)) {
|
|
14750
|
+
requirements.push(
|
|
14751
|
+
requirement2(
|
|
14752
|
+
"control_plane.write",
|
|
14753
|
+
"control_plane.write",
|
|
14754
|
+
{ kind: "path", path: resolved },
|
|
14755
|
+
segment,
|
|
14756
|
+
[...signals, "protected_path"]
|
|
14685
14757
|
)
|
|
14686
14758
|
);
|
|
14687
14759
|
}
|
|
14688
|
-
return lowered;
|
|
14689
|
-
}
|
|
14690
|
-
function startsLocalPostgresService(command) {
|
|
14691
|
-
const tokens = tokenizeShell(command);
|
|
14692
|
-
return path42.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
14693
14760
|
}
|
|
14694
|
-
function
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
return { cwd: currentCwd, known: false };
|
|
14761
|
+
function addSecretRead(requirements, resolved, segment) {
|
|
14762
|
+
if (SECRET_PATH_PATTERN.test(resolved)) {
|
|
14763
|
+
requirements.push(
|
|
14764
|
+
requirement2("secret.read", "secret.read", { kind: "path", path: resolved }, segment, [
|
|
14765
|
+
"secret_path_read"
|
|
14766
|
+
])
|
|
14767
|
+
);
|
|
14702
14768
|
}
|
|
14703
|
-
return { cwd: resolvePathOperand(target, currentCwd), known: true };
|
|
14704
14769
|
}
|
|
14705
|
-
function
|
|
14706
|
-
if (
|
|
14707
|
-
|
|
14770
|
+
function ensureRequirement(requirements, candidate) {
|
|
14771
|
+
if (!requirements.some(
|
|
14772
|
+
(entry) => entry.action === candidate.action && JSON.stringify(entry.resource) === JSON.stringify(candidate.resource)
|
|
14773
|
+
)) {
|
|
14774
|
+
requirements.push(candidate);
|
|
14708
14775
|
}
|
|
14709
|
-
return requirementValue.action === "process.exec" && requirementValue.resource.kind === "executable" && requirementValue.resource.operation === "spawn";
|
|
14710
|
-
}
|
|
14711
|
-
function joinNestedOpacity(outer, nested) {
|
|
14712
|
-
const nestedOpacity = nested.completeness === "partial" && nested.opacity === "transparent" ? "recursive" : nested.opacity;
|
|
14713
|
-
return joinEffectOpacity(outer, nestedOpacity);
|
|
14714
14776
|
}
|
|
14715
|
-
function
|
|
14716
|
-
const
|
|
14717
|
-
|
|
14718
|
-
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
14723
|
-
const tokens = stripRedirects(
|
|
14724
|
-
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
14725
|
-
).map((token) => expandKnownVariables(token, env));
|
|
14726
|
-
const decoderTokens = alignStructuredTokens(
|
|
14727
|
-
stripStructuredRedirects(lexed.tokens),
|
|
14728
|
-
stripRedirects(parsedTokens)
|
|
14777
|
+
function withProvenances(requirementValue, provenance, contributing) {
|
|
14778
|
+
const provenances = [
|
|
14779
|
+
...requirementValue.provenances ?? [requirementValue.provenance],
|
|
14780
|
+
contributing,
|
|
14781
|
+
provenance
|
|
14782
|
+
].filter(
|
|
14783
|
+
(candidate, index, all) => all.findIndex((entry) => JSON.stringify(entry) === JSON.stringify(candidate)) === index
|
|
14729
14784
|
);
|
|
14730
|
-
|
|
14731
|
-
|
|
14732
|
-
|
|
14733
|
-
const
|
|
14734
|
-
|
|
14735
|
-
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
|
|
14755
|
-
|
|
14756
|
-
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
);
|
|
14768
|
-
return shellSegment(
|
|
14769
|
-
commandRedacted,
|
|
14770
|
-
head,
|
|
14771
|
-
requirements,
|
|
14772
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14773
|
-
signals
|
|
14774
|
-
);
|
|
14775
|
-
}
|
|
14776
|
-
const packageExec = peelPackageExecArgv(tokens);
|
|
14777
|
-
if (packageExec) {
|
|
14778
|
-
requirements.push(
|
|
14779
|
-
...decodePackageExec(packageExec, context.cwd, context.repoRoot, commandRedacted)
|
|
14780
|
-
);
|
|
14781
|
-
for (const signal of packageExec.signals) {
|
|
14782
|
-
signals.add(signal);
|
|
14783
|
-
}
|
|
14784
|
-
if (packageExec.opaque) {
|
|
14785
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14786
|
-
}
|
|
14787
|
-
const innerRecipe = packageExecInnerIsMetadata(packageExec) ? null : innerRecipeFromPeel(packageExec);
|
|
14788
|
-
if (innerRecipe) {
|
|
14789
|
-
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
14790
|
-
...context,
|
|
14791
|
-
command: innerRecipe,
|
|
14792
|
-
env,
|
|
14793
|
-
depth: context.depth + 1
|
|
14794
|
-
});
|
|
14795
|
-
for (const nestedSegment of nested) {
|
|
14796
|
-
requirements.push(
|
|
14797
|
-
...nestedSegment.requirements.map(
|
|
14798
|
-
(entry) => withInnerProvenance(entry, innerRecipe, packageExec.launcher, commandRedacted)
|
|
14799
|
-
)
|
|
14800
|
-
);
|
|
14801
|
-
for (const signal of nestedSegment.signals) {
|
|
14802
|
-
signals.add(signal);
|
|
14785
|
+
return { ...requirementValue, provenance, provenances };
|
|
14786
|
+
}
|
|
14787
|
+
function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegment) {
|
|
14788
|
+
const provenance = {
|
|
14789
|
+
...requirementValue.provenance,
|
|
14790
|
+
segment: outerSegment,
|
|
14791
|
+
innerCommand: requirementValue.provenance.innerCommand ?? innerCommand,
|
|
14792
|
+
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
14793
|
+
};
|
|
14794
|
+
const launcherProvenance = {
|
|
14795
|
+
segment: outerSegment,
|
|
14796
|
+
innerCommand,
|
|
14797
|
+
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
14798
|
+
};
|
|
14799
|
+
return withProvenances(requirementValue, provenance, launcherProvenance);
|
|
14800
|
+
}
|
|
14801
|
+
|
|
14802
|
+
// src/core/effect-ir/shell-lower/tokens.ts
|
|
14803
|
+
init_shell_tokenizer();
|
|
14804
|
+
import path43 from "node:path";
|
|
14805
|
+
var ENV_PREFIX_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
14806
|
+
var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "0:0:0:0:0:0:0:1"]);
|
|
14807
|
+
var METADATA_ONLY_FLAGS = /* @__PURE__ */ new Set(["--version", "-v", "-V", "--help", "-h"]);
|
|
14808
|
+
function extractEnvironment(tokens, inherited) {
|
|
14809
|
+
const env = { ...inherited };
|
|
14810
|
+
const changedNames = /* @__PURE__ */ new Set();
|
|
14811
|
+
if (tokens[0] === "env") {
|
|
14812
|
+
let index = 1;
|
|
14813
|
+
let malformed = false;
|
|
14814
|
+
while (index < tokens.length) {
|
|
14815
|
+
const option = tokens[index] ?? "";
|
|
14816
|
+
if (option === "-u" || option === "--unset") {
|
|
14817
|
+
const name = tokens[index + 1] ?? "";
|
|
14818
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
14819
|
+
malformed = true;
|
|
14820
|
+
index += 1;
|
|
14821
|
+
break;
|
|
14803
14822
|
}
|
|
14804
|
-
|
|
14823
|
+
delete env[name];
|
|
14824
|
+
changedNames.add(name);
|
|
14825
|
+
index += 2;
|
|
14826
|
+
continue;
|
|
14805
14827
|
}
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
14811
|
-
|
|
14812
|
-
|
|
14813
|
-
|
|
14814
|
-
|
|
14815
|
-
|
|
14816
|
-
|
|
14817
|
-
if (recursive.script !== "") {
|
|
14818
|
-
const nested = lowerTopLevelSegments(recursive.script, {
|
|
14819
|
-
...context,
|
|
14820
|
-
command: recursive.script,
|
|
14821
|
-
env,
|
|
14822
|
-
depth: context.depth + 1
|
|
14823
|
-
});
|
|
14824
|
-
for (const nestedSegment of nested) {
|
|
14825
|
-
requirements.push(
|
|
14826
|
-
...nestedSegment.requirements.map(
|
|
14827
|
-
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
14828
|
-
)
|
|
14829
|
-
);
|
|
14830
|
-
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14828
|
+
if (option.startsWith("--unset=")) {
|
|
14829
|
+
const name = option.slice("--unset=".length);
|
|
14830
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
14831
|
+
malformed = true;
|
|
14832
|
+
index += 1;
|
|
14833
|
+
break;
|
|
14834
|
+
}
|
|
14835
|
+
delete env[name];
|
|
14836
|
+
changedNames.add(name);
|
|
14837
|
+
index += 1;
|
|
14838
|
+
continue;
|
|
14831
14839
|
}
|
|
14832
|
-
|
|
14833
|
-
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
recursive.signal,
|
|
14840
|
-
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
14841
|
-
];
|
|
14842
|
-
requirements.push(
|
|
14843
|
-
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
14844
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14845
|
-
...recursiveSignals
|
|
14846
|
-
])
|
|
14847
|
-
);
|
|
14848
|
-
for (const signal of recursiveSignals) signals.add(signal);
|
|
14849
|
-
return shellSegment(
|
|
14850
|
-
commandRedacted,
|
|
14851
|
-
head,
|
|
14852
|
-
requirements,
|
|
14853
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14854
|
-
signals
|
|
14855
|
-
);
|
|
14856
|
-
}
|
|
14857
|
-
const compose = decodeDockerComposeRun(decoderTokens);
|
|
14858
|
-
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14859
|
-
requirements.push(
|
|
14860
|
-
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
14861
|
-
);
|
|
14862
|
-
if (compose.script !== "") {
|
|
14863
|
-
const nested = lowerTopLevelSegments(compose.script, {
|
|
14864
|
-
...context,
|
|
14865
|
-
command: compose.script,
|
|
14866
|
-
env,
|
|
14867
|
-
depth: context.depth + 1
|
|
14868
|
-
});
|
|
14869
|
-
for (const nestedSegment of nested) {
|
|
14870
|
-
requirements.push(
|
|
14871
|
-
...nestedSegment.requirements.map(
|
|
14872
|
-
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
14873
|
-
)
|
|
14874
|
-
);
|
|
14875
|
-
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14876
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14840
|
+
if (option === "-i" || option === "--ignore-environment") {
|
|
14841
|
+
for (const name of Object.keys(env)) {
|
|
14842
|
+
delete env[name];
|
|
14843
|
+
}
|
|
14844
|
+
changedNames.add("*");
|
|
14845
|
+
index += 1;
|
|
14846
|
+
continue;
|
|
14877
14847
|
}
|
|
14848
|
+
if (option === "--") {
|
|
14849
|
+
index += 1;
|
|
14850
|
+
break;
|
|
14851
|
+
}
|
|
14852
|
+
if (option.startsWith("-")) {
|
|
14853
|
+
malformed = true;
|
|
14854
|
+
index += 1;
|
|
14855
|
+
break;
|
|
14856
|
+
}
|
|
14857
|
+
break;
|
|
14878
14858
|
}
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
signals.add("process.docker_compose_run");
|
|
14890
|
-
signals.add(compose.signal);
|
|
14891
|
-
return shellSegment(
|
|
14892
|
-
commandRedacted,
|
|
14893
|
-
head,
|
|
14894
|
-
requirements,
|
|
14895
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14896
|
-
signals
|
|
14897
|
-
);
|
|
14898
|
-
}
|
|
14899
|
-
const launcher = resolveLauncherRecipe({
|
|
14900
|
-
tokens,
|
|
14901
|
-
cwd: context.cwd,
|
|
14902
|
-
repoRoot: context.repoRoot,
|
|
14903
|
-
depth: context.depth
|
|
14904
|
-
});
|
|
14905
|
-
if (launcher) {
|
|
14906
|
-
signals.add(`launcher.${launcher.reason}`);
|
|
14907
|
-
requirements.push(
|
|
14908
|
-
requirement2(
|
|
14909
|
-
"process.exec",
|
|
14910
|
-
"process.exec",
|
|
14911
|
-
{ kind: "executable", command: head, operation: "spawn" },
|
|
14912
|
-
commandRedacted,
|
|
14913
|
-
["launcher.invoke"]
|
|
14914
|
-
)
|
|
14915
|
-
);
|
|
14916
|
-
for (const recipe of launcher.recipes) {
|
|
14917
|
-
const nested = lowerTopLevelSegments(recipe, {
|
|
14918
|
-
...context,
|
|
14919
|
-
command: recipe,
|
|
14920
|
-
env,
|
|
14921
|
-
depth: context.depth + 1
|
|
14922
|
-
});
|
|
14923
|
-
for (const nestedSegment of nested) {
|
|
14924
|
-
requirements.push(
|
|
14925
|
-
...nestedSegment.requirements.map(
|
|
14926
|
-
(entry) => withInnerProvenance(entry, recipe, head, commandRedacted)
|
|
14927
|
-
)
|
|
14928
|
-
);
|
|
14929
|
-
for (const signal of nestedSegment.signals) {
|
|
14930
|
-
signals.add(signal);
|
|
14931
|
-
}
|
|
14932
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14859
|
+
while (index < tokens.length) {
|
|
14860
|
+
const token = tokens[index] ?? "";
|
|
14861
|
+
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
14862
|
+
if (!match) {
|
|
14863
|
+
break;
|
|
14864
|
+
}
|
|
14865
|
+
const [, name, value] = match;
|
|
14866
|
+
if (name) {
|
|
14867
|
+
env[name] = expandKnownVariables(value ?? "", env);
|
|
14868
|
+
changedNames.add(name);
|
|
14933
14869
|
}
|
|
14870
|
+
index += 1;
|
|
14934
14871
|
}
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14942
|
-
}
|
|
14943
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14872
|
+
const commandTokens = tokens.slice(index);
|
|
14873
|
+
return {
|
|
14874
|
+
env,
|
|
14875
|
+
commandTokens,
|
|
14876
|
+
malformed: malformed || commandTokens.length === 0,
|
|
14877
|
+
changedNames
|
|
14878
|
+
};
|
|
14944
14879
|
}
|
|
14945
|
-
const
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
});
|
|
14950
|
-
if (egress) {
|
|
14951
|
-
requirements.push(...egress);
|
|
14952
|
-
for (const signal of egress.flatMap((entry) => entry.evidence.signals)) {
|
|
14953
|
-
signals.add(signal);
|
|
14880
|
+
for (const token of tokens) {
|
|
14881
|
+
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
14882
|
+
if (!match) {
|
|
14883
|
+
break;
|
|
14954
14884
|
}
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
repoRoot: context.repoRoot,
|
|
14960
|
-
segment: commandRedacted
|
|
14961
|
-
});
|
|
14962
|
-
if (git) {
|
|
14963
|
-
requirements.push(...git);
|
|
14964
|
-
for (const signal of git.flatMap((entry) => entry.evidence.signals)) {
|
|
14965
|
-
signals.add(signal);
|
|
14966
|
-
}
|
|
14967
|
-
} else {
|
|
14968
|
-
requirements.push(
|
|
14969
|
-
...decodeProcessOrFilesystem({
|
|
14970
|
-
tokens,
|
|
14971
|
-
head,
|
|
14972
|
-
env,
|
|
14973
|
-
cwd: context.cwd,
|
|
14974
|
-
repoRoot: context.repoRoot,
|
|
14975
|
-
segment: commandRedacted
|
|
14976
|
-
})
|
|
14977
|
-
);
|
|
14885
|
+
const [, name, value] = match;
|
|
14886
|
+
if (name) {
|
|
14887
|
+
env[name] = expandKnownVariables(value ?? "", env);
|
|
14888
|
+
changedNames.add(name);
|
|
14978
14889
|
}
|
|
14979
14890
|
}
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
environmentSignals
|
|
14989
|
-
)
|
|
14990
|
-
);
|
|
14991
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14992
|
-
for (const signal of environmentSignals) {
|
|
14993
|
-
signals.add(signal);
|
|
14891
|
+
return { env, malformed: false, changedNames };
|
|
14892
|
+
}
|
|
14893
|
+
function expandKnownVariables(token, env) {
|
|
14894
|
+
return token.replace(
|
|
14895
|
+
/\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g,
|
|
14896
|
+
(raw, a, b) => {
|
|
14897
|
+
const value = env[a ?? b];
|
|
14898
|
+
return value === void 0 ? raw : value;
|
|
14994
14899
|
}
|
|
14900
|
+
);
|
|
14901
|
+
}
|
|
14902
|
+
function stripRedirects(tokens) {
|
|
14903
|
+
const stripped = [];
|
|
14904
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14905
|
+
const token = tokens[index] ?? "";
|
|
14906
|
+
if (isFdDuplication(token)) {
|
|
14907
|
+
continue;
|
|
14908
|
+
}
|
|
14909
|
+
if (!isRedirectOperator(token)) {
|
|
14910
|
+
stripped.push(token);
|
|
14911
|
+
continue;
|
|
14912
|
+
}
|
|
14913
|
+
index += 1;
|
|
14995
14914
|
}
|
|
14996
|
-
|
|
14997
|
-
signals.add("pipe_to_shell");
|
|
14998
|
-
ensureRequirement(
|
|
14999
|
-
requirements,
|
|
15000
|
-
requirement2(
|
|
15001
|
-
"process.exec",
|
|
15002
|
-
"process.exec",
|
|
15003
|
-
{ kind: "executable", command: head || "sh", operation: "spawn" },
|
|
15004
|
-
commandRedacted,
|
|
15005
|
-
["pipe_to_shell"]
|
|
15006
|
-
)
|
|
15007
|
-
);
|
|
15008
|
-
ensureRequirement(
|
|
15009
|
-
requirements,
|
|
15010
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
15011
|
-
"pipe_to_shell"
|
|
15012
|
-
])
|
|
15013
|
-
);
|
|
15014
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
15015
|
-
}
|
|
15016
|
-
if (opacity === "unparseable" || opacity === "opaque") {
|
|
15017
|
-
ensureRequirement(
|
|
15018
|
-
requirements,
|
|
15019
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
15020
|
-
`shell.${opacity}`
|
|
15021
|
-
])
|
|
15022
|
-
);
|
|
15023
|
-
}
|
|
15024
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14915
|
+
return stripped;
|
|
15025
14916
|
}
|
|
15026
|
-
function
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15030
|
-
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
14917
|
+
function stripStructuredRedirects(tokens) {
|
|
14918
|
+
const stripped = [];
|
|
14919
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14920
|
+
const token = tokens[index];
|
|
14921
|
+
if (!token) continue;
|
|
14922
|
+
if (isFdDuplication(token.value)) {
|
|
14923
|
+
continue;
|
|
14924
|
+
}
|
|
14925
|
+
if (!isRedirectOperator(token.value)) {
|
|
14926
|
+
stripped.push(token);
|
|
14927
|
+
continue;
|
|
14928
|
+
}
|
|
14929
|
+
index += 1;
|
|
15034
14930
|
}
|
|
15035
|
-
|
|
15036
|
-
|
|
14931
|
+
return stripped;
|
|
14932
|
+
}
|
|
14933
|
+
function alignStructuredTokens(tokens, values) {
|
|
14934
|
+
if (values.length === 0) return [];
|
|
14935
|
+
for (let start = tokens.length - values.length; start >= 0; start -= 1) {
|
|
14936
|
+
const candidate = tokens.slice(start);
|
|
14937
|
+
if (candidate.length === values.length && candidate.every((token, index) => token.value === values[index])) {
|
|
14938
|
+
return candidate;
|
|
14939
|
+
}
|
|
15037
14940
|
}
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
if (
|
|
15042
|
-
return
|
|
15043
|
-
requirement2(
|
|
15044
|
-
"process.exec",
|
|
15045
|
-
"process.exec",
|
|
15046
|
-
{ kind: "executable", command: local.path, operation: "inspect" },
|
|
15047
|
-
segment,
|
|
15048
|
-
["package_exec.delegate", "package_exec.local_bin_resolved"]
|
|
15049
|
-
)
|
|
15050
|
-
] : [];
|
|
14941
|
+
return [];
|
|
14942
|
+
}
|
|
14943
|
+
function resolvePathOperand(operand, cwd) {
|
|
14944
|
+
if (operand === "~") {
|
|
14945
|
+
return process.env.HOME ?? operand;
|
|
15051
14946
|
}
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
kind: "network",
|
|
15055
|
-
host: "registry.npmjs.org",
|
|
15056
|
-
protocol: "registry",
|
|
15057
|
-
mode: "read",
|
|
15058
|
-
payload: "none"
|
|
15059
|
-
} : {
|
|
15060
|
-
kind: "network",
|
|
15061
|
-
host: source.host,
|
|
15062
|
-
...source.port ? { port: source.port } : {},
|
|
15063
|
-
protocol: source.protocol,
|
|
15064
|
-
mode: "read",
|
|
15065
|
-
payload: "none"
|
|
15066
|
-
}
|
|
15067
|
-
);
|
|
15068
|
-
if (networkResources.length === 0) {
|
|
15069
|
-
networkResources.push({
|
|
15070
|
-
kind: "network",
|
|
15071
|
-
host: "registry.npmjs.org",
|
|
15072
|
-
protocol: "registry",
|
|
15073
|
-
mode: "read",
|
|
15074
|
-
payload: "none"
|
|
15075
|
-
});
|
|
14947
|
+
if (operand.startsWith("~/")) {
|
|
14948
|
+
return path43.join(process.env.HOME ?? "~", operand.slice(2));
|
|
15076
14949
|
}
|
|
15077
|
-
return
|
|
15078
|
-
...networkResources.map(
|
|
15079
|
-
(resource) => requirement2("network.acquire", "network.connect", resource, segment, [
|
|
15080
|
-
"package_acquire_possible"
|
|
15081
|
-
])
|
|
15082
|
-
),
|
|
15083
|
-
requirement2(
|
|
15084
|
-
"fs.write",
|
|
15085
|
-
"fs.write",
|
|
15086
|
-
{ kind: "package-cache", manager: peel.launcher === "pnpm" ? "pnpm" : "npm" },
|
|
15087
|
-
segment,
|
|
15088
|
-
["package_cache_write"]
|
|
15089
|
-
),
|
|
15090
|
-
...metadataOnly ? [
|
|
15091
|
-
requirement2(
|
|
15092
|
-
"process.exec",
|
|
15093
|
-
"process.exec",
|
|
15094
|
-
{ kind: "executable", command: binHead || peel.launcher, operation: "inspect" },
|
|
15095
|
-
segment,
|
|
15096
|
-
["package_exec.delegate"]
|
|
15097
|
-
)
|
|
15098
|
-
] : []
|
|
15099
|
-
];
|
|
14950
|
+
return path43.resolve(cwd, operand);
|
|
15100
14951
|
}
|
|
15101
|
-
function
|
|
15102
|
-
|
|
15103
|
-
return args.length > 0 && args.every((arg) => ["--help", "--version", "-V", "-h", "-v"].includes(arg));
|
|
14952
|
+
function isOptionToken(value) {
|
|
14953
|
+
return value.startsWith("-") || value.startsWith("+");
|
|
15104
14954
|
}
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
14955
|
+
function isShellHead(head) {
|
|
14956
|
+
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
14957
|
+
}
|
|
14958
|
+
function pipeToShell(command) {
|
|
14959
|
+
return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
|
|
15108
14960
|
}
|
|
15109
14961
|
function executableBaseName(head) {
|
|
15110
|
-
return
|
|
14962
|
+
return path43.basename(head);
|
|
15111
14963
|
}
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
const subcommand = args[0];
|
|
15115
|
-
if (!subcommand || subcommand.startsWith("-")) {
|
|
15116
|
-
return false;
|
|
15117
|
-
}
|
|
15118
|
-
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
14964
|
+
function isMetadataOnlyArgv(argv) {
|
|
14965
|
+
return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
|
|
15119
14966
|
}
|
|
15120
|
-
function
|
|
15121
|
-
|
|
15122
|
-
|
|
14967
|
+
function databaseEndpoint(raw) {
|
|
14968
|
+
if (!raw || raw.includes("$")) {
|
|
14969
|
+
return null;
|
|
14970
|
+
}
|
|
14971
|
+
try {
|
|
14972
|
+
const url = new URL(raw);
|
|
14973
|
+
if (!url.hostname || !url.protocol) {
|
|
14974
|
+
return null;
|
|
14975
|
+
}
|
|
14976
|
+
return {
|
|
14977
|
+
host: url.hostname.toLowerCase(),
|
|
14978
|
+
protocol: url.protocol.slice(0, -1),
|
|
14979
|
+
...url.port ? { port: Number(url.port) } : {}
|
|
14980
|
+
};
|
|
14981
|
+
} catch {
|
|
14982
|
+
return null;
|
|
14983
|
+
}
|
|
15123
14984
|
}
|
|
15124
|
-
|
|
15125
|
-
|
|
15126
|
-
|
|
15127
|
-
|
|
15128
|
-
|
|
15129
|
-
|
|
14985
|
+
|
|
14986
|
+
// src/core/effect-ir/shell-lower/augment.ts
|
|
14987
|
+
function addRedirectEffects(requirements, tokens, env, context, segment) {
|
|
14988
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14989
|
+
const operator = tokens[index] ?? "";
|
|
14990
|
+
if (!isRedirectOperator(operator) || isFdDuplication(operator)) {
|
|
14991
|
+
continue;
|
|
15130
14992
|
}
|
|
15131
|
-
|
|
15132
|
-
|
|
15133
|
-
|
|
15134
|
-
|
|
15135
|
-
|
|
15136
|
-
|
|
14993
|
+
const rawTarget = tokens[index + 1];
|
|
14994
|
+
if (!rawTarget) {
|
|
14995
|
+
requirements.push(
|
|
14996
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14997
|
+
"shell.redirect_target_missing"
|
|
14998
|
+
])
|
|
14999
|
+
);
|
|
15000
|
+
continue;
|
|
15001
|
+
}
|
|
15002
|
+
if (operator.includes("<<")) {
|
|
15003
|
+
requirements.push(
|
|
15004
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15005
|
+
"shell.heredoc_opaque"
|
|
15006
|
+
])
|
|
15007
|
+
);
|
|
15137
15008
|
index += 1;
|
|
15138
15009
|
continue;
|
|
15139
15010
|
}
|
|
15140
|
-
|
|
15141
|
-
|
|
15011
|
+
const target = expandKnownVariables(rawTarget, env);
|
|
15012
|
+
const resolved = resolvePathOperand(target, context.cwd);
|
|
15013
|
+
if (resolved === "/dev/null") {
|
|
15014
|
+
index += 1;
|
|
15142
15015
|
continue;
|
|
15143
15016
|
}
|
|
15144
|
-
if (
|
|
15145
|
-
|
|
15146
|
-
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
}
|
|
15152
|
-
if (arg.startsWith("-n")) {
|
|
15153
|
-
continue;
|
|
15154
|
-
}
|
|
15155
|
-
return null;
|
|
15017
|
+
if (operator.includes("<")) {
|
|
15018
|
+
requirements.push(
|
|
15019
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
15020
|
+
"shell.input_redirect"
|
|
15021
|
+
])
|
|
15022
|
+
);
|
|
15023
|
+
addSecretRead(requirements, resolved, segment);
|
|
15156
15024
|
}
|
|
15157
|
-
if (
|
|
15158
|
-
|
|
15025
|
+
if (operator.includes(">")) {
|
|
15026
|
+
addWriteEffects(requirements, resolved, segment, ["shell.output_redirect"]);
|
|
15159
15027
|
}
|
|
15160
|
-
|
|
15028
|
+
index += 1;
|
|
15161
15029
|
}
|
|
15162
|
-
return null;
|
|
15163
15030
|
}
|
|
15164
|
-
function
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15031
|
+
function effectChangingEnvironmentSignals(head, env, changedNames) {
|
|
15032
|
+
if (head === "curl" && (env.CURL_HOME || changedNames.has("CURL_HOME") || changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME"))) {
|
|
15033
|
+
return ["egress.curl.environment_config_override"];
|
|
15034
|
+
}
|
|
15035
|
+
if (head === "wget" && (env.WGETRC || changedNames.has("WGETRC") || changedNames.has("HOME"))) {
|
|
15036
|
+
return ["egress.wget.environment_config_override"];
|
|
15037
|
+
}
|
|
15038
|
+
if (head !== "git") {
|
|
15039
|
+
return [];
|
|
15040
|
+
}
|
|
15041
|
+
const hazardousNames = /* @__PURE__ */ new Set([
|
|
15042
|
+
"GIT_ASKPASS",
|
|
15043
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
15044
|
+
"GIT_CEILING_DIRECTORIES",
|
|
15045
|
+
"GIT_COMMON_DIR",
|
|
15046
|
+
"GIT_CONFIG",
|
|
15047
|
+
"GIT_CONFIG_GLOBAL",
|
|
15048
|
+
"GIT_CONFIG_SYSTEM",
|
|
15049
|
+
"GIT_DIR",
|
|
15050
|
+
"GIT_DISCOVERY_ACROSS_FILESYSTEM",
|
|
15051
|
+
"GIT_EDITOR",
|
|
15052
|
+
"GIT_EXEC_PATH",
|
|
15053
|
+
"GIT_EXTERNAL_DIFF",
|
|
15054
|
+
"GIT_INDEX_FILE",
|
|
15055
|
+
"GIT_NAMESPACE",
|
|
15056
|
+
"GIT_OBJECT_DIRECTORY",
|
|
15057
|
+
"GIT_PAGER",
|
|
15058
|
+
"GIT_PROXY_COMMAND",
|
|
15059
|
+
"GIT_QUARANTINE_PATH",
|
|
15060
|
+
"GIT_SEQUENCE_EDITOR",
|
|
15061
|
+
"GIT_SHALLOW_FILE",
|
|
15062
|
+
"GIT_SSH",
|
|
15063
|
+
"GIT_SSH_COMMAND",
|
|
15064
|
+
"GIT_TEMPLATE_DIR",
|
|
15065
|
+
"GIT_WORK_TREE",
|
|
15066
|
+
"SSH_ASKPASS"
|
|
15067
|
+
]);
|
|
15068
|
+
const overridden = changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME") || Object.entries(env).some(([name, value]) => {
|
|
15069
|
+
if (!value) {
|
|
15070
|
+
return false;
|
|
15071
|
+
}
|
|
15072
|
+
if (hazardousNames.has(name) || /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(name) || /^GIT_TRACE/.test(name)) {
|
|
15073
|
+
return true;
|
|
15074
|
+
}
|
|
15075
|
+
return name === "GIT_CONFIG_COUNT" && value !== "0";
|
|
15076
|
+
});
|
|
15077
|
+
return overridden ? ["git.environment_execution_or_config_override"] : [];
|
|
15168
15078
|
}
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15079
|
+
|
|
15080
|
+
// src/core/effect-ir/shell-lower/decode-process.ts
|
|
15081
|
+
import path47 from "node:path";
|
|
15082
|
+
|
|
15083
|
+
// src/core/effect-ir/shell-lower/decoders/belay.ts
|
|
15084
|
+
import path44 from "node:path";
|
|
15085
|
+
function decodeBelay(args, repoRoot, segment) {
|
|
15086
|
+
const [section, operation, key] = args;
|
|
15087
|
+
const judgeCommand = section === "judge" && operation !== void 0 && ["consent", "list", "status", "test", "use"].includes(operation);
|
|
15088
|
+
const configRead = section === "config" && (operation === void 0 || operation === "list" || operation === "get" && key?.startsWith("judge."));
|
|
15089
|
+
const configJudgeMutation = section === "config" && (["set", "unset"].includes(operation ?? "") && key?.startsWith("judge.") || operation === "credential" && key === "mode");
|
|
15090
|
+
if (judgeCommand || configRead || configJudgeMutation) {
|
|
15173
15091
|
return [
|
|
15174
|
-
processRequirement(
|
|
15175
|
-
|
|
15176
|
-
|
|
15092
|
+
processRequirement("belay", "inspect", segment, [
|
|
15093
|
+
"belay_control_plane_command",
|
|
15094
|
+
configJudgeMutation ? "belay.config_judge_mutation" : "belay.config_read"
|
|
15095
|
+
])
|
|
15096
|
+
];
|
|
15097
|
+
}
|
|
15098
|
+
if (section === "config" && ["set", "unset", "credential"].includes(operation ?? "")) {
|
|
15099
|
+
return [
|
|
15100
|
+
requirement2(
|
|
15101
|
+
"control_plane.write",
|
|
15102
|
+
"control_plane.write",
|
|
15103
|
+
{ kind: "path", path: path44.join(repoRoot, ".belay-control-plane") },
|
|
15177
15104
|
segment,
|
|
15178
|
-
|
|
15105
|
+
["belay.config_non_judge_mutation"]
|
|
15179
15106
|
)
|
|
15180
15107
|
];
|
|
15181
15108
|
}
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15109
|
+
return [processRequirement("belay", "spawn", segment, ["process.known_local_spawn"])];
|
|
15110
|
+
}
|
|
15111
|
+
|
|
15112
|
+
// src/core/effect-ir/shell-lower/decoders/builtins.ts
|
|
15113
|
+
function decodeSetBuiltin(args) {
|
|
15114
|
+
let index = 0;
|
|
15115
|
+
while (index < args.length) {
|
|
15116
|
+
const arg = args[index] ?? "";
|
|
15117
|
+
if (arg === "--") {
|
|
15118
|
+
index += 1;
|
|
15119
|
+
continue;
|
|
15186
15120
|
}
|
|
15187
|
-
|
|
15121
|
+
if (arg === "-o" || arg === "+o") {
|
|
15122
|
+
if (!args[index + 1]) {
|
|
15123
|
+
return false;
|
|
15124
|
+
}
|
|
15125
|
+
index += 2;
|
|
15126
|
+
continue;
|
|
15127
|
+
}
|
|
15128
|
+
if (/^[-+][A-Za-z0-9]+$/.test(arg)) {
|
|
15129
|
+
index += 1;
|
|
15130
|
+
continue;
|
|
15131
|
+
}
|
|
15132
|
+
return false;
|
|
15188
15133
|
}
|
|
15189
|
-
return
|
|
15134
|
+
return true;
|
|
15190
15135
|
}
|
|
15191
|
-
function
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
return unsupportedProcess("ruby", segment, "process.ruby_grammar_incomplete");
|
|
15195
|
-
}
|
|
15196
|
-
const scriptPath = resolvePathOperand(parsed.scriptPath, cwd);
|
|
15197
|
-
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15198
|
-
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15136
|
+
function decodeShellControlBuiltin(head, args) {
|
|
15137
|
+
if (head === "set") {
|
|
15138
|
+
return decodeSetBuiltin(args) ? [] : null;
|
|
15199
15139
|
}
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15140
|
+
if (head === "wait") {
|
|
15141
|
+
if (args.length === 0 || args.every((arg) => /^\d+$/.test(arg))) {
|
|
15142
|
+
return [];
|
|
15204
15143
|
}
|
|
15144
|
+
return null;
|
|
15205
15145
|
}
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
];
|
|
15212
|
-
for (const includePath of parsed.includePaths) {
|
|
15213
|
-
lowered.push(
|
|
15214
|
-
requirement2(
|
|
15215
|
-
"fs.read",
|
|
15216
|
-
"fs.read",
|
|
15217
|
-
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15218
|
-
segment,
|
|
15219
|
-
["ruby.minitest_load_path_read"]
|
|
15220
|
-
)
|
|
15221
|
-
);
|
|
15146
|
+
if (head === "exit") {
|
|
15147
|
+
if (args.length === 0 || args.length === 1 && /^-?\d+$/.test(args[0] ?? "")) {
|
|
15148
|
+
return [];
|
|
15149
|
+
}
|
|
15150
|
+
return null;
|
|
15222
15151
|
}
|
|
15223
|
-
return
|
|
15152
|
+
return null;
|
|
15224
15153
|
}
|
|
15225
|
-
function
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15154
|
+
function validLsof(args) {
|
|
15155
|
+
const flagsWithoutValues = /* @__PURE__ */ new Set(["-a", "-b", "-l", "-n", "-P", "-R", "-t", "-V"]);
|
|
15156
|
+
const flagsWithValues = /* @__PURE__ */ new Set(["-c", "-d", "-F", "-g", "-p", "-T", "-u", "+d", "+D"]);
|
|
15157
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15158
|
+
const arg = args[index] ?? "";
|
|
15159
|
+
if (flagsWithoutValues.has(arg) || arg === "-i") {
|
|
15160
|
+
continue;
|
|
15229
15161
|
}
|
|
15230
|
-
if (
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
const innerBase = executableBaseName(innerHead);
|
|
15234
|
-
if ((innerBase === "rails" || innerBase === "rake") && railsReadOnlySubcommand(innerArgs)) {
|
|
15235
|
-
return [
|
|
15236
|
-
processRequirement(innerHead, "inspect", segment, ["process.inspect.rails_read_only"])
|
|
15237
|
-
];
|
|
15238
|
-
}
|
|
15239
|
-
if (isMetadataOnlyArgv(innerArgs)) {
|
|
15240
|
-
return [
|
|
15241
|
-
processRequirement(innerHead, "inspect", segment, [
|
|
15242
|
-
"process.inspect.bundle_exec_metadata"
|
|
15243
|
-
])
|
|
15244
|
-
];
|
|
15245
|
-
}
|
|
15246
|
-
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15247
|
-
if (bundleExecInner) {
|
|
15248
|
-
return bundleExecInner;
|
|
15162
|
+
if (flagsWithValues.has(arg)) {
|
|
15163
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15164
|
+
return false;
|
|
15249
15165
|
}
|
|
15166
|
+
index += 1;
|
|
15167
|
+
continue;
|
|
15168
|
+
}
|
|
15169
|
+
if (/^-[ablnPRtV]+$/.test(arg) && [...arg.slice(1)].every((flag) => "ablnPRtV".includes(flag)) || /^-i(?:TCP|UDP)?(?::\d+(?:-\d+)?)?$/.test(arg) || /^-s(?:TCP|UDP):[A-Za-z]+$/.test(arg) || /^-(?:c|d|F|g|p|T|u).+$/.test(arg) || /^\+(?:d|D).+$/.test(arg)) {
|
|
15170
|
+
continue;
|
|
15250
15171
|
}
|
|
15251
|
-
return
|
|
15252
|
-
}
|
|
15253
|
-
if ((head === "ruby" || head === "yarn") && args.length >= 1 && isMetadataOnlyArgv(args)) {
|
|
15254
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15255
|
-
}
|
|
15256
|
-
if (head === "make" && args.includes("-n")) {
|
|
15257
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.make_dry_run"])];
|
|
15258
|
-
}
|
|
15259
|
-
const base = executableBaseName(head);
|
|
15260
|
-
if ((base === "rails" || base === "rake") && railsReadOnlySubcommand(args)) {
|
|
15261
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.rails_read_only"])];
|
|
15172
|
+
return false;
|
|
15262
15173
|
}
|
|
15263
|
-
return
|
|
15174
|
+
return true;
|
|
15264
15175
|
}
|
|
15265
|
-
function
|
|
15266
|
-
|
|
15267
|
-
|
|
15176
|
+
function validPs(args) {
|
|
15177
|
+
const bareForms = /* @__PURE__ */ new Set(["aux", "ax", "x", "u"]);
|
|
15178
|
+
const flagsWithoutValues = /* @__PURE__ */ new Set(["-A", "-a", "-d", "-e", "-f", "-j", "-l", "-T", "-x"]);
|
|
15179
|
+
const flagsWithValues = /* @__PURE__ */ new Set([
|
|
15180
|
+
"--format",
|
|
15181
|
+
"--group",
|
|
15182
|
+
"--pid",
|
|
15183
|
+
"--ppid",
|
|
15184
|
+
"--sort",
|
|
15185
|
+
"--tty",
|
|
15186
|
+
"--user"
|
|
15187
|
+
]);
|
|
15188
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15268
15189
|
const arg = args[index] ?? "";
|
|
15269
|
-
if (arg
|
|
15270
|
-
index += 1;
|
|
15190
|
+
if (bareForms.has(arg) || flagsWithoutValues.has(arg)) {
|
|
15271
15191
|
continue;
|
|
15272
15192
|
}
|
|
15273
|
-
if (arg
|
|
15274
|
-
if (!args[index + 1]) {
|
|
15193
|
+
if (flagsWithValues.has(arg)) {
|
|
15194
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15275
15195
|
return false;
|
|
15276
15196
|
}
|
|
15277
|
-
index +=
|
|
15197
|
+
index += 1;
|
|
15278
15198
|
continue;
|
|
15279
15199
|
}
|
|
15280
|
-
if (/^
|
|
15281
|
-
index += 1;
|
|
15200
|
+
if (/^(?:--format|--group|--pid|--ppid|--sort|--tty|--user)=.+$/.test(arg)) {
|
|
15282
15201
|
continue;
|
|
15283
15202
|
}
|
|
15203
|
+
if (/^-[^-]/.test(arg)) {
|
|
15204
|
+
const noValue = /* @__PURE__ */ new Set(["A", "a", "d", "e", "f", "j", "l", "T", "x"]);
|
|
15205
|
+
const withValue = /* @__PURE__ */ new Set(["G", "g", "N", "o", "p", "t", "U", "u"]);
|
|
15206
|
+
const characters = arg.slice(1);
|
|
15207
|
+
let valid = true;
|
|
15208
|
+
for (let optionIndex = 0; optionIndex < characters.length; optionIndex += 1) {
|
|
15209
|
+
const option = characters[optionIndex] ?? "";
|
|
15210
|
+
if (noValue.has(option)) {
|
|
15211
|
+
continue;
|
|
15212
|
+
}
|
|
15213
|
+
if (withValue.has(option)) {
|
|
15214
|
+
if (optionIndex === characters.length - 1) {
|
|
15215
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15216
|
+
return false;
|
|
15217
|
+
}
|
|
15218
|
+
index += 1;
|
|
15219
|
+
}
|
|
15220
|
+
break;
|
|
15221
|
+
}
|
|
15222
|
+
valid = false;
|
|
15223
|
+
break;
|
|
15224
|
+
}
|
|
15225
|
+
if (valid) {
|
|
15226
|
+
continue;
|
|
15227
|
+
}
|
|
15228
|
+
}
|
|
15284
15229
|
return false;
|
|
15285
15230
|
}
|
|
15286
15231
|
return true;
|
|
15287
15232
|
}
|
|
15288
|
-
function
|
|
15289
|
-
|
|
15290
|
-
|
|
15233
|
+
function validFilesystemTest(head, args) {
|
|
15234
|
+
const operands = head === "[" && args.at(-1) === "]" ? args.slice(0, -1) : args;
|
|
15235
|
+
if (head === "[" && args.at(-1) !== "]") {
|
|
15236
|
+
return false;
|
|
15291
15237
|
}
|
|
15292
|
-
|
|
15293
|
-
|
|
15294
|
-
|
|
15238
|
+
return operands.length === 2 && (/* @__PURE__ */ new Set(["-b", "-c", "-d", "-e", "-f", "-h", "-L", "-r", "-s", "-w", "-x"])).has(
|
|
15239
|
+
operands[0] ?? ""
|
|
15240
|
+
) && Boolean(operands[1]);
|
|
15241
|
+
}
|
|
15242
|
+
function bashSyntaxTarget(args) {
|
|
15243
|
+
let syntaxOnly = false;
|
|
15244
|
+
let script = null;
|
|
15245
|
+
const shortFlags = new Set("abefhkmnptuvxBCEHPT".split(""));
|
|
15246
|
+
const longFlags = /* @__PURE__ */ new Set([
|
|
15247
|
+
"--debugger",
|
|
15248
|
+
"--dump-po-strings",
|
|
15249
|
+
"--dump-strings",
|
|
15250
|
+
"--help",
|
|
15251
|
+
"--login",
|
|
15252
|
+
"--noediting",
|
|
15253
|
+
"--noprofile",
|
|
15254
|
+
"--norc",
|
|
15255
|
+
"--posix",
|
|
15256
|
+
"--restricted",
|
|
15257
|
+
"--verbose",
|
|
15258
|
+
"--version"
|
|
15259
|
+
]);
|
|
15260
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15261
|
+
const arg = args[index] ?? "";
|
|
15262
|
+
if (arg === "-c" || arg === "-lc") {
|
|
15263
|
+
return null;
|
|
15295
15264
|
}
|
|
15296
|
-
|
|
15297
|
-
|
|
15298
|
-
|
|
15299
|
-
|
|
15300
|
-
|
|
15265
|
+
if (arg === "-O" || arg === "+O" || arg === "--rcfile" || arg === "--init-file") {
|
|
15266
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15267
|
+
return null;
|
|
15268
|
+
}
|
|
15269
|
+
index += 1;
|
|
15270
|
+
continue;
|
|
15301
15271
|
}
|
|
15302
|
-
|
|
15272
|
+
if (arg.startsWith("-O") && arg.length > 2 || arg.startsWith("+O") && arg.length > 2 || arg.startsWith("--rcfile=") && arg.length > "--rcfile=".length || arg.startsWith("--init-file=") && arg.length > "--init-file=".length) {
|
|
15273
|
+
continue;
|
|
15274
|
+
}
|
|
15275
|
+
if (longFlags.has(arg)) {
|
|
15276
|
+
continue;
|
|
15277
|
+
}
|
|
15278
|
+
if (/^[+-][A-Za-z]+$/.test(arg)) {
|
|
15279
|
+
const options = arg.slice(1);
|
|
15280
|
+
if ([...options].some((option) => !shortFlags.has(option))) {
|
|
15281
|
+
return null;
|
|
15282
|
+
}
|
|
15283
|
+
syntaxOnly ||= options.includes("n");
|
|
15284
|
+
continue;
|
|
15285
|
+
}
|
|
15286
|
+
if (arg === "--") {
|
|
15287
|
+
script = args[index + 1] ?? null;
|
|
15288
|
+
break;
|
|
15289
|
+
}
|
|
15290
|
+
if (arg.startsWith("-") || arg.startsWith("+")) {
|
|
15291
|
+
return null;
|
|
15292
|
+
}
|
|
15293
|
+
script = arg;
|
|
15294
|
+
break;
|
|
15303
15295
|
}
|
|
15304
|
-
return null;
|
|
15296
|
+
return syntaxOnly ? script : null;
|
|
15305
15297
|
}
|
|
15298
|
+
|
|
15299
|
+
// src/core/effect-ir/shell-lower/decoders/docker.ts
|
|
15306
15300
|
function decodeDockerComposeRun2(head, args, segment) {
|
|
15307
15301
|
let composeArgs = null;
|
|
15308
15302
|
let command = head;
|
|
@@ -15320,402 +15314,499 @@ function decodeDockerComposeRun2(head, args, segment) {
|
|
|
15320
15314
|
}
|
|
15321
15315
|
return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
|
|
15322
15316
|
}
|
|
15323
|
-
function
|
|
15324
|
-
|
|
15325
|
-
|
|
15326
|
-
|
|
15327
|
-
|
|
15328
|
-
}
|
|
15329
|
-
const shellControl = decodeShellControlBuiltin(head, args);
|
|
15330
|
-
if (shellControl) {
|
|
15331
|
-
return shellControl;
|
|
15332
|
-
}
|
|
15333
|
-
if (isCommandInspection(tokens)) {
|
|
15334
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
15335
|
-
}
|
|
15336
|
-
if (head === "lsof") {
|
|
15337
|
-
return validLsof(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.lsof"])] : unsupportedProcess(head, segment, "process.lsof_grammar_incomplete");
|
|
15338
|
-
}
|
|
15339
|
-
if (head === "ps") {
|
|
15340
|
-
return validPs(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.ps"])] : unsupportedProcess(head, segment, "process.ps_grammar_incomplete");
|
|
15341
|
-
}
|
|
15342
|
-
if (head === "test" || head === "[") {
|
|
15343
|
-
return validFilesystemTest(head, args) ? [processRequirement(head, "inspect", segment, ["process.inspect.filesystem_test"])] : unsupportedProcess(head, segment, "process.filesystem_test_grammar_incomplete");
|
|
15344
|
-
}
|
|
15345
|
-
if (head === "docker") {
|
|
15346
|
-
if (args[0] === "info") {
|
|
15347
|
-
return validDockerInfo(args.slice(1)) ? [processRequirement(head, "inspect", segment, ["process.inspect.docker_info"])] : unsupportedProcess(head, segment, "process.docker_info_grammar_incomplete");
|
|
15317
|
+
function validDockerInfo(args) {
|
|
15318
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15319
|
+
const arg = args[index] ?? "";
|
|
15320
|
+
if (arg === "--help") {
|
|
15321
|
+
continue;
|
|
15348
15322
|
}
|
|
15349
|
-
if (
|
|
15350
|
-
|
|
15323
|
+
if (arg === "--format" || arg === "-f") {
|
|
15324
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15325
|
+
return false;
|
|
15326
|
+
}
|
|
15327
|
+
index += 1;
|
|
15328
|
+
continue;
|
|
15351
15329
|
}
|
|
15352
|
-
if (
|
|
15353
|
-
(arg
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
requirement2(
|
|
15358
|
-
"network.connect",
|
|
15359
|
-
"network.connect",
|
|
15360
|
-
{
|
|
15361
|
-
kind: "network",
|
|
15362
|
-
host: "registry",
|
|
15363
|
-
protocol: "container-registry",
|
|
15364
|
-
mode: "mutate",
|
|
15365
|
-
payload: "present"
|
|
15366
|
-
},
|
|
15367
|
-
segment,
|
|
15368
|
-
["tier0_external", "docker.remote_mutation"]
|
|
15369
|
-
)
|
|
15370
|
-
];
|
|
15330
|
+
if (arg.startsWith("--format=")) {
|
|
15331
|
+
if (arg.slice("--format=".length).length === 0) {
|
|
15332
|
+
return false;
|
|
15333
|
+
}
|
|
15334
|
+
continue;
|
|
15371
15335
|
}
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15336
|
+
return false;
|
|
15337
|
+
}
|
|
15338
|
+
return true;
|
|
15339
|
+
}
|
|
15340
|
+
|
|
15341
|
+
// src/core/effect-ir/shell-lower/decoders/filesystem.ts
|
|
15342
|
+
init_git_resource_identity();
|
|
15343
|
+
import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
15344
|
+
import path45 from "node:path";
|
|
15345
|
+
function decodeCopyMove(head, args, cwd, segment) {
|
|
15346
|
+
const requirements = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
15347
|
+
const operands = [];
|
|
15348
|
+
let targetDirectory = null;
|
|
15349
|
+
let recursive = false;
|
|
15350
|
+
let incomplete = false;
|
|
15351
|
+
let optionsEnded = false;
|
|
15352
|
+
const neutralFlags = /* @__PURE__ */ new Set([
|
|
15353
|
+
"-f",
|
|
15354
|
+
"-i",
|
|
15355
|
+
"-n",
|
|
15356
|
+
"-p",
|
|
15357
|
+
"-v",
|
|
15358
|
+
"--force",
|
|
15359
|
+
"--interactive",
|
|
15360
|
+
"--no-clobber"
|
|
15361
|
+
]);
|
|
15362
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15363
|
+
const arg = args[index] ?? "";
|
|
15364
|
+
if (!optionsEnded && arg === "--") {
|
|
15365
|
+
optionsEnded = true;
|
|
15366
|
+
continue;
|
|
15367
|
+
}
|
|
15368
|
+
if (!optionsEnded && (arg === "-r" || arg === "-R" || arg === "--recursive")) {
|
|
15369
|
+
recursive = true;
|
|
15370
|
+
continue;
|
|
15371
|
+
}
|
|
15372
|
+
if (!optionsEnded && (arg === "-t" || arg === "--target-directory")) {
|
|
15373
|
+
const value = args[index + 1];
|
|
15374
|
+
if (!value || value.startsWith("-")) {
|
|
15375
|
+
incomplete = true;
|
|
15376
|
+
} else {
|
|
15377
|
+
targetDirectory = value;
|
|
15378
|
+
index += 1;
|
|
15379
|
+
}
|
|
15380
|
+
continue;
|
|
15389
15381
|
}
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
if (syntax) {
|
|
15395
|
-
return [
|
|
15396
|
-
processRequirement(head, "inspect", segment, ["process.inspect.shell_syntax"]),
|
|
15397
|
-
requirement2(
|
|
15398
|
-
"fs.read",
|
|
15399
|
-
"fs.read",
|
|
15400
|
-
{ kind: "path", path: path42.resolve(cwd, syntax) },
|
|
15401
|
-
segment,
|
|
15402
|
-
["shell.syntax_source_read"]
|
|
15403
|
-
)
|
|
15404
|
-
];
|
|
15382
|
+
if (!optionsEnded && arg.startsWith("--target-directory=")) {
|
|
15383
|
+
targetDirectory = arg.slice("--target-directory=".length) || null;
|
|
15384
|
+
incomplete ||= !targetDirectory;
|
|
15385
|
+
continue;
|
|
15405
15386
|
}
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
const runtimeMetadata = decodeRuntimeMetadataProcess(head, args, segment);
|
|
15412
|
-
if (runtimeMetadata) {
|
|
15413
|
-
return runtimeMetadata;
|
|
15414
|
-
}
|
|
15415
|
-
if (head === "ruby") {
|
|
15416
|
-
return decodeRuby(args, cwd, repoRoot, segment);
|
|
15417
|
-
}
|
|
15418
|
-
if (head === "rubocop" || head === "rspec") {
|
|
15419
|
-
const decoded = decodeBundleExecInner(head, args, segment);
|
|
15420
|
-
if (decoded) {
|
|
15421
|
-
return decoded;
|
|
15387
|
+
if (!optionsEnded && arg.startsWith("-")) {
|
|
15388
|
+
if (!neutralFlags.has(arg)) {
|
|
15389
|
+
incomplete = true;
|
|
15390
|
+
}
|
|
15391
|
+
continue;
|
|
15422
15392
|
}
|
|
15393
|
+
operands.push(arg);
|
|
15423
15394
|
}
|
|
15424
|
-
const
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
15429
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
15430
|
-
}
|
|
15431
|
-
if (head === "belay") {
|
|
15432
|
-
return decodeBelay(args, repoRoot, segment);
|
|
15433
|
-
}
|
|
15434
|
-
if (head === "tsc") {
|
|
15435
|
-
return decodeTsc(args, cwd, segment);
|
|
15436
|
-
}
|
|
15437
|
-
if (head === "go") {
|
|
15438
|
-
return decodeGo(args, segment);
|
|
15439
|
-
}
|
|
15440
|
-
if (head === "rsync") {
|
|
15441
|
-
return decodeRsync(args, cwd, segment);
|
|
15442
|
-
}
|
|
15443
|
-
if (head === "sed") {
|
|
15444
|
-
return decodeSed(args, cwd, segment);
|
|
15395
|
+
const sources = targetDirectory ? operands : operands.slice(0, -1);
|
|
15396
|
+
const destination = targetDirectory ?? (operands.length >= 2 ? operands.at(-1) ?? null : null);
|
|
15397
|
+
if (sources.length === 0 || !destination) {
|
|
15398
|
+
incomplete = true;
|
|
15445
15399
|
}
|
|
15446
|
-
|
|
15447
|
-
|
|
15400
|
+
for (const source of sources) {
|
|
15401
|
+
const resolved = resolvePathOperand(source, cwd);
|
|
15402
|
+
requirements.push(
|
|
15403
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
15404
|
+
`${head}.source_read`
|
|
15405
|
+
])
|
|
15406
|
+
);
|
|
15407
|
+
addSecretRead(requirements, resolved, segment);
|
|
15408
|
+
if (head === "mv") {
|
|
15409
|
+
addWriteEffects(requirements, resolved, segment, ["mv.source_remove"]);
|
|
15410
|
+
}
|
|
15448
15411
|
}
|
|
15449
|
-
if (
|
|
15450
|
-
|
|
15412
|
+
if (destination) {
|
|
15413
|
+
addWriteEffects(requirements, resolvePathOperand(destination, cwd), segment, [
|
|
15414
|
+
`${head}.destination_write`
|
|
15415
|
+
]);
|
|
15451
15416
|
}
|
|
15452
|
-
if (
|
|
15453
|
-
|
|
15417
|
+
if (recursive || incomplete) {
|
|
15418
|
+
requirements.push(
|
|
15419
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15420
|
+
recursive ? `${head}.recursive_source` : `${head}.grammar_incomplete`
|
|
15421
|
+
])
|
|
15422
|
+
);
|
|
15454
15423
|
}
|
|
15455
|
-
|
|
15424
|
+
return requirements;
|
|
15425
|
+
}
|
|
15426
|
+
function decodeRm(args, cwd, repoRoot, segment) {
|
|
15427
|
+
const requirements = [processRequirement("rm", "spawn", segment, ["process.filesystem_mutation"])];
|
|
15428
|
+
const recursive = args.some(
|
|
15429
|
+
(arg) => arg === "-r" || arg === "-R" || arg === "--recursive" || /^-[^-]*[rR]/.test(arg)
|
|
15430
|
+
);
|
|
15431
|
+
const operands = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15432
|
+
if (operands.length === 0) {
|
|
15456
15433
|
return [
|
|
15457
|
-
|
|
15458
|
-
requirement2(
|
|
15459
|
-
"
|
|
15460
|
-
|
|
15461
|
-
{
|
|
15462
|
-
kind: "network",
|
|
15463
|
-
host: "control-plane",
|
|
15464
|
-
protocol: head,
|
|
15465
|
-
mode: "mutate",
|
|
15466
|
-
payload: "present"
|
|
15467
|
-
},
|
|
15468
|
-
segment,
|
|
15469
|
-
["tier0_external"]
|
|
15470
|
-
)
|
|
15434
|
+
...requirements,
|
|
15435
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15436
|
+
"rm.operand_missing"
|
|
15437
|
+
])
|
|
15471
15438
|
];
|
|
15472
15439
|
}
|
|
15473
|
-
|
|
15474
|
-
|
|
15475
|
-
|
|
15476
|
-
|
|
15477
|
-
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15440
|
+
const identity = inspectGitResourceIdentity(repoRoot);
|
|
15441
|
+
for (const operand of operands) {
|
|
15442
|
+
const resolved = resolvePathOperand(operand, cwd);
|
|
15443
|
+
addWriteEffects(requirements, resolved, segment, ["filesystem.write", "rm.remove"]);
|
|
15444
|
+
const finalOperandIsSymlink = isSymbolicLink(resolved);
|
|
15445
|
+
const canonicalResolved = canonicalRmOperand(resolved, finalOperandIsSymlink);
|
|
15446
|
+
const targetIdentity = recursive && !finalOperandIsSymlink ? inspectGitResourceIdentity(resolved) : { status: "absent" };
|
|
15447
|
+
const sameIdentityTargetRoot = identity.status === "resolved" && targetIdentity.status === "resolved" && identity.identity.commonDir === targetIdentity.identity.commonDir && pathContains(canonicalResolved, targetIdentity.identity.repositoryRoot);
|
|
15448
|
+
if (recursive && identity.status === "resolved" && (sameIdentityTargetRoot || [
|
|
15449
|
+
repoRoot,
|
|
15450
|
+
identity.identity.repositoryRoot,
|
|
15451
|
+
identity.identity.gitDir,
|
|
15452
|
+
identity.identity.commonDir,
|
|
15453
|
+
identity.identity.gitEntryPath
|
|
15454
|
+
].some((metadataPath) => pathContains(canonicalResolved, metadataPath)))) {
|
|
15455
|
+
const gitEntryPath = targetIdentity.status === "resolved" ? targetIdentity.identity.gitEntryPath : identity.identity.gitEntryPath;
|
|
15456
|
+
requirements.push(
|
|
15457
|
+
requirement2(
|
|
15458
|
+
"control_plane.write",
|
|
15459
|
+
"control_plane.write",
|
|
15460
|
+
{ kind: "path", path: gitEntryPath },
|
|
15461
|
+
segment,
|
|
15462
|
+
["rm.recursive_git_boundary", "tier1_catastrophic"]
|
|
15463
|
+
)
|
|
15464
|
+
);
|
|
15465
|
+
}
|
|
15481
15466
|
}
|
|
15482
|
-
|
|
15483
|
-
|
|
15467
|
+
return requirements;
|
|
15468
|
+
}
|
|
15469
|
+
function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
|
|
15470
|
+
try {
|
|
15471
|
+
if (finalOperandIsSymlink) {
|
|
15472
|
+
return path45.join(realpathSync4.native(path45.dirname(targetPath)), path45.basename(targetPath));
|
|
15473
|
+
}
|
|
15474
|
+
return realpathSync4.native(targetPath);
|
|
15475
|
+
} catch {
|
|
15476
|
+
return path45.resolve(targetPath);
|
|
15484
15477
|
}
|
|
15485
|
-
|
|
15486
|
-
|
|
15478
|
+
}
|
|
15479
|
+
function isSymbolicLink(targetPath) {
|
|
15480
|
+
try {
|
|
15481
|
+
return lstatSync2(targetPath).isSymbolicLink();
|
|
15482
|
+
} catch {
|
|
15483
|
+
return false;
|
|
15487
15484
|
}
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
addSecretRead(lowered, resolved, segment);
|
|
15485
|
+
}
|
|
15486
|
+
function pathContains(ancestor, candidate) {
|
|
15487
|
+
const relative = path45.relative(path45.resolve(ancestor), path45.resolve(candidate));
|
|
15488
|
+
return relative === "" || !relative.startsWith("..") && !path45.isAbsolute(relative);
|
|
15489
|
+
}
|
|
15490
|
+
function filesystemReadOperands(head, args) {
|
|
15491
|
+
switch (head) {
|
|
15492
|
+
case "ls": {
|
|
15493
|
+
const operands = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15494
|
+
return operands.length > 0 ? operands : ["."];
|
|
15499
15495
|
}
|
|
15500
|
-
|
|
15496
|
+
case "find":
|
|
15497
|
+
return findReadOperands(args);
|
|
15498
|
+
case "cat":
|
|
15499
|
+
case "head":
|
|
15500
|
+
case "tail":
|
|
15501
|
+
case "less":
|
|
15502
|
+
case "stat":
|
|
15503
|
+
case "file":
|
|
15504
|
+
case "du":
|
|
15505
|
+
case "wc":
|
|
15506
|
+
return args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15507
|
+
case "grep":
|
|
15508
|
+
case "rg":
|
|
15509
|
+
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
15510
|
+
case "jq":
|
|
15511
|
+
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
15512
|
+
default:
|
|
15513
|
+
return null;
|
|
15501
15514
|
}
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
|
|
15515
|
+
}
|
|
15516
|
+
function findReadOperands(args) {
|
|
15517
|
+
const mutatingPrimaries = /* @__PURE__ */ new Set([
|
|
15518
|
+
"-delete",
|
|
15519
|
+
"-exec",
|
|
15520
|
+
"-execdir",
|
|
15521
|
+
"-fls",
|
|
15522
|
+
"-fprint",
|
|
15523
|
+
"-fprintf",
|
|
15524
|
+
"-ok",
|
|
15525
|
+
"-okdir"
|
|
15526
|
+
]);
|
|
15527
|
+
if (args.some(
|
|
15528
|
+
(arg) => mutatingPrimaries.has(arg) || [...mutatingPrimaries].some((primary) => arg.startsWith(`${primary}=`))
|
|
15529
|
+
)) {
|
|
15530
|
+
return null;
|
|
15531
|
+
}
|
|
15532
|
+
const paths = [];
|
|
15533
|
+
for (const arg of args) {
|
|
15534
|
+
if (arg.startsWith("-") || arg === "!" || arg === "(") {
|
|
15535
|
+
break;
|
|
15507
15536
|
}
|
|
15508
|
-
|
|
15537
|
+
paths.push(arg);
|
|
15509
15538
|
}
|
|
15510
|
-
|
|
15511
|
-
|
|
15539
|
+
return paths.length > 0 ? paths : ["."];
|
|
15540
|
+
}
|
|
15541
|
+
function filesystemWriteOperands(head, args) {
|
|
15542
|
+
const positional = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15543
|
+
switch (head) {
|
|
15544
|
+
case "touch":
|
|
15545
|
+
case "mkdir":
|
|
15546
|
+
case "rm":
|
|
15547
|
+
case "truncate":
|
|
15548
|
+
case "chmod":
|
|
15549
|
+
return positional;
|
|
15550
|
+
case "cp":
|
|
15551
|
+
case "mv":
|
|
15552
|
+
return positional.length > 0 ? [positional[positional.length - 1] ?? ""] : [];
|
|
15553
|
+
case "tee":
|
|
15554
|
+
return positional;
|
|
15555
|
+
default:
|
|
15556
|
+
return null;
|
|
15512
15557
|
}
|
|
15513
|
-
|
|
15558
|
+
}
|
|
15559
|
+
|
|
15560
|
+
// src/core/effect-ir/shell-lower/decoders/prisma.ts
|
|
15561
|
+
function decodePrisma(args, env, repoRoot, segment) {
|
|
15562
|
+
const processEffect = processRequirement("prisma", "spawn", segment, ["process.prisma"]);
|
|
15563
|
+
if (args[0] === "generate") {
|
|
15514
15564
|
return [
|
|
15515
|
-
|
|
15516
|
-
|
|
15565
|
+
processEffect,
|
|
15566
|
+
requirement2("fs.write", "fs.write", { kind: "path", path: repoRoot }, segment, [
|
|
15567
|
+
"prisma.generate.repo_local"
|
|
15517
15568
|
])
|
|
15518
15569
|
];
|
|
15519
15570
|
}
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
function decodeBelay(args, repoRoot, segment) {
|
|
15523
|
-
const [section, operation, key] = args;
|
|
15524
|
-
const judgeCommand = section === "judge" && operation !== void 0 && ["consent", "list", "status", "test", "use"].includes(operation);
|
|
15525
|
-
const configRead = section === "config" && (operation === void 0 || operation === "list" || operation === "get" && key?.startsWith("judge."));
|
|
15526
|
-
const configJudgeMutation = section === "config" && (["set", "unset"].includes(operation ?? "") && key?.startsWith("judge.") || operation === "credential" && key === "mode");
|
|
15527
|
-
if (judgeCommand || configRead || configJudgeMutation) {
|
|
15571
|
+
const databaseMutation = args[0] === "migrate" || args[0] === "db" && args[1] === "seed" || args[0] === "seed";
|
|
15572
|
+
if (!databaseMutation) {
|
|
15528
15573
|
return [
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15574
|
+
processEffect,
|
|
15575
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15576
|
+
"prisma.grammar_incomplete"
|
|
15532
15577
|
])
|
|
15533
15578
|
];
|
|
15534
15579
|
}
|
|
15535
|
-
|
|
15580
|
+
const endpoint = databaseEndpoint(env.DATABASE_URL);
|
|
15581
|
+
if (!endpoint) {
|
|
15536
15582
|
return [
|
|
15583
|
+
processEffect,
|
|
15537
15584
|
requirement2(
|
|
15538
|
-
"
|
|
15539
|
-
"
|
|
15540
|
-
{
|
|
15585
|
+
"network.connect",
|
|
15586
|
+
"network.connect",
|
|
15587
|
+
{
|
|
15588
|
+
kind: "network",
|
|
15589
|
+
host: "unknown",
|
|
15590
|
+
protocol: "database",
|
|
15591
|
+
mode: "ambiguous",
|
|
15592
|
+
payload: "present"
|
|
15593
|
+
},
|
|
15541
15594
|
segment,
|
|
15542
|
-
["
|
|
15543
|
-
)
|
|
15595
|
+
["prisma.database_endpoint_unknown"]
|
|
15596
|
+
),
|
|
15597
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15598
|
+
"prisma.database_endpoint_unknown"
|
|
15599
|
+
])
|
|
15544
15600
|
];
|
|
15545
15601
|
}
|
|
15546
|
-
|
|
15602
|
+
const network = requirement2(
|
|
15603
|
+
"network.connect",
|
|
15604
|
+
"network.connect",
|
|
15605
|
+
{
|
|
15606
|
+
kind: "network",
|
|
15607
|
+
...endpoint,
|
|
15608
|
+
mode: "mutate",
|
|
15609
|
+
payload: "present"
|
|
15610
|
+
},
|
|
15611
|
+
segment,
|
|
15612
|
+
[LOOPBACK_HOSTS2.has(endpoint.host) ? "prisma.database_local" : "prisma.database_remote"]
|
|
15613
|
+
);
|
|
15614
|
+
if (LOOPBACK_HOSTS2.has(endpoint.host)) {
|
|
15615
|
+
return [processEffect, network];
|
|
15616
|
+
}
|
|
15617
|
+
return [
|
|
15618
|
+
processEffect,
|
|
15619
|
+
network,
|
|
15620
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15621
|
+
"prisma.remote_database_mutation"
|
|
15622
|
+
])
|
|
15623
|
+
];
|
|
15547
15624
|
}
|
|
15548
|
-
|
|
15549
|
-
|
|
15550
|
-
|
|
15551
|
-
|
|
15625
|
+
|
|
15626
|
+
// src/core/effect-ir/shell-lower/decoders/ruby.ts
|
|
15627
|
+
init_path_utils();
|
|
15628
|
+
import path46 from "node:path";
|
|
15629
|
+
var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
|
|
15630
|
+
function railsReadOnlySubcommand(args) {
|
|
15631
|
+
const subcommand = args[0];
|
|
15632
|
+
if (!subcommand || subcommand.startsWith("-")) {
|
|
15633
|
+
return false;
|
|
15634
|
+
}
|
|
15635
|
+
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
15636
|
+
}
|
|
15637
|
+
function isRubyTestScript(scriptPath) {
|
|
15638
|
+
const base = path46.basename(scriptPath);
|
|
15639
|
+
return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
|
|
15640
|
+
}
|
|
15641
|
+
function parseRubyTestInvocation(args) {
|
|
15642
|
+
const includePaths = [];
|
|
15552
15643
|
for (let index = 0; index < args.length; index += 1) {
|
|
15553
15644
|
const arg = args[index] ?? "";
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
const output = inline ?? separate;
|
|
15557
|
-
if (!output) {
|
|
15558
|
-
continue;
|
|
15645
|
+
if (arg === "-e" || arg === "-r") {
|
|
15646
|
+
return null;
|
|
15559
15647
|
}
|
|
15560
|
-
|
|
15561
|
-
|
|
15562
|
-
|
|
15648
|
+
if (arg === "-I") {
|
|
15649
|
+
const includePath = args[index + 1];
|
|
15650
|
+
if (!includePath) {
|
|
15651
|
+
return null;
|
|
15652
|
+
}
|
|
15653
|
+
includePaths.push(includePath);
|
|
15563
15654
|
index += 1;
|
|
15655
|
+
continue;
|
|
15656
|
+
}
|
|
15657
|
+
if (arg.startsWith("-I") && arg.length > 2) {
|
|
15658
|
+
includePaths.push(arg.slice(2));
|
|
15659
|
+
continue;
|
|
15660
|
+
}
|
|
15661
|
+
if (arg.startsWith("-")) {
|
|
15662
|
+
if (arg === "-n") {
|
|
15663
|
+
if (!args[index + 1]) {
|
|
15664
|
+
return null;
|
|
15665
|
+
}
|
|
15666
|
+
index += 1;
|
|
15667
|
+
continue;
|
|
15668
|
+
}
|
|
15669
|
+
if (arg.startsWith("-n")) {
|
|
15670
|
+
continue;
|
|
15671
|
+
}
|
|
15672
|
+
return null;
|
|
15673
|
+
}
|
|
15674
|
+
if (isRubyTestScript(arg)) {
|
|
15675
|
+
return { includePaths, scriptPath: arg };
|
|
15564
15676
|
}
|
|
15677
|
+
return null;
|
|
15565
15678
|
}
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
])
|
|
15679
|
+
return null;
|
|
15680
|
+
}
|
|
15681
|
+
function isRubocopMutating(args) {
|
|
15682
|
+
return args.some(
|
|
15683
|
+
(arg) => arg === "-A" || arg === "-a" || arg === "--auto-correct" || arg === "--autocorrect" || arg.startsWith("--auto-correct-all") || arg.startsWith("--autocorrect-all")
|
|
15572
15684
|
);
|
|
15573
|
-
return requirements;
|
|
15574
15685
|
}
|
|
15575
|
-
function
|
|
15576
|
-
const
|
|
15577
|
-
|
|
15578
|
-
|
|
15579
|
-
|
|
15580
|
-
|
|
15581
|
-
|
|
15582
|
-
|
|
15583
|
-
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
"
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
15593
|
-
const arg = args[index] ?? "";
|
|
15594
|
-
if (!optionsEnded && arg === "--") {
|
|
15595
|
-
optionsEnded = true;
|
|
15596
|
-
continue;
|
|
15686
|
+
function decodeBundleExecInner(innerHead, innerArgs, segment) {
|
|
15687
|
+
const innerBase = executableBaseName(innerHead);
|
|
15688
|
+
if (innerBase === "rubocop") {
|
|
15689
|
+
const mutating = isRubocopMutating(innerArgs);
|
|
15690
|
+
return [
|
|
15691
|
+
processRequirement(
|
|
15692
|
+
innerHead,
|
|
15693
|
+
mutating ? "spawn" : "inspect",
|
|
15694
|
+
segment,
|
|
15695
|
+
mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
|
|
15696
|
+
)
|
|
15697
|
+
];
|
|
15698
|
+
}
|
|
15699
|
+
if (innerBase === "rspec") {
|
|
15700
|
+
const targetArgs = innerArgs.filter((arg) => !arg.startsWith("-"));
|
|
15701
|
+
if (targetArgs.length === 0) {
|
|
15702
|
+
return null;
|
|
15597
15703
|
}
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15704
|
+
return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
|
|
15705
|
+
}
|
|
15706
|
+
return null;
|
|
15707
|
+
}
|
|
15708
|
+
function decodeRuby(args, cwd, repoRoot, segment) {
|
|
15709
|
+
const parsed = parseRubyTestInvocation(args);
|
|
15710
|
+
if (!parsed) {
|
|
15711
|
+
return unsupportedProcess("ruby", segment, "process.ruby_grammar_incomplete");
|
|
15712
|
+
}
|
|
15713
|
+
const scriptPath = resolvePathOperand(parsed.scriptPath, cwd);
|
|
15714
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15715
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15716
|
+
}
|
|
15717
|
+
for (const includePath of parsed.includePaths) {
|
|
15718
|
+
const resolvedInclude = resolvePathOperand(includePath, cwd);
|
|
15719
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
|
|
15720
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15601
15721
|
}
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15722
|
+
}
|
|
15723
|
+
const lowered = [
|
|
15724
|
+
processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
|
|
15725
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
|
|
15726
|
+
"ruby.minitest_script_read"
|
|
15727
|
+
])
|
|
15728
|
+
];
|
|
15729
|
+
for (const includePath of parsed.includePaths) {
|
|
15730
|
+
lowered.push(
|
|
15731
|
+
requirement2(
|
|
15732
|
+
"fs.read",
|
|
15733
|
+
"fs.read",
|
|
15734
|
+
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15735
|
+
segment,
|
|
15736
|
+
["ruby.minitest_load_path_read"]
|
|
15737
|
+
)
|
|
15738
|
+
);
|
|
15739
|
+
}
|
|
15740
|
+
return lowered;
|
|
15741
|
+
}
|
|
15742
|
+
function decodeRuntimeMetadataProcess(head, args, segment) {
|
|
15743
|
+
if (head === "bundle") {
|
|
15744
|
+
if (args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
15745
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15746
|
+
}
|
|
15747
|
+
if (args[0] === "exec" && args.length >= 2) {
|
|
15748
|
+
const innerHead = args[1] ?? "";
|
|
15749
|
+
const innerArgs = args.slice(2);
|
|
15750
|
+
const innerBase = executableBaseName(innerHead);
|
|
15751
|
+
if ((innerBase === "rails" || innerBase === "rake") && railsReadOnlySubcommand(innerArgs)) {
|
|
15752
|
+
return [
|
|
15753
|
+
processRequirement(innerHead, "inspect", segment, ["process.inspect.rails_read_only"])
|
|
15754
|
+
];
|
|
15755
|
+
}
|
|
15756
|
+
if (isMetadataOnlyArgv(innerArgs)) {
|
|
15757
|
+
return [
|
|
15758
|
+
processRequirement(innerHead, "inspect", segment, [
|
|
15759
|
+
"process.inspect.bundle_exec_metadata"
|
|
15760
|
+
])
|
|
15761
|
+
];
|
|
15609
15762
|
}
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
targetDirectory = arg.slice("--target-directory=".length) || null;
|
|
15614
|
-
incomplete ||= !targetDirectory;
|
|
15615
|
-
continue;
|
|
15616
|
-
}
|
|
15617
|
-
if (!optionsEnded && arg.startsWith("-")) {
|
|
15618
|
-
if (!neutralFlags.has(arg)) {
|
|
15619
|
-
incomplete = true;
|
|
15763
|
+
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15764
|
+
if (bundleExecInner) {
|
|
15765
|
+
return bundleExecInner;
|
|
15620
15766
|
}
|
|
15621
|
-
continue;
|
|
15622
15767
|
}
|
|
15623
|
-
|
|
15624
|
-
}
|
|
15625
|
-
const sources = targetDirectory ? operands : operands.slice(0, -1);
|
|
15626
|
-
const destination = targetDirectory ?? (operands.length >= 2 ? operands.at(-1) ?? null : null);
|
|
15627
|
-
if (sources.length === 0 || !destination) {
|
|
15628
|
-
incomplete = true;
|
|
15768
|
+
return null;
|
|
15629
15769
|
}
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
requirements.push(
|
|
15633
|
-
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
15634
|
-
`${head}.source_read`
|
|
15635
|
-
])
|
|
15636
|
-
);
|
|
15637
|
-
addSecretRead(requirements, resolved, segment);
|
|
15638
|
-
if (head === "mv") {
|
|
15639
|
-
addWriteEffects(requirements, resolved, segment, ["mv.source_remove"]);
|
|
15640
|
-
}
|
|
15770
|
+
if ((head === "ruby" || head === "yarn") && args.length >= 1 && isMetadataOnlyArgv(args)) {
|
|
15771
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15641
15772
|
}
|
|
15642
|
-
if (
|
|
15643
|
-
|
|
15644
|
-
`${head}.destination_write`
|
|
15645
|
-
]);
|
|
15773
|
+
if (head === "make" && args.includes("-n")) {
|
|
15774
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.make_dry_run"])];
|
|
15646
15775
|
}
|
|
15647
|
-
|
|
15648
|
-
|
|
15649
|
-
|
|
15650
|
-
recursive ? `${head}.recursive_source` : `${head}.grammar_incomplete`
|
|
15651
|
-
])
|
|
15652
|
-
);
|
|
15776
|
+
const base = executableBaseName(head);
|
|
15777
|
+
if ((base === "rails" || base === "rake") && railsReadOnlySubcommand(args)) {
|
|
15778
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.rails_read_only"])];
|
|
15653
15779
|
}
|
|
15654
|
-
return
|
|
15780
|
+
return null;
|
|
15655
15781
|
}
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
}
|
|
15670
|
-
const identity = inspectGitResourceIdentity(repoRoot);
|
|
15671
|
-
for (const operand of operands) {
|
|
15672
|
-
const resolved = resolvePathOperand(operand, cwd);
|
|
15673
|
-
addWriteEffects(requirements, resolved, segment, ["filesystem.write", "rm.remove"]);
|
|
15674
|
-
const finalOperandIsSymlink = isSymbolicLink(resolved);
|
|
15675
|
-
const canonicalResolved = canonicalRmOperand(resolved, finalOperandIsSymlink);
|
|
15676
|
-
const targetIdentity = recursive && !finalOperandIsSymlink ? inspectGitResourceIdentity(resolved) : { status: "absent" };
|
|
15677
|
-
const sameIdentityTargetRoot = identity.status === "resolved" && targetIdentity.status === "resolved" && identity.identity.commonDir === targetIdentity.identity.commonDir && pathContains(canonicalResolved, targetIdentity.identity.repositoryRoot);
|
|
15678
|
-
if (recursive && identity.status === "resolved" && (sameIdentityTargetRoot || [
|
|
15679
|
-
repoRoot,
|
|
15680
|
-
identity.identity.repositoryRoot,
|
|
15681
|
-
identity.identity.gitDir,
|
|
15682
|
-
identity.identity.commonDir,
|
|
15683
|
-
identity.identity.gitEntryPath
|
|
15684
|
-
].some((metadataPath) => pathContains(canonicalResolved, metadataPath)))) {
|
|
15685
|
-
const gitEntryPath = targetIdentity.status === "resolved" ? targetIdentity.identity.gitEntryPath : identity.identity.gitEntryPath;
|
|
15686
|
-
requirements.push(
|
|
15687
|
-
requirement2(
|
|
15688
|
-
"control_plane.write",
|
|
15689
|
-
"control_plane.write",
|
|
15690
|
-
{ kind: "path", path: gitEntryPath },
|
|
15691
|
-
segment,
|
|
15692
|
-
["rm.recursive_git_boundary", "tier1_catastrophic"]
|
|
15693
|
-
)
|
|
15694
|
-
);
|
|
15782
|
+
|
|
15783
|
+
// src/core/effect-ir/shell-lower/decoders/toolchain.ts
|
|
15784
|
+
function decodeTsc(args, cwd, segment) {
|
|
15785
|
+
const metadataOnly = args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg));
|
|
15786
|
+
const requirements = [];
|
|
15787
|
+
let hasOutput = false;
|
|
15788
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15789
|
+
const arg = args[index] ?? "";
|
|
15790
|
+
const inline = arg.match(/^--(?:outDir|outFile)=(.+)$/)?.[1];
|
|
15791
|
+
const separate = (arg === "--outDir" || arg === "--outFile") && args[index + 1] ? args[index + 1] : null;
|
|
15792
|
+
const output = inline ?? separate;
|
|
15793
|
+
if (!output) {
|
|
15794
|
+
continue;
|
|
15695
15795
|
}
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
try {
|
|
15701
|
-
if (finalOperandIsSymlink) {
|
|
15702
|
-
return path42.join(realpathSync4.native(path42.dirname(targetPath)), path42.basename(targetPath));
|
|
15796
|
+
hasOutput = true;
|
|
15797
|
+
addWriteEffects(requirements, resolvePathOperand(output, cwd), segment, ["tsc.output"]);
|
|
15798
|
+
if (separate) {
|
|
15799
|
+
index += 1;
|
|
15703
15800
|
}
|
|
15704
|
-
return realpathSync4.native(targetPath);
|
|
15705
|
-
} catch {
|
|
15706
|
-
return path42.resolve(targetPath);
|
|
15707
|
-
}
|
|
15708
|
-
}
|
|
15709
|
-
function isSymbolicLink(targetPath) {
|
|
15710
|
-
try {
|
|
15711
|
-
return lstatSync2(targetPath).isSymbolicLink();
|
|
15712
|
-
} catch {
|
|
15713
|
-
return false;
|
|
15714
15801
|
}
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15802
|
+
const typecheckOnly = args.includes("--noEmit") && !hasOutput;
|
|
15803
|
+
const inspect = metadataOnly || typecheckOnly;
|
|
15804
|
+
requirements.unshift(
|
|
15805
|
+
processRequirement("tsc", inspect ? "inspect" : "spawn", segment, [
|
|
15806
|
+
metadataOnly ? "process.inspect.tsc_metadata" : typecheckOnly ? "process.inspect.tsc_typecheck" : "process.known_local_spawn"
|
|
15807
|
+
])
|
|
15808
|
+
);
|
|
15809
|
+
return requirements;
|
|
15719
15810
|
}
|
|
15720
15811
|
function decodeGo(args, segment) {
|
|
15721
15812
|
if (["test", "list", "vet"].includes(args[0] ?? "")) {
|
|
@@ -15877,285 +15968,320 @@ function decodeNode2(args, cwd, segment) {
|
|
|
15877
15968
|
)
|
|
15878
15969
|
];
|
|
15879
15970
|
}
|
|
15880
|
-
return unsupportedProcess("node", segment, "process.node_grammar_incomplete");
|
|
15881
|
-
}
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15971
|
+
return unsupportedProcess("node", segment, "process.node_grammar_incomplete");
|
|
15972
|
+
}
|
|
15973
|
+
|
|
15974
|
+
// src/core/effect-ir/shell-lower/decode-process.ts
|
|
15975
|
+
function decodeProcessOrFilesystem(params) {
|
|
15976
|
+
const { tokens, head, env, cwd, repoRoot, segment } = params;
|
|
15977
|
+
const args = tokens.slice(1);
|
|
15978
|
+
if (tokens.length > 0 && tokens.every((token) => ENV_PREFIX_PATTERN2.test(token))) {
|
|
15979
|
+
return [];
|
|
15980
|
+
}
|
|
15981
|
+
const shellControl = decodeShellControlBuiltin(head, args);
|
|
15982
|
+
if (shellControl) {
|
|
15983
|
+
return shellControl;
|
|
15984
|
+
}
|
|
15985
|
+
if (isCommandInspection(tokens)) {
|
|
15986
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
15987
|
+
}
|
|
15988
|
+
if (head === "lsof") {
|
|
15989
|
+
return validLsof(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.lsof"])] : unsupportedProcess(head, segment, "process.lsof_grammar_incomplete");
|
|
15990
|
+
}
|
|
15991
|
+
if (head === "ps") {
|
|
15992
|
+
return validPs(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.ps"])] : unsupportedProcess(head, segment, "process.ps_grammar_incomplete");
|
|
15993
|
+
}
|
|
15994
|
+
if (head === "test" || head === "[") {
|
|
15995
|
+
return validFilesystemTest(head, args) ? [processRequirement(head, "inspect", segment, ["process.inspect.filesystem_test"])] : unsupportedProcess(head, segment, "process.filesystem_test_grammar_incomplete");
|
|
15996
|
+
}
|
|
15997
|
+
if (head === "docker") {
|
|
15998
|
+
if (args[0] === "info") {
|
|
15999
|
+
return validDockerInfo(args.slice(1)) ? [processRequirement(head, "inspect", segment, ["process.inspect.docker_info"])] : unsupportedProcess(head, segment, "process.docker_info_grammar_incomplete");
|
|
16000
|
+
}
|
|
16001
|
+
if (args[0] === "compose" && ["up", "down", "start", "stop", "restart", "create", "rm"].includes(args[1] ?? "")) {
|
|
16002
|
+
return [processRequirement(head, "spawn", segment, ["service.local_mutation"])];
|
|
16003
|
+
}
|
|
16004
|
+
if (args[0] === "push" || args[0] === "build" && args.includes("--push") || args[0] === "buildx" && args[1] === "build" && (args.includes("--push") || args.some(
|
|
16005
|
+
(arg) => arg.startsWith("--output=type=registry") || arg.startsWith("-o=type=registry")
|
|
16006
|
+
))) {
|
|
16007
|
+
return [
|
|
16008
|
+
processRequirement(head, "spawn", segment, ["tier0_external", "docker.remote_mutation"]),
|
|
16009
|
+
requirement2(
|
|
16010
|
+
"network.connect",
|
|
16011
|
+
"network.connect",
|
|
16012
|
+
{
|
|
16013
|
+
kind: "network",
|
|
16014
|
+
host: "registry",
|
|
16015
|
+
protocol: "container-registry",
|
|
16016
|
+
mode: "mutate",
|
|
16017
|
+
payload: "present"
|
|
16018
|
+
},
|
|
16019
|
+
segment,
|
|
16020
|
+
["tier0_external", "docker.remote_mutation"]
|
|
16021
|
+
)
|
|
16022
|
+
];
|
|
16023
|
+
}
|
|
16024
|
+
if (args[0] === "run" || args[0] === "create" || args[0] === "pull" || args[0] === "build" || args[0] === "buildx" && args[1] === "build") {
|
|
16025
|
+
return [
|
|
16026
|
+
processRequirement(head, "spawn", segment, ["process.docker_spawn"]),
|
|
16027
|
+
requirement2(
|
|
16028
|
+
"network.acquire",
|
|
16029
|
+
"network.connect",
|
|
16030
|
+
{
|
|
16031
|
+
kind: "network",
|
|
16032
|
+
host: "unknown",
|
|
16033
|
+
protocol: "container-registry",
|
|
16034
|
+
mode: "ambiguous",
|
|
16035
|
+
payload: "none"
|
|
16036
|
+
},
|
|
16037
|
+
segment,
|
|
16038
|
+
["docker.image_acquisition_possible"]
|
|
16039
|
+
)
|
|
16040
|
+
];
|
|
16041
|
+
}
|
|
16042
|
+
return [processRequirement(head, "spawn", segment, ["process.docker_spawn"])];
|
|
16043
|
+
}
|
|
16044
|
+
if (isShellHead(head)) {
|
|
16045
|
+
const syntax = bashSyntaxTarget(args);
|
|
16046
|
+
if (syntax) {
|
|
16047
|
+
return [
|
|
16048
|
+
processRequirement(head, "inspect", segment, ["process.inspect.shell_syntax"]),
|
|
16049
|
+
requirement2(
|
|
16050
|
+
"fs.read",
|
|
16051
|
+
"fs.read",
|
|
16052
|
+
{ kind: "path", path: path47.resolve(cwd, syntax) },
|
|
16053
|
+
segment,
|
|
16054
|
+
["shell.syntax_source_read"]
|
|
16055
|
+
)
|
|
16056
|
+
];
|
|
16057
|
+
}
|
|
16058
|
+
return unsupportedProcess(head, segment, "process.shell_grammar_incomplete");
|
|
16059
|
+
}
|
|
16060
|
+
if (head === "prisma") {
|
|
16061
|
+
return decodePrisma(args, env, repoRoot, segment);
|
|
16062
|
+
}
|
|
16063
|
+
const runtimeMetadata = decodeRuntimeMetadataProcess(head, args, segment);
|
|
16064
|
+
if (runtimeMetadata) {
|
|
16065
|
+
return runtimeMetadata;
|
|
16066
|
+
}
|
|
16067
|
+
if (head === "ruby") {
|
|
16068
|
+
return decodeRuby(args, cwd, repoRoot, segment);
|
|
16069
|
+
}
|
|
16070
|
+
if (head === "rubocop" || head === "rspec") {
|
|
16071
|
+
const decoded = decodeBundleExecInner(head, args, segment);
|
|
16072
|
+
if (decoded) {
|
|
16073
|
+
return decoded;
|
|
16074
|
+
}
|
|
16075
|
+
}
|
|
16076
|
+
const dockerCompose = decodeDockerComposeRun2(head, args, segment);
|
|
16077
|
+
if (dockerCompose) {
|
|
16078
|
+
return dockerCompose;
|
|
16079
|
+
}
|
|
16080
|
+
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
16081
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
16082
|
+
}
|
|
16083
|
+
if (head === "belay") {
|
|
16084
|
+
return decodeBelay(args, repoRoot, segment);
|
|
16085
|
+
}
|
|
16086
|
+
if (head === "tsc") {
|
|
16087
|
+
return decodeTsc(args, cwd, segment);
|
|
16088
|
+
}
|
|
16089
|
+
if (head === "go") {
|
|
16090
|
+
return decodeGo(args, segment);
|
|
16091
|
+
}
|
|
16092
|
+
if (head === "rsync") {
|
|
16093
|
+
return decodeRsync(args, cwd, segment);
|
|
16094
|
+
}
|
|
16095
|
+
if (head === "sed") {
|
|
16096
|
+
return decodeSed(args, cwd, segment);
|
|
15891
16097
|
}
|
|
15892
|
-
|
|
15893
|
-
|
|
15894
|
-
return [
|
|
15895
|
-
processEffect,
|
|
15896
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15897
|
-
"prisma.grammar_incomplete"
|
|
15898
|
-
])
|
|
15899
|
-
];
|
|
16098
|
+
if (head === "base64" && args.length === 1 && ["-d", "-D", "--decode"].includes(args[0] ?? "")) {
|
|
16099
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
15900
16100
|
}
|
|
15901
|
-
|
|
15902
|
-
|
|
16101
|
+
if (head === "node") {
|
|
16102
|
+
return decodeNode2(args, cwd, segment);
|
|
16103
|
+
}
|
|
16104
|
+
if (head === "vite" || head === "vite-node") {
|
|
16105
|
+
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
16106
|
+
}
|
|
16107
|
+
if ((head === "npm" || head === "pnpm") && args[0] === "publish" || head === "terraform" && args[0] === "apply") {
|
|
15903
16108
|
return [
|
|
15904
|
-
|
|
16109
|
+
processRequirement(head, "spawn", segment, ["tier0_external"]),
|
|
15905
16110
|
requirement2(
|
|
15906
16111
|
"network.connect",
|
|
15907
16112
|
"network.connect",
|
|
15908
16113
|
{
|
|
15909
16114
|
kind: "network",
|
|
15910
|
-
host: "
|
|
15911
|
-
protocol:
|
|
15912
|
-
mode: "
|
|
16115
|
+
host: "control-plane",
|
|
16116
|
+
protocol: head,
|
|
16117
|
+
mode: "mutate",
|
|
15913
16118
|
payload: "present"
|
|
15914
16119
|
},
|
|
15915
16120
|
segment,
|
|
15916
|
-
["
|
|
15917
|
-
)
|
|
15918
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15919
|
-
"prisma.database_endpoint_unknown"
|
|
15920
|
-
])
|
|
16121
|
+
["tier0_external"]
|
|
16122
|
+
)
|
|
15921
16123
|
];
|
|
15922
16124
|
}
|
|
15923
|
-
|
|
15924
|
-
|
|
15925
|
-
"network.connect",
|
|
15926
|
-
{
|
|
15927
|
-
kind: "network",
|
|
15928
|
-
...endpoint,
|
|
15929
|
-
mode: "mutate",
|
|
15930
|
-
payload: "present"
|
|
15931
|
-
},
|
|
15932
|
-
segment,
|
|
15933
|
-
[LOOPBACK_HOSTS2.has(endpoint.host) ? "prisma.database_local" : "prisma.database_remote"]
|
|
15934
|
-
);
|
|
15935
|
-
if (LOOPBACK_HOSTS2.has(endpoint.host)) {
|
|
15936
|
-
return [processEffect, network];
|
|
16125
|
+
if (head === "cd") {
|
|
16126
|
+
return [];
|
|
15937
16127
|
}
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
const
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
"shell.redirect_target_missing"
|
|
15957
|
-
])
|
|
15958
|
-
);
|
|
15959
|
-
continue;
|
|
15960
|
-
}
|
|
15961
|
-
if (operator.includes("<<")) {
|
|
15962
|
-
requirements.push(
|
|
15963
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15964
|
-
"shell.heredoc_opaque"
|
|
15965
|
-
])
|
|
15966
|
-
);
|
|
15967
|
-
index += 1;
|
|
15968
|
-
continue;
|
|
15969
|
-
}
|
|
15970
|
-
const target = expandKnownVariables(rawTarget, env);
|
|
15971
|
-
const resolved = resolvePathOperand(target, context.cwd);
|
|
15972
|
-
if (resolved === "/dev/null") {
|
|
15973
|
-
index += 1;
|
|
15974
|
-
continue;
|
|
15975
|
-
}
|
|
15976
|
-
if (operator.includes("<")) {
|
|
15977
|
-
requirements.push(
|
|
16128
|
+
if (head === "cp" || head === "mv") {
|
|
16129
|
+
return decodeCopyMove(head, args, cwd, segment);
|
|
16130
|
+
}
|
|
16131
|
+
if (head === "rm") {
|
|
16132
|
+
return decodeRm(args, cwd, repoRoot, segment);
|
|
16133
|
+
}
|
|
16134
|
+
if (head === "vitest" || head === "eslint" || head === "biome" || head === "belay") {
|
|
16135
|
+
return [processRequirement(head, "spawn", segment, ["process.known_local_spawn"])];
|
|
16136
|
+
}
|
|
16137
|
+
if (head === "pwd" || head === "which" || head === "whoami") {
|
|
16138
|
+
return [processRequirement(head, "inspect", segment, ["process.pure_inspection"])];
|
|
16139
|
+
}
|
|
16140
|
+
const readOperands = filesystemReadOperands(head, args);
|
|
16141
|
+
if (readOperands !== null) {
|
|
16142
|
+
const lowered = [processRequirement(head, "inspect", segment, ["process.filesystem_inspect"])];
|
|
16143
|
+
for (const operand of readOperands) {
|
|
16144
|
+
const resolved = resolvePathOperand(operand, cwd);
|
|
16145
|
+
lowered.push(
|
|
15978
16146
|
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
15979
|
-
"
|
|
16147
|
+
"filesystem.read"
|
|
15980
16148
|
])
|
|
15981
16149
|
);
|
|
15982
|
-
addSecretRead(
|
|
15983
|
-
}
|
|
15984
|
-
if (operator.includes(">")) {
|
|
15985
|
-
addWriteEffects(requirements, resolved, segment, ["shell.output_redirect"]);
|
|
16150
|
+
addSecretRead(lowered, resolved, segment);
|
|
15986
16151
|
}
|
|
15987
|
-
|
|
16152
|
+
return lowered;
|
|
15988
16153
|
}
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
if (context.depth >= MAX_LOWER_DEPTH) {
|
|
15995
|
-
requirements.push(
|
|
15996
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15997
|
-
"shell.substitution_depth_exceeded"
|
|
15998
|
-
])
|
|
15999
|
-
);
|
|
16000
|
-
continue;
|
|
16001
|
-
}
|
|
16002
|
-
const nestedSegments = lowerTopLevelSegments(inner, {
|
|
16003
|
-
...context,
|
|
16004
|
-
command: inner,
|
|
16005
|
-
depth: context.depth + 1
|
|
16006
|
-
});
|
|
16007
|
-
for (const nested of nestedSegments) {
|
|
16008
|
-
requirements.push(
|
|
16009
|
-
...nested.requirements.map((entry) => {
|
|
16010
|
-
const outerProvenance = {
|
|
16011
|
-
segment,
|
|
16012
|
-
innerCommand: inner
|
|
16013
|
-
};
|
|
16014
|
-
const provenance = {
|
|
16015
|
-
...entry.provenance,
|
|
16016
|
-
segment,
|
|
16017
|
-
innerCommand: entry.provenance.innerCommand ?? inner
|
|
16018
|
-
};
|
|
16019
|
-
return withProvenances(entry, provenance, outerProvenance);
|
|
16020
|
-
})
|
|
16021
|
-
);
|
|
16154
|
+
const writeOperands = filesystemWriteOperands(head, args);
|
|
16155
|
+
if (writeOperands !== null) {
|
|
16156
|
+
const lowered = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
16157
|
+
for (const operand of writeOperands) {
|
|
16158
|
+
addWriteEffects(lowered, resolvePathOperand(operand, cwd), segment, ["filesystem.write"]);
|
|
16022
16159
|
}
|
|
16160
|
+
return lowered;
|
|
16023
16161
|
}
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
const env = { ...inherited };
|
|
16027
|
-
const changedNames = /* @__PURE__ */ new Set();
|
|
16028
|
-
if (tokens[0] === "env") {
|
|
16029
|
-
let index = 1;
|
|
16030
|
-
let malformed = false;
|
|
16031
|
-
while (index < tokens.length) {
|
|
16032
|
-
const option = tokens[index] ?? "";
|
|
16033
|
-
if (option === "-u" || option === "--unset") {
|
|
16034
|
-
const name = tokens[index + 1] ?? "";
|
|
16035
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
16036
|
-
malformed = true;
|
|
16037
|
-
index += 1;
|
|
16038
|
-
break;
|
|
16039
|
-
}
|
|
16040
|
-
delete env[name];
|
|
16041
|
-
changedNames.add(name);
|
|
16042
|
-
index += 2;
|
|
16043
|
-
continue;
|
|
16044
|
-
}
|
|
16045
|
-
if (option.startsWith("--unset=")) {
|
|
16046
|
-
const name = option.slice("--unset=".length);
|
|
16047
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
16048
|
-
malformed = true;
|
|
16049
|
-
index += 1;
|
|
16050
|
-
break;
|
|
16051
|
-
}
|
|
16052
|
-
delete env[name];
|
|
16053
|
-
changedNames.add(name);
|
|
16054
|
-
index += 1;
|
|
16055
|
-
continue;
|
|
16056
|
-
}
|
|
16057
|
-
if (option === "-i" || option === "--ignore-environment") {
|
|
16058
|
-
for (const name of Object.keys(env)) {
|
|
16059
|
-
delete env[name];
|
|
16060
|
-
}
|
|
16061
|
-
changedNames.add("*");
|
|
16062
|
-
index += 1;
|
|
16063
|
-
continue;
|
|
16064
|
-
}
|
|
16065
|
-
if (option === "--") {
|
|
16066
|
-
index += 1;
|
|
16067
|
-
break;
|
|
16068
|
-
}
|
|
16069
|
-
if (option.startsWith("-")) {
|
|
16070
|
-
malformed = true;
|
|
16071
|
-
index += 1;
|
|
16072
|
-
break;
|
|
16073
|
-
}
|
|
16074
|
-
break;
|
|
16075
|
-
}
|
|
16076
|
-
while (index < tokens.length) {
|
|
16077
|
-
const token = tokens[index] ?? "";
|
|
16078
|
-
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
16079
|
-
if (!match) {
|
|
16080
|
-
break;
|
|
16081
|
-
}
|
|
16082
|
-
const [, name, value] = match;
|
|
16083
|
-
if (name) {
|
|
16084
|
-
env[name] = expandKnownVariables(value ?? "", env);
|
|
16085
|
-
changedNames.add(name);
|
|
16086
|
-
}
|
|
16087
|
-
index += 1;
|
|
16088
|
-
}
|
|
16089
|
-
const commandTokens = tokens.slice(index);
|
|
16090
|
-
return {
|
|
16091
|
-
env,
|
|
16092
|
-
commandTokens,
|
|
16093
|
-
malformed: malformed || commandTokens.length === 0,
|
|
16094
|
-
changedNames
|
|
16095
|
-
};
|
|
16162
|
+
if (head === "printf" || head === "echo" || head === "true" || head === "false" || head === ":") {
|
|
16163
|
+
return [];
|
|
16096
16164
|
}
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
if (name) {
|
|
16104
|
-
env[name] = expandKnownVariables(value ?? "", env);
|
|
16105
|
-
changedNames.add(name);
|
|
16106
|
-
}
|
|
16165
|
+
if (!head) {
|
|
16166
|
+
return [
|
|
16167
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16168
|
+
"shell.segment_empty"
|
|
16169
|
+
])
|
|
16170
|
+
];
|
|
16107
16171
|
}
|
|
16108
|
-
return
|
|
16172
|
+
return unsupportedProcess(head, segment, "process.grammar_unknown");
|
|
16109
16173
|
}
|
|
16110
|
-
|
|
16111
|
-
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16174
|
+
|
|
16175
|
+
// src/core/effect-ir/shell-lower/decoders/decode-package-exec.ts
|
|
16176
|
+
function decodePackageExec(peel, cwd, repoRoot, segment) {
|
|
16177
|
+
if (peel.opaque) {
|
|
16178
|
+
return [
|
|
16179
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16180
|
+
peel.reason,
|
|
16181
|
+
...peel.signals
|
|
16182
|
+
])
|
|
16183
|
+
];
|
|
16184
|
+
}
|
|
16185
|
+
if (peel.reason === "npx_wrapper_readonly") {
|
|
16186
|
+
return [];
|
|
16187
|
+
}
|
|
16188
|
+
const binHead = peel.innerTokens[0] ?? "";
|
|
16189
|
+
const metadataOnly = packageExecInnerIsMetadata(peel);
|
|
16190
|
+
const local = !peel.forceAcquire ? resolveLocalBin(binHead, cwd, repoRoot) : null;
|
|
16191
|
+
if (local) {
|
|
16192
|
+
return metadataOnly ? [
|
|
16193
|
+
requirement2(
|
|
16194
|
+
"process.exec",
|
|
16195
|
+
"process.exec",
|
|
16196
|
+
{ kind: "executable", command: local.path, operation: "inspect" },
|
|
16197
|
+
segment,
|
|
16198
|
+
["package_exec.delegate", "package_exec.local_bin_resolved"]
|
|
16199
|
+
)
|
|
16200
|
+
] : [];
|
|
16201
|
+
}
|
|
16202
|
+
const networkResources = peel.acquisitionSpecs.map((spec) => classifyPackageAcquisitionSpec(spec)).filter((source) => source.kind !== "local").map(
|
|
16203
|
+
(source) => source.kind === "registry" ? {
|
|
16204
|
+
kind: "network",
|
|
16205
|
+
host: "registry.npmjs.org",
|
|
16206
|
+
protocol: "registry",
|
|
16207
|
+
mode: "read",
|
|
16208
|
+
payload: "none"
|
|
16209
|
+
} : {
|
|
16210
|
+
kind: "network",
|
|
16211
|
+
host: source.host,
|
|
16212
|
+
...source.port ? { port: source.port } : {},
|
|
16213
|
+
protocol: source.protocol,
|
|
16214
|
+
mode: "read",
|
|
16215
|
+
payload: "none"
|
|
16116
16216
|
}
|
|
16117
16217
|
);
|
|
16118
|
-
|
|
16119
|
-
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
}
|
|
16126
|
-
if (!isRedirectOperator(token)) {
|
|
16127
|
-
stripped.push(token);
|
|
16128
|
-
continue;
|
|
16129
|
-
}
|
|
16130
|
-
index += 1;
|
|
16218
|
+
if (networkResources.length === 0) {
|
|
16219
|
+
networkResources.push({
|
|
16220
|
+
kind: "network",
|
|
16221
|
+
host: "registry.npmjs.org",
|
|
16222
|
+
protocol: "registry",
|
|
16223
|
+
mode: "read",
|
|
16224
|
+
payload: "none"
|
|
16225
|
+
});
|
|
16131
16226
|
}
|
|
16132
|
-
return
|
|
16227
|
+
return [
|
|
16228
|
+
...networkResources.map(
|
|
16229
|
+
(resource) => requirement2("network.acquire", "network.connect", resource, segment, [
|
|
16230
|
+
"package_acquire_possible"
|
|
16231
|
+
])
|
|
16232
|
+
),
|
|
16233
|
+
requirement2(
|
|
16234
|
+
"fs.write",
|
|
16235
|
+
"fs.write",
|
|
16236
|
+
{ kind: "package-cache", manager: peel.launcher === "pnpm" ? "pnpm" : "npm" },
|
|
16237
|
+
segment,
|
|
16238
|
+
["package_cache_write"]
|
|
16239
|
+
),
|
|
16240
|
+
...metadataOnly ? [
|
|
16241
|
+
requirement2(
|
|
16242
|
+
"process.exec",
|
|
16243
|
+
"process.exec",
|
|
16244
|
+
{ kind: "executable", command: binHead || peel.launcher, operation: "inspect" },
|
|
16245
|
+
segment,
|
|
16246
|
+
["package_exec.delegate"]
|
|
16247
|
+
)
|
|
16248
|
+
] : []
|
|
16249
|
+
];
|
|
16133
16250
|
}
|
|
16134
|
-
function
|
|
16135
|
-
const
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16146
|
-
|
|
16251
|
+
function packageExecInnerIsMetadata(peel) {
|
|
16252
|
+
const args = peel.innerTokens.slice(1);
|
|
16253
|
+
return args.length > 0 && args.every((arg) => ["--help", "--version", "-V", "-h", "-v"].includes(arg));
|
|
16254
|
+
}
|
|
16255
|
+
|
|
16256
|
+
// src/core/effect-ir/shell-lower/segment.ts
|
|
16257
|
+
init_shell_tokenizer();
|
|
16258
|
+
import path48 from "node:path";
|
|
16259
|
+
var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
|
|
16260
|
+
var SHELL_GLOB_PATTERN = /[*?[]/;
|
|
16261
|
+
function requiresKnownCwd(requirementValue) {
|
|
16262
|
+
if (requirementValue.action === "fs.write" || requirementValue.action === "git.ref.write" || requirementValue.action === "control_plane.write") {
|
|
16263
|
+
return true;
|
|
16147
16264
|
}
|
|
16148
|
-
return
|
|
16265
|
+
return requirementValue.action === "process.exec" && requirementValue.resource.kind === "executable" && requirementValue.resource.operation === "spawn";
|
|
16149
16266
|
}
|
|
16150
|
-
function
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16267
|
+
function joinNestedOpacity(outer, nested) {
|
|
16268
|
+
const nestedOpacity = nested.completeness === "partial" && nested.opacity === "transparent" ? "recursive" : nested.opacity;
|
|
16269
|
+
return joinEffectOpacity(outer, nestedOpacity);
|
|
16270
|
+
}
|
|
16271
|
+
function startsLocalPostgresService(command) {
|
|
16272
|
+
const tokens = tokenizeShell(command);
|
|
16273
|
+
return path48.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
16274
|
+
}
|
|
16275
|
+
function resolveCdTransition(command, currentCwd) {
|
|
16276
|
+
const tokens = tokenizeShell(command);
|
|
16277
|
+
if (path48.basename(tokens[0] ?? "") !== "cd") {
|
|
16278
|
+
return null;
|
|
16157
16279
|
}
|
|
16158
|
-
|
|
16280
|
+
const target = tokens[1] ?? "~";
|
|
16281
|
+
if (!target || target === "-" || target.includes("$") || target.includes("`")) {
|
|
16282
|
+
return { cwd: currentCwd, known: false };
|
|
16283
|
+
}
|
|
16284
|
+
return { cwd: resolvePathOperand(target, currentCwd), known: true };
|
|
16159
16285
|
}
|
|
16160
16286
|
function shellSegment(commandRedacted, segmentHead, requirements, opacity, signals) {
|
|
16161
16287
|
const normalizedRequirements = requirements.flatMap((entry) => {
|
|
@@ -16186,430 +16312,520 @@ function shellSegment(commandRedacted, segmentHead, requirements, opacity, signa
|
|
|
16186
16312
|
signals: [...signals].sort()
|
|
16187
16313
|
};
|
|
16188
16314
|
}
|
|
16189
|
-
|
|
16190
|
-
|
|
16191
|
-
|
|
16192
|
-
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
|
|
16315
|
+
function dynamicResourceSignal(resource) {
|
|
16316
|
+
const expanded = (value) => Boolean(value && DYNAMIC_SHELL_VALUE_PATTERN.test(value));
|
|
16317
|
+
const pathLike = (value, allowSemanticWildcard = false) => Boolean(
|
|
16318
|
+
value && (expanded(value) || !allowSemanticWildcard && SHELL_GLOB_PATTERN.test(value))
|
|
16319
|
+
);
|
|
16320
|
+
switch (resource.kind) {
|
|
16321
|
+
case "path":
|
|
16322
|
+
return pathLike(resource.path) ? "shell.path_unresolved" : null;
|
|
16323
|
+
case "network":
|
|
16324
|
+
return expanded(resource.host) || expanded(resource.protocol) ? "shell.network_resource_unresolved" : null;
|
|
16325
|
+
case "git-ref":
|
|
16326
|
+
return pathLike(resource.repoPath) || pathLike(resource.ref, resource.ref.endsWith("/*")) ? "shell.git_resource_unresolved" : null;
|
|
16327
|
+
case "executable":
|
|
16328
|
+
return expanded(resource.command) ? "shell.executable_unresolved" : null;
|
|
16329
|
+
default:
|
|
16330
|
+
return null;
|
|
16197
16331
|
}
|
|
16198
|
-
|
|
16199
|
-
|
|
16332
|
+
}
|
|
16333
|
+
|
|
16334
|
+
// src/core/effect-ir/shell-lower.ts
|
|
16335
|
+
var MAX_LOWER_DEPTH = 8;
|
|
16336
|
+
function lowerShellEffectPlan(params) {
|
|
16337
|
+
const context = { ...params, depth: 0 };
|
|
16338
|
+
const segments = lowerTopLevelSegments(params.command, context);
|
|
16339
|
+
return buildShellEffectPlan({
|
|
16340
|
+
inputFingerprint: params.inputFingerprint,
|
|
16341
|
+
segments,
|
|
16342
|
+
signals: pipeToShell(params.command) ? ["pipe_to_shell"] : []
|
|
16343
|
+
});
|
|
16344
|
+
}
|
|
16345
|
+
function lowerTopLevelSegments(command, context) {
|
|
16346
|
+
const commands = splitStructuralShellSegments(command);
|
|
16347
|
+
if (commands.length === 0 && command.trim()) {
|
|
16348
|
+
commands.push(command.trim());
|
|
16200
16349
|
}
|
|
16201
|
-
const
|
|
16202
|
-
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
|
|
16214
|
-
|
|
16215
|
-
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16350
|
+
const pipedToShell = pipeToShell(command);
|
|
16351
|
+
const lowered = [];
|
|
16352
|
+
let cwd = context.cwd;
|
|
16353
|
+
let cwdKnown = true;
|
|
16354
|
+
let inferredEnv = { ...context.env };
|
|
16355
|
+
for (const segment of commands) {
|
|
16356
|
+
let result = lowerSegment(segment, {
|
|
16357
|
+
...context,
|
|
16358
|
+
cwd,
|
|
16359
|
+
env: inferredEnv,
|
|
16360
|
+
command: segment,
|
|
16361
|
+
depth: context.depth,
|
|
16362
|
+
inputFingerprint: context.inputFingerprint,
|
|
16363
|
+
...pipedToShell && isShellHead(parseSegment(segment).head) ? { pipeToShellSegment: true } : {}
|
|
16364
|
+
});
|
|
16365
|
+
if (!cwdKnown) {
|
|
16366
|
+
const requiresCwd = result.requirements.some(requiresKnownCwd);
|
|
16367
|
+
const requirements = [...result.requirements];
|
|
16368
|
+
if (requiresCwd) {
|
|
16369
|
+
requirements.push(
|
|
16370
|
+
requirement2(
|
|
16371
|
+
"indeterminate",
|
|
16372
|
+
"indeterminate",
|
|
16373
|
+
{ kind: "unknown" },
|
|
16374
|
+
result.commandRedacted,
|
|
16375
|
+
["shell.cwd_unknown"]
|
|
16376
|
+
)
|
|
16377
|
+
);
|
|
16378
|
+
}
|
|
16379
|
+
result = {
|
|
16380
|
+
...result,
|
|
16381
|
+
requirements,
|
|
16382
|
+
...requiresCwd ? {
|
|
16383
|
+
completeness: "partial",
|
|
16384
|
+
opacity: joinEffectOpacity(result.opacity, "opaque")
|
|
16385
|
+
} : {},
|
|
16386
|
+
signals: [.../* @__PURE__ */ new Set([...result.signals, "shell.cwd_unknown"])]
|
|
16387
|
+
};
|
|
16231
16388
|
}
|
|
16232
|
-
|
|
16233
|
-
|
|
16389
|
+
lowered.push(result);
|
|
16390
|
+
if (!inferredEnv.DATABASE_URL && startsLocalPostgresService(segment)) {
|
|
16391
|
+
inferredEnv = {
|
|
16392
|
+
...inferredEnv,
|
|
16393
|
+
DATABASE_URL: "postgresql://127.0.0.1:5432/local"
|
|
16394
|
+
};
|
|
16395
|
+
}
|
|
16396
|
+
const nextCwd = resolveCdTransition(segment, cwd);
|
|
16397
|
+
if (nextCwd) {
|
|
16398
|
+
cwd = nextCwd.cwd;
|
|
16399
|
+
cwdKnown = nextCwd.known;
|
|
16234
16400
|
}
|
|
16235
|
-
return name === "GIT_CONFIG_COUNT" && value !== "0";
|
|
16236
|
-
});
|
|
16237
|
-
return overridden ? ["git.environment_execution_or_config_override"] : [];
|
|
16238
|
-
}
|
|
16239
|
-
function dynamicResourceSignal(resource) {
|
|
16240
|
-
const expanded = (value) => Boolean(value && DYNAMIC_SHELL_VALUE_PATTERN.test(value));
|
|
16241
|
-
const pathLike = (value, allowSemanticWildcard = false) => Boolean(
|
|
16242
|
-
value && (expanded(value) || !allowSemanticWildcard && SHELL_GLOB_PATTERN.test(value))
|
|
16243
|
-
);
|
|
16244
|
-
switch (resource.kind) {
|
|
16245
|
-
case "path":
|
|
16246
|
-
return pathLike(resource.path) ? "shell.path_unresolved" : null;
|
|
16247
|
-
case "network":
|
|
16248
|
-
return expanded(resource.host) || expanded(resource.protocol) ? "shell.network_resource_unresolved" : null;
|
|
16249
|
-
case "git-ref":
|
|
16250
|
-
return pathLike(resource.repoPath) || pathLike(resource.ref, resource.ref.endsWith("/*")) ? "shell.git_resource_unresolved" : null;
|
|
16251
|
-
case "executable":
|
|
16252
|
-
return expanded(resource.command) ? "shell.executable_unresolved" : null;
|
|
16253
|
-
default:
|
|
16254
|
-
return null;
|
|
16255
16401
|
}
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
requirement2("fs.write", "fs.write", { kind: "path", path: resolved }, segment, signals)
|
|
16275
|
-
);
|
|
16276
|
-
if (CONTROL_PLANE_PATH_PATTERN.test(resolved)) {
|
|
16277
|
-
requirements.push(
|
|
16278
|
-
requirement2(
|
|
16279
|
-
"control_plane.write",
|
|
16280
|
-
"control_plane.write",
|
|
16281
|
-
{ kind: "path", path: resolved },
|
|
16282
|
-
segment,
|
|
16283
|
-
[...signals, "protected_path"]
|
|
16402
|
+
if (commands.length > 1 && /[\r\n]/.test(command) && lowered.some(
|
|
16403
|
+
(segment) => segment.requirements.some((entry) => entry.action === "network.connect")
|
|
16404
|
+
)) {
|
|
16405
|
+
lowered.push(
|
|
16406
|
+
shellSegment(
|
|
16407
|
+
"[multiline network boundary]",
|
|
16408
|
+
"shell-boundary",
|
|
16409
|
+
[
|
|
16410
|
+
requirement2(
|
|
16411
|
+
"indeterminate",
|
|
16412
|
+
"indeterminate",
|
|
16413
|
+
{ kind: "unknown" },
|
|
16414
|
+
"[multiline network boundary]",
|
|
16415
|
+
["shell.multiline_network_boundary"]
|
|
16416
|
+
)
|
|
16417
|
+
],
|
|
16418
|
+
"opaque",
|
|
16419
|
+
/* @__PURE__ */ new Set(["shell.multiline_network_boundary"])
|
|
16284
16420
|
)
|
|
16285
16421
|
);
|
|
16286
16422
|
}
|
|
16423
|
+
return lowered;
|
|
16287
16424
|
}
|
|
16288
|
-
function
|
|
16289
|
-
|
|
16425
|
+
function lowerSegment(command, context) {
|
|
16426
|
+
const commandRedacted = redactCommand(command);
|
|
16427
|
+
const lexed = lexShell(command);
|
|
16428
|
+
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
16429
|
+
const environment = extractEnvironment(rawTokens, context.env);
|
|
16430
|
+
const env = environment.env;
|
|
16431
|
+
const parsed = parseSegment(command);
|
|
16432
|
+
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
16433
|
+
const tokens = stripRedirects(
|
|
16434
|
+
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
16435
|
+
).map((token) => expandKnownVariables(token, env));
|
|
16436
|
+
const decoderTokens = alignStructuredTokens(
|
|
16437
|
+
stripStructuredRedirects(lexed.tokens),
|
|
16438
|
+
stripRedirects(parsedTokens)
|
|
16439
|
+
);
|
|
16440
|
+
const head = path49.basename(tokens[0] ?? parsed.head);
|
|
16441
|
+
let opacity = segmentOpacity(command);
|
|
16442
|
+
const signals = /* @__PURE__ */ new Set();
|
|
16443
|
+
const requirements = [];
|
|
16444
|
+
if (!lexed.complete) {
|
|
16290
16445
|
requirements.push(
|
|
16291
|
-
requirement2("
|
|
16292
|
-
"
|
|
16446
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16447
|
+
"shell.grammar_incomplete"
|
|
16293
16448
|
])
|
|
16294
16449
|
);
|
|
16450
|
+
signals.add("shell.grammar_incomplete");
|
|
16451
|
+
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
16295
16452
|
}
|
|
16296
|
-
|
|
16297
|
-
|
|
16298
|
-
|
|
16299
|
-
|
|
16300
|
-
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
case "cat":
|
|
16306
|
-
case "head":
|
|
16307
|
-
case "tail":
|
|
16308
|
-
case "less":
|
|
16309
|
-
case "stat":
|
|
16310
|
-
case "file":
|
|
16311
|
-
case "du":
|
|
16312
|
-
case "wc":
|
|
16313
|
-
return args.filter((arg) => arg && !arg.startsWith("-"));
|
|
16314
|
-
case "grep":
|
|
16315
|
-
case "rg":
|
|
16316
|
-
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
16317
|
-
case "jq":
|
|
16318
|
-
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
16319
|
-
default:
|
|
16320
|
-
return null;
|
|
16321
|
-
}
|
|
16322
|
-
}
|
|
16323
|
-
function findReadOperands(args) {
|
|
16324
|
-
const mutatingPrimaries = /* @__PURE__ */ new Set([
|
|
16325
|
-
"-delete",
|
|
16326
|
-
"-exec",
|
|
16327
|
-
"-execdir",
|
|
16328
|
-
"-fls",
|
|
16329
|
-
"-fprint",
|
|
16330
|
-
"-fprintf",
|
|
16331
|
-
"-ok",
|
|
16332
|
-
"-okdir"
|
|
16333
|
-
]);
|
|
16334
|
-
if (args.some(
|
|
16335
|
-
(arg) => mutatingPrimaries.has(arg) || [...mutatingPrimaries].some((primary) => arg.startsWith(`${primary}=`))
|
|
16336
|
-
)) {
|
|
16337
|
-
return null;
|
|
16338
|
-
}
|
|
16339
|
-
const paths = [];
|
|
16340
|
-
for (const arg of args) {
|
|
16341
|
-
if (arg.startsWith("-") || arg === "!" || arg === "(") {
|
|
16342
|
-
break;
|
|
16343
|
-
}
|
|
16344
|
-
paths.push(arg);
|
|
16453
|
+
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
16454
|
+
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
16455
|
+
if (environment.malformed) {
|
|
16456
|
+
requirements.push(
|
|
16457
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16458
|
+
"shell.env_wrapper_incomplete"
|
|
16459
|
+
])
|
|
16460
|
+
);
|
|
16461
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16345
16462
|
}
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
case "truncate":
|
|
16355
|
-
case "chmod":
|
|
16356
|
-
return positional;
|
|
16357
|
-
case "cp":
|
|
16358
|
-
case "mv":
|
|
16359
|
-
return positional.length > 0 ? [positional[positional.length - 1] ?? ""] : [];
|
|
16360
|
-
case "tee":
|
|
16361
|
-
return positional;
|
|
16362
|
-
default:
|
|
16363
|
-
return null;
|
|
16463
|
+
if (parsed.encounteredXargs) {
|
|
16464
|
+
requirements.push(
|
|
16465
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16466
|
+
"shell.xargs_stdin_dynamic"
|
|
16467
|
+
])
|
|
16468
|
+
);
|
|
16469
|
+
signals.add("shell.xargs_stdin_dynamic");
|
|
16470
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16364
16471
|
}
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
index += 1;
|
|
16379
|
-
continue;
|
|
16380
|
-
}
|
|
16381
|
-
if (/^-[ablnPRtV]+$/.test(arg) && [...arg.slice(1)].every((flag) => "ablnPRtV".includes(flag)) || /^-i(?:TCP|UDP)?(?::\d+(?:-\d+)?)?$/.test(arg) || /^-s(?:TCP|UDP):[A-Za-z]+$/.test(arg) || /^-(?:c|d|F|g|p|T|u).+$/.test(arg) || /^\+(?:d|D).+$/.test(arg)) {
|
|
16382
|
-
continue;
|
|
16383
|
-
}
|
|
16384
|
-
return false;
|
|
16472
|
+
if (context.depth > MAX_LOWER_DEPTH) {
|
|
16473
|
+
requirements.push(
|
|
16474
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16475
|
+
"shell.lower_depth_exceeded"
|
|
16476
|
+
])
|
|
16477
|
+
);
|
|
16478
|
+
return shellSegment(
|
|
16479
|
+
commandRedacted,
|
|
16480
|
+
head,
|
|
16481
|
+
requirements,
|
|
16482
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16483
|
+
signals
|
|
16484
|
+
);
|
|
16385
16485
|
}
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
"--group",
|
|
16394
|
-
"--pid",
|
|
16395
|
-
"--ppid",
|
|
16396
|
-
"--sort",
|
|
16397
|
-
"--tty",
|
|
16398
|
-
"--user"
|
|
16399
|
-
]);
|
|
16400
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
16401
|
-
const arg = args[index] ?? "";
|
|
16402
|
-
if (bareForms.has(arg) || flagsWithoutValues.has(arg)) {
|
|
16403
|
-
continue;
|
|
16404
|
-
}
|
|
16405
|
-
if (flagsWithValues.has(arg)) {
|
|
16406
|
-
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
16407
|
-
return false;
|
|
16408
|
-
}
|
|
16409
|
-
index += 1;
|
|
16410
|
-
continue;
|
|
16486
|
+
const packageExec = peelPackageExecArgv(tokens);
|
|
16487
|
+
if (packageExec) {
|
|
16488
|
+
requirements.push(
|
|
16489
|
+
...decodePackageExec(packageExec, context.cwd, context.repoRoot, commandRedacted)
|
|
16490
|
+
);
|
|
16491
|
+
for (const signal of packageExec.signals) {
|
|
16492
|
+
signals.add(signal);
|
|
16411
16493
|
}
|
|
16412
|
-
if (
|
|
16413
|
-
|
|
16494
|
+
if (packageExec.opaque) {
|
|
16495
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16414
16496
|
}
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
const
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
16430
|
-
|
|
16431
|
-
}
|
|
16432
|
-
break;
|
|
16497
|
+
const innerRecipe = packageExecInnerIsMetadata(packageExec) ? null : innerRecipeFromPeel(packageExec);
|
|
16498
|
+
if (innerRecipe) {
|
|
16499
|
+
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
16500
|
+
...context,
|
|
16501
|
+
command: innerRecipe,
|
|
16502
|
+
env,
|
|
16503
|
+
depth: context.depth + 1
|
|
16504
|
+
});
|
|
16505
|
+
for (const nestedSegment of nested) {
|
|
16506
|
+
requirements.push(
|
|
16507
|
+
...nestedSegment.requirements.map(
|
|
16508
|
+
(entry) => withInnerProvenance(entry, innerRecipe, packageExec.launcher, commandRedacted)
|
|
16509
|
+
)
|
|
16510
|
+
);
|
|
16511
|
+
for (const signal of nestedSegment.signals) {
|
|
16512
|
+
signals.add(signal);
|
|
16433
16513
|
}
|
|
16434
|
-
|
|
16435
|
-
break;
|
|
16436
|
-
}
|
|
16437
|
-
if (valid) {
|
|
16438
|
-
continue;
|
|
16514
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16439
16515
|
}
|
|
16440
16516
|
}
|
|
16441
|
-
return
|
|
16442
|
-
}
|
|
16443
|
-
return true;
|
|
16444
|
-
}
|
|
16445
|
-
function validFilesystemTest(head, args) {
|
|
16446
|
-
const operands = head === "[" && args.at(-1) === "]" ? args.slice(0, -1) : args;
|
|
16447
|
-
if (head === "[" && args.at(-1) !== "]") {
|
|
16448
|
-
return false;
|
|
16517
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16449
16518
|
}
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16519
|
+
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
16520
|
+
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
16521
|
+
requirements.push(
|
|
16522
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
16523
|
+
"shell.recursive_wrapper",
|
|
16524
|
+
"dynamic_shell_evaluation"
|
|
16525
|
+
])
|
|
16526
|
+
);
|
|
16527
|
+
if (recursive.script !== "") {
|
|
16528
|
+
const nested = lowerTopLevelSegments(recursive.script, {
|
|
16529
|
+
...context,
|
|
16530
|
+
command: recursive.script,
|
|
16531
|
+
env,
|
|
16532
|
+
depth: context.depth + 1
|
|
16533
|
+
});
|
|
16534
|
+
for (const nestedSegment of nested) {
|
|
16535
|
+
requirements.push(
|
|
16536
|
+
...nestedSegment.requirements.map(
|
|
16537
|
+
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
16538
|
+
)
|
|
16539
|
+
);
|
|
16540
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
16463
16541
|
}
|
|
16464
|
-
index += 1;
|
|
16465
|
-
continue;
|
|
16466
16542
|
}
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16543
|
+
signals.add("shell.recursive_wrapper");
|
|
16544
|
+
signals.add("dynamic_shell_evaluation");
|
|
16545
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
16546
|
+
}
|
|
16547
|
+
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
16548
|
+
const recursiveSignals = [
|
|
16549
|
+
recursive.signal,
|
|
16550
|
+
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
16551
|
+
];
|
|
16552
|
+
requirements.push(
|
|
16553
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
16554
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16555
|
+
...recursiveSignals
|
|
16556
|
+
])
|
|
16557
|
+
);
|
|
16558
|
+
for (const signal of recursiveSignals) signals.add(signal);
|
|
16559
|
+
return shellSegment(
|
|
16560
|
+
commandRedacted,
|
|
16561
|
+
head,
|
|
16562
|
+
requirements,
|
|
16563
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16564
|
+
signals
|
|
16565
|
+
);
|
|
16566
|
+
}
|
|
16567
|
+
const compose = decodeDockerComposeRun(decoderTokens);
|
|
16568
|
+
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
16569
|
+
requirements.push(
|
|
16570
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
16571
|
+
);
|
|
16572
|
+
if (compose.script !== "") {
|
|
16573
|
+
const nested = lowerTopLevelSegments(compose.script, {
|
|
16574
|
+
...context,
|
|
16575
|
+
command: compose.script,
|
|
16576
|
+
env,
|
|
16577
|
+
depth: context.depth + 1
|
|
16578
|
+
});
|
|
16579
|
+
for (const nestedSegment of nested) {
|
|
16580
|
+
requirements.push(
|
|
16581
|
+
...nestedSegment.requirements.map(
|
|
16582
|
+
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
16583
|
+
)
|
|
16584
|
+
);
|
|
16585
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
16586
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16470
16587
|
}
|
|
16471
|
-
continue;
|
|
16472
16588
|
}
|
|
16473
|
-
|
|
16589
|
+
signals.add("process.docker_compose_run");
|
|
16590
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
16474
16591
|
}
|
|
16475
|
-
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
|
|
16482
|
-
"
|
|
16483
|
-
|
|
16484
|
-
|
|
16485
|
-
|
|
16486
|
-
|
|
16487
|
-
|
|
16488
|
-
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16492
|
-
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
}
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16592
|
+
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
16593
|
+
requirements.push(
|
|
16594
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
16595
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16596
|
+
compose.signal
|
|
16597
|
+
])
|
|
16598
|
+
);
|
|
16599
|
+
signals.add("process.docker_compose_run");
|
|
16600
|
+
signals.add(compose.signal);
|
|
16601
|
+
return shellSegment(
|
|
16602
|
+
commandRedacted,
|
|
16603
|
+
head,
|
|
16604
|
+
requirements,
|
|
16605
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16606
|
+
signals
|
|
16607
|
+
);
|
|
16608
|
+
}
|
|
16609
|
+
const launcher = resolveLauncherRecipe({
|
|
16610
|
+
tokens,
|
|
16611
|
+
cwd: context.cwd,
|
|
16612
|
+
repoRoot: context.repoRoot,
|
|
16613
|
+
depth: context.depth
|
|
16614
|
+
});
|
|
16615
|
+
if (launcher) {
|
|
16616
|
+
signals.add(`launcher.${launcher.reason}`);
|
|
16617
|
+
requirements.push(
|
|
16618
|
+
requirement2(
|
|
16619
|
+
"process.exec",
|
|
16620
|
+
"process.exec",
|
|
16621
|
+
{ kind: "executable", command: head, operation: "spawn" },
|
|
16622
|
+
commandRedacted,
|
|
16623
|
+
["launcher.invoke"]
|
|
16624
|
+
)
|
|
16625
|
+
);
|
|
16626
|
+
for (const recipe of launcher.recipes) {
|
|
16627
|
+
const nested = lowerTopLevelSegments(recipe, {
|
|
16628
|
+
...context,
|
|
16629
|
+
command: recipe,
|
|
16630
|
+
env,
|
|
16631
|
+
depth: context.depth + 1
|
|
16632
|
+
});
|
|
16633
|
+
for (const nestedSegment of nested) {
|
|
16634
|
+
requirements.push(
|
|
16635
|
+
...nestedSegment.requirements.map(
|
|
16636
|
+
(entry) => withInnerProvenance(entry, recipe, head, commandRedacted)
|
|
16637
|
+
)
|
|
16638
|
+
);
|
|
16639
|
+
for (const signal of nestedSegment.signals) {
|
|
16640
|
+
signals.add(signal);
|
|
16641
|
+
}
|
|
16642
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16503
16643
|
}
|
|
16504
|
-
index += 1;
|
|
16505
|
-
continue;
|
|
16506
16644
|
}
|
|
16507
|
-
if (
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
const options = arg.slice(1);
|
|
16515
|
-
if ([...options].some((option) => !shortFlags.has(option))) {
|
|
16516
|
-
return null;
|
|
16517
|
-
}
|
|
16518
|
-
syntaxOnly ||= options.includes("n");
|
|
16519
|
-
continue;
|
|
16645
|
+
if (launcher.opaque || launcher.recipes.length === 0) {
|
|
16646
|
+
requirements.push(
|
|
16647
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16648
|
+
`launcher.${launcher.reason}`
|
|
16649
|
+
])
|
|
16650
|
+
);
|
|
16651
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16520
16652
|
}
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16653
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16654
|
+
}
|
|
16655
|
+
const egress = decodeEgressEffects({
|
|
16656
|
+
tokens,
|
|
16657
|
+
cwd: context.cwd,
|
|
16658
|
+
segment: commandRedacted
|
|
16659
|
+
});
|
|
16660
|
+
if (egress) {
|
|
16661
|
+
requirements.push(...egress);
|
|
16662
|
+
for (const signal of egress.flatMap((entry) => entry.evidence.signals)) {
|
|
16663
|
+
signals.add(signal);
|
|
16524
16664
|
}
|
|
16525
|
-
|
|
16526
|
-
|
|
16665
|
+
} else {
|
|
16666
|
+
const git = decodeGitEffects({
|
|
16667
|
+
tokens,
|
|
16668
|
+
cwd: context.cwd,
|
|
16669
|
+
repoRoot: context.repoRoot,
|
|
16670
|
+
segment: commandRedacted
|
|
16671
|
+
});
|
|
16672
|
+
if (git) {
|
|
16673
|
+
requirements.push(...git);
|
|
16674
|
+
for (const signal of git.flatMap((entry) => entry.evidence.signals)) {
|
|
16675
|
+
signals.add(signal);
|
|
16676
|
+
}
|
|
16677
|
+
} else {
|
|
16678
|
+
const processRequirements = decodeProcessOrFilesystem({
|
|
16679
|
+
tokens,
|
|
16680
|
+
head,
|
|
16681
|
+
env,
|
|
16682
|
+
cwd: context.cwd,
|
|
16683
|
+
repoRoot: context.repoRoot,
|
|
16684
|
+
segment: commandRedacted
|
|
16685
|
+
});
|
|
16686
|
+
if (isGrammarUnknownOnly(processRequirements, head)) {
|
|
16687
|
+
const argvDelegate = peelArgvDelegateArgv(tokens);
|
|
16688
|
+
if (argvDelegate && !argvDelegate.opaque && shouldApplyArgvDelegate(head, argvDelegate.innerTokens, context.depth)) {
|
|
16689
|
+
const innerRecipe = innerRecipeFromArgvDelegate(argvDelegate);
|
|
16690
|
+
if (innerRecipe) {
|
|
16691
|
+
requirements.push(
|
|
16692
|
+
processRequirement(head, "inspect", commandRedacted, [
|
|
16693
|
+
"process.argv_delegate",
|
|
16694
|
+
...argvDelegate.signals
|
|
16695
|
+
])
|
|
16696
|
+
);
|
|
16697
|
+
for (const signal of argvDelegate.signals) {
|
|
16698
|
+
signals.add(signal);
|
|
16699
|
+
}
|
|
16700
|
+
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
16701
|
+
...context,
|
|
16702
|
+
command: innerRecipe,
|
|
16703
|
+
env,
|
|
16704
|
+
depth: context.depth + 1
|
|
16705
|
+
});
|
|
16706
|
+
for (const nestedSegment of nested) {
|
|
16707
|
+
requirements.push(
|
|
16708
|
+
...nestedSegment.requirements.map(
|
|
16709
|
+
(entry) => withInnerProvenance(entry, innerRecipe, head, commandRedacted)
|
|
16710
|
+
)
|
|
16711
|
+
);
|
|
16712
|
+
for (const signal of nestedSegment.signals) {
|
|
16713
|
+
signals.add(signal);
|
|
16714
|
+
}
|
|
16715
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16716
|
+
}
|
|
16717
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16718
|
+
}
|
|
16719
|
+
}
|
|
16720
|
+
if (argvDelegate?.opaque) {
|
|
16721
|
+
requirements.push(
|
|
16722
|
+
processRequirement(head, "spawn", commandRedacted, [
|
|
16723
|
+
"process.argv_delegate",
|
|
16724
|
+
argvDelegate.reason,
|
|
16725
|
+
...argvDelegate.signals
|
|
16726
|
+
]),
|
|
16727
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16728
|
+
argvDelegate.reason,
|
|
16729
|
+
"process.argv_delegate_opaque"
|
|
16730
|
+
])
|
|
16731
|
+
);
|
|
16732
|
+
for (const signal of argvDelegate.signals) {
|
|
16733
|
+
signals.add(signal);
|
|
16734
|
+
}
|
|
16735
|
+
signals.add("process.argv_delegate_opaque");
|
|
16736
|
+
return shellSegment(
|
|
16737
|
+
commandRedacted,
|
|
16738
|
+
head,
|
|
16739
|
+
requirements,
|
|
16740
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16741
|
+
signals
|
|
16742
|
+
);
|
|
16743
|
+
}
|
|
16744
|
+
}
|
|
16745
|
+
requirements.push(...processRequirements);
|
|
16527
16746
|
}
|
|
16528
|
-
script = arg;
|
|
16529
|
-
break;
|
|
16530
|
-
}
|
|
16531
|
-
return syntaxOnly ? script : null;
|
|
16532
|
-
}
|
|
16533
|
-
function isOptionToken(value) {
|
|
16534
|
-
return value.startsWith("-") || value.startsWith("+");
|
|
16535
|
-
}
|
|
16536
|
-
function databaseEndpoint(raw) {
|
|
16537
|
-
if (!raw || raw.includes("$")) {
|
|
16538
|
-
return null;
|
|
16539
16747
|
}
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16748
|
+
const environmentSignals = effectChangingEnvironmentSignals(head, env, environment.changedNames);
|
|
16749
|
+
if (environmentSignals.length > 0) {
|
|
16750
|
+
requirements.push(
|
|
16751
|
+
requirement2(
|
|
16752
|
+
"indeterminate",
|
|
16753
|
+
"indeterminate",
|
|
16754
|
+
{ kind: "unknown" },
|
|
16755
|
+
commandRedacted,
|
|
16756
|
+
environmentSignals
|
|
16757
|
+
)
|
|
16758
|
+
);
|
|
16759
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16760
|
+
for (const signal of environmentSignals) {
|
|
16761
|
+
signals.add(signal);
|
|
16544
16762
|
}
|
|
16545
|
-
return {
|
|
16546
|
-
host: url.hostname.toLowerCase(),
|
|
16547
|
-
protocol: url.protocol.slice(0, -1),
|
|
16548
|
-
...url.port ? { port: Number(url.port) } : {}
|
|
16549
|
-
};
|
|
16550
|
-
} catch {
|
|
16551
|
-
return null;
|
|
16552
16763
|
}
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16764
|
+
if (context.pipeToShellSegment) {
|
|
16765
|
+
signals.add("pipe_to_shell");
|
|
16766
|
+
ensureRequirement(
|
|
16767
|
+
requirements,
|
|
16768
|
+
requirement2(
|
|
16769
|
+
"process.exec",
|
|
16770
|
+
"process.exec",
|
|
16771
|
+
{ kind: "executable", command: head || "sh", operation: "spawn" },
|
|
16772
|
+
commandRedacted,
|
|
16773
|
+
["pipe_to_shell"]
|
|
16774
|
+
)
|
|
16775
|
+
);
|
|
16776
|
+
ensureRequirement(
|
|
16777
|
+
requirements,
|
|
16778
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16779
|
+
"pipe_to_shell"
|
|
16780
|
+
])
|
|
16781
|
+
);
|
|
16782
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16557
16783
|
}
|
|
16558
|
-
if (
|
|
16559
|
-
|
|
16784
|
+
if (opacity === "unparseable" || opacity === "opaque") {
|
|
16785
|
+
ensureRequirement(
|
|
16786
|
+
requirements,
|
|
16787
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16788
|
+
`shell.${opacity}`
|
|
16789
|
+
])
|
|
16790
|
+
);
|
|
16560
16791
|
}
|
|
16561
|
-
return
|
|
16562
|
-
}
|
|
16563
|
-
function isShellHead(head) {
|
|
16564
|
-
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
16565
|
-
}
|
|
16566
|
-
function pipeToShell(command) {
|
|
16567
|
-
return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
|
|
16568
|
-
}
|
|
16569
|
-
function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegment) {
|
|
16570
|
-
const provenance = {
|
|
16571
|
-
...requirementValue.provenance,
|
|
16572
|
-
segment: outerSegment,
|
|
16573
|
-
innerCommand: requirementValue.provenance.innerCommand ?? innerCommand,
|
|
16574
|
-
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
16575
|
-
};
|
|
16576
|
-
const launcherProvenance = {
|
|
16577
|
-
segment: outerSegment,
|
|
16578
|
-
innerCommand,
|
|
16579
|
-
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
16580
|
-
};
|
|
16581
|
-
return withProvenances(requirementValue, provenance, launcherProvenance);
|
|
16582
|
-
}
|
|
16583
|
-
function withProvenances(requirementValue, provenance, contributing) {
|
|
16584
|
-
const provenances = [
|
|
16585
|
-
...requirementValue.provenances ?? [requirementValue.provenance],
|
|
16586
|
-
contributing,
|
|
16587
|
-
provenance
|
|
16588
|
-
].filter(
|
|
16589
|
-
(candidate, index, all) => all.findIndex((entry) => JSON.stringify(entry) === JSON.stringify(candidate)) === index
|
|
16590
|
-
);
|
|
16591
|
-
return { ...requirementValue, provenance, provenances };
|
|
16792
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16592
16793
|
}
|
|
16593
|
-
function
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16794
|
+
function addSubstitutionEffects(requirements, command, context, segment, signals) {
|
|
16795
|
+
const inners = structuralSubstitutionInners(command);
|
|
16796
|
+
for (const inner of inners) {
|
|
16797
|
+
signals.add("command_substitution");
|
|
16798
|
+
if (context.depth >= MAX_LOWER_DEPTH) {
|
|
16799
|
+
requirements.push(
|
|
16800
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16801
|
+
"shell.substitution_depth_exceeded"
|
|
16802
|
+
])
|
|
16803
|
+
);
|
|
16804
|
+
continue;
|
|
16805
|
+
}
|
|
16806
|
+
const nestedSegments = lowerTopLevelSegments(inner, {
|
|
16807
|
+
...context,
|
|
16808
|
+
command: inner,
|
|
16809
|
+
depth: context.depth + 1
|
|
16810
|
+
});
|
|
16811
|
+
for (const nested of nestedSegments) {
|
|
16812
|
+
requirements.push(
|
|
16813
|
+
...nested.requirements.map((entry) => {
|
|
16814
|
+
const outerProvenance = {
|
|
16815
|
+
segment,
|
|
16816
|
+
innerCommand: inner
|
|
16817
|
+
};
|
|
16818
|
+
const provenance = {
|
|
16819
|
+
...entry.provenance,
|
|
16820
|
+
segment,
|
|
16821
|
+
innerCommand: entry.provenance.innerCommand ?? inner
|
|
16822
|
+
};
|
|
16823
|
+
return withProvenances(entry, provenance, outerProvenance);
|
|
16824
|
+
})
|
|
16825
|
+
);
|
|
16826
|
+
}
|
|
16598
16827
|
}
|
|
16599
16828
|
}
|
|
16600
|
-
function requirement2(tag, action, resource, segment, signals) {
|
|
16601
|
-
return {
|
|
16602
|
-
tag,
|
|
16603
|
-
action,
|
|
16604
|
-
resource,
|
|
16605
|
-
evidence: {
|
|
16606
|
-
level: tag === "indeterminate" ? "indeterminate" : "certain",
|
|
16607
|
-
signals: [...new Set(signals)].sort(),
|
|
16608
|
-
basis: ["shell_semantic_lowering"]
|
|
16609
|
-
},
|
|
16610
|
-
provenance: { segment }
|
|
16611
|
-
};
|
|
16612
|
-
}
|
|
16613
16829
|
|
|
16614
16830
|
// src/core/verdict/verdict.ts
|
|
16615
16831
|
init_path_utils();
|
|
@@ -16829,6 +17045,13 @@ function policyAuth(options) {
|
|
|
16829
17045
|
function scrubPayload(value, options) {
|
|
16830
17046
|
return scrubValue(value, options.scrubOptions);
|
|
16831
17047
|
}
|
|
17048
|
+
function fingerprintPayload(payload, options) {
|
|
17049
|
+
const toolInput = fingerprintToolInputSource(payload);
|
|
17050
|
+
if (Object.keys(toolInput).length > 0) {
|
|
17051
|
+
return toolInput;
|
|
17052
|
+
}
|
|
17053
|
+
return scrubPayload(payload.tool_input ?? {}, options);
|
|
17054
|
+
}
|
|
16832
17055
|
function extractFilePath(payload) {
|
|
16833
17056
|
const toolInput = payload.tool_input;
|
|
16834
17057
|
if (!toolInput || typeof toolInput !== "object") {
|
|
@@ -17003,11 +17226,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17003
17226
|
verdict: "deny_pending_approval",
|
|
17004
17227
|
reason: "tool_shell_missing_command",
|
|
17005
17228
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17006
|
-
fingerprint: toolFingerprint(
|
|
17007
|
-
toolName,
|
|
17008
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17009
|
-
repoRoot
|
|
17010
|
-
),
|
|
17229
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17011
17230
|
assessment: {
|
|
17012
17231
|
reversibility: "irreversible",
|
|
17013
17232
|
external: false,
|
|
@@ -17021,11 +17240,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17021
17240
|
verdict: "allow_flagged",
|
|
17022
17241
|
reason: "tool_shell_missing_command",
|
|
17023
17242
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17024
|
-
fingerprint: toolFingerprint(
|
|
17025
|
-
toolName,
|
|
17026
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17027
|
-
repoRoot
|
|
17028
|
-
),
|
|
17243
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17029
17244
|
assessment: {
|
|
17030
17245
|
reversibility: "recoverable_with_cost",
|
|
17031
17246
|
external: false,
|
|
@@ -17049,11 +17264,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17049
17264
|
verdict: "deny_pending_approval",
|
|
17050
17265
|
reason: "file_mutation_missing_path",
|
|
17051
17266
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17052
|
-
fingerprint: toolFingerprint(
|
|
17053
|
-
toolName,
|
|
17054
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17055
|
-
repoRoot
|
|
17056
|
-
),
|
|
17267
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17057
17268
|
assessment: {
|
|
17058
17269
|
reversibility: "irreversible",
|
|
17059
17270
|
external: false,
|
|
@@ -17067,11 +17278,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17067
17278
|
verdict: "allow_flagged",
|
|
17068
17279
|
reason: "file_mutation_missing_path",
|
|
17069
17280
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17070
|
-
fingerprint: toolFingerprint(
|
|
17071
|
-
toolName,
|
|
17072
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17073
|
-
repoRoot
|
|
17074
|
-
),
|
|
17281
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17075
17282
|
assessment: {
|
|
17076
17283
|
reversibility: "recoverable_with_cost",
|
|
17077
17284
|
external: false,
|
|
@@ -17082,7 +17289,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17082
17289
|
};
|
|
17083
17290
|
}
|
|
17084
17291
|
const signals = [];
|
|
17085
|
-
const resolvedPath =
|
|
17292
|
+
const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
|
|
17086
17293
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17087
17294
|
if (hitsProtectedRoot) {
|
|
17088
17295
|
signals.push("control_plane_path");
|
|
@@ -17221,11 +17428,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17221
17428
|
verdict: "deny_pending_approval",
|
|
17222
17429
|
reason: "apply_patch_missing_path",
|
|
17223
17430
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17224
|
-
fingerprint: toolFingerprint(
|
|
17225
|
-
toolName,
|
|
17226
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17227
|
-
repoRoot
|
|
17228
|
-
),
|
|
17431
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17229
17432
|
assessment: {
|
|
17230
17433
|
reversibility: "irreversible",
|
|
17231
17434
|
external: false,
|
|
@@ -17239,11 +17442,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17239
17442
|
verdict: "allow_flagged",
|
|
17240
17443
|
reason: "apply_patch_missing_path",
|
|
17241
17444
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17242
|
-
fingerprint: toolFingerprint(
|
|
17243
|
-
toolName,
|
|
17244
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17245
|
-
repoRoot
|
|
17246
|
-
),
|
|
17445
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17247
17446
|
assessment: {
|
|
17248
17447
|
reversibility: "recoverable_with_cost",
|
|
17249
17448
|
external: false,
|
|
@@ -17274,11 +17473,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17274
17473
|
verdict: "allow_flagged",
|
|
17275
17474
|
reason: sawDelete ? "file_delete" : "file_mutation",
|
|
17276
17475
|
summary: targets.map((target) => target.path).join(", "),
|
|
17277
|
-
fingerprint: toolFingerprint(
|
|
17278
|
-
toolName,
|
|
17279
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17280
|
-
repoRoot
|
|
17281
|
-
),
|
|
17476
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17282
17477
|
assessment: {
|
|
17283
17478
|
reversibility: "recoverable_with_cost",
|
|
17284
17479
|
external: false,
|
|
@@ -17292,11 +17487,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17292
17487
|
verdict: "allow",
|
|
17293
17488
|
reason: "unclassified_tool",
|
|
17294
17489
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17295
|
-
fingerprint: toolFingerprint(
|
|
17296
|
-
toolName,
|
|
17297
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17298
|
-
repoRoot
|
|
17299
|
-
),
|
|
17490
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17300
17491
|
assessment: {
|
|
17301
17492
|
reversibility: "reversible",
|
|
17302
17493
|
external: false,
|
|
@@ -17684,7 +17875,7 @@ function hashDecisionConfig(config) {
|
|
|
17684
17875
|
init_fingerprint2();
|
|
17685
17876
|
|
|
17686
17877
|
// src/version.ts
|
|
17687
|
-
var PACKAGE_VERSION = "0.9.
|
|
17878
|
+
var PACKAGE_VERSION = "0.9.4";
|
|
17688
17879
|
|
|
17689
17880
|
// src/runtime-provenance.ts
|
|
17690
17881
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -17759,7 +17950,7 @@ init_path_utils();
|
|
|
17759
17950
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17760
17951
|
import { existsSync as existsSync15 } from "node:fs";
|
|
17761
17952
|
import { mkdir as mkdir11, readdir as readdir3, readFile as readFile13, rename as rename3, rm as rm6 } from "node:fs/promises";
|
|
17762
|
-
import
|
|
17953
|
+
import path55 from "node:path";
|
|
17763
17954
|
|
|
17764
17955
|
// src/core/recovery/artifact-store.ts
|
|
17765
17956
|
init_fingerprint2();
|
|
@@ -17767,7 +17958,7 @@ init_path_utils();
|
|
|
17767
17958
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
17768
17959
|
import { existsSync as existsSync13 } from "node:fs";
|
|
17769
17960
|
import { lstat as lstat7, mkdir as mkdir10, open as open5, readdir as readdir2, readFile as readFile10, rename as rename2, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
|
|
17770
|
-
import
|
|
17961
|
+
import path52 from "node:path";
|
|
17771
17962
|
|
|
17772
17963
|
// src/core/recovery/snapshot-node.ts
|
|
17773
17964
|
init_fingerprint2();
|
|
@@ -17787,25 +17978,25 @@ import {
|
|
|
17787
17978
|
symlink as symlink3,
|
|
17788
17979
|
writeFile as writeFile6
|
|
17789
17980
|
} from "node:fs/promises";
|
|
17790
|
-
import
|
|
17981
|
+
import path51 from "node:path";
|
|
17791
17982
|
var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
|
|
17792
17983
|
function validRecoveryRelativePath(relativePath) {
|
|
17793
|
-
if (!relativePath || relativePath.includes("\0") ||
|
|
17794
|
-
const normalized =
|
|
17795
|
-
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${
|
|
17984
|
+
if (!relativePath || relativePath.includes("\0") || path51.isAbsolute(relativePath)) return false;
|
|
17985
|
+
const normalized = path51.normalize(relativePath);
|
|
17986
|
+
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path51.sep}`);
|
|
17796
17987
|
}
|
|
17797
17988
|
async function assertRecoverySafeTarget(resourceRoot, relativePath) {
|
|
17798
17989
|
if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
|
|
17799
17990
|
const root = canonicalPath(resourceRoot);
|
|
17800
|
-
const target =
|
|
17801
|
-
const relative =
|
|
17802
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
17991
|
+
const target = path51.resolve(root, relativePath);
|
|
17992
|
+
const relative = path51.relative(root, target);
|
|
17993
|
+
if (relative === ".." || relative.startsWith(`..${path51.sep}`) || path51.isAbsolute(relative)) {
|
|
17803
17994
|
throw new Error("recovery_path_escape");
|
|
17804
17995
|
}
|
|
17805
17996
|
let current = root;
|
|
17806
|
-
const parentParts =
|
|
17997
|
+
const parentParts = path51.relative(root, path51.dirname(target)).split(path51.sep).filter(Boolean);
|
|
17807
17998
|
for (const part of parentParts) {
|
|
17808
|
-
current =
|
|
17999
|
+
current = path51.join(current, part);
|
|
17809
18000
|
if (!existsSync12(current)) break;
|
|
17810
18001
|
const info = await lstat6(current);
|
|
17811
18002
|
if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
|
|
@@ -17861,7 +18052,7 @@ async function captureRecoverySnapshot(filePath, options) {
|
|
|
17861
18052
|
let blob;
|
|
17862
18053
|
if (options?.blobDir) {
|
|
17863
18054
|
await mkdir9(options.blobDir, { recursive: true, mode: 448 });
|
|
17864
|
-
const blobPath =
|
|
18055
|
+
const blobPath = path51.join(options.blobDir, hash);
|
|
17865
18056
|
if (!existsSync12(blobPath)) {
|
|
17866
18057
|
await writeFile6(blobPath, content, { mode: 384 });
|
|
17867
18058
|
await fsyncPath(blobPath);
|
|
@@ -17916,7 +18107,7 @@ async function validateRecoverySnapshot(params) {
|
|
|
17916
18107
|
if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
|
|
17917
18108
|
let content;
|
|
17918
18109
|
try {
|
|
17919
|
-
content = await readFile9(
|
|
18110
|
+
content = await readFile9(path51.join(params.artifactDir, record.blob));
|
|
17920
18111
|
} catch {
|
|
17921
18112
|
throw new Error(params.corruptReason);
|
|
17922
18113
|
}
|
|
@@ -17944,13 +18135,13 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
|
|
|
17944
18135
|
]);
|
|
17945
18136
|
var STAGING_STALE_MS = 5 * 6e4;
|
|
17946
18137
|
function checkpointsRoot(stateDir) {
|
|
17947
|
-
return
|
|
18138
|
+
return path52.join(stateDir, "recovery", "checkpoints");
|
|
17948
18139
|
}
|
|
17949
18140
|
function checkpointDir(stateDir, checkpointId) {
|
|
17950
18141
|
if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
|
|
17951
18142
|
throw new Error("invalid_recovery_checkpoint_id");
|
|
17952
18143
|
}
|
|
17953
|
-
return
|
|
18144
|
+
return path52.join(checkpointsRoot(stateDir), checkpointId);
|
|
17954
18145
|
}
|
|
17955
18146
|
async function fsyncPath2(filePath) {
|
|
17956
18147
|
const handle = await open5(filePath, "r");
|
|
@@ -17961,13 +18152,13 @@ async function fsyncPath2(filePath) {
|
|
|
17961
18152
|
}
|
|
17962
18153
|
}
|
|
17963
18154
|
async function atomicWriteJson(filePath, value) {
|
|
17964
|
-
await mkdir10(
|
|
18155
|
+
await mkdir10(path52.dirname(filePath), { recursive: true, mode: 448 });
|
|
17965
18156
|
const temporary = `${filePath}.tmp-${randomUUID4()}`;
|
|
17966
18157
|
await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
|
|
17967
18158
|
`, { mode: 384 });
|
|
17968
18159
|
await fsyncPath2(temporary);
|
|
17969
18160
|
await rename2(temporary, filePath);
|
|
17970
|
-
await fsyncPath2(
|
|
18161
|
+
await fsyncPath2(path52.dirname(filePath));
|
|
17971
18162
|
}
|
|
17972
18163
|
async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
17973
18164
|
const value = {
|
|
@@ -17977,13 +18168,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
|
17977
18168
|
manifestHash,
|
|
17978
18169
|
...detail ? { detail } : {}
|
|
17979
18170
|
};
|
|
17980
|
-
await atomicWriteJson(
|
|
18171
|
+
await atomicWriteJson(path52.join(artifactDir, "state.json"), value);
|
|
17981
18172
|
}
|
|
17982
18173
|
async function directorySize(root) {
|
|
17983
18174
|
if (!existsSync13(root)) return 0;
|
|
17984
18175
|
let total = 0;
|
|
17985
18176
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17986
|
-
const entryPath =
|
|
18177
|
+
const entryPath = path52.join(root, entry.name);
|
|
17987
18178
|
if (entry.isDirectory()) total += await directorySize(entryPath);
|
|
17988
18179
|
else total += (await lstat7(entryPath)).size;
|
|
17989
18180
|
}
|
|
@@ -18028,9 +18219,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18028
18219
|
let rawManifest;
|
|
18029
18220
|
let state;
|
|
18030
18221
|
try {
|
|
18031
|
-
rawManifest = JSON.parse(await readFile10(
|
|
18222
|
+
rawManifest = JSON.parse(await readFile10(path52.join(artifactDir, "manifest.json"), "utf8"));
|
|
18032
18223
|
state = JSON.parse(
|
|
18033
|
-
await readFile10(
|
|
18224
|
+
await readFile10(path52.join(artifactDir, "state.json"), "utf8")
|
|
18034
18225
|
);
|
|
18035
18226
|
} catch {
|
|
18036
18227
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
@@ -18046,10 +18237,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18046
18237
|
}
|
|
18047
18238
|
const entryPaths = /* @__PURE__ */ new Set();
|
|
18048
18239
|
for (const entry of manifest.entries) {
|
|
18049
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).length !== 3 || !Object.keys(entry).every((key) => ["path", "before", "after"].includes(key)) || typeof entry.path !== "string" || !("before" in entry) || !("after" in entry) || !validRecoveryRelativePath(entry.path) || entryPaths.has(
|
|
18240
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).length !== 3 || !Object.keys(entry).every((key) => ["path", "before", "after"].includes(key)) || typeof entry.path !== "string" || !("before" in entry) || !("after" in entry) || !validRecoveryRelativePath(entry.path) || entryPaths.has(path52.normalize(entry.path))) {
|
|
18050
18241
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
18051
18242
|
}
|
|
18052
|
-
entryPaths.add(
|
|
18243
|
+
entryPaths.add(path52.normalize(entry.path));
|
|
18053
18244
|
for (const [side, snapshot] of [
|
|
18054
18245
|
["before", entry.before],
|
|
18055
18246
|
["after", entry.after]
|
|
@@ -18063,7 +18254,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18063
18254
|
});
|
|
18064
18255
|
}
|
|
18065
18256
|
}
|
|
18066
|
-
const receiptPath =
|
|
18257
|
+
const receiptPath = path52.join(artifactDir, "receipt.json");
|
|
18067
18258
|
let receipt;
|
|
18068
18259
|
if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
|
|
18069
18260
|
receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
@@ -18073,7 +18264,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18073
18264
|
async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
18074
18265
|
let rawReceipt;
|
|
18075
18266
|
try {
|
|
18076
|
-
rawReceipt = JSON.parse(await readFile10(
|
|
18267
|
+
rawReceipt = JSON.parse(await readFile10(path52.join(artifactDir, "receipt.json"), "utf8"));
|
|
18077
18268
|
} catch {
|
|
18078
18269
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
18079
18270
|
}
|
|
@@ -18096,7 +18287,7 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
|
|
|
18096
18287
|
return receipt;
|
|
18097
18288
|
}
|
|
18098
18289
|
async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
18099
|
-
const receiptPath =
|
|
18290
|
+
const receiptPath = path52.join(artifactDir, "receipt.json");
|
|
18100
18291
|
if (existsSync13(receiptPath)) {
|
|
18101
18292
|
return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
18102
18293
|
}
|
|
@@ -18121,7 +18312,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
18121
18312
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
18122
18313
|
try {
|
|
18123
18314
|
const manifest = JSON.parse(
|
|
18124
|
-
await readFile10(
|
|
18315
|
+
await readFile10(path52.join(artifactDir, "manifest.json"), "utf8")
|
|
18125
18316
|
);
|
|
18126
18317
|
if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
|
|
18127
18318
|
return canonicalPath(manifest.repoRoot);
|
|
@@ -18129,7 +18320,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
18129
18320
|
} catch {
|
|
18130
18321
|
}
|
|
18131
18322
|
try {
|
|
18132
|
-
const owner = JSON.parse(await readFile10(
|
|
18323
|
+
const owner = JSON.parse(await readFile10(path52.join(artifactDir, "owner.json"), "utf8"));
|
|
18133
18324
|
return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
|
|
18134
18325
|
} catch {
|
|
18135
18326
|
return null;
|
|
@@ -18149,10 +18340,10 @@ async function cleanupOrphanedStaging(stateDir) {
|
|
|
18149
18340
|
const now = Date.now();
|
|
18150
18341
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
18151
18342
|
if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
|
|
18152
|
-
const stagingPath =
|
|
18343
|
+
const stagingPath = path52.join(root, entry.name);
|
|
18153
18344
|
let stale = false;
|
|
18154
18345
|
try {
|
|
18155
|
-
const owner = JSON.parse(await readFile10(
|
|
18346
|
+
const owner = JSON.parse(await readFile10(path52.join(stagingPath, "owner.json"), "utf8"));
|
|
18156
18347
|
const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
|
|
18157
18348
|
const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
|
|
18158
18349
|
let alive = false;
|
|
@@ -18194,7 +18385,7 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
|
|
|
18194
18385
|
init_fingerprint2();
|
|
18195
18386
|
import { existsSync as existsSync14 } from "node:fs";
|
|
18196
18387
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
18197
|
-
import
|
|
18388
|
+
import path53 from "node:path";
|
|
18198
18389
|
async function matchRecoverySide(resourceRoot, entries, side) {
|
|
18199
18390
|
for (const entry of entries) {
|
|
18200
18391
|
const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
|
|
@@ -18209,7 +18400,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
18209
18400
|
} catch {
|
|
18210
18401
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
18211
18402
|
if (existsSync14(artifactDir)) {
|
|
18212
|
-
const manifestPath =
|
|
18403
|
+
const manifestPath = path53.join(artifactDir, "manifest.json");
|
|
18213
18404
|
const hash = existsSync14(manifestPath) ? hashValue(await readFile11(manifestPath, "utf8")) : "unavailable";
|
|
18214
18405
|
await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
|
|
18215
18406
|
}
|
|
@@ -18246,7 +18437,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
18246
18437
|
// src/core/recovery/resource-identity.ts
|
|
18247
18438
|
init_fingerprint2();
|
|
18248
18439
|
import { lstat as lstat8, readFile as readFile12, realpath as realpath3 } from "node:fs/promises";
|
|
18249
|
-
import
|
|
18440
|
+
import path54 from "node:path";
|
|
18250
18441
|
async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
18251
18442
|
const resolvedRoot = await realpath3(resourceRoot);
|
|
18252
18443
|
if (resourceKind === "directory") {
|
|
@@ -18254,13 +18445,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
|
18254
18445
|
if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
|
|
18255
18446
|
return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
|
|
18256
18447
|
}
|
|
18257
|
-
const dotGit =
|
|
18448
|
+
const dotGit = path54.join(resolvedRoot, ".git");
|
|
18258
18449
|
const gitInfo = await lstat8(dotGit);
|
|
18259
18450
|
let gitMetadataPath = dotGit;
|
|
18260
18451
|
if (gitInfo.isFile()) {
|
|
18261
18452
|
const marker = (await readFile12(dotGit, "utf8")).trim();
|
|
18262
18453
|
if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
|
|
18263
|
-
gitMetadataPath =
|
|
18454
|
+
gitMetadataPath = path54.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
|
|
18264
18455
|
} else if (!gitInfo.isDirectory()) {
|
|
18265
18456
|
throw new Error("recovery_repo_identity_unavailable");
|
|
18266
18457
|
}
|
|
@@ -18333,16 +18524,16 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18333
18524
|
throw new Error(RECOVERY_CHECKPOINT_QUOTA);
|
|
18334
18525
|
}
|
|
18335
18526
|
const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
|
|
18336
|
-
const temporary =
|
|
18527
|
+
const temporary = path55.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
|
|
18337
18528
|
const finalDir = checkpointDir(params.stateDir, checkpointId);
|
|
18338
18529
|
await mkdir11(temporary, { recursive: true, mode: 448 });
|
|
18339
|
-
await atomicWriteJson(
|
|
18530
|
+
await atomicWriteJson(path55.join(temporary, "owner.json"), {
|
|
18340
18531
|
version: 1,
|
|
18341
18532
|
pid: process.pid,
|
|
18342
18533
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18343
18534
|
repoRoot: canonicalPath(params.repoRoot)
|
|
18344
18535
|
});
|
|
18345
|
-
await mkdir11(
|
|
18536
|
+
await mkdir11(path55.join(temporary, "blobs"), { recursive: true, mode: 448 });
|
|
18346
18537
|
try {
|
|
18347
18538
|
const entries = [];
|
|
18348
18539
|
const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
|
|
@@ -18351,8 +18542,8 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18351
18542
|
)) {
|
|
18352
18543
|
const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
|
|
18353
18544
|
if (protectedRoots.some((root) => {
|
|
18354
|
-
const relative =
|
|
18355
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18545
|
+
const relative = path55.relative(root, target);
|
|
18546
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path55.sep}`) && !path55.isAbsolute(relative);
|
|
18356
18547
|
})) {
|
|
18357
18548
|
throw new Error("recovery_protected_path");
|
|
18358
18549
|
}
|
|
@@ -18364,7 +18555,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18364
18555
|
entries.push({
|
|
18365
18556
|
path: change.relativePath,
|
|
18366
18557
|
before: await captureRecoverySnapshot(baseline, {
|
|
18367
|
-
blobDir:
|
|
18558
|
+
blobDir: path55.join(temporary, "blobs")
|
|
18368
18559
|
}),
|
|
18369
18560
|
after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
|
|
18370
18561
|
});
|
|
@@ -18401,7 +18592,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18401
18592
|
entries
|
|
18402
18593
|
};
|
|
18403
18594
|
const manifestHash = hashValue(canonicalStringify(manifest));
|
|
18404
|
-
await atomicWriteJson(
|
|
18595
|
+
await atomicWriteJson(path55.join(temporary, "manifest.json"), manifest);
|
|
18405
18596
|
await writeRecoveryState(temporary, "prepared", manifestHash);
|
|
18406
18597
|
await fsyncPath2(temporary);
|
|
18407
18598
|
const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
|
|
@@ -18444,7 +18635,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
18444
18635
|
} catch {
|
|
18445
18636
|
try {
|
|
18446
18637
|
const raw = JSON.parse(
|
|
18447
|
-
await readFile13(
|
|
18638
|
+
await readFile13(path55.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
18448
18639
|
);
|
|
18449
18640
|
rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
|
|
18450
18641
|
} catch {
|
|
@@ -18478,7 +18669,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
18478
18669
|
} catch {
|
|
18479
18670
|
try {
|
|
18480
18671
|
const manifest = JSON.parse(
|
|
18481
|
-
await readFile13(
|
|
18672
|
+
await readFile13(path55.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
18482
18673
|
);
|
|
18483
18674
|
if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
|
|
18484
18675
|
if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
|
|
@@ -18508,7 +18699,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
18508
18699
|
let total = 0;
|
|
18509
18700
|
for (const entry of await readdir3(root, { withFileTypes: true })) {
|
|
18510
18701
|
if (!entry.isDirectory()) continue;
|
|
18511
|
-
const entryPath =
|
|
18702
|
+
const entryPath = path55.join(root, entry.name);
|
|
18512
18703
|
if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
18513
18704
|
if (await artifactRepoRoot(stateDir, entry.name) === expected) {
|
|
18514
18705
|
total += await directorySize(entryPath);
|
|
@@ -18517,7 +18708,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
18517
18708
|
}
|
|
18518
18709
|
if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
18519
18710
|
try {
|
|
18520
|
-
const owner = JSON.parse(await readFile13(
|
|
18711
|
+
const owner = JSON.parse(await readFile13(path55.join(entryPath, "owner.json"), "utf8"));
|
|
18521
18712
|
if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
|
|
18522
18713
|
total += await directorySize(entryPath);
|
|
18523
18714
|
}
|
|
@@ -18561,14 +18752,14 @@ init_scrub();
|
|
|
18561
18752
|
// src/core/transactional/file-checkpoint-backend.ts
|
|
18562
18753
|
import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
|
|
18563
18754
|
import os5 from "node:os";
|
|
18564
|
-
import
|
|
18755
|
+
import path59 from "node:path";
|
|
18565
18756
|
|
|
18566
18757
|
// src/core/transactional/file-checkpoint-git.ts
|
|
18567
18758
|
init_path_utils();
|
|
18568
18759
|
import { spawn as spawn8 } from "node:child_process";
|
|
18569
18760
|
import { createHash as createHash13 } from "node:crypto";
|
|
18570
18761
|
import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile14 } from "node:fs/promises";
|
|
18571
|
-
import
|
|
18762
|
+
import path56 from "node:path";
|
|
18572
18763
|
var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
|
|
18573
18764
|
var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
|
|
18574
18765
|
var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
|
|
@@ -18602,7 +18793,7 @@ function rethrowStableFileCheckpointError(error) {
|
|
|
18602
18793
|
}
|
|
18603
18794
|
async function rootGitMetadataPresent(repoRoot) {
|
|
18604
18795
|
try {
|
|
18605
|
-
await lstat9(
|
|
18796
|
+
await lstat9(path56.join(repoRoot, ".git"));
|
|
18606
18797
|
return true;
|
|
18607
18798
|
} catch {
|
|
18608
18799
|
return false;
|
|
@@ -18651,10 +18842,10 @@ function execGit2(repoRoot, args) {
|
|
|
18651
18842
|
}
|
|
18652
18843
|
async function resolveGitPath(repoRoot, gitPath) {
|
|
18653
18844
|
const trimmed = gitPath.trim();
|
|
18654
|
-
if (
|
|
18845
|
+
if (path56.isAbsolute(trimmed)) {
|
|
18655
18846
|
return trimmed;
|
|
18656
18847
|
}
|
|
18657
|
-
return
|
|
18848
|
+
return path56.join(repoRoot, trimmed);
|
|
18658
18849
|
}
|
|
18659
18850
|
async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
|
|
18660
18851
|
await execGit2(sourceRoot, [
|
|
@@ -18696,7 +18887,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18696
18887
|
destinationRoot,
|
|
18697
18888
|
await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
|
|
18698
18889
|
);
|
|
18699
|
-
const destinationShared =
|
|
18890
|
+
const destinationShared = path56.join(destinationGitDir, path56.basename(sourceShared));
|
|
18700
18891
|
try {
|
|
18701
18892
|
await copyFile3(sourceShared, destinationShared);
|
|
18702
18893
|
} catch (error) {
|
|
@@ -18705,7 +18896,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18705
18896
|
}
|
|
18706
18897
|
async function readGitFile(gitDir, relativePath) {
|
|
18707
18898
|
try {
|
|
18708
|
-
return await readFile14(
|
|
18899
|
+
return await readFile14(path56.join(gitDir, relativePath));
|
|
18709
18900
|
} catch {
|
|
18710
18901
|
return null;
|
|
18711
18902
|
}
|
|
@@ -18729,8 +18920,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18729
18920
|
repoRoot,
|
|
18730
18921
|
await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
|
|
18731
18922
|
);
|
|
18732
|
-
const relative =
|
|
18733
|
-
const content = typeof relative === "string" && !relative.startsWith("..") && !
|
|
18923
|
+
const relative = path56.resolve(resolved).startsWith(path56.resolve(gitDir)) ? path56.relative(gitDir, resolved) : resolved;
|
|
18924
|
+
const content = typeof relative === "string" && !relative.startsWith("..") && !path56.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18734
18925
|
if (content !== null) {
|
|
18735
18926
|
hashGitFileContent(hash, gitPath, content);
|
|
18736
18927
|
}
|
|
@@ -18740,13 +18931,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18740
18931
|
async function hashGitTree(gitDir, relativeDir, hash) {
|
|
18741
18932
|
let names;
|
|
18742
18933
|
try {
|
|
18743
|
-
names = await readdir4(
|
|
18934
|
+
names = await readdir4(path56.join(gitDir, relativeDir));
|
|
18744
18935
|
} catch {
|
|
18745
18936
|
return;
|
|
18746
18937
|
}
|
|
18747
18938
|
for (const name of names.sort()) {
|
|
18748
|
-
const relativePath = relativeDir ?
|
|
18749
|
-
const absolutePath =
|
|
18939
|
+
const relativePath = relativeDir ? path56.join(relativeDir, name) : name;
|
|
18940
|
+
const absolutePath = path56.join(gitDir, relativePath);
|
|
18750
18941
|
let childNames = null;
|
|
18751
18942
|
try {
|
|
18752
18943
|
childNames = await readdir4(absolutePath);
|
|
@@ -18768,7 +18959,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
|
|
|
18768
18959
|
}
|
|
18769
18960
|
async function computeGitMetadataFingerprint(repoRoot) {
|
|
18770
18961
|
const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18771
|
-
const gitDir =
|
|
18962
|
+
const gitDir = path56.isAbsolute(gitDirRel) ? gitDirRel : path56.join(repoRoot, gitDirRel);
|
|
18772
18963
|
const hash = createHash13("sha256");
|
|
18773
18964
|
for (const file of [
|
|
18774
18965
|
"HEAD",
|
|
@@ -18791,8 +18982,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18791
18982
|
const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
|
|
18792
18983
|
if (sharedIndex) {
|
|
18793
18984
|
const resolved = await resolveGitPath(repoRoot, sharedIndex);
|
|
18794
|
-
const relative =
|
|
18795
|
-
const content = relative && !relative.startsWith("..") && !
|
|
18985
|
+
const relative = path56.relative(gitDir, resolved);
|
|
18986
|
+
const content = relative && !relative.startsWith("..") && !path56.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18796
18987
|
if (content !== null) {
|
|
18797
18988
|
hashGitFileContent(hash, "shared-index", content);
|
|
18798
18989
|
}
|
|
@@ -18803,7 +18994,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18803
18994
|
await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
|
|
18804
18995
|
}
|
|
18805
18996
|
try {
|
|
18806
|
-
const rootGitPath =
|
|
18997
|
+
const rootGitPath = path56.join(repoRoot, ".git");
|
|
18807
18998
|
const rootGitInfo = await lstat9(rootGitPath);
|
|
18808
18999
|
if (rootGitInfo.isFile()) {
|
|
18809
19000
|
const content = await readAbsoluteGitFile(rootGitPath);
|
|
@@ -18819,14 +19010,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18819
19010
|
function resolveExecutionCwdRelative(resourceRoot, cwd) {
|
|
18820
19011
|
const resolvedCwd = canonicalPath(cwd);
|
|
18821
19012
|
const resourceCanonical = canonicalPath(resourceRoot);
|
|
18822
|
-
const relative =
|
|
19013
|
+
const relative = path56.relative(resourceCanonical, resolvedCwd);
|
|
18823
19014
|
if (relative === "" || relative === ".") {
|
|
18824
19015
|
return "";
|
|
18825
19016
|
}
|
|
18826
|
-
if (relative.startsWith("..") ||
|
|
19017
|
+
if (relative.startsWith("..") || path56.isAbsolute(relative)) {
|
|
18827
19018
|
throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
|
|
18828
19019
|
}
|
|
18829
|
-
return relative.split(
|
|
19020
|
+
return relative.split(path56.sep).join("/");
|
|
18830
19021
|
}
|
|
18831
19022
|
|
|
18832
19023
|
// src/core/transactional/file-checkpoint-isolation.ts
|
|
@@ -18848,7 +19039,7 @@ function fileCheckpointIsolationReason(context) {
|
|
|
18848
19039
|
|
|
18849
19040
|
// src/core/transactional/file-checkpoint-staging.ts
|
|
18850
19041
|
import { readdir as readdir5, readFile as readFile15, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
|
|
18851
|
-
import
|
|
19042
|
+
import path57 from "node:path";
|
|
18852
19043
|
function isOwnerProcessAlive(pid) {
|
|
18853
19044
|
try {
|
|
18854
19045
|
process.kill(pid, 0);
|
|
@@ -18858,12 +19049,12 @@ function isOwnerProcessAlive(pid) {
|
|
|
18858
19049
|
}
|
|
18859
19050
|
}
|
|
18860
19051
|
async function writeOwnerMarker(stagingRoot, marker) {
|
|
18861
|
-
await writeFile8(
|
|
19052
|
+
await writeFile8(path57.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
|
|
18862
19053
|
`, "utf8");
|
|
18863
19054
|
}
|
|
18864
19055
|
async function readOwnerMarker(stagingRoot) {
|
|
18865
19056
|
try {
|
|
18866
|
-
const raw = await readFile15(
|
|
19057
|
+
const raw = await readFile15(path57.join(stagingRoot, "owner.json"), "utf8");
|
|
18867
19058
|
return JSON.parse(raw.trim());
|
|
18868
19059
|
} catch {
|
|
18869
19060
|
return null;
|
|
@@ -18881,7 +19072,7 @@ async function collectDeadOwnerStaging(parentDir) {
|
|
|
18881
19072
|
if (!name.startsWith("belay-file-checkpoint-")) {
|
|
18882
19073
|
continue;
|
|
18883
19074
|
}
|
|
18884
|
-
const stagingRoot =
|
|
19075
|
+
const stagingRoot = path57.join(parentDir, name);
|
|
18885
19076
|
const marker = await readOwnerMarker(stagingRoot);
|
|
18886
19077
|
if (!marker) {
|
|
18887
19078
|
dead.push(stagingRoot);
|
|
@@ -18913,7 +19104,7 @@ import {
|
|
|
18913
19104
|
writeFile as writeFile9
|
|
18914
19105
|
} from "node:fs/promises";
|
|
18915
19106
|
import os4 from "node:os";
|
|
18916
|
-
import
|
|
19107
|
+
import path58 from "node:path";
|
|
18917
19108
|
var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
|
|
18918
19109
|
async function chmodSafe2(target, mode) {
|
|
18919
19110
|
try {
|
|
@@ -18923,7 +19114,7 @@ async function chmodSafe2(target, mode) {
|
|
|
18923
19114
|
}
|
|
18924
19115
|
}
|
|
18925
19116
|
async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
|
|
18926
|
-
await mkdir12(
|
|
19117
|
+
await mkdir12(path58.dirname(destinationPath), { recursive: true });
|
|
18927
19118
|
if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
|
|
18928
19119
|
try {
|
|
18929
19120
|
await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
|
|
@@ -18949,7 +19140,7 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
|
|
|
18949
19140
|
return strategy;
|
|
18950
19141
|
}
|
|
18951
19142
|
if (info.isSymbolicLink()) {
|
|
18952
|
-
await mkdir12(
|
|
19143
|
+
await mkdir12(path58.dirname(destinationPath), { recursive: true });
|
|
18953
19144
|
await symlink4(await readlink5(sourcePath), destinationPath);
|
|
18954
19145
|
return strategy;
|
|
18955
19146
|
}
|
|
@@ -19005,9 +19196,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
|
|
|
19005
19196
|
async function probeFileCloneStrategy() {
|
|
19006
19197
|
let tempDir = null;
|
|
19007
19198
|
try {
|
|
19008
|
-
tempDir = await mkdtemp4(
|
|
19009
|
-
const source =
|
|
19010
|
-
const destination =
|
|
19199
|
+
tempDir = await mkdtemp4(path58.join(os4.tmpdir(), "belay-clone-probe-"));
|
|
19200
|
+
const source = path58.join(tempDir, "source.txt");
|
|
19201
|
+
const destination = path58.join(tempDir, "dest.txt");
|
|
19011
19202
|
await writeFile9(source, "probe\n");
|
|
19012
19203
|
if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
|
|
19013
19204
|
try {
|
|
@@ -19160,11 +19351,11 @@ async function protectedRootState(root) {
|
|
|
19160
19351
|
return `directory:${node.hash}:${index.treeHash}`;
|
|
19161
19352
|
}
|
|
19162
19353
|
function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
|
|
19163
|
-
const relative =
|
|
19164
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
19354
|
+
const relative = path59.relative(path59.resolve(resourceRoot), path59.resolve(protectedRoot));
|
|
19355
|
+
if (relative === "" || relative.startsWith("..") || path59.isAbsolute(relative)) {
|
|
19165
19356
|
return null;
|
|
19166
19357
|
}
|
|
19167
|
-
return
|
|
19358
|
+
return path59.join(executionRoot, relative);
|
|
19168
19359
|
}
|
|
19169
19360
|
async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
|
|
19170
19361
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -19189,15 +19380,15 @@ async function directoryByteSize(root, deadlineMs) {
|
|
|
19189
19380
|
}
|
|
19190
19381
|
let total = 0;
|
|
19191
19382
|
for (const name of await readdir6(root)) {
|
|
19192
|
-
total += await directoryByteSize(
|
|
19383
|
+
total += await directoryByteSize(path59.join(root, name), deadlineMs);
|
|
19193
19384
|
}
|
|
19194
19385
|
return total;
|
|
19195
19386
|
}
|
|
19196
19387
|
async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
|
|
19197
19388
|
const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
|
|
19198
|
-
const sourceGitDir =
|
|
19199
|
-
const relativeGitDir =
|
|
19200
|
-
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ?
|
|
19389
|
+
const sourceGitDir = path59.isAbsolute(gitDirRel) ? gitDirRel : path59.join(sourceRoot, gitDirRel);
|
|
19390
|
+
const relativeGitDir = path59.relative(path59.resolve(sourceRoot), path59.resolve(sourceGitDir));
|
|
19391
|
+
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path59.join(destinationRoot, relativeGitDir) : path59.join(destinationRoot, ".git");
|
|
19201
19392
|
await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
|
|
19202
19393
|
}
|
|
19203
19394
|
async function prepareDirtyGitSnapshot(context) {
|
|
@@ -19206,7 +19397,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19206
19397
|
const quotas = context.fileCheckpoint;
|
|
19207
19398
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
19208
19399
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
19209
|
-
const stagingRoot = await mkdtemp5(
|
|
19400
|
+
const stagingRoot = await mkdtemp5(path59.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
19210
19401
|
await writeOwnerMarker(stagingRoot, {
|
|
19211
19402
|
version: 1,
|
|
19212
19403
|
pid: process.pid,
|
|
@@ -19214,8 +19405,8 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19214
19405
|
resourceRoot: context.repoRoot,
|
|
19215
19406
|
backend: "file_checkpoint"
|
|
19216
19407
|
});
|
|
19217
|
-
const baselineRoot =
|
|
19218
|
-
const executionRoot =
|
|
19408
|
+
const baselineRoot = path59.join(stagingRoot, "baseline");
|
|
19409
|
+
const executionRoot = path59.join(stagingRoot, "execution");
|
|
19219
19410
|
try {
|
|
19220
19411
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
19221
19412
|
const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
|
|
@@ -19249,7 +19440,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19249
19440
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
19250
19441
|
}
|
|
19251
19442
|
await writeFile10(
|
|
19252
|
-
|
|
19443
|
+
path59.join(stagingRoot, "baseline-index.json"),
|
|
19253
19444
|
`${JSON.stringify(baselineIndex)}
|
|
19254
19445
|
`,
|
|
19255
19446
|
"utf8"
|
|
@@ -19299,7 +19490,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19299
19490
|
const quotas = context.fileCheckpoint;
|
|
19300
19491
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
19301
19492
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
19302
|
-
const stagingRoot = await mkdtemp5(
|
|
19493
|
+
const stagingRoot = await mkdtemp5(path59.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
19303
19494
|
await writeOwnerMarker(stagingRoot, {
|
|
19304
19495
|
version: 1,
|
|
19305
19496
|
pid: process.pid,
|
|
@@ -19307,8 +19498,8 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19307
19498
|
resourceRoot: context.repoRoot,
|
|
19308
19499
|
backend: "file_checkpoint"
|
|
19309
19500
|
});
|
|
19310
|
-
const baselineRoot =
|
|
19311
|
-
const executionRoot =
|
|
19501
|
+
const baselineRoot = path59.join(stagingRoot, "baseline");
|
|
19502
|
+
const executionRoot = path59.join(stagingRoot, "execution");
|
|
19312
19503
|
try {
|
|
19313
19504
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
19314
19505
|
const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
|
|
@@ -19337,7 +19528,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19337
19528
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
19338
19529
|
}
|
|
19339
19530
|
await writeFile10(
|
|
19340
|
-
|
|
19531
|
+
path59.join(stagingRoot, "baseline-index.json"),
|
|
19341
19532
|
`${JSON.stringify(baselineIndex)}
|
|
19342
19533
|
`,
|
|
19343
19534
|
"utf8"
|
|
@@ -19690,10 +19881,10 @@ async function selectTransactionalBackend(context) {
|
|
|
19690
19881
|
}
|
|
19691
19882
|
|
|
19692
19883
|
// src/core/transactional/diff-evaluator.ts
|
|
19693
|
-
import
|
|
19884
|
+
import path60 from "node:path";
|
|
19694
19885
|
init_path_utils();
|
|
19695
19886
|
function categorizeChange(change, ctx) {
|
|
19696
|
-
const absolutePath = canonicalPath(
|
|
19887
|
+
const absolutePath = canonicalPath(path60.join(ctx.repoRoot, change.relativePath));
|
|
19697
19888
|
if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
|
|
19698
19889
|
return "repo_outside";
|
|
19699
19890
|
}
|
|
@@ -20287,7 +20478,7 @@ async function notifyDeny(config, event) {
|
|
|
20287
20478
|
init_path_utils();
|
|
20288
20479
|
|
|
20289
20480
|
// src/adapters/layouts/protected-paths.ts
|
|
20290
|
-
import
|
|
20481
|
+
import path61 from "node:path";
|
|
20291
20482
|
function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
20292
20483
|
const roots = [
|
|
20293
20484
|
layout.configPath(repoRoot),
|
|
@@ -20299,7 +20490,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
|
20299
20490
|
if (controlPlaneDir) {
|
|
20300
20491
|
roots.push(controlPlaneDir);
|
|
20301
20492
|
}
|
|
20302
|
-
return roots.map((entry) =>
|
|
20493
|
+
return roots.map((entry) => path61.resolve(entry));
|
|
20303
20494
|
}
|
|
20304
20495
|
|
|
20305
20496
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -20352,8 +20543,8 @@ function createDefaultGateRuntimeDeps() {
|
|
|
20352
20543
|
return loadJsonFile(configPath, {});
|
|
20353
20544
|
},
|
|
20354
20545
|
async appendAudit(ctx, event) {
|
|
20355
|
-
const auditPath =
|
|
20356
|
-
await mkdir14(
|
|
20546
|
+
const auditPath = path62.join(ctx.repoRoot, ctx.config.audit.logPath);
|
|
20547
|
+
await mkdir14(path62.dirname(auditPath), { recursive: true });
|
|
20357
20548
|
const provenance = auditProvenance(ctx.config);
|
|
20358
20549
|
const record = {
|
|
20359
20550
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -20386,7 +20577,7 @@ function createDefaultGateRuntimeDeps() {
|
|
|
20386
20577
|
};
|
|
20387
20578
|
},
|
|
20388
20579
|
async writeApprovals(filePath, state) {
|
|
20389
|
-
await mkdir14(
|
|
20580
|
+
await mkdir14(path62.dirname(filePath), { recursive: true });
|
|
20390
20581
|
await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
|
|
20391
20582
|
`, "utf8");
|
|
20392
20583
|
},
|
|
@@ -20548,7 +20739,7 @@ function deriveWorkspaceRootScopeHint(params) {
|
|
|
20548
20739
|
if (!targetPath) {
|
|
20549
20740
|
return void 0;
|
|
20550
20741
|
}
|
|
20551
|
-
const candidateRoot = canonicalPath(
|
|
20742
|
+
const candidateRoot = canonicalPath(path62.dirname(targetPath));
|
|
20552
20743
|
const validation = validateTrustedWorkspaceRootCandidate({
|
|
20553
20744
|
candidatePath: candidateRoot,
|
|
20554
20745
|
repoRoot: action.repoRoot,
|
|
@@ -21124,6 +21315,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
21124
21315
|
event: auditEvent,
|
|
21125
21316
|
sourceEvent,
|
|
21126
21317
|
kind,
|
|
21318
|
+
repoLabel: path62.basename(ctx.repoRoot),
|
|
21127
21319
|
...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
|
|
21128
21320
|
fingerprint: result.fingerprint,
|
|
21129
21321
|
summary: result.normalizedCommand ?? result.summary ?? "",
|
|
@@ -21571,18 +21763,18 @@ async function appendObservedAudit(ctx, deps, eventName, payload) {
|
|
|
21571
21763
|
|
|
21572
21764
|
// src/adapters/shared/repo-root.ts
|
|
21573
21765
|
import { existsSync as existsSync17 } from "node:fs";
|
|
21574
|
-
import
|
|
21766
|
+
import path63 from "node:path";
|
|
21575
21767
|
function belayConfigPath(current, adapterName) {
|
|
21576
21768
|
if (adapterName === "cursor") {
|
|
21577
|
-
return
|
|
21769
|
+
return path63.join(current, ".cursor", "belay.config.json");
|
|
21578
21770
|
}
|
|
21579
21771
|
if (adapterName === "claude") {
|
|
21580
|
-
return
|
|
21772
|
+
return path63.join(current, ".claude", "belay.config.json");
|
|
21581
21773
|
}
|
|
21582
|
-
return
|
|
21774
|
+
return path63.join(current, ".codex", "belay.config.json");
|
|
21583
21775
|
}
|
|
21584
21776
|
function markerMatches(current, marker, layout) {
|
|
21585
|
-
const markerPath =
|
|
21777
|
+
const markerPath = path63.join(current, marker);
|
|
21586
21778
|
if (!existsSync17(markerPath)) {
|
|
21587
21779
|
return false;
|
|
21588
21780
|
}
|
|
@@ -21592,16 +21784,16 @@ function markerMatches(current, marker, layout) {
|
|
|
21592
21784
|
return true;
|
|
21593
21785
|
}
|
|
21594
21786
|
function findRepoRoot(startPath, layout) {
|
|
21595
|
-
let current =
|
|
21787
|
+
let current = path63.resolve(startPath);
|
|
21596
21788
|
while (true) {
|
|
21597
21789
|
for (const marker of layout.repoRootMarkers) {
|
|
21598
21790
|
if (markerMatches(current, marker, layout)) {
|
|
21599
21791
|
return current;
|
|
21600
21792
|
}
|
|
21601
21793
|
}
|
|
21602
|
-
const parent =
|
|
21794
|
+
const parent = path63.dirname(current);
|
|
21603
21795
|
if (parent === current) {
|
|
21604
|
-
return
|
|
21796
|
+
return path63.resolve(startPath);
|
|
21605
21797
|
}
|
|
21606
21798
|
current = parent;
|
|
21607
21799
|
}
|
|
@@ -21609,7 +21801,7 @@ function findRepoRoot(startPath, layout) {
|
|
|
21609
21801
|
|
|
21610
21802
|
// src/adapters/cursor/cwd-resolution.ts
|
|
21611
21803
|
import os6 from "node:os";
|
|
21612
|
-
import
|
|
21804
|
+
import path64 from "node:path";
|
|
21613
21805
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
21614
21806
|
function nonEmptyPathString(value) {
|
|
21615
21807
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -21621,36 +21813,36 @@ function resolveCursorActionCwdDetails(payload, fallback = process.cwd()) {
|
|
|
21621
21813
|
const workspaceRoot = Array.isArray(payload.workspace_roots) ? payload.workspace_roots.map(nonEmptyPathString).find(Boolean) : void 0;
|
|
21622
21814
|
if (toolInputWorkingDirectory) {
|
|
21623
21815
|
return {
|
|
21624
|
-
cwd:
|
|
21816
|
+
cwd: path64.resolve(toolInputWorkingDirectory),
|
|
21625
21817
|
source: "tool_input.working_directory",
|
|
21626
21818
|
fromPayload: true
|
|
21627
21819
|
};
|
|
21628
21820
|
}
|
|
21629
21821
|
if (topLevelCwd) {
|
|
21630
21822
|
return {
|
|
21631
|
-
cwd:
|
|
21823
|
+
cwd: path64.resolve(topLevelCwd),
|
|
21632
21824
|
source: "cwd",
|
|
21633
21825
|
fromPayload: true
|
|
21634
21826
|
};
|
|
21635
21827
|
}
|
|
21636
21828
|
if (workspaceRoot) {
|
|
21637
21829
|
return {
|
|
21638
|
-
cwd:
|
|
21830
|
+
cwd: path64.resolve(workspaceRoot),
|
|
21639
21831
|
source: "workspace_roots",
|
|
21640
21832
|
fromPayload: true
|
|
21641
21833
|
};
|
|
21642
21834
|
}
|
|
21643
21835
|
return {
|
|
21644
|
-
cwd:
|
|
21836
|
+
cwd: path64.resolve(fallback),
|
|
21645
21837
|
source: "fallback",
|
|
21646
21838
|
fromPayload: false
|
|
21647
21839
|
};
|
|
21648
21840
|
}
|
|
21649
21841
|
function isGlobalCursorHookRuntime() {
|
|
21650
21842
|
try {
|
|
21651
|
-
const runtimePath =
|
|
21652
|
-
const globalRuntimeDir =
|
|
21653
|
-
return runtimePath === globalRuntimeDir || runtimePath.startsWith(`${globalRuntimeDir}${
|
|
21843
|
+
const runtimePath = path64.resolve(fileURLToPath2(import.meta.url));
|
|
21844
|
+
const globalRuntimeDir = path64.resolve(path64.join(os6.homedir(), ".cursor", "belay", "runtime"));
|
|
21845
|
+
return runtimePath === globalRuntimeDir || runtimePath.startsWith(`${globalRuntimeDir}${path64.sep}`);
|
|
21654
21846
|
} catch {
|
|
21655
21847
|
return false;
|
|
21656
21848
|
}
|
|
@@ -21700,7 +21892,7 @@ function resolveCursorToolActionCwdDetails(payload, fallback, eventName, toolNam
|
|
|
21700
21892
|
function collectCandidateRepoRoots(payload, resolution) {
|
|
21701
21893
|
const roots = [];
|
|
21702
21894
|
const add = (value) => {
|
|
21703
|
-
const resolved =
|
|
21895
|
+
const resolved = path65.resolve(value);
|
|
21704
21896
|
if (!roots.includes(resolved)) {
|
|
21705
21897
|
roots.push(resolved);
|
|
21706
21898
|
}
|
|
@@ -21762,17 +21954,15 @@ function isSubagentEvent(payload, eventName) {
|
|
|
21762
21954
|
function isFileMutationTool(toolName) {
|
|
21763
21955
|
return toolName === "Write" || toolName === "StrReplace" || toolName === "Delete";
|
|
21764
21956
|
}
|
|
21765
|
-
async function
|
|
21957
|
+
async function handleBeforeSubmitPromptHook(payload) {
|
|
21766
21958
|
try {
|
|
21767
|
-
const payload = await readStdinJson();
|
|
21768
21959
|
const prompt = String(payload.prompt ?? "");
|
|
21769
21960
|
const resolution = resolveCursorActionCwdDetails(payload);
|
|
21770
21961
|
if (isUnsafeGlobalHookFallback(resolution)) {
|
|
21771
|
-
|
|
21962
|
+
return {
|
|
21772
21963
|
continue: false,
|
|
21773
21964
|
user_message: GLOBAL_HOOK_WORKSPACE_MISSING_MESSAGE
|
|
21774
|
-
}
|
|
21775
|
-
return;
|
|
21965
|
+
};
|
|
21776
21966
|
}
|
|
21777
21967
|
const ctx = await loadRuntimeContext(resolution.cwd);
|
|
21778
21968
|
const deps = createDefaultGateRuntimeDeps();
|
|
@@ -21783,29 +21973,30 @@ async function runBeforeSubmitPromptHook() {
|
|
|
21783
21973
|
payload,
|
|
21784
21974
|
resolution
|
|
21785
21975
|
);
|
|
21786
|
-
|
|
21976
|
+
return {
|
|
21787
21977
|
continue: result.continue,
|
|
21788
21978
|
...result.user_message ? { user_message: result.user_message } : {},
|
|
21789
21979
|
...result.replay ? { replay: result.replay } : {}
|
|
21790
|
-
}
|
|
21980
|
+
};
|
|
21791
21981
|
} catch {
|
|
21792
|
-
|
|
21982
|
+
return {
|
|
21793
21983
|
continue: false,
|
|
21794
21984
|
user_message: "belay failed while processing approval state. Run belay doctor, then retry."
|
|
21795
|
-
}
|
|
21985
|
+
};
|
|
21796
21986
|
}
|
|
21797
21987
|
}
|
|
21798
|
-
async function
|
|
21988
|
+
async function runBeforeSubmitPromptHook() {
|
|
21989
|
+
jsonResponse(await handleBeforeSubmitPromptHook(await readStdinJson()));
|
|
21990
|
+
}
|
|
21991
|
+
async function handleShellGateHook(payload) {
|
|
21799
21992
|
try {
|
|
21800
|
-
const payload = await readStdinJson();
|
|
21801
21993
|
const command = String(payload.command ?? "").trim();
|
|
21802
21994
|
const resolution = resolveCursorActionCwdDetails(payload);
|
|
21803
21995
|
if (isUnsafeGlobalHookFallback(resolution)) {
|
|
21804
|
-
|
|
21996
|
+
return {
|
|
21805
21997
|
permission: "deny",
|
|
21806
21998
|
user_message: GLOBAL_HOOK_WORKSPACE_MISSING_MESSAGE
|
|
21807
|
-
}
|
|
21808
|
-
return;
|
|
21999
|
+
};
|
|
21809
22000
|
}
|
|
21810
22001
|
const cwd = resolution.cwd;
|
|
21811
22002
|
const ctx = await loadRuntimeContext(cwd);
|
|
@@ -21817,17 +22008,19 @@ async function runShellGateHook() {
|
|
|
21817
22008
|
payload,
|
|
21818
22009
|
sourceEvent: "beforeShellExecution"
|
|
21819
22010
|
});
|
|
21820
|
-
|
|
22011
|
+
return gateVerdictToCursorResponse(verdict2);
|
|
21821
22012
|
} catch {
|
|
21822
|
-
|
|
22013
|
+
return {
|
|
21823
22014
|
permission: "deny",
|
|
21824
22015
|
user_message: "belay failed while classifying this shell command. Run belay doctor, then retry."
|
|
21825
|
-
}
|
|
22016
|
+
};
|
|
21826
22017
|
}
|
|
21827
22018
|
}
|
|
21828
|
-
async function
|
|
22019
|
+
async function runShellGateHook() {
|
|
22020
|
+
jsonResponse(await handleShellGateHook(await readStdinJson()));
|
|
22021
|
+
}
|
|
22022
|
+
async function handleToolGateHook(eventName, payload) {
|
|
21829
22023
|
try {
|
|
21830
|
-
const payload = await readStdinJson();
|
|
21831
22024
|
const toolName = String(payload.tool_name ?? "");
|
|
21832
22025
|
const resolution = resolveCursorToolActionCwdDetails(
|
|
21833
22026
|
payload,
|
|
@@ -21836,11 +22029,10 @@ async function runToolGateHook(eventName) {
|
|
|
21836
22029
|
toolName
|
|
21837
22030
|
);
|
|
21838
22031
|
if (isUnsafeGlobalHookFallback(resolution)) {
|
|
21839
|
-
|
|
22032
|
+
return {
|
|
21840
22033
|
permission: "deny",
|
|
21841
22034
|
user_message: GLOBAL_HOOK_WORKSPACE_MISSING_MESSAGE
|
|
21842
|
-
}
|
|
21843
|
-
return;
|
|
22035
|
+
};
|
|
21844
22036
|
}
|
|
21845
22037
|
const cwd = resolution.cwd;
|
|
21846
22038
|
const ctx = await loadRuntimeContext(cwd);
|
|
@@ -21852,8 +22044,7 @@ async function runToolGateHook(eventName) {
|
|
|
21852
22044
|
payload,
|
|
21853
22045
|
sourceEvent: eventName
|
|
21854
22046
|
});
|
|
21855
|
-
|
|
21856
|
-
return;
|
|
22047
|
+
return gateVerdictToCursorResponse(verdict2);
|
|
21857
22048
|
}
|
|
21858
22049
|
if (toolName === "Shell") {
|
|
21859
22050
|
const verdict2 = await evaluateGatedAction(ctx, deps, {
|
|
@@ -21863,8 +22054,7 @@ async function runToolGateHook(eventName) {
|
|
|
21863
22054
|
toolName,
|
|
21864
22055
|
sourceEvent: eventName
|
|
21865
22056
|
});
|
|
21866
|
-
|
|
21867
|
-
return;
|
|
22057
|
+
return gateVerdictToCursorResponse(verdict2);
|
|
21868
22058
|
}
|
|
21869
22059
|
if (isFileMutationTool(toolName)) {
|
|
21870
22060
|
const verdict2 = await evaluateGatedAction(ctx, deps, {
|
|
@@ -21874,8 +22064,7 @@ async function runToolGateHook(eventName) {
|
|
|
21874
22064
|
toolName,
|
|
21875
22065
|
sourceEvent: eventName
|
|
21876
22066
|
});
|
|
21877
|
-
|
|
21878
|
-
return;
|
|
22067
|
+
return gateVerdictToCursorResponse(verdict2);
|
|
21879
22068
|
}
|
|
21880
22069
|
if (payload.tool_name === "Task") {
|
|
21881
22070
|
const verdict2 = await evaluateGatedAction(ctx, deps, {
|
|
@@ -21884,20 +22073,21 @@ async function runToolGateHook(eventName) {
|
|
|
21884
22073
|
payload,
|
|
21885
22074
|
sourceEvent: eventName
|
|
21886
22075
|
});
|
|
21887
|
-
|
|
21888
|
-
return;
|
|
22076
|
+
return gateVerdictToCursorResponse(verdict2);
|
|
21889
22077
|
}
|
|
21890
|
-
|
|
22078
|
+
return { permission: "allow" };
|
|
21891
22079
|
} catch {
|
|
21892
|
-
|
|
22080
|
+
return {
|
|
21893
22081
|
permission: "deny",
|
|
21894
22082
|
user_message: "belay failed while classifying this tool action. Run belay doctor, then retry."
|
|
21895
|
-
}
|
|
22083
|
+
};
|
|
21896
22084
|
}
|
|
21897
22085
|
}
|
|
21898
|
-
async function
|
|
22086
|
+
async function runToolGateHook(eventName) {
|
|
22087
|
+
jsonResponse(await handleToolGateHook(eventName, await readStdinJson()));
|
|
22088
|
+
}
|
|
22089
|
+
async function handleAuditHook(eventName, payload) {
|
|
21899
22090
|
try {
|
|
21900
|
-
const payload = await readStdinJson();
|
|
21901
22091
|
const toolName = String(payload.tool_name ?? "");
|
|
21902
22092
|
const resolution = resolveCursorToolActionCwdDetails(
|
|
21903
22093
|
payload,
|
|
@@ -21906,22 +22096,28 @@ async function runAuditHook(eventName) {
|
|
|
21906
22096
|
toolName
|
|
21907
22097
|
);
|
|
21908
22098
|
if (isUnsafeGlobalHookFallback(resolution)) {
|
|
21909
|
-
|
|
21910
|
-
return;
|
|
22099
|
+
return {};
|
|
21911
22100
|
}
|
|
21912
22101
|
const ctx = await loadRuntimeContext(resolution.cwd);
|
|
21913
22102
|
const deps = createDefaultGateRuntimeDeps();
|
|
21914
22103
|
await appendObservedAudit(ctx, deps, eventName, payload);
|
|
21915
|
-
|
|
22104
|
+
return {};
|
|
21916
22105
|
} catch (error) {
|
|
21917
22106
|
console.error(
|
|
21918
22107
|
"belay audit hook failed:",
|
|
21919
22108
|
error instanceof Error ? error.message : String(error)
|
|
21920
22109
|
);
|
|
21921
|
-
|
|
22110
|
+
return {};
|
|
21922
22111
|
}
|
|
21923
22112
|
}
|
|
22113
|
+
async function runAuditHook(eventName) {
|
|
22114
|
+
jsonResponse(await handleAuditHook(eventName, await readStdinJson()));
|
|
22115
|
+
}
|
|
21924
22116
|
export {
|
|
22117
|
+
handleAuditHook,
|
|
22118
|
+
handleBeforeSubmitPromptHook,
|
|
22119
|
+
handleShellGateHook,
|
|
22120
|
+
handleToolGateHook,
|
|
21925
22121
|
resolveCursorActionCwd,
|
|
21926
22122
|
runAuditHook,
|
|
21927
22123
|
runBeforeSubmitPromptHook,
|