@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
|
@@ -3574,7 +3574,7 @@ var init_config_io = __esm({
|
|
|
3574
3574
|
|
|
3575
3575
|
// src/adapters/codex/runtime-entry.ts
|
|
3576
3576
|
init_codex();
|
|
3577
|
-
import
|
|
3577
|
+
import path63 from "node:path";
|
|
3578
3578
|
import process2 from "node:process";
|
|
3579
3579
|
|
|
3580
3580
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -3583,7 +3583,7 @@ init_approval_replay();
|
|
|
3583
3583
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
3584
3584
|
import { existsSync as existsSync16 } from "node:fs";
|
|
3585
3585
|
import { mkdir as mkdir14, readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
|
|
3586
|
-
import
|
|
3586
|
+
import path61 from "node:path";
|
|
3587
3587
|
|
|
3588
3588
|
// src/core/approval-service.ts
|
|
3589
3589
|
init_config_io();
|
|
@@ -6590,31 +6590,44 @@ import { randomUUID as randomUUID3 } from "node:crypto";
|
|
|
6590
6590
|
import path21 from "node:path";
|
|
6591
6591
|
|
|
6592
6592
|
// src/core/glob.ts
|
|
6593
|
+
init_approval();
|
|
6594
|
+
function globPatternToRegexSource(pattern) {
|
|
6595
|
+
let result = "";
|
|
6596
|
+
let index = 0;
|
|
6597
|
+
while (index < pattern.length) {
|
|
6598
|
+
const char = pattern[index];
|
|
6599
|
+
if (char === "*" && pattern[index + 1] === "*") {
|
|
6600
|
+
index += 2;
|
|
6601
|
+
if (pattern[index] === "/") {
|
|
6602
|
+
result += "(?:.*/)?";
|
|
6603
|
+
index += 1;
|
|
6604
|
+
} else {
|
|
6605
|
+
result += ".*";
|
|
6606
|
+
}
|
|
6607
|
+
continue;
|
|
6608
|
+
}
|
|
6609
|
+
if (char === "*") {
|
|
6610
|
+
result += "[^/]*";
|
|
6611
|
+
index += 1;
|
|
6612
|
+
continue;
|
|
6613
|
+
}
|
|
6614
|
+
result += escapeRegex(char);
|
|
6615
|
+
index += 1;
|
|
6616
|
+
}
|
|
6617
|
+
return result;
|
|
6618
|
+
}
|
|
6619
|
+
function globPatternMatches(pattern, normalized, baseName) {
|
|
6620
|
+
const regex = new RegExp(`^${globPatternToRegexSource(pattern)}$`);
|
|
6621
|
+
return regex.test(normalized) || regex.test(baseName);
|
|
6622
|
+
}
|
|
6593
6623
|
function matchesSensitivePath(filePath, patterns) {
|
|
6594
6624
|
const normalized = filePath.replaceAll("\\", "/");
|
|
6595
6625
|
const segments = normalized.split("/");
|
|
6596
6626
|
const baseName = segments.at(-1) ?? normalized;
|
|
6597
6627
|
for (const pattern of patterns) {
|
|
6598
6628
|
const normalizedPattern = pattern.replaceAll("\\", "/");
|
|
6599
|
-
if (normalizedPattern.includes("**")) {
|
|
6600
|
-
const parts = normalizedPattern.split("**").map((part) => part.replace(/^\/+|\/+$/g, ""));
|
|
6601
|
-
const prefix = parts[0]?.replace(/\/+$/, "") ?? "";
|
|
6602
|
-
const suffix = parts[1]?.replace(/^\/+/, "") ?? "";
|
|
6603
|
-
if (prefix && !normalized.startsWith(prefix)) {
|
|
6604
|
-
continue;
|
|
6605
|
-
}
|
|
6606
|
-
if (suffix && !normalized.includes(suffix)) {
|
|
6607
|
-
continue;
|
|
6608
|
-
}
|
|
6609
|
-
if (prefix || suffix) {
|
|
6610
|
-
return true;
|
|
6611
|
-
}
|
|
6612
|
-
}
|
|
6613
6629
|
if (normalizedPattern.includes("*")) {
|
|
6614
|
-
|
|
6615
|
-
`^${normalizedPattern.replaceAll(".", "\\.").replaceAll("*", ".*")}$`
|
|
6616
|
-
);
|
|
6617
|
-
if (regex.test(normalized) || regex.test(baseName)) {
|
|
6630
|
+
if (globPatternMatches(normalizedPattern, normalized, baseName)) {
|
|
6618
6631
|
return true;
|
|
6619
6632
|
}
|
|
6620
6633
|
continue;
|
|
@@ -11016,6 +11029,16 @@ function subagentFingerprintSource(payload, scrubOptions) {
|
|
|
11016
11029
|
}
|
|
11017
11030
|
return scrubValue(payload, scrubOptions);
|
|
11018
11031
|
}
|
|
11032
|
+
function fingerprintToolInputSource(payload) {
|
|
11033
|
+
const toolInput = payload.tool_input;
|
|
11034
|
+
if (!toolInput || typeof toolInput !== "object") {
|
|
11035
|
+
return {};
|
|
11036
|
+
}
|
|
11037
|
+
return redactToolInvocationId(
|
|
11038
|
+
toolInput,
|
|
11039
|
+
typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0
|
|
11040
|
+
);
|
|
11041
|
+
}
|
|
11019
11042
|
function fingerprintReplayPayload(kind, payload, scrubOptions) {
|
|
11020
11043
|
if (!payload) {
|
|
11021
11044
|
return void 0;
|
|
@@ -11125,7 +11148,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
|
|
|
11125
11148
|
}
|
|
11126
11149
|
|
|
11127
11150
|
// src/core/classify-tool.ts
|
|
11128
|
-
import
|
|
11151
|
+
import path49 from "node:path";
|
|
11129
11152
|
init_fingerprint2();
|
|
11130
11153
|
init_path_utils();
|
|
11131
11154
|
init_scrub();
|
|
@@ -11244,11 +11267,8 @@ function worstEffectDecision(decisions) {
|
|
|
11244
11267
|
}
|
|
11245
11268
|
|
|
11246
11269
|
// src/core/effect-ir/shell-lower.ts
|
|
11247
|
-
init_git_resource_identity();
|
|
11248
|
-
init_path_utils();
|
|
11249
11270
|
init_shell_tokenizer();
|
|
11250
|
-
import
|
|
11251
|
-
import path41 from "node:path";
|
|
11271
|
+
import path48 from "node:path";
|
|
11252
11272
|
|
|
11253
11273
|
// src/core/verdict/docker-compose-run.ts
|
|
11254
11274
|
import path36 from "node:path";
|
|
@@ -11588,6 +11608,17 @@ function decodeDockerComposeRun(tokens) {
|
|
|
11588
11608
|
|
|
11589
11609
|
// src/core/verdict/egress-classify.ts
|
|
11590
11610
|
import path37 from "node:path";
|
|
11611
|
+
var EGRESS_TOOL_HEADS = /* @__PURE__ */ new Set([
|
|
11612
|
+
"aws",
|
|
11613
|
+
"curl",
|
|
11614
|
+
"gh",
|
|
11615
|
+
"gcloud",
|
|
11616
|
+
"heroku",
|
|
11617
|
+
"kubectl",
|
|
11618
|
+
"netlify",
|
|
11619
|
+
"vercel",
|
|
11620
|
+
"wget"
|
|
11621
|
+
]);
|
|
11591
11622
|
var CURL_EFFECT_NEUTRAL_FLAGS = /* @__PURE__ */ new Set([
|
|
11592
11623
|
"-f",
|
|
11593
11624
|
"-L",
|
|
@@ -11621,6 +11652,9 @@ var GH_READ_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11621
11652
|
"workflow list",
|
|
11622
11653
|
"workflow view"
|
|
11623
11654
|
]);
|
|
11655
|
+
function isEgressToolHead(head) {
|
|
11656
|
+
return EGRESS_TOOL_HEADS.has(head);
|
|
11657
|
+
}
|
|
11624
11658
|
function decodeEgressEffects(params) {
|
|
11625
11659
|
const head = path37.basename(params.tokens[0] ?? "");
|
|
11626
11660
|
if (head !== "curl" && head !== "wget" && head !== "gh") {
|
|
@@ -13883,7 +13917,7 @@ function extractBalancedParenContent(command, start) {
|
|
|
13883
13917
|
index += 1;
|
|
13884
13918
|
continue;
|
|
13885
13919
|
}
|
|
13886
|
-
if (char === "\\" &&
|
|
13920
|
+
if (char === "\\" && inDouble) {
|
|
13887
13921
|
escaping = true;
|
|
13888
13922
|
index += 1;
|
|
13889
13923
|
continue;
|
|
@@ -13961,7 +13995,9 @@ function hasUnclosedQuote(command) {
|
|
|
13961
13995
|
continue;
|
|
13962
13996
|
}
|
|
13963
13997
|
if (char === "\\") {
|
|
13964
|
-
|
|
13998
|
+
if (quote !== "'") {
|
|
13999
|
+
escaping = true;
|
|
14000
|
+
}
|
|
13965
14001
|
continue;
|
|
13966
14002
|
}
|
|
13967
14003
|
if (quote) {
|
|
@@ -14478,6 +14514,50 @@ function redactCommand(command) {
|
|
|
14478
14514
|
return command.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]").replace(/sk-[A-Za-z0-9]{8,}/g, "sk-[REDACTED]").trim();
|
|
14479
14515
|
}
|
|
14480
14516
|
|
|
14517
|
+
// src/core/effect-ir/argv-delegate.ts
|
|
14518
|
+
function innerRecipeFromArgvDelegate(peel) {
|
|
14519
|
+
if (peel.opaque || peel.innerTokens.length === 0) {
|
|
14520
|
+
return null;
|
|
14521
|
+
}
|
|
14522
|
+
return peel.innerTokens.join(" ");
|
|
14523
|
+
}
|
|
14524
|
+
function peelArgvDelegateArgv(tokens) {
|
|
14525
|
+
const launcher = tokens[0] ?? "";
|
|
14526
|
+
if (!launcher || tokens.length < 2) {
|
|
14527
|
+
return null;
|
|
14528
|
+
}
|
|
14529
|
+
const signals = ["process.argv_delegate"];
|
|
14530
|
+
let index = 1;
|
|
14531
|
+
while (index < tokens.length) {
|
|
14532
|
+
const token = tokens[index] ?? "";
|
|
14533
|
+
if (token === "--") {
|
|
14534
|
+
index += 1;
|
|
14535
|
+
break;
|
|
14536
|
+
}
|
|
14537
|
+
if (token.startsWith("-")) {
|
|
14538
|
+
return {
|
|
14539
|
+
launcher,
|
|
14540
|
+
innerTokens: [],
|
|
14541
|
+
opaque: true,
|
|
14542
|
+
reason: "argv_delegate_wrapper_options",
|
|
14543
|
+
signals: [...signals, "argv_delegate_wrapper_options"]
|
|
14544
|
+
};
|
|
14545
|
+
}
|
|
14546
|
+
break;
|
|
14547
|
+
}
|
|
14548
|
+
const innerTokens = tokens.slice(index);
|
|
14549
|
+
if (innerTokens.length === 0) {
|
|
14550
|
+
return null;
|
|
14551
|
+
}
|
|
14552
|
+
return {
|
|
14553
|
+
launcher,
|
|
14554
|
+
innerTokens,
|
|
14555
|
+
opaque: false,
|
|
14556
|
+
reason: "argv_delegate_peel",
|
|
14557
|
+
signals
|
|
14558
|
+
};
|
|
14559
|
+
}
|
|
14560
|
+
|
|
14481
14561
|
// src/core/effect-ir/shell-build.ts
|
|
14482
14562
|
function buildShellEffectPlan(params) {
|
|
14483
14563
|
const nodes = params.segments.map(buildSegmentNode);
|
|
@@ -14535,933 +14615,416 @@ function mergeNodes(nodes) {
|
|
|
14535
14615
|
return { kind: "merge", children: nodes };
|
|
14536
14616
|
}
|
|
14537
14617
|
|
|
14538
|
-
// src/core/effect-ir/shell-lower.ts
|
|
14539
|
-
|
|
14540
|
-
var
|
|
14541
|
-
|
|
14618
|
+
// src/core/effect-ir/shell-lower/argv-delegate-gate.ts
|
|
14619
|
+
import path41 from "node:path";
|
|
14620
|
+
var ARGV_DELEGATE_INNER_BLOCKLIST = /* @__PURE__ */ new Set([
|
|
14621
|
+
"sudo",
|
|
14622
|
+
"env",
|
|
14623
|
+
"command",
|
|
14624
|
+
"builtin",
|
|
14625
|
+
"exec",
|
|
14626
|
+
"time",
|
|
14627
|
+
"nice",
|
|
14628
|
+
"nohup",
|
|
14629
|
+
"stdbuf",
|
|
14630
|
+
"setsid",
|
|
14631
|
+
"("
|
|
14632
|
+
]);
|
|
14633
|
+
function shouldApplyArgvDelegate(head, innerTokens, depth) {
|
|
14634
|
+
if (depth > 0 || isEgressToolHead(head) || head === "bundle") {
|
|
14635
|
+
return false;
|
|
14636
|
+
}
|
|
14637
|
+
if (ARGV_DELEGATE_INNER_BLOCKLIST.has(head)) {
|
|
14638
|
+
return false;
|
|
14639
|
+
}
|
|
14640
|
+
const innerHead = path41.basename(innerTokens[0] ?? "");
|
|
14641
|
+
if (ARGV_DELEGATE_INNER_BLOCKLIST.has(innerHead)) {
|
|
14642
|
+
return false;
|
|
14643
|
+
}
|
|
14644
|
+
return innerTokens.length >= 2;
|
|
14645
|
+
}
|
|
14646
|
+
function isGrammarUnknownOnly(requirements, head) {
|
|
14647
|
+
if (requirements.length !== 2) {
|
|
14648
|
+
return false;
|
|
14649
|
+
}
|
|
14650
|
+
const [spawn9, indeterminate] = requirements;
|
|
14651
|
+
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");
|
|
14652
|
+
}
|
|
14653
|
+
|
|
14654
|
+
// src/core/effect-ir/shell-lower/augment.ts
|
|
14655
|
+
init_shell_tokenizer();
|
|
14656
|
+
|
|
14657
|
+
// src/core/effect-ir/shell-lower/requirement.ts
|
|
14542
14658
|
var SECRET_PATH_PATTERN = /(?:^|[/\\])(?:\.env(?:\..*)?|credentials?|secrets?|id_rsa)(?:$|[/\\])/i;
|
|
14543
14659
|
var CONTROL_PLANE_PATH_PATTERN = /^(?:\/etc(?:\/|$)|\/var\/run(?:\/|$)|.*(?:^|[/\\])\.(?:git|ssh|cursor|claude)(?:[/\\]|$))/;
|
|
14544
|
-
function
|
|
14545
|
-
|
|
14546
|
-
|
|
14547
|
-
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14660
|
+
function requirement2(tag, action, resource, segment, signals) {
|
|
14661
|
+
return {
|
|
14662
|
+
tag,
|
|
14663
|
+
action,
|
|
14664
|
+
resource,
|
|
14665
|
+
evidence: {
|
|
14666
|
+
level: tag === "indeterminate" ? "indeterminate" : "certain",
|
|
14667
|
+
signals: [...new Set(signals)].sort(),
|
|
14668
|
+
basis: ["shell_semantic_lowering"]
|
|
14669
|
+
},
|
|
14670
|
+
provenance: { segment }
|
|
14671
|
+
};
|
|
14552
14672
|
}
|
|
14553
|
-
function
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
"indeterminate",
|
|
14581
|
-
{ kind: "unknown" },
|
|
14582
|
-
result.commandRedacted,
|
|
14583
|
-
["shell.cwd_unknown"]
|
|
14584
|
-
)
|
|
14585
|
-
);
|
|
14586
|
-
}
|
|
14587
|
-
result = {
|
|
14588
|
-
...result,
|
|
14589
|
-
requirements,
|
|
14590
|
-
...requiresCwd ? {
|
|
14591
|
-
completeness: "partial",
|
|
14592
|
-
opacity: joinEffectOpacity(result.opacity, "opaque")
|
|
14593
|
-
} : {},
|
|
14594
|
-
signals: [.../* @__PURE__ */ new Set([...result.signals, "shell.cwd_unknown"])]
|
|
14595
|
-
};
|
|
14596
|
-
}
|
|
14597
|
-
lowered.push(result);
|
|
14598
|
-
if (!inferredEnv.DATABASE_URL && startsLocalPostgresService(segment)) {
|
|
14599
|
-
inferredEnv = {
|
|
14600
|
-
...inferredEnv,
|
|
14601
|
-
DATABASE_URL: "postgresql://127.0.0.1:5432/local"
|
|
14602
|
-
};
|
|
14603
|
-
}
|
|
14604
|
-
const nextCwd = resolveCdTransition(segment, cwd);
|
|
14605
|
-
if (nextCwd) {
|
|
14606
|
-
cwd = nextCwd.cwd;
|
|
14607
|
-
cwdKnown = nextCwd.known;
|
|
14608
|
-
}
|
|
14609
|
-
}
|
|
14610
|
-
if (commands.length > 1 && /[\r\n]/.test(command) && lowered.some(
|
|
14611
|
-
(segment) => segment.requirements.some((entry) => entry.action === "network.connect")
|
|
14612
|
-
)) {
|
|
14613
|
-
lowered.push(
|
|
14614
|
-
shellSegment(
|
|
14615
|
-
"[multiline network boundary]",
|
|
14616
|
-
"shell-boundary",
|
|
14617
|
-
[
|
|
14618
|
-
requirement2(
|
|
14619
|
-
"indeterminate",
|
|
14620
|
-
"indeterminate",
|
|
14621
|
-
{ kind: "unknown" },
|
|
14622
|
-
"[multiline network boundary]",
|
|
14623
|
-
["shell.multiline_network_boundary"]
|
|
14624
|
-
)
|
|
14625
|
-
],
|
|
14626
|
-
"opaque",
|
|
14627
|
-
/* @__PURE__ */ new Set(["shell.multiline_network_boundary"])
|
|
14673
|
+
function processRequirement(command, operation, segment, signals) {
|
|
14674
|
+
return requirement2(
|
|
14675
|
+
"process.exec",
|
|
14676
|
+
"process.exec",
|
|
14677
|
+
{ kind: "executable", command, operation },
|
|
14678
|
+
segment,
|
|
14679
|
+
signals
|
|
14680
|
+
);
|
|
14681
|
+
}
|
|
14682
|
+
function unsupportedProcess(command, segment, signal) {
|
|
14683
|
+
return [
|
|
14684
|
+
processRequirement(command, "spawn", segment, [signal]),
|
|
14685
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [signal])
|
|
14686
|
+
];
|
|
14687
|
+
}
|
|
14688
|
+
function addWriteEffects(requirements, resolved, segment, signals) {
|
|
14689
|
+
requirements.push(
|
|
14690
|
+
requirement2("fs.write", "fs.write", { kind: "path", path: resolved }, segment, signals)
|
|
14691
|
+
);
|
|
14692
|
+
if (CONTROL_PLANE_PATH_PATTERN.test(resolved)) {
|
|
14693
|
+
requirements.push(
|
|
14694
|
+
requirement2(
|
|
14695
|
+
"control_plane.write",
|
|
14696
|
+
"control_plane.write",
|
|
14697
|
+
{ kind: "path", path: resolved },
|
|
14698
|
+
segment,
|
|
14699
|
+
[...signals, "protected_path"]
|
|
14628
14700
|
)
|
|
14629
14701
|
);
|
|
14630
14702
|
}
|
|
14631
|
-
return lowered;
|
|
14632
|
-
}
|
|
14633
|
-
function startsLocalPostgresService(command) {
|
|
14634
|
-
const tokens = tokenizeShell(command);
|
|
14635
|
-
return path41.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
14636
14703
|
}
|
|
14637
|
-
function
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
return { cwd: currentCwd, known: false };
|
|
14704
|
+
function addSecretRead(requirements, resolved, segment) {
|
|
14705
|
+
if (SECRET_PATH_PATTERN.test(resolved)) {
|
|
14706
|
+
requirements.push(
|
|
14707
|
+
requirement2("secret.read", "secret.read", { kind: "path", path: resolved }, segment, [
|
|
14708
|
+
"secret_path_read"
|
|
14709
|
+
])
|
|
14710
|
+
);
|
|
14645
14711
|
}
|
|
14646
|
-
return { cwd: resolvePathOperand(target, currentCwd), known: true };
|
|
14647
14712
|
}
|
|
14648
|
-
function
|
|
14649
|
-
if (
|
|
14650
|
-
|
|
14713
|
+
function ensureRequirement(requirements, candidate) {
|
|
14714
|
+
if (!requirements.some(
|
|
14715
|
+
(entry) => entry.action === candidate.action && JSON.stringify(entry.resource) === JSON.stringify(candidate.resource)
|
|
14716
|
+
)) {
|
|
14717
|
+
requirements.push(candidate);
|
|
14651
14718
|
}
|
|
14652
|
-
return requirementValue.action === "process.exec" && requirementValue.resource.kind === "executable" && requirementValue.resource.operation === "spawn";
|
|
14653
|
-
}
|
|
14654
|
-
function joinNestedOpacity(outer, nested) {
|
|
14655
|
-
const nestedOpacity = nested.completeness === "partial" && nested.opacity === "transparent" ? "recursive" : nested.opacity;
|
|
14656
|
-
return joinEffectOpacity(outer, nestedOpacity);
|
|
14657
14719
|
}
|
|
14658
|
-
function
|
|
14659
|
-
const
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
14666
|
-
const tokens = stripRedirects(
|
|
14667
|
-
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
14668
|
-
).map((token) => expandKnownVariables(token, env));
|
|
14669
|
-
const decoderTokens = alignStructuredTokens(
|
|
14670
|
-
stripStructuredRedirects(lexed.tokens),
|
|
14671
|
-
stripRedirects(parsedTokens)
|
|
14672
|
-
);
|
|
14673
|
-
const head = path41.basename(tokens[0] ?? parsed.head);
|
|
14674
|
-
let opacity = segmentOpacity(command);
|
|
14675
|
-
const signals = /* @__PURE__ */ new Set();
|
|
14676
|
-
const requirements = [];
|
|
14677
|
-
if (!lexed.complete) {
|
|
14678
|
-
requirements.push(
|
|
14679
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14680
|
-
"shell.grammar_incomplete"
|
|
14681
|
-
])
|
|
14682
|
-
);
|
|
14683
|
-
signals.add("shell.grammar_incomplete");
|
|
14684
|
-
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
14685
|
-
}
|
|
14686
|
-
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
14687
|
-
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
14688
|
-
if (environment.malformed) {
|
|
14689
|
-
requirements.push(
|
|
14690
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14691
|
-
"shell.env_wrapper_incomplete"
|
|
14692
|
-
])
|
|
14693
|
-
);
|
|
14694
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14695
|
-
}
|
|
14696
|
-
if (parsed.encounteredXargs) {
|
|
14697
|
-
requirements.push(
|
|
14698
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14699
|
-
"shell.xargs_stdin_dynamic"
|
|
14700
|
-
])
|
|
14701
|
-
);
|
|
14702
|
-
signals.add("shell.xargs_stdin_dynamic");
|
|
14703
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14704
|
-
}
|
|
14705
|
-
if (context.depth > MAX_LOWER_DEPTH) {
|
|
14706
|
-
requirements.push(
|
|
14707
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14708
|
-
"shell.lower_depth_exceeded"
|
|
14709
|
-
])
|
|
14710
|
-
);
|
|
14711
|
-
return shellSegment(
|
|
14712
|
-
commandRedacted,
|
|
14713
|
-
head,
|
|
14714
|
-
requirements,
|
|
14715
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14716
|
-
signals
|
|
14717
|
-
);
|
|
14718
|
-
}
|
|
14719
|
-
const packageExec = peelPackageExecArgv(tokens);
|
|
14720
|
-
if (packageExec) {
|
|
14721
|
-
requirements.push(
|
|
14722
|
-
...decodePackageExec(packageExec, context.cwd, context.repoRoot, commandRedacted)
|
|
14723
|
-
);
|
|
14724
|
-
for (const signal of packageExec.signals) {
|
|
14725
|
-
signals.add(signal);
|
|
14726
|
-
}
|
|
14727
|
-
if (packageExec.opaque) {
|
|
14728
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14729
|
-
}
|
|
14730
|
-
const innerRecipe = packageExecInnerIsMetadata(packageExec) ? null : innerRecipeFromPeel(packageExec);
|
|
14731
|
-
if (innerRecipe) {
|
|
14732
|
-
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
14733
|
-
...context,
|
|
14734
|
-
command: innerRecipe,
|
|
14735
|
-
env,
|
|
14736
|
-
depth: context.depth + 1
|
|
14737
|
-
});
|
|
14738
|
-
for (const nestedSegment of nested) {
|
|
14739
|
-
requirements.push(
|
|
14740
|
-
...nestedSegment.requirements.map(
|
|
14741
|
-
(entry) => withInnerProvenance(entry, innerRecipe, packageExec.launcher, commandRedacted)
|
|
14742
|
-
)
|
|
14743
|
-
);
|
|
14744
|
-
for (const signal of nestedSegment.signals) {
|
|
14745
|
-
signals.add(signal);
|
|
14746
|
-
}
|
|
14747
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14748
|
-
}
|
|
14749
|
-
}
|
|
14750
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14751
|
-
}
|
|
14752
|
-
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
14753
|
-
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14754
|
-
requirements.push(
|
|
14755
|
-
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
14756
|
-
"shell.recursive_wrapper",
|
|
14757
|
-
"dynamic_shell_evaluation"
|
|
14758
|
-
])
|
|
14759
|
-
);
|
|
14760
|
-
if (recursive.script !== "") {
|
|
14761
|
-
const nested = lowerTopLevelSegments(recursive.script, {
|
|
14762
|
-
...context,
|
|
14763
|
-
command: recursive.script,
|
|
14764
|
-
env,
|
|
14765
|
-
depth: context.depth + 1
|
|
14766
|
-
});
|
|
14767
|
-
for (const nestedSegment of nested) {
|
|
14768
|
-
requirements.push(
|
|
14769
|
-
...nestedSegment.requirements.map(
|
|
14770
|
-
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
14771
|
-
)
|
|
14772
|
-
);
|
|
14773
|
-
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14774
|
-
}
|
|
14775
|
-
}
|
|
14776
|
-
signals.add("shell.recursive_wrapper");
|
|
14777
|
-
signals.add("dynamic_shell_evaluation");
|
|
14778
|
-
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14779
|
-
}
|
|
14780
|
-
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
14781
|
-
const recursiveSignals = [
|
|
14782
|
-
recursive.signal,
|
|
14783
|
-
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
14784
|
-
];
|
|
14785
|
-
requirements.push(
|
|
14786
|
-
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
14787
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14788
|
-
...recursiveSignals
|
|
14789
|
-
])
|
|
14790
|
-
);
|
|
14791
|
-
for (const signal of recursiveSignals) signals.add(signal);
|
|
14792
|
-
return shellSegment(
|
|
14793
|
-
commandRedacted,
|
|
14794
|
-
head,
|
|
14795
|
-
requirements,
|
|
14796
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14797
|
-
signals
|
|
14798
|
-
);
|
|
14799
|
-
}
|
|
14800
|
-
const compose = decodeDockerComposeRun(decoderTokens);
|
|
14801
|
-
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14802
|
-
requirements.push(
|
|
14803
|
-
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
14804
|
-
);
|
|
14805
|
-
if (compose.script !== "") {
|
|
14806
|
-
const nested = lowerTopLevelSegments(compose.script, {
|
|
14807
|
-
...context,
|
|
14808
|
-
command: compose.script,
|
|
14809
|
-
env,
|
|
14810
|
-
depth: context.depth + 1
|
|
14811
|
-
});
|
|
14812
|
-
for (const nestedSegment of nested) {
|
|
14813
|
-
requirements.push(
|
|
14814
|
-
...nestedSegment.requirements.map(
|
|
14815
|
-
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
14816
|
-
)
|
|
14817
|
-
);
|
|
14818
|
-
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14819
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14820
|
-
}
|
|
14821
|
-
}
|
|
14822
|
-
signals.add("process.docker_compose_run");
|
|
14823
|
-
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14824
|
-
}
|
|
14825
|
-
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
14826
|
-
requirements.push(
|
|
14827
|
-
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
14828
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14829
|
-
compose.signal
|
|
14830
|
-
])
|
|
14831
|
-
);
|
|
14832
|
-
signals.add("process.docker_compose_run");
|
|
14833
|
-
signals.add(compose.signal);
|
|
14834
|
-
return shellSegment(
|
|
14835
|
-
commandRedacted,
|
|
14836
|
-
head,
|
|
14837
|
-
requirements,
|
|
14838
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14839
|
-
signals
|
|
14840
|
-
);
|
|
14841
|
-
}
|
|
14842
|
-
const launcher = resolveLauncherRecipe({
|
|
14843
|
-
tokens,
|
|
14844
|
-
cwd: context.cwd,
|
|
14845
|
-
repoRoot: context.repoRoot,
|
|
14846
|
-
depth: context.depth
|
|
14847
|
-
});
|
|
14848
|
-
if (launcher) {
|
|
14849
|
-
signals.add(`launcher.${launcher.reason}`);
|
|
14850
|
-
requirements.push(
|
|
14851
|
-
requirement2(
|
|
14852
|
-
"process.exec",
|
|
14853
|
-
"process.exec",
|
|
14854
|
-
{ kind: "executable", command: head, operation: "spawn" },
|
|
14855
|
-
commandRedacted,
|
|
14856
|
-
["launcher.invoke"]
|
|
14857
|
-
)
|
|
14858
|
-
);
|
|
14859
|
-
for (const recipe of launcher.recipes) {
|
|
14860
|
-
const nested = lowerTopLevelSegments(recipe, {
|
|
14861
|
-
...context,
|
|
14862
|
-
command: recipe,
|
|
14863
|
-
env,
|
|
14864
|
-
depth: context.depth + 1
|
|
14865
|
-
});
|
|
14866
|
-
for (const nestedSegment of nested) {
|
|
14867
|
-
requirements.push(
|
|
14868
|
-
...nestedSegment.requirements.map(
|
|
14869
|
-
(entry) => withInnerProvenance(entry, recipe, head, commandRedacted)
|
|
14870
|
-
)
|
|
14871
|
-
);
|
|
14872
|
-
for (const signal of nestedSegment.signals) {
|
|
14873
|
-
signals.add(signal);
|
|
14874
|
-
}
|
|
14875
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14876
|
-
}
|
|
14877
|
-
}
|
|
14878
|
-
if (launcher.opaque || launcher.recipes.length === 0) {
|
|
14879
|
-
requirements.push(
|
|
14880
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14881
|
-
`launcher.${launcher.reason}`
|
|
14882
|
-
])
|
|
14883
|
-
);
|
|
14884
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14885
|
-
}
|
|
14886
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14887
|
-
}
|
|
14888
|
-
const egress = decodeEgressEffects({
|
|
14889
|
-
tokens,
|
|
14890
|
-
cwd: context.cwd,
|
|
14891
|
-
segment: commandRedacted
|
|
14892
|
-
});
|
|
14893
|
-
if (egress) {
|
|
14894
|
-
requirements.push(...egress);
|
|
14895
|
-
for (const signal of egress.flatMap((entry) => entry.evidence.signals)) {
|
|
14896
|
-
signals.add(signal);
|
|
14897
|
-
}
|
|
14898
|
-
} else {
|
|
14899
|
-
const git = decodeGitEffects({
|
|
14900
|
-
tokens,
|
|
14901
|
-
cwd: context.cwd,
|
|
14902
|
-
repoRoot: context.repoRoot,
|
|
14903
|
-
segment: commandRedacted
|
|
14904
|
-
});
|
|
14905
|
-
if (git) {
|
|
14906
|
-
requirements.push(...git);
|
|
14907
|
-
for (const signal of git.flatMap((entry) => entry.evidence.signals)) {
|
|
14908
|
-
signals.add(signal);
|
|
14909
|
-
}
|
|
14910
|
-
} else {
|
|
14911
|
-
requirements.push(
|
|
14912
|
-
...decodeProcessOrFilesystem({
|
|
14913
|
-
tokens,
|
|
14914
|
-
head,
|
|
14915
|
-
env,
|
|
14916
|
-
cwd: context.cwd,
|
|
14917
|
-
repoRoot: context.repoRoot,
|
|
14918
|
-
segment: commandRedacted
|
|
14919
|
-
})
|
|
14920
|
-
);
|
|
14921
|
-
}
|
|
14922
|
-
}
|
|
14923
|
-
const environmentSignals = effectChangingEnvironmentSignals(head, env, environment.changedNames);
|
|
14924
|
-
if (environmentSignals.length > 0) {
|
|
14925
|
-
requirements.push(
|
|
14926
|
-
requirement2(
|
|
14927
|
-
"indeterminate",
|
|
14928
|
-
"indeterminate",
|
|
14929
|
-
{ kind: "unknown" },
|
|
14930
|
-
commandRedacted,
|
|
14931
|
-
environmentSignals
|
|
14932
|
-
)
|
|
14933
|
-
);
|
|
14934
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14935
|
-
for (const signal of environmentSignals) {
|
|
14936
|
-
signals.add(signal);
|
|
14937
|
-
}
|
|
14938
|
-
}
|
|
14939
|
-
if (context.pipeToShellSegment) {
|
|
14940
|
-
signals.add("pipe_to_shell");
|
|
14941
|
-
ensureRequirement(
|
|
14942
|
-
requirements,
|
|
14943
|
-
requirement2(
|
|
14944
|
-
"process.exec",
|
|
14945
|
-
"process.exec",
|
|
14946
|
-
{ kind: "executable", command: head || "sh", operation: "spawn" },
|
|
14947
|
-
commandRedacted,
|
|
14948
|
-
["pipe_to_shell"]
|
|
14949
|
-
)
|
|
14950
|
-
);
|
|
14951
|
-
ensureRequirement(
|
|
14952
|
-
requirements,
|
|
14953
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14954
|
-
"pipe_to_shell"
|
|
14955
|
-
])
|
|
14956
|
-
);
|
|
14957
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14958
|
-
}
|
|
14959
|
-
if (opacity === "unparseable" || opacity === "opaque") {
|
|
14960
|
-
ensureRequirement(
|
|
14961
|
-
requirements,
|
|
14962
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14963
|
-
`shell.${opacity}`
|
|
14964
|
-
])
|
|
14965
|
-
);
|
|
14966
|
-
}
|
|
14967
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14968
|
-
}
|
|
14969
|
-
function decodePackageExec(peel, cwd, repoRoot, segment) {
|
|
14970
|
-
if (peel.opaque) {
|
|
14971
|
-
return [
|
|
14972
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14973
|
-
peel.reason,
|
|
14974
|
-
...peel.signals
|
|
14975
|
-
])
|
|
14976
|
-
];
|
|
14977
|
-
}
|
|
14978
|
-
if (peel.reason === "npx_wrapper_readonly") {
|
|
14979
|
-
return [];
|
|
14980
|
-
}
|
|
14981
|
-
const binHead = peel.innerTokens[0] ?? "";
|
|
14982
|
-
const metadataOnly = packageExecInnerIsMetadata(peel);
|
|
14983
|
-
const local = !peel.forceAcquire ? resolveLocalBin(binHead, cwd, repoRoot) : null;
|
|
14984
|
-
if (local) {
|
|
14985
|
-
return metadataOnly ? [
|
|
14986
|
-
requirement2(
|
|
14987
|
-
"process.exec",
|
|
14988
|
-
"process.exec",
|
|
14989
|
-
{ kind: "executable", command: local.path, operation: "inspect" },
|
|
14990
|
-
segment,
|
|
14991
|
-
["package_exec.delegate", "package_exec.local_bin_resolved"]
|
|
14992
|
-
)
|
|
14993
|
-
] : [];
|
|
14994
|
-
}
|
|
14995
|
-
const networkResources = peel.acquisitionSpecs.map((spec) => classifyPackageAcquisitionSpec(spec)).filter((source) => source.kind !== "local").map(
|
|
14996
|
-
(source) => source.kind === "registry" ? {
|
|
14997
|
-
kind: "network",
|
|
14998
|
-
host: "registry.npmjs.org",
|
|
14999
|
-
protocol: "registry",
|
|
15000
|
-
mode: "read",
|
|
15001
|
-
payload: "none"
|
|
15002
|
-
} : {
|
|
15003
|
-
kind: "network",
|
|
15004
|
-
host: source.host,
|
|
15005
|
-
...source.port ? { port: source.port } : {},
|
|
15006
|
-
protocol: source.protocol,
|
|
15007
|
-
mode: "read",
|
|
15008
|
-
payload: "none"
|
|
15009
|
-
}
|
|
14720
|
+
function withProvenances(requirementValue, provenance, contributing) {
|
|
14721
|
+
const provenances = [
|
|
14722
|
+
...requirementValue.provenances ?? [requirementValue.provenance],
|
|
14723
|
+
contributing,
|
|
14724
|
+
provenance
|
|
14725
|
+
].filter(
|
|
14726
|
+
(candidate, index, all) => all.findIndex((entry) => JSON.stringify(entry) === JSON.stringify(candidate)) === index
|
|
15010
14727
|
);
|
|
15011
|
-
|
|
15012
|
-
networkResources.push({
|
|
15013
|
-
kind: "network",
|
|
15014
|
-
host: "registry.npmjs.org",
|
|
15015
|
-
protocol: "registry",
|
|
15016
|
-
mode: "read",
|
|
15017
|
-
payload: "none"
|
|
15018
|
-
});
|
|
15019
|
-
}
|
|
15020
|
-
return [
|
|
15021
|
-
...networkResources.map(
|
|
15022
|
-
(resource) => requirement2("network.acquire", "network.connect", resource, segment, [
|
|
15023
|
-
"package_acquire_possible"
|
|
15024
|
-
])
|
|
15025
|
-
),
|
|
15026
|
-
requirement2(
|
|
15027
|
-
"fs.write",
|
|
15028
|
-
"fs.write",
|
|
15029
|
-
{ kind: "package-cache", manager: peel.launcher === "pnpm" ? "pnpm" : "npm" },
|
|
15030
|
-
segment,
|
|
15031
|
-
["package_cache_write"]
|
|
15032
|
-
),
|
|
15033
|
-
...metadataOnly ? [
|
|
15034
|
-
requirement2(
|
|
15035
|
-
"process.exec",
|
|
15036
|
-
"process.exec",
|
|
15037
|
-
{ kind: "executable", command: binHead || peel.launcher, operation: "inspect" },
|
|
15038
|
-
segment,
|
|
15039
|
-
["package_exec.delegate"]
|
|
15040
|
-
)
|
|
15041
|
-
] : []
|
|
15042
|
-
];
|
|
14728
|
+
return { ...requirementValue, provenance, provenances };
|
|
15043
14729
|
}
|
|
15044
|
-
function
|
|
15045
|
-
const
|
|
15046
|
-
|
|
14730
|
+
function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegment) {
|
|
14731
|
+
const provenance = {
|
|
14732
|
+
...requirementValue.provenance,
|
|
14733
|
+
segment: outerSegment,
|
|
14734
|
+
innerCommand: requirementValue.provenance.innerCommand ?? innerCommand,
|
|
14735
|
+
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
14736
|
+
};
|
|
14737
|
+
const launcherProvenance = {
|
|
14738
|
+
segment: outerSegment,
|
|
14739
|
+
innerCommand,
|
|
14740
|
+
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
14741
|
+
};
|
|
14742
|
+
return withProvenances(requirementValue, provenance, launcherProvenance);
|
|
15047
14743
|
}
|
|
14744
|
+
|
|
14745
|
+
// src/core/effect-ir/shell-lower/tokens.ts
|
|
14746
|
+
init_shell_tokenizer();
|
|
14747
|
+
import path42 from "node:path";
|
|
14748
|
+
var ENV_PREFIX_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
14749
|
+
var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "0:0:0:0:0:0:0:1"]);
|
|
15048
14750
|
var METADATA_ONLY_FLAGS = /* @__PURE__ */ new Set(["--version", "-v", "-V", "--help", "-h"]);
|
|
15049
|
-
function
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
const includePaths = [];
|
|
15069
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
15070
|
-
const arg = args[index] ?? "";
|
|
15071
|
-
if (arg === "-e" || arg === "-r") {
|
|
15072
|
-
return null;
|
|
15073
|
-
}
|
|
15074
|
-
if (arg === "-I") {
|
|
15075
|
-
const includePath = args[index + 1];
|
|
15076
|
-
if (!includePath) {
|
|
15077
|
-
return null;
|
|
14751
|
+
function extractEnvironment(tokens, inherited) {
|
|
14752
|
+
const env = { ...inherited };
|
|
14753
|
+
const changedNames = /* @__PURE__ */ new Set();
|
|
14754
|
+
if (tokens[0] === "env") {
|
|
14755
|
+
let index = 1;
|
|
14756
|
+
let malformed = false;
|
|
14757
|
+
while (index < tokens.length) {
|
|
14758
|
+
const option = tokens[index] ?? "";
|
|
14759
|
+
if (option === "-u" || option === "--unset") {
|
|
14760
|
+
const name = tokens[index + 1] ?? "";
|
|
14761
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
14762
|
+
malformed = true;
|
|
14763
|
+
index += 1;
|
|
14764
|
+
break;
|
|
14765
|
+
}
|
|
14766
|
+
delete env[name];
|
|
14767
|
+
changedNames.add(name);
|
|
14768
|
+
index += 2;
|
|
14769
|
+
continue;
|
|
15078
14770
|
}
|
|
15079
|
-
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
continue;
|
|
15086
|
-
}
|
|
15087
|
-
if (arg.startsWith("-")) {
|
|
15088
|
-
if (arg === "-n") {
|
|
15089
|
-
if (!args[index + 1]) {
|
|
15090
|
-
return null;
|
|
14771
|
+
if (option.startsWith("--unset=")) {
|
|
14772
|
+
const name = option.slice("--unset=".length);
|
|
14773
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
14774
|
+
malformed = true;
|
|
14775
|
+
index += 1;
|
|
14776
|
+
break;
|
|
15091
14777
|
}
|
|
14778
|
+
delete env[name];
|
|
14779
|
+
changedNames.add(name);
|
|
15092
14780
|
index += 1;
|
|
15093
14781
|
continue;
|
|
15094
14782
|
}
|
|
15095
|
-
if (
|
|
14783
|
+
if (option === "-i" || option === "--ignore-environment") {
|
|
14784
|
+
for (const name of Object.keys(env)) {
|
|
14785
|
+
delete env[name];
|
|
14786
|
+
}
|
|
14787
|
+
changedNames.add("*");
|
|
14788
|
+
index += 1;
|
|
15096
14789
|
continue;
|
|
15097
14790
|
}
|
|
15098
|
-
|
|
14791
|
+
if (option === "--") {
|
|
14792
|
+
index += 1;
|
|
14793
|
+
break;
|
|
14794
|
+
}
|
|
14795
|
+
if (option.startsWith("-")) {
|
|
14796
|
+
malformed = true;
|
|
14797
|
+
index += 1;
|
|
14798
|
+
break;
|
|
14799
|
+
}
|
|
14800
|
+
break;
|
|
15099
14801
|
}
|
|
15100
|
-
|
|
15101
|
-
|
|
14802
|
+
while (index < tokens.length) {
|
|
14803
|
+
const token = tokens[index] ?? "";
|
|
14804
|
+
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
14805
|
+
if (!match) {
|
|
14806
|
+
break;
|
|
14807
|
+
}
|
|
14808
|
+
const [, name, value] = match;
|
|
14809
|
+
if (name) {
|
|
14810
|
+
env[name] = expandKnownVariables(value ?? "", env);
|
|
14811
|
+
changedNames.add(name);
|
|
14812
|
+
}
|
|
14813
|
+
index += 1;
|
|
15102
14814
|
}
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
);
|
|
15111
|
-
}
|
|
15112
|
-
function decodeBundleExecInner(innerHead, innerArgs, segment) {
|
|
15113
|
-
const innerBase = executableBaseName(innerHead);
|
|
15114
|
-
if (innerBase === "rubocop") {
|
|
15115
|
-
const mutating = isRubocopMutating(innerArgs);
|
|
15116
|
-
return [
|
|
15117
|
-
processRequirement(
|
|
15118
|
-
innerHead,
|
|
15119
|
-
mutating ? "spawn" : "inspect",
|
|
15120
|
-
segment,
|
|
15121
|
-
mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
|
|
15122
|
-
)
|
|
15123
|
-
];
|
|
14815
|
+
const commandTokens = tokens.slice(index);
|
|
14816
|
+
return {
|
|
14817
|
+
env,
|
|
14818
|
+
commandTokens,
|
|
14819
|
+
malformed: malformed || commandTokens.length === 0,
|
|
14820
|
+
changedNames
|
|
14821
|
+
};
|
|
15124
14822
|
}
|
|
15125
|
-
|
|
15126
|
-
const
|
|
15127
|
-
if (
|
|
15128
|
-
|
|
14823
|
+
for (const token of tokens) {
|
|
14824
|
+
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
14825
|
+
if (!match) {
|
|
14826
|
+
break;
|
|
14827
|
+
}
|
|
14828
|
+
const [, name, value] = match;
|
|
14829
|
+
if (name) {
|
|
14830
|
+
env[name] = expandKnownVariables(value ?? "", env);
|
|
14831
|
+
changedNames.add(name);
|
|
15129
14832
|
}
|
|
15130
|
-
return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
|
|
15131
14833
|
}
|
|
15132
|
-
return
|
|
14834
|
+
return { env, malformed: false, changedNames };
|
|
15133
14835
|
}
|
|
15134
|
-
function
|
|
15135
|
-
|
|
15136
|
-
|
|
15137
|
-
|
|
15138
|
-
|
|
15139
|
-
|
|
15140
|
-
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15141
|
-
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15142
|
-
}
|
|
15143
|
-
for (const includePath of parsed.includePaths) {
|
|
15144
|
-
const resolvedInclude = resolvePathOperand(includePath, cwd);
|
|
15145
|
-
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
|
|
15146
|
-
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
14836
|
+
function expandKnownVariables(token, env) {
|
|
14837
|
+
return token.replace(
|
|
14838
|
+
/\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g,
|
|
14839
|
+
(raw, a, b) => {
|
|
14840
|
+
const value = env[a ?? b];
|
|
14841
|
+
return value === void 0 ? raw : value;
|
|
15147
14842
|
}
|
|
15148
|
-
|
|
15149
|
-
const lowered = [
|
|
15150
|
-
processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
|
|
15151
|
-
requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
|
|
15152
|
-
"ruby.minitest_script_read"
|
|
15153
|
-
])
|
|
15154
|
-
];
|
|
15155
|
-
for (const includePath of parsed.includePaths) {
|
|
15156
|
-
lowered.push(
|
|
15157
|
-
requirement2(
|
|
15158
|
-
"fs.read",
|
|
15159
|
-
"fs.read",
|
|
15160
|
-
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15161
|
-
segment,
|
|
15162
|
-
["ruby.minitest_load_path_read"]
|
|
15163
|
-
)
|
|
15164
|
-
);
|
|
15165
|
-
}
|
|
15166
|
-
return lowered;
|
|
14843
|
+
);
|
|
15167
14844
|
}
|
|
15168
|
-
function
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
14845
|
+
function stripRedirects(tokens) {
|
|
14846
|
+
const stripped = [];
|
|
14847
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14848
|
+
const token = tokens[index] ?? "";
|
|
14849
|
+
if (isFdDuplication(token)) {
|
|
14850
|
+
continue;
|
|
15172
14851
|
}
|
|
15173
|
-
if (
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
const innerBase = executableBaseName(innerHead);
|
|
15177
|
-
if ((innerBase === "rails" || innerBase === "rake") && railsReadOnlySubcommand(innerArgs)) {
|
|
15178
|
-
return [
|
|
15179
|
-
processRequirement(innerHead, "inspect", segment, ["process.inspect.rails_read_only"])
|
|
15180
|
-
];
|
|
15181
|
-
}
|
|
15182
|
-
if (isMetadataOnlyArgv(innerArgs)) {
|
|
15183
|
-
return [
|
|
15184
|
-
processRequirement(innerHead, "inspect", segment, [
|
|
15185
|
-
"process.inspect.bundle_exec_metadata"
|
|
15186
|
-
])
|
|
15187
|
-
];
|
|
15188
|
-
}
|
|
15189
|
-
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15190
|
-
if (bundleExecInner) {
|
|
15191
|
-
return bundleExecInner;
|
|
15192
|
-
}
|
|
14852
|
+
if (!isRedirectOperator(token)) {
|
|
14853
|
+
stripped.push(token);
|
|
14854
|
+
continue;
|
|
15193
14855
|
}
|
|
15194
|
-
|
|
15195
|
-
}
|
|
15196
|
-
if ((head === "ruby" || head === "yarn") && args.length >= 1 && isMetadataOnlyArgv(args)) {
|
|
15197
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15198
|
-
}
|
|
15199
|
-
if (head === "make" && args.includes("-n")) {
|
|
15200
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.make_dry_run"])];
|
|
15201
|
-
}
|
|
15202
|
-
const base = executableBaseName(head);
|
|
15203
|
-
if ((base === "rails" || base === "rake") && railsReadOnlySubcommand(args)) {
|
|
15204
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.rails_read_only"])];
|
|
14856
|
+
index += 1;
|
|
15205
14857
|
}
|
|
15206
|
-
return
|
|
14858
|
+
return stripped;
|
|
15207
14859
|
}
|
|
15208
|
-
function
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
const
|
|
15212
|
-
if (
|
|
15213
|
-
|
|
14860
|
+
function stripStructuredRedirects(tokens) {
|
|
14861
|
+
const stripped = [];
|
|
14862
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14863
|
+
const token = tokens[index];
|
|
14864
|
+
if (!token) continue;
|
|
14865
|
+
if (isFdDuplication(token.value)) {
|
|
15214
14866
|
continue;
|
|
15215
14867
|
}
|
|
15216
|
-
if (
|
|
15217
|
-
|
|
15218
|
-
return false;
|
|
15219
|
-
}
|
|
15220
|
-
index += 2;
|
|
14868
|
+
if (!isRedirectOperator(token.value)) {
|
|
14869
|
+
stripped.push(token);
|
|
15221
14870
|
continue;
|
|
15222
14871
|
}
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
14872
|
+
index += 1;
|
|
14873
|
+
}
|
|
14874
|
+
return stripped;
|
|
14875
|
+
}
|
|
14876
|
+
function alignStructuredTokens(tokens, values) {
|
|
14877
|
+
if (values.length === 0) return [];
|
|
14878
|
+
for (let start = tokens.length - values.length; start >= 0; start -= 1) {
|
|
14879
|
+
const candidate = tokens.slice(start);
|
|
14880
|
+
if (candidate.length === values.length && candidate.every((token, index) => token.value === values[index])) {
|
|
14881
|
+
return candidate;
|
|
15226
14882
|
}
|
|
15227
|
-
return false;
|
|
15228
14883
|
}
|
|
15229
|
-
return
|
|
14884
|
+
return [];
|
|
15230
14885
|
}
|
|
15231
|
-
function
|
|
15232
|
-
if (
|
|
15233
|
-
return
|
|
14886
|
+
function resolvePathOperand(operand, cwd) {
|
|
14887
|
+
if (operand === "~") {
|
|
14888
|
+
return process.env.HOME ?? operand;
|
|
15234
14889
|
}
|
|
15235
|
-
if (
|
|
15236
|
-
|
|
15237
|
-
|
|
15238
|
-
|
|
14890
|
+
if (operand.startsWith("~/")) {
|
|
14891
|
+
return path42.join(process.env.HOME ?? "~", operand.slice(2));
|
|
14892
|
+
}
|
|
14893
|
+
return path42.resolve(cwd, operand);
|
|
14894
|
+
}
|
|
14895
|
+
function isOptionToken(value) {
|
|
14896
|
+
return value.startsWith("-") || value.startsWith("+");
|
|
14897
|
+
}
|
|
14898
|
+
function isShellHead(head) {
|
|
14899
|
+
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
14900
|
+
}
|
|
14901
|
+
function pipeToShell(command) {
|
|
14902
|
+
return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
|
|
14903
|
+
}
|
|
14904
|
+
function executableBaseName(head) {
|
|
14905
|
+
return path42.basename(head);
|
|
14906
|
+
}
|
|
14907
|
+
function isMetadataOnlyArgv(argv) {
|
|
14908
|
+
return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
|
|
14909
|
+
}
|
|
14910
|
+
function databaseEndpoint(raw) {
|
|
14911
|
+
if (!raw || raw.includes("$")) {
|
|
15239
14912
|
return null;
|
|
15240
14913
|
}
|
|
15241
|
-
|
|
15242
|
-
|
|
15243
|
-
|
|
14914
|
+
try {
|
|
14915
|
+
const url = new URL(raw);
|
|
14916
|
+
if (!url.hostname || !url.protocol) {
|
|
14917
|
+
return null;
|
|
15244
14918
|
}
|
|
14919
|
+
return {
|
|
14920
|
+
host: url.hostname.toLowerCase(),
|
|
14921
|
+
protocol: url.protocol.slice(0, -1),
|
|
14922
|
+
...url.port ? { port: Number(url.port) } : {}
|
|
14923
|
+
};
|
|
14924
|
+
} catch {
|
|
15245
14925
|
return null;
|
|
15246
14926
|
}
|
|
15247
|
-
return null;
|
|
15248
|
-
}
|
|
15249
|
-
function decodeDockerComposeRun2(head, args, segment) {
|
|
15250
|
-
let composeArgs = null;
|
|
15251
|
-
let command = head;
|
|
15252
|
-
if (head === "docker-compose") {
|
|
15253
|
-
composeArgs = args;
|
|
15254
|
-
} else if (head === "docker" && args[0] === "compose") {
|
|
15255
|
-
composeArgs = args.slice(1);
|
|
15256
|
-
command = "docker";
|
|
15257
|
-
}
|
|
15258
|
-
if (!composeArgs) {
|
|
15259
|
-
return null;
|
|
15260
|
-
}
|
|
15261
|
-
if (composeArgs.includes("run")) {
|
|
15262
|
-
return [processRequirement(command, "spawn", segment, ["process.docker_compose_run"])];
|
|
15263
|
-
}
|
|
15264
|
-
return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
|
|
15265
14927
|
}
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
15271
|
-
|
|
15272
|
-
|
|
15273
|
-
if (shellControl) {
|
|
15274
|
-
return shellControl;
|
|
15275
|
-
}
|
|
15276
|
-
if (isCommandInspection(tokens)) {
|
|
15277
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
15278
|
-
}
|
|
15279
|
-
if (head === "lsof") {
|
|
15280
|
-
return validLsof(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.lsof"])] : unsupportedProcess(head, segment, "process.lsof_grammar_incomplete");
|
|
15281
|
-
}
|
|
15282
|
-
if (head === "ps") {
|
|
15283
|
-
return validPs(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.ps"])] : unsupportedProcess(head, segment, "process.ps_grammar_incomplete");
|
|
15284
|
-
}
|
|
15285
|
-
if (head === "test" || head === "[") {
|
|
15286
|
-
return validFilesystemTest(head, args) ? [processRequirement(head, "inspect", segment, ["process.inspect.filesystem_test"])] : unsupportedProcess(head, segment, "process.filesystem_test_grammar_incomplete");
|
|
15287
|
-
}
|
|
15288
|
-
if (head === "docker") {
|
|
15289
|
-
if (args[0] === "info") {
|
|
15290
|
-
return validDockerInfo(args.slice(1)) ? [processRequirement(head, "inspect", segment, ["process.inspect.docker_info"])] : unsupportedProcess(head, segment, "process.docker_info_grammar_incomplete");
|
|
14928
|
+
|
|
14929
|
+
// src/core/effect-ir/shell-lower/augment.ts
|
|
14930
|
+
function addRedirectEffects(requirements, tokens, env, context, segment) {
|
|
14931
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14932
|
+
const operator = tokens[index] ?? "";
|
|
14933
|
+
if (!isRedirectOperator(operator) || isFdDuplication(operator)) {
|
|
14934
|
+
continue;
|
|
15291
14935
|
}
|
|
15292
|
-
|
|
15293
|
-
|
|
14936
|
+
const rawTarget = tokens[index + 1];
|
|
14937
|
+
if (!rawTarget) {
|
|
14938
|
+
requirements.push(
|
|
14939
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14940
|
+
"shell.redirect_target_missing"
|
|
14941
|
+
])
|
|
14942
|
+
);
|
|
14943
|
+
continue;
|
|
15294
14944
|
}
|
|
15295
|
-
if (
|
|
15296
|
-
|
|
15297
|
-
|
|
15298
|
-
|
|
15299
|
-
|
|
15300
|
-
|
|
15301
|
-
|
|
15302
|
-
|
|
15303
|
-
{
|
|
15304
|
-
kind: "network",
|
|
15305
|
-
host: "registry",
|
|
15306
|
-
protocol: "container-registry",
|
|
15307
|
-
mode: "mutate",
|
|
15308
|
-
payload: "present"
|
|
15309
|
-
},
|
|
15310
|
-
segment,
|
|
15311
|
-
["tier0_external", "docker.remote_mutation"]
|
|
15312
|
-
)
|
|
15313
|
-
];
|
|
14945
|
+
if (operator.includes("<<")) {
|
|
14946
|
+
requirements.push(
|
|
14947
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14948
|
+
"shell.heredoc_opaque"
|
|
14949
|
+
])
|
|
14950
|
+
);
|
|
14951
|
+
index += 1;
|
|
14952
|
+
continue;
|
|
15314
14953
|
}
|
|
15315
|
-
|
|
15316
|
-
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
"network.connect",
|
|
15321
|
-
{
|
|
15322
|
-
kind: "network",
|
|
15323
|
-
host: "unknown",
|
|
15324
|
-
protocol: "container-registry",
|
|
15325
|
-
mode: "ambiguous",
|
|
15326
|
-
payload: "none"
|
|
15327
|
-
},
|
|
15328
|
-
segment,
|
|
15329
|
-
["docker.image_acquisition_possible"]
|
|
15330
|
-
)
|
|
15331
|
-
];
|
|
14954
|
+
const target = expandKnownVariables(rawTarget, env);
|
|
14955
|
+
const resolved = resolvePathOperand(target, context.cwd);
|
|
14956
|
+
if (resolved === "/dev/null") {
|
|
14957
|
+
index += 1;
|
|
14958
|
+
continue;
|
|
15332
14959
|
}
|
|
15333
|
-
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15337
|
-
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
requirement2(
|
|
15341
|
-
"fs.read",
|
|
15342
|
-
"fs.read",
|
|
15343
|
-
{ kind: "path", path: path41.resolve(cwd, syntax) },
|
|
15344
|
-
segment,
|
|
15345
|
-
["shell.syntax_source_read"]
|
|
15346
|
-
)
|
|
15347
|
-
];
|
|
14960
|
+
if (operator.includes("<")) {
|
|
14961
|
+
requirements.push(
|
|
14962
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
14963
|
+
"shell.input_redirect"
|
|
14964
|
+
])
|
|
14965
|
+
);
|
|
14966
|
+
addSecretRead(requirements, resolved, segment);
|
|
15348
14967
|
}
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
if (head === "prisma") {
|
|
15352
|
-
return decodePrisma(args, env, repoRoot, segment);
|
|
15353
|
-
}
|
|
15354
|
-
const runtimeMetadata = decodeRuntimeMetadataProcess(head, args, segment);
|
|
15355
|
-
if (runtimeMetadata) {
|
|
15356
|
-
return runtimeMetadata;
|
|
15357
|
-
}
|
|
15358
|
-
if (head === "ruby") {
|
|
15359
|
-
return decodeRuby(args, cwd, repoRoot, segment);
|
|
15360
|
-
}
|
|
15361
|
-
if (head === "rubocop" || head === "rspec") {
|
|
15362
|
-
const decoded = decodeBundleExecInner(head, args, segment);
|
|
15363
|
-
if (decoded) {
|
|
15364
|
-
return decoded;
|
|
14968
|
+
if (operator.includes(">")) {
|
|
14969
|
+
addWriteEffects(requirements, resolved, segment, ["shell.output_redirect"]);
|
|
15365
14970
|
}
|
|
14971
|
+
index += 1;
|
|
15366
14972
|
}
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
15372
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
15373
|
-
}
|
|
15374
|
-
if (head === "belay") {
|
|
15375
|
-
return decodeBelay(args, repoRoot, segment);
|
|
15376
|
-
}
|
|
15377
|
-
if (head === "tsc") {
|
|
15378
|
-
return decodeTsc(args, cwd, segment);
|
|
15379
|
-
}
|
|
15380
|
-
if (head === "go") {
|
|
15381
|
-
return decodeGo(args, segment);
|
|
15382
|
-
}
|
|
15383
|
-
if (head === "rsync") {
|
|
15384
|
-
return decodeRsync(args, cwd, segment);
|
|
15385
|
-
}
|
|
15386
|
-
if (head === "sed") {
|
|
15387
|
-
return decodeSed(args, cwd, segment);
|
|
15388
|
-
}
|
|
15389
|
-
if (head === "base64" && args.length === 1 && ["-d", "-D", "--decode"].includes(args[0] ?? "")) {
|
|
15390
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
15391
|
-
}
|
|
15392
|
-
if (head === "node") {
|
|
15393
|
-
return decodeNode2(args, cwd, segment);
|
|
15394
|
-
}
|
|
15395
|
-
if (head === "vite" || head === "vite-node") {
|
|
15396
|
-
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
14973
|
+
}
|
|
14974
|
+
function effectChangingEnvironmentSignals(head, env, changedNames) {
|
|
14975
|
+
if (head === "curl" && (env.CURL_HOME || changedNames.has("CURL_HOME") || changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME"))) {
|
|
14976
|
+
return ["egress.curl.environment_config_override"];
|
|
15397
14977
|
}
|
|
15398
|
-
if (
|
|
15399
|
-
return [
|
|
15400
|
-
processRequirement(head, "spawn", segment, ["tier0_external"]),
|
|
15401
|
-
requirement2(
|
|
15402
|
-
"network.connect",
|
|
15403
|
-
"network.connect",
|
|
15404
|
-
{
|
|
15405
|
-
kind: "network",
|
|
15406
|
-
host: "control-plane",
|
|
15407
|
-
protocol: head,
|
|
15408
|
-
mode: "mutate",
|
|
15409
|
-
payload: "present"
|
|
15410
|
-
},
|
|
15411
|
-
segment,
|
|
15412
|
-
["tier0_external"]
|
|
15413
|
-
)
|
|
15414
|
-
];
|
|
14978
|
+
if (head === "wget" && (env.WGETRC || changedNames.has("WGETRC") || changedNames.has("HOME"))) {
|
|
14979
|
+
return ["egress.wget.environment_config_override"];
|
|
15415
14980
|
}
|
|
15416
|
-
if (head
|
|
14981
|
+
if (head !== "git") {
|
|
15417
14982
|
return [];
|
|
15418
14983
|
}
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15440
|
-
|
|
15441
|
-
|
|
14984
|
+
const hazardousNames = /* @__PURE__ */ new Set([
|
|
14985
|
+
"GIT_ASKPASS",
|
|
14986
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
14987
|
+
"GIT_CEILING_DIRECTORIES",
|
|
14988
|
+
"GIT_COMMON_DIR",
|
|
14989
|
+
"GIT_CONFIG",
|
|
14990
|
+
"GIT_CONFIG_GLOBAL",
|
|
14991
|
+
"GIT_CONFIG_SYSTEM",
|
|
14992
|
+
"GIT_DIR",
|
|
14993
|
+
"GIT_DISCOVERY_ACROSS_FILESYSTEM",
|
|
14994
|
+
"GIT_EDITOR",
|
|
14995
|
+
"GIT_EXEC_PATH",
|
|
14996
|
+
"GIT_EXTERNAL_DIFF",
|
|
14997
|
+
"GIT_INDEX_FILE",
|
|
14998
|
+
"GIT_NAMESPACE",
|
|
14999
|
+
"GIT_OBJECT_DIRECTORY",
|
|
15000
|
+
"GIT_PAGER",
|
|
15001
|
+
"GIT_PROXY_COMMAND",
|
|
15002
|
+
"GIT_QUARANTINE_PATH",
|
|
15003
|
+
"GIT_SEQUENCE_EDITOR",
|
|
15004
|
+
"GIT_SHALLOW_FILE",
|
|
15005
|
+
"GIT_SSH",
|
|
15006
|
+
"GIT_SSH_COMMAND",
|
|
15007
|
+
"GIT_TEMPLATE_DIR",
|
|
15008
|
+
"GIT_WORK_TREE",
|
|
15009
|
+
"SSH_ASKPASS"
|
|
15010
|
+
]);
|
|
15011
|
+
const overridden = changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME") || Object.entries(env).some(([name, value]) => {
|
|
15012
|
+
if (!value) {
|
|
15013
|
+
return false;
|
|
15442
15014
|
}
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
const writeOperands = filesystemWriteOperands(head, args);
|
|
15446
|
-
if (writeOperands !== null) {
|
|
15447
|
-
const lowered = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
15448
|
-
for (const operand of writeOperands) {
|
|
15449
|
-
addWriteEffects(lowered, resolvePathOperand(operand, cwd), segment, ["filesystem.write"]);
|
|
15015
|
+
if (hazardousNames.has(name) || /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(name) || /^GIT_TRACE/.test(name)) {
|
|
15016
|
+
return true;
|
|
15450
15017
|
}
|
|
15451
|
-
return
|
|
15452
|
-
}
|
|
15453
|
-
|
|
15454
|
-
return [];
|
|
15455
|
-
}
|
|
15456
|
-
if (!head) {
|
|
15457
|
-
return [
|
|
15458
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15459
|
-
"shell.segment_empty"
|
|
15460
|
-
])
|
|
15461
|
-
];
|
|
15462
|
-
}
|
|
15463
|
-
return unsupportedProcess(head, segment, "process.grammar_unknown");
|
|
15018
|
+
return name === "GIT_CONFIG_COUNT" && value !== "0";
|
|
15019
|
+
});
|
|
15020
|
+
return overridden ? ["git.environment_execution_or_config_override"] : [];
|
|
15464
15021
|
}
|
|
15022
|
+
|
|
15023
|
+
// src/core/effect-ir/shell-lower/decode-process.ts
|
|
15024
|
+
import path46 from "node:path";
|
|
15025
|
+
|
|
15026
|
+
// src/core/effect-ir/shell-lower/decoders/belay.ts
|
|
15027
|
+
import path43 from "node:path";
|
|
15465
15028
|
function decodeBelay(args, repoRoot, segment) {
|
|
15466
15029
|
const [section, operation, key] = args;
|
|
15467
15030
|
const judgeCommand = section === "judge" && operation !== void 0 && ["consent", "list", "status", "test", "use"].includes(operation);
|
|
@@ -15480,7 +15043,7 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
15480
15043
|
requirement2(
|
|
15481
15044
|
"control_plane.write",
|
|
15482
15045
|
"control_plane.write",
|
|
15483
|
-
{ kind: "path", path:
|
|
15046
|
+
{ kind: "path", path: path43.join(repoRoot, ".belay-control-plane") },
|
|
15484
15047
|
segment,
|
|
15485
15048
|
["belay.config_non_judge_mutation"]
|
|
15486
15049
|
)
|
|
@@ -15488,33 +15051,240 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
15488
15051
|
}
|
|
15489
15052
|
return [processRequirement("belay", "spawn", segment, ["process.known_local_spawn"])];
|
|
15490
15053
|
}
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
let
|
|
15054
|
+
|
|
15055
|
+
// src/core/effect-ir/shell-lower/decoders/builtins.ts
|
|
15056
|
+
function decodeSetBuiltin(args) {
|
|
15057
|
+
let index = 0;
|
|
15058
|
+
while (index < args.length) {
|
|
15059
|
+
const arg = args[index] ?? "";
|
|
15060
|
+
if (arg === "--") {
|
|
15061
|
+
index += 1;
|
|
15062
|
+
continue;
|
|
15063
|
+
}
|
|
15064
|
+
if (arg === "-o" || arg === "+o") {
|
|
15065
|
+
if (!args[index + 1]) {
|
|
15066
|
+
return false;
|
|
15067
|
+
}
|
|
15068
|
+
index += 2;
|
|
15069
|
+
continue;
|
|
15070
|
+
}
|
|
15071
|
+
if (/^[-+][A-Za-z0-9]+$/.test(arg)) {
|
|
15072
|
+
index += 1;
|
|
15073
|
+
continue;
|
|
15074
|
+
}
|
|
15075
|
+
return false;
|
|
15076
|
+
}
|
|
15077
|
+
return true;
|
|
15078
|
+
}
|
|
15079
|
+
function decodeShellControlBuiltin(head, args) {
|
|
15080
|
+
if (head === "set") {
|
|
15081
|
+
return decodeSetBuiltin(args) ? [] : null;
|
|
15082
|
+
}
|
|
15083
|
+
if (head === "wait") {
|
|
15084
|
+
if (args.length === 0 || args.every((arg) => /^\d+$/.test(arg))) {
|
|
15085
|
+
return [];
|
|
15086
|
+
}
|
|
15087
|
+
return null;
|
|
15088
|
+
}
|
|
15089
|
+
if (head === "exit") {
|
|
15090
|
+
if (args.length === 0 || args.length === 1 && /^-?\d+$/.test(args[0] ?? "")) {
|
|
15091
|
+
return [];
|
|
15092
|
+
}
|
|
15093
|
+
return null;
|
|
15094
|
+
}
|
|
15095
|
+
return null;
|
|
15096
|
+
}
|
|
15097
|
+
function validLsof(args) {
|
|
15098
|
+
const flagsWithoutValues = /* @__PURE__ */ new Set(["-a", "-b", "-l", "-n", "-P", "-R", "-t", "-V"]);
|
|
15099
|
+
const flagsWithValues = /* @__PURE__ */ new Set(["-c", "-d", "-F", "-g", "-p", "-T", "-u", "+d", "+D"]);
|
|
15495
15100
|
for (let index = 0; index < args.length; index += 1) {
|
|
15496
15101
|
const arg = args[index] ?? "";
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
if (
|
|
15102
|
+
if (flagsWithoutValues.has(arg) || arg === "-i") {
|
|
15103
|
+
continue;
|
|
15104
|
+
}
|
|
15105
|
+
if (flagsWithValues.has(arg)) {
|
|
15106
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15107
|
+
return false;
|
|
15108
|
+
}
|
|
15109
|
+
index += 1;
|
|
15110
|
+
continue;
|
|
15111
|
+
}
|
|
15112
|
+
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)) {
|
|
15113
|
+
continue;
|
|
15114
|
+
}
|
|
15115
|
+
return false;
|
|
15116
|
+
}
|
|
15117
|
+
return true;
|
|
15118
|
+
}
|
|
15119
|
+
function validPs(args) {
|
|
15120
|
+
const bareForms = /* @__PURE__ */ new Set(["aux", "ax", "x", "u"]);
|
|
15121
|
+
const flagsWithoutValues = /* @__PURE__ */ new Set(["-A", "-a", "-d", "-e", "-f", "-j", "-l", "-T", "-x"]);
|
|
15122
|
+
const flagsWithValues = /* @__PURE__ */ new Set([
|
|
15123
|
+
"--format",
|
|
15124
|
+
"--group",
|
|
15125
|
+
"--pid",
|
|
15126
|
+
"--ppid",
|
|
15127
|
+
"--sort",
|
|
15128
|
+
"--tty",
|
|
15129
|
+
"--user"
|
|
15130
|
+
]);
|
|
15131
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15132
|
+
const arg = args[index] ?? "";
|
|
15133
|
+
if (bareForms.has(arg) || flagsWithoutValues.has(arg)) {
|
|
15134
|
+
continue;
|
|
15135
|
+
}
|
|
15136
|
+
if (flagsWithValues.has(arg)) {
|
|
15137
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15138
|
+
return false;
|
|
15139
|
+
}
|
|
15140
|
+
index += 1;
|
|
15141
|
+
continue;
|
|
15142
|
+
}
|
|
15143
|
+
if (/^(?:--format|--group|--pid|--ppid|--sort|--tty|--user)=.+$/.test(arg)) {
|
|
15144
|
+
continue;
|
|
15145
|
+
}
|
|
15146
|
+
if (/^-[^-]/.test(arg)) {
|
|
15147
|
+
const noValue = /* @__PURE__ */ new Set(["A", "a", "d", "e", "f", "j", "l", "T", "x"]);
|
|
15148
|
+
const withValue = /* @__PURE__ */ new Set(["G", "g", "N", "o", "p", "t", "U", "u"]);
|
|
15149
|
+
const characters = arg.slice(1);
|
|
15150
|
+
let valid = true;
|
|
15151
|
+
for (let optionIndex = 0; optionIndex < characters.length; optionIndex += 1) {
|
|
15152
|
+
const option = characters[optionIndex] ?? "";
|
|
15153
|
+
if (noValue.has(option)) {
|
|
15154
|
+
continue;
|
|
15155
|
+
}
|
|
15156
|
+
if (withValue.has(option)) {
|
|
15157
|
+
if (optionIndex === characters.length - 1) {
|
|
15158
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15159
|
+
return false;
|
|
15160
|
+
}
|
|
15161
|
+
index += 1;
|
|
15162
|
+
}
|
|
15163
|
+
break;
|
|
15164
|
+
}
|
|
15165
|
+
valid = false;
|
|
15166
|
+
break;
|
|
15167
|
+
}
|
|
15168
|
+
if (valid) {
|
|
15169
|
+
continue;
|
|
15170
|
+
}
|
|
15171
|
+
}
|
|
15172
|
+
return false;
|
|
15173
|
+
}
|
|
15174
|
+
return true;
|
|
15175
|
+
}
|
|
15176
|
+
function validFilesystemTest(head, args) {
|
|
15177
|
+
const operands = head === "[" && args.at(-1) === "]" ? args.slice(0, -1) : args;
|
|
15178
|
+
if (head === "[" && args.at(-1) !== "]") {
|
|
15179
|
+
return false;
|
|
15180
|
+
}
|
|
15181
|
+
return operands.length === 2 && (/* @__PURE__ */ new Set(["-b", "-c", "-d", "-e", "-f", "-h", "-L", "-r", "-s", "-w", "-x"])).has(
|
|
15182
|
+
operands[0] ?? ""
|
|
15183
|
+
) && Boolean(operands[1]);
|
|
15184
|
+
}
|
|
15185
|
+
function bashSyntaxTarget(args) {
|
|
15186
|
+
let syntaxOnly = false;
|
|
15187
|
+
let script = null;
|
|
15188
|
+
const shortFlags = new Set("abefhkmnptuvxBCEHPT".split(""));
|
|
15189
|
+
const longFlags = /* @__PURE__ */ new Set([
|
|
15190
|
+
"--debugger",
|
|
15191
|
+
"--dump-po-strings",
|
|
15192
|
+
"--dump-strings",
|
|
15193
|
+
"--help",
|
|
15194
|
+
"--login",
|
|
15195
|
+
"--noediting",
|
|
15196
|
+
"--noprofile",
|
|
15197
|
+
"--norc",
|
|
15198
|
+
"--posix",
|
|
15199
|
+
"--restricted",
|
|
15200
|
+
"--verbose",
|
|
15201
|
+
"--version"
|
|
15202
|
+
]);
|
|
15203
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15204
|
+
const arg = args[index] ?? "";
|
|
15205
|
+
if (arg === "-c" || arg === "-lc") {
|
|
15206
|
+
return null;
|
|
15207
|
+
}
|
|
15208
|
+
if (arg === "-O" || arg === "+O" || arg === "--rcfile" || arg === "--init-file") {
|
|
15209
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15210
|
+
return null;
|
|
15211
|
+
}
|
|
15212
|
+
index += 1;
|
|
15213
|
+
continue;
|
|
15214
|
+
}
|
|
15215
|
+
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) {
|
|
15216
|
+
continue;
|
|
15217
|
+
}
|
|
15218
|
+
if (longFlags.has(arg)) {
|
|
15219
|
+
continue;
|
|
15220
|
+
}
|
|
15221
|
+
if (/^[+-][A-Za-z]+$/.test(arg)) {
|
|
15222
|
+
const options = arg.slice(1);
|
|
15223
|
+
if ([...options].some((option) => !shortFlags.has(option))) {
|
|
15224
|
+
return null;
|
|
15225
|
+
}
|
|
15226
|
+
syntaxOnly ||= options.includes("n");
|
|
15227
|
+
continue;
|
|
15228
|
+
}
|
|
15229
|
+
if (arg === "--") {
|
|
15230
|
+
script = args[index + 1] ?? null;
|
|
15231
|
+
break;
|
|
15232
|
+
}
|
|
15233
|
+
if (arg.startsWith("-") || arg.startsWith("+")) {
|
|
15234
|
+
return null;
|
|
15235
|
+
}
|
|
15236
|
+
script = arg;
|
|
15237
|
+
break;
|
|
15238
|
+
}
|
|
15239
|
+
return syntaxOnly ? script : null;
|
|
15240
|
+
}
|
|
15241
|
+
|
|
15242
|
+
// src/core/effect-ir/shell-lower/decoders/docker.ts
|
|
15243
|
+
function decodeDockerComposeRun2(head, args, segment) {
|
|
15244
|
+
let composeArgs = null;
|
|
15245
|
+
let command = head;
|
|
15246
|
+
if (head === "docker-compose") {
|
|
15247
|
+
composeArgs = args;
|
|
15248
|
+
} else if (head === "docker" && args[0] === "compose") {
|
|
15249
|
+
composeArgs = args.slice(1);
|
|
15250
|
+
command = "docker";
|
|
15251
|
+
}
|
|
15252
|
+
if (!composeArgs) {
|
|
15253
|
+
return null;
|
|
15254
|
+
}
|
|
15255
|
+
if (composeArgs.includes("run")) {
|
|
15256
|
+
return [processRequirement(command, "spawn", segment, ["process.docker_compose_run"])];
|
|
15257
|
+
}
|
|
15258
|
+
return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
|
|
15259
|
+
}
|
|
15260
|
+
function validDockerInfo(args) {
|
|
15261
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15262
|
+
const arg = args[index] ?? "";
|
|
15263
|
+
if (arg === "--help") {
|
|
15501
15264
|
continue;
|
|
15502
15265
|
}
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15266
|
+
if (arg === "--format" || arg === "-f") {
|
|
15267
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15268
|
+
return false;
|
|
15269
|
+
}
|
|
15506
15270
|
index += 1;
|
|
15271
|
+
continue;
|
|
15507
15272
|
}
|
|
15273
|
+
if (arg.startsWith("--format=")) {
|
|
15274
|
+
if (arg.slice("--format=".length).length === 0) {
|
|
15275
|
+
return false;
|
|
15276
|
+
}
|
|
15277
|
+
continue;
|
|
15278
|
+
}
|
|
15279
|
+
return false;
|
|
15508
15280
|
}
|
|
15509
|
-
|
|
15510
|
-
const inspect = metadataOnly || typecheckOnly;
|
|
15511
|
-
requirements.unshift(
|
|
15512
|
-
processRequirement("tsc", inspect ? "inspect" : "spawn", segment, [
|
|
15513
|
-
metadataOnly ? "process.inspect.tsc_metadata" : typecheckOnly ? "process.inspect.tsc_typecheck" : "process.known_local_spawn"
|
|
15514
|
-
])
|
|
15515
|
-
);
|
|
15516
|
-
return requirements;
|
|
15281
|
+
return true;
|
|
15517
15282
|
}
|
|
15283
|
+
|
|
15284
|
+
// src/core/effect-ir/shell-lower/decoders/filesystem.ts
|
|
15285
|
+
init_git_resource_identity();
|
|
15286
|
+
import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
15287
|
+
import path44 from "node:path";
|
|
15518
15288
|
function decodeCopyMove(head, args, cwd, segment) {
|
|
15519
15289
|
const requirements = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
15520
15290
|
const operands = [];
|
|
@@ -15637,28 +15407,349 @@ function decodeRm(args, cwd, repoRoot, segment) {
|
|
|
15637
15407
|
);
|
|
15638
15408
|
}
|
|
15639
15409
|
}
|
|
15640
|
-
return requirements;
|
|
15410
|
+
return requirements;
|
|
15411
|
+
}
|
|
15412
|
+
function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
|
|
15413
|
+
try {
|
|
15414
|
+
if (finalOperandIsSymlink) {
|
|
15415
|
+
return path44.join(realpathSync4.native(path44.dirname(targetPath)), path44.basename(targetPath));
|
|
15416
|
+
}
|
|
15417
|
+
return realpathSync4.native(targetPath);
|
|
15418
|
+
} catch {
|
|
15419
|
+
return path44.resolve(targetPath);
|
|
15420
|
+
}
|
|
15421
|
+
}
|
|
15422
|
+
function isSymbolicLink(targetPath) {
|
|
15423
|
+
try {
|
|
15424
|
+
return lstatSync2(targetPath).isSymbolicLink();
|
|
15425
|
+
} catch {
|
|
15426
|
+
return false;
|
|
15427
|
+
}
|
|
15428
|
+
}
|
|
15429
|
+
function pathContains(ancestor, candidate) {
|
|
15430
|
+
const relative = path44.relative(path44.resolve(ancestor), path44.resolve(candidate));
|
|
15431
|
+
return relative === "" || !relative.startsWith("..") && !path44.isAbsolute(relative);
|
|
15432
|
+
}
|
|
15433
|
+
function filesystemReadOperands(head, args) {
|
|
15434
|
+
switch (head) {
|
|
15435
|
+
case "ls": {
|
|
15436
|
+
const operands = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15437
|
+
return operands.length > 0 ? operands : ["."];
|
|
15438
|
+
}
|
|
15439
|
+
case "find":
|
|
15440
|
+
return findReadOperands(args);
|
|
15441
|
+
case "cat":
|
|
15442
|
+
case "head":
|
|
15443
|
+
case "tail":
|
|
15444
|
+
case "less":
|
|
15445
|
+
case "stat":
|
|
15446
|
+
case "file":
|
|
15447
|
+
case "du":
|
|
15448
|
+
case "wc":
|
|
15449
|
+
return args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15450
|
+
case "grep":
|
|
15451
|
+
case "rg":
|
|
15452
|
+
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
15453
|
+
case "jq":
|
|
15454
|
+
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
15455
|
+
default:
|
|
15456
|
+
return null;
|
|
15457
|
+
}
|
|
15458
|
+
}
|
|
15459
|
+
function findReadOperands(args) {
|
|
15460
|
+
const mutatingPrimaries = /* @__PURE__ */ new Set([
|
|
15461
|
+
"-delete",
|
|
15462
|
+
"-exec",
|
|
15463
|
+
"-execdir",
|
|
15464
|
+
"-fls",
|
|
15465
|
+
"-fprint",
|
|
15466
|
+
"-fprintf",
|
|
15467
|
+
"-ok",
|
|
15468
|
+
"-okdir"
|
|
15469
|
+
]);
|
|
15470
|
+
if (args.some(
|
|
15471
|
+
(arg) => mutatingPrimaries.has(arg) || [...mutatingPrimaries].some((primary) => arg.startsWith(`${primary}=`))
|
|
15472
|
+
)) {
|
|
15473
|
+
return null;
|
|
15474
|
+
}
|
|
15475
|
+
const paths = [];
|
|
15476
|
+
for (const arg of args) {
|
|
15477
|
+
if (arg.startsWith("-") || arg === "!" || arg === "(") {
|
|
15478
|
+
break;
|
|
15479
|
+
}
|
|
15480
|
+
paths.push(arg);
|
|
15481
|
+
}
|
|
15482
|
+
return paths.length > 0 ? paths : ["."];
|
|
15483
|
+
}
|
|
15484
|
+
function filesystemWriteOperands(head, args) {
|
|
15485
|
+
const positional = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15486
|
+
switch (head) {
|
|
15487
|
+
case "touch":
|
|
15488
|
+
case "mkdir":
|
|
15489
|
+
case "rm":
|
|
15490
|
+
case "truncate":
|
|
15491
|
+
case "chmod":
|
|
15492
|
+
return positional;
|
|
15493
|
+
case "cp":
|
|
15494
|
+
case "mv":
|
|
15495
|
+
return positional.length > 0 ? [positional[positional.length - 1] ?? ""] : [];
|
|
15496
|
+
case "tee":
|
|
15497
|
+
return positional;
|
|
15498
|
+
default:
|
|
15499
|
+
return null;
|
|
15500
|
+
}
|
|
15501
|
+
}
|
|
15502
|
+
|
|
15503
|
+
// src/core/effect-ir/shell-lower/decoders/prisma.ts
|
|
15504
|
+
function decodePrisma(args, env, repoRoot, segment) {
|
|
15505
|
+
const processEffect = processRequirement("prisma", "spawn", segment, ["process.prisma"]);
|
|
15506
|
+
if (args[0] === "generate") {
|
|
15507
|
+
return [
|
|
15508
|
+
processEffect,
|
|
15509
|
+
requirement2("fs.write", "fs.write", { kind: "path", path: repoRoot }, segment, [
|
|
15510
|
+
"prisma.generate.repo_local"
|
|
15511
|
+
])
|
|
15512
|
+
];
|
|
15513
|
+
}
|
|
15514
|
+
const databaseMutation = args[0] === "migrate" || args[0] === "db" && args[1] === "seed" || args[0] === "seed";
|
|
15515
|
+
if (!databaseMutation) {
|
|
15516
|
+
return [
|
|
15517
|
+
processEffect,
|
|
15518
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15519
|
+
"prisma.grammar_incomplete"
|
|
15520
|
+
])
|
|
15521
|
+
];
|
|
15522
|
+
}
|
|
15523
|
+
const endpoint = databaseEndpoint(env.DATABASE_URL);
|
|
15524
|
+
if (!endpoint) {
|
|
15525
|
+
return [
|
|
15526
|
+
processEffect,
|
|
15527
|
+
requirement2(
|
|
15528
|
+
"network.connect",
|
|
15529
|
+
"network.connect",
|
|
15530
|
+
{
|
|
15531
|
+
kind: "network",
|
|
15532
|
+
host: "unknown",
|
|
15533
|
+
protocol: "database",
|
|
15534
|
+
mode: "ambiguous",
|
|
15535
|
+
payload: "present"
|
|
15536
|
+
},
|
|
15537
|
+
segment,
|
|
15538
|
+
["prisma.database_endpoint_unknown"]
|
|
15539
|
+
),
|
|
15540
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15541
|
+
"prisma.database_endpoint_unknown"
|
|
15542
|
+
])
|
|
15543
|
+
];
|
|
15544
|
+
}
|
|
15545
|
+
const network = requirement2(
|
|
15546
|
+
"network.connect",
|
|
15547
|
+
"network.connect",
|
|
15548
|
+
{
|
|
15549
|
+
kind: "network",
|
|
15550
|
+
...endpoint,
|
|
15551
|
+
mode: "mutate",
|
|
15552
|
+
payload: "present"
|
|
15553
|
+
},
|
|
15554
|
+
segment,
|
|
15555
|
+
[LOOPBACK_HOSTS2.has(endpoint.host) ? "prisma.database_local" : "prisma.database_remote"]
|
|
15556
|
+
);
|
|
15557
|
+
if (LOOPBACK_HOSTS2.has(endpoint.host)) {
|
|
15558
|
+
return [processEffect, network];
|
|
15559
|
+
}
|
|
15560
|
+
return [
|
|
15561
|
+
processEffect,
|
|
15562
|
+
network,
|
|
15563
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15564
|
+
"prisma.remote_database_mutation"
|
|
15565
|
+
])
|
|
15566
|
+
];
|
|
15567
|
+
}
|
|
15568
|
+
|
|
15569
|
+
// src/core/effect-ir/shell-lower/decoders/ruby.ts
|
|
15570
|
+
init_path_utils();
|
|
15571
|
+
import path45 from "node:path";
|
|
15572
|
+
var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
|
|
15573
|
+
function railsReadOnlySubcommand(args) {
|
|
15574
|
+
const subcommand = args[0];
|
|
15575
|
+
if (!subcommand || subcommand.startsWith("-")) {
|
|
15576
|
+
return false;
|
|
15577
|
+
}
|
|
15578
|
+
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
15579
|
+
}
|
|
15580
|
+
function isRubyTestScript(scriptPath) {
|
|
15581
|
+
const base = path45.basename(scriptPath);
|
|
15582
|
+
return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
|
|
15583
|
+
}
|
|
15584
|
+
function parseRubyTestInvocation(args) {
|
|
15585
|
+
const includePaths = [];
|
|
15586
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15587
|
+
const arg = args[index] ?? "";
|
|
15588
|
+
if (arg === "-e" || arg === "-r") {
|
|
15589
|
+
return null;
|
|
15590
|
+
}
|
|
15591
|
+
if (arg === "-I") {
|
|
15592
|
+
const includePath = args[index + 1];
|
|
15593
|
+
if (!includePath) {
|
|
15594
|
+
return null;
|
|
15595
|
+
}
|
|
15596
|
+
includePaths.push(includePath);
|
|
15597
|
+
index += 1;
|
|
15598
|
+
continue;
|
|
15599
|
+
}
|
|
15600
|
+
if (arg.startsWith("-I") && arg.length > 2) {
|
|
15601
|
+
includePaths.push(arg.slice(2));
|
|
15602
|
+
continue;
|
|
15603
|
+
}
|
|
15604
|
+
if (arg.startsWith("-")) {
|
|
15605
|
+
if (arg === "-n") {
|
|
15606
|
+
if (!args[index + 1]) {
|
|
15607
|
+
return null;
|
|
15608
|
+
}
|
|
15609
|
+
index += 1;
|
|
15610
|
+
continue;
|
|
15611
|
+
}
|
|
15612
|
+
if (arg.startsWith("-n")) {
|
|
15613
|
+
continue;
|
|
15614
|
+
}
|
|
15615
|
+
return null;
|
|
15616
|
+
}
|
|
15617
|
+
if (isRubyTestScript(arg)) {
|
|
15618
|
+
return { includePaths, scriptPath: arg };
|
|
15619
|
+
}
|
|
15620
|
+
return null;
|
|
15621
|
+
}
|
|
15622
|
+
return null;
|
|
15623
|
+
}
|
|
15624
|
+
function isRubocopMutating(args) {
|
|
15625
|
+
return args.some(
|
|
15626
|
+
(arg) => arg === "-A" || arg === "-a" || arg === "--auto-correct" || arg === "--autocorrect" || arg.startsWith("--auto-correct-all") || arg.startsWith("--autocorrect-all")
|
|
15627
|
+
);
|
|
15628
|
+
}
|
|
15629
|
+
function decodeBundleExecInner(innerHead, innerArgs, segment) {
|
|
15630
|
+
const innerBase = executableBaseName(innerHead);
|
|
15631
|
+
if (innerBase === "rubocop") {
|
|
15632
|
+
const mutating = isRubocopMutating(innerArgs);
|
|
15633
|
+
return [
|
|
15634
|
+
processRequirement(
|
|
15635
|
+
innerHead,
|
|
15636
|
+
mutating ? "spawn" : "inspect",
|
|
15637
|
+
segment,
|
|
15638
|
+
mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
|
|
15639
|
+
)
|
|
15640
|
+
];
|
|
15641
|
+
}
|
|
15642
|
+
if (innerBase === "rspec") {
|
|
15643
|
+
const targetArgs = innerArgs.filter((arg) => !arg.startsWith("-"));
|
|
15644
|
+
if (targetArgs.length === 0) {
|
|
15645
|
+
return null;
|
|
15646
|
+
}
|
|
15647
|
+
return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
|
|
15648
|
+
}
|
|
15649
|
+
return null;
|
|
15641
15650
|
}
|
|
15642
|
-
function
|
|
15643
|
-
|
|
15644
|
-
|
|
15645
|
-
|
|
15651
|
+
function decodeRuby(args, cwd, repoRoot, segment) {
|
|
15652
|
+
const parsed = parseRubyTestInvocation(args);
|
|
15653
|
+
if (!parsed) {
|
|
15654
|
+
return unsupportedProcess("ruby", segment, "process.ruby_grammar_incomplete");
|
|
15655
|
+
}
|
|
15656
|
+
const scriptPath = resolvePathOperand(parsed.scriptPath, cwd);
|
|
15657
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15658
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15659
|
+
}
|
|
15660
|
+
for (const includePath of parsed.includePaths) {
|
|
15661
|
+
const resolvedInclude = resolvePathOperand(includePath, cwd);
|
|
15662
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
|
|
15663
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15646
15664
|
}
|
|
15647
|
-
return realpathSync4.native(targetPath);
|
|
15648
|
-
} catch {
|
|
15649
|
-
return path41.resolve(targetPath);
|
|
15650
15665
|
}
|
|
15666
|
+
const lowered = [
|
|
15667
|
+
processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
|
|
15668
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
|
|
15669
|
+
"ruby.minitest_script_read"
|
|
15670
|
+
])
|
|
15671
|
+
];
|
|
15672
|
+
for (const includePath of parsed.includePaths) {
|
|
15673
|
+
lowered.push(
|
|
15674
|
+
requirement2(
|
|
15675
|
+
"fs.read",
|
|
15676
|
+
"fs.read",
|
|
15677
|
+
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15678
|
+
segment,
|
|
15679
|
+
["ruby.minitest_load_path_read"]
|
|
15680
|
+
)
|
|
15681
|
+
);
|
|
15682
|
+
}
|
|
15683
|
+
return lowered;
|
|
15651
15684
|
}
|
|
15652
|
-
function
|
|
15653
|
-
|
|
15654
|
-
|
|
15655
|
-
|
|
15656
|
-
|
|
15685
|
+
function decodeRuntimeMetadataProcess(head, args, segment) {
|
|
15686
|
+
if (head === "bundle") {
|
|
15687
|
+
if (args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
15688
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15689
|
+
}
|
|
15690
|
+
if (args[0] === "exec" && args.length >= 2) {
|
|
15691
|
+
const innerHead = args[1] ?? "";
|
|
15692
|
+
const innerArgs = args.slice(2);
|
|
15693
|
+
const innerBase = executableBaseName(innerHead);
|
|
15694
|
+
if ((innerBase === "rails" || innerBase === "rake") && railsReadOnlySubcommand(innerArgs)) {
|
|
15695
|
+
return [
|
|
15696
|
+
processRequirement(innerHead, "inspect", segment, ["process.inspect.rails_read_only"])
|
|
15697
|
+
];
|
|
15698
|
+
}
|
|
15699
|
+
if (isMetadataOnlyArgv(innerArgs)) {
|
|
15700
|
+
return [
|
|
15701
|
+
processRequirement(innerHead, "inspect", segment, [
|
|
15702
|
+
"process.inspect.bundle_exec_metadata"
|
|
15703
|
+
])
|
|
15704
|
+
];
|
|
15705
|
+
}
|
|
15706
|
+
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15707
|
+
if (bundleExecInner) {
|
|
15708
|
+
return bundleExecInner;
|
|
15709
|
+
}
|
|
15710
|
+
}
|
|
15711
|
+
return null;
|
|
15712
|
+
}
|
|
15713
|
+
if ((head === "ruby" || head === "yarn") && args.length >= 1 && isMetadataOnlyArgv(args)) {
|
|
15714
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15715
|
+
}
|
|
15716
|
+
if (head === "make" && args.includes("-n")) {
|
|
15717
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.make_dry_run"])];
|
|
15657
15718
|
}
|
|
15719
|
+
const base = executableBaseName(head);
|
|
15720
|
+
if ((base === "rails" || base === "rake") && railsReadOnlySubcommand(args)) {
|
|
15721
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.rails_read_only"])];
|
|
15722
|
+
}
|
|
15723
|
+
return null;
|
|
15658
15724
|
}
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15725
|
+
|
|
15726
|
+
// src/core/effect-ir/shell-lower/decoders/toolchain.ts
|
|
15727
|
+
function decodeTsc(args, cwd, segment) {
|
|
15728
|
+
const metadataOnly = args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg));
|
|
15729
|
+
const requirements = [];
|
|
15730
|
+
let hasOutput = false;
|
|
15731
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15732
|
+
const arg = args[index] ?? "";
|
|
15733
|
+
const inline = arg.match(/^--(?:outDir|outFile)=(.+)$/)?.[1];
|
|
15734
|
+
const separate = (arg === "--outDir" || arg === "--outFile") && args[index + 1] ? args[index + 1] : null;
|
|
15735
|
+
const output = inline ?? separate;
|
|
15736
|
+
if (!output) {
|
|
15737
|
+
continue;
|
|
15738
|
+
}
|
|
15739
|
+
hasOutput = true;
|
|
15740
|
+
addWriteEffects(requirements, resolvePathOperand(output, cwd), segment, ["tsc.output"]);
|
|
15741
|
+
if (separate) {
|
|
15742
|
+
index += 1;
|
|
15743
|
+
}
|
|
15744
|
+
}
|
|
15745
|
+
const typecheckOnly = args.includes("--noEmit") && !hasOutput;
|
|
15746
|
+
const inspect = metadataOnly || typecheckOnly;
|
|
15747
|
+
requirements.unshift(
|
|
15748
|
+
processRequirement("tsc", inspect ? "inspect" : "spawn", segment, [
|
|
15749
|
+
metadataOnly ? "process.inspect.tsc_metadata" : typecheckOnly ? "process.inspect.tsc_typecheck" : "process.known_local_spawn"
|
|
15750
|
+
])
|
|
15751
|
+
);
|
|
15752
|
+
return requirements;
|
|
15662
15753
|
}
|
|
15663
15754
|
function decodeGo(args, segment) {
|
|
15664
15755
|
if (["test", "list", "vet"].includes(args[0] ?? "")) {
|
|
@@ -15789,316 +15880,351 @@ function decodeSed(args, cwd, segment) {
|
|
|
15789
15880
|
}
|
|
15790
15881
|
files.push(arg);
|
|
15791
15882
|
}
|
|
15792
|
-
const operation = inline ? "spawn" : "inspect";
|
|
15793
|
-
const lowered = [processRequirement("sed", operation, segment, ["process.sed"])];
|
|
15794
|
-
for (const file of files) {
|
|
15795
|
-
lowered.push(
|
|
15796
|
-
requirement2(
|
|
15797
|
-
inline ? "fs.write" : "fs.read",
|
|
15798
|
-
inline ? "fs.write" : "fs.read",
|
|
15799
|
-
{ kind: "path", path: resolvePathOperand(file, cwd) },
|
|
15800
|
-
segment,
|
|
15801
|
-
[inline ? "sed.in_place_write" : "sed.file_read"]
|
|
15802
|
-
)
|
|
15803
|
-
);
|
|
15883
|
+
const operation = inline ? "spawn" : "inspect";
|
|
15884
|
+
const lowered = [processRequirement("sed", operation, segment, ["process.sed"])];
|
|
15885
|
+
for (const file of files) {
|
|
15886
|
+
lowered.push(
|
|
15887
|
+
requirement2(
|
|
15888
|
+
inline ? "fs.write" : "fs.read",
|
|
15889
|
+
inline ? "fs.write" : "fs.read",
|
|
15890
|
+
{ kind: "path", path: resolvePathOperand(file, cwd) },
|
|
15891
|
+
segment,
|
|
15892
|
+
[inline ? "sed.in_place_write" : "sed.file_read"]
|
|
15893
|
+
)
|
|
15894
|
+
);
|
|
15895
|
+
}
|
|
15896
|
+
return lowered;
|
|
15897
|
+
}
|
|
15898
|
+
function decodeNode2(args, cwd, segment) {
|
|
15899
|
+
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
15900
|
+
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
15901
|
+
}
|
|
15902
|
+
if ((args[0] === "--check" || args[0] === "-c") && args.length === 2 && args[1]) {
|
|
15903
|
+
return [
|
|
15904
|
+
processRequirement("node", "inspect", segment, ["process.inspect.node_syntax"]),
|
|
15905
|
+
requirement2(
|
|
15906
|
+
"fs.read",
|
|
15907
|
+
"fs.read",
|
|
15908
|
+
{ kind: "path", path: resolvePathOperand(args[1], cwd) },
|
|
15909
|
+
segment,
|
|
15910
|
+
["node.syntax_source_read"]
|
|
15911
|
+
)
|
|
15912
|
+
];
|
|
15913
|
+
}
|
|
15914
|
+
return unsupportedProcess("node", segment, "process.node_grammar_incomplete");
|
|
15915
|
+
}
|
|
15916
|
+
|
|
15917
|
+
// src/core/effect-ir/shell-lower/decode-process.ts
|
|
15918
|
+
function decodeProcessOrFilesystem(params) {
|
|
15919
|
+
const { tokens, head, env, cwd, repoRoot, segment } = params;
|
|
15920
|
+
const args = tokens.slice(1);
|
|
15921
|
+
if (tokens.length > 0 && tokens.every((token) => ENV_PREFIX_PATTERN2.test(token))) {
|
|
15922
|
+
return [];
|
|
15923
|
+
}
|
|
15924
|
+
const shellControl = decodeShellControlBuiltin(head, args);
|
|
15925
|
+
if (shellControl) {
|
|
15926
|
+
return shellControl;
|
|
15927
|
+
}
|
|
15928
|
+
if (isCommandInspection(tokens)) {
|
|
15929
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
15930
|
+
}
|
|
15931
|
+
if (head === "lsof") {
|
|
15932
|
+
return validLsof(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.lsof"])] : unsupportedProcess(head, segment, "process.lsof_grammar_incomplete");
|
|
15933
|
+
}
|
|
15934
|
+
if (head === "ps") {
|
|
15935
|
+
return validPs(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.ps"])] : unsupportedProcess(head, segment, "process.ps_grammar_incomplete");
|
|
15936
|
+
}
|
|
15937
|
+
if (head === "test" || head === "[") {
|
|
15938
|
+
return validFilesystemTest(head, args) ? [processRequirement(head, "inspect", segment, ["process.inspect.filesystem_test"])] : unsupportedProcess(head, segment, "process.filesystem_test_grammar_incomplete");
|
|
15939
|
+
}
|
|
15940
|
+
if (head === "docker") {
|
|
15941
|
+
if (args[0] === "info") {
|
|
15942
|
+
return validDockerInfo(args.slice(1)) ? [processRequirement(head, "inspect", segment, ["process.inspect.docker_info"])] : unsupportedProcess(head, segment, "process.docker_info_grammar_incomplete");
|
|
15943
|
+
}
|
|
15944
|
+
if (args[0] === "compose" && ["up", "down", "start", "stop", "restart", "create", "rm"].includes(args[1] ?? "")) {
|
|
15945
|
+
return [processRequirement(head, "spawn", segment, ["service.local_mutation"])];
|
|
15946
|
+
}
|
|
15947
|
+
if (args[0] === "push" || args[0] === "build" && args.includes("--push") || args[0] === "buildx" && args[1] === "build" && (args.includes("--push") || args.some(
|
|
15948
|
+
(arg) => arg.startsWith("--output=type=registry") || arg.startsWith("-o=type=registry")
|
|
15949
|
+
))) {
|
|
15950
|
+
return [
|
|
15951
|
+
processRequirement(head, "spawn", segment, ["tier0_external", "docker.remote_mutation"]),
|
|
15952
|
+
requirement2(
|
|
15953
|
+
"network.connect",
|
|
15954
|
+
"network.connect",
|
|
15955
|
+
{
|
|
15956
|
+
kind: "network",
|
|
15957
|
+
host: "registry",
|
|
15958
|
+
protocol: "container-registry",
|
|
15959
|
+
mode: "mutate",
|
|
15960
|
+
payload: "present"
|
|
15961
|
+
},
|
|
15962
|
+
segment,
|
|
15963
|
+
["tier0_external", "docker.remote_mutation"]
|
|
15964
|
+
)
|
|
15965
|
+
];
|
|
15966
|
+
}
|
|
15967
|
+
if (args[0] === "run" || args[0] === "create" || args[0] === "pull" || args[0] === "build" || args[0] === "buildx" && args[1] === "build") {
|
|
15968
|
+
return [
|
|
15969
|
+
processRequirement(head, "spawn", segment, ["process.docker_spawn"]),
|
|
15970
|
+
requirement2(
|
|
15971
|
+
"network.acquire",
|
|
15972
|
+
"network.connect",
|
|
15973
|
+
{
|
|
15974
|
+
kind: "network",
|
|
15975
|
+
host: "unknown",
|
|
15976
|
+
protocol: "container-registry",
|
|
15977
|
+
mode: "ambiguous",
|
|
15978
|
+
payload: "none"
|
|
15979
|
+
},
|
|
15980
|
+
segment,
|
|
15981
|
+
["docker.image_acquisition_possible"]
|
|
15982
|
+
)
|
|
15983
|
+
];
|
|
15984
|
+
}
|
|
15985
|
+
return [processRequirement(head, "spawn", segment, ["process.docker_spawn"])];
|
|
15986
|
+
}
|
|
15987
|
+
if (isShellHead(head)) {
|
|
15988
|
+
const syntax = bashSyntaxTarget(args);
|
|
15989
|
+
if (syntax) {
|
|
15990
|
+
return [
|
|
15991
|
+
processRequirement(head, "inspect", segment, ["process.inspect.shell_syntax"]),
|
|
15992
|
+
requirement2(
|
|
15993
|
+
"fs.read",
|
|
15994
|
+
"fs.read",
|
|
15995
|
+
{ kind: "path", path: path46.resolve(cwd, syntax) },
|
|
15996
|
+
segment,
|
|
15997
|
+
["shell.syntax_source_read"]
|
|
15998
|
+
)
|
|
15999
|
+
];
|
|
16000
|
+
}
|
|
16001
|
+
return unsupportedProcess(head, segment, "process.shell_grammar_incomplete");
|
|
16002
|
+
}
|
|
16003
|
+
if (head === "prisma") {
|
|
16004
|
+
return decodePrisma(args, env, repoRoot, segment);
|
|
16005
|
+
}
|
|
16006
|
+
const runtimeMetadata = decodeRuntimeMetadataProcess(head, args, segment);
|
|
16007
|
+
if (runtimeMetadata) {
|
|
16008
|
+
return runtimeMetadata;
|
|
16009
|
+
}
|
|
16010
|
+
if (head === "ruby") {
|
|
16011
|
+
return decodeRuby(args, cwd, repoRoot, segment);
|
|
16012
|
+
}
|
|
16013
|
+
if (head === "rubocop" || head === "rspec") {
|
|
16014
|
+
const decoded = decodeBundleExecInner(head, args, segment);
|
|
16015
|
+
if (decoded) {
|
|
16016
|
+
return decoded;
|
|
16017
|
+
}
|
|
16018
|
+
}
|
|
16019
|
+
const dockerCompose = decodeDockerComposeRun2(head, args, segment);
|
|
16020
|
+
if (dockerCompose) {
|
|
16021
|
+
return dockerCompose;
|
|
16022
|
+
}
|
|
16023
|
+
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
16024
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
16025
|
+
}
|
|
16026
|
+
if (head === "belay") {
|
|
16027
|
+
return decodeBelay(args, repoRoot, segment);
|
|
16028
|
+
}
|
|
16029
|
+
if (head === "tsc") {
|
|
16030
|
+
return decodeTsc(args, cwd, segment);
|
|
15804
16031
|
}
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
function decodeNode2(args, cwd, segment) {
|
|
15808
|
-
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
15809
|
-
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
16032
|
+
if (head === "go") {
|
|
16033
|
+
return decodeGo(args, segment);
|
|
15810
16034
|
}
|
|
15811
|
-
if (
|
|
15812
|
-
return
|
|
15813
|
-
processRequirement("node", "inspect", segment, ["process.inspect.node_syntax"]),
|
|
15814
|
-
requirement2(
|
|
15815
|
-
"fs.read",
|
|
15816
|
-
"fs.read",
|
|
15817
|
-
{ kind: "path", path: resolvePathOperand(args[1], cwd) },
|
|
15818
|
-
segment,
|
|
15819
|
-
["node.syntax_source_read"]
|
|
15820
|
-
)
|
|
15821
|
-
];
|
|
16035
|
+
if (head === "rsync") {
|
|
16036
|
+
return decodeRsync(args, cwd, segment);
|
|
15822
16037
|
}
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
function decodePrisma(args, env, repoRoot, segment) {
|
|
15826
|
-
const processEffect = processRequirement("prisma", "spawn", segment, ["process.prisma"]);
|
|
15827
|
-
if (args[0] === "generate") {
|
|
15828
|
-
return [
|
|
15829
|
-
processEffect,
|
|
15830
|
-
requirement2("fs.write", "fs.write", { kind: "path", path: repoRoot }, segment, [
|
|
15831
|
-
"prisma.generate.repo_local"
|
|
15832
|
-
])
|
|
15833
|
-
];
|
|
16038
|
+
if (head === "sed") {
|
|
16039
|
+
return decodeSed(args, cwd, segment);
|
|
15834
16040
|
}
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
return [
|
|
15838
|
-
processEffect,
|
|
15839
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15840
|
-
"prisma.grammar_incomplete"
|
|
15841
|
-
])
|
|
15842
|
-
];
|
|
16041
|
+
if (head === "base64" && args.length === 1 && ["-d", "-D", "--decode"].includes(args[0] ?? "")) {
|
|
16042
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
15843
16043
|
}
|
|
15844
|
-
|
|
15845
|
-
|
|
16044
|
+
if (head === "node") {
|
|
16045
|
+
return decodeNode2(args, cwd, segment);
|
|
16046
|
+
}
|
|
16047
|
+
if (head === "vite" || head === "vite-node") {
|
|
16048
|
+
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
16049
|
+
}
|
|
16050
|
+
if ((head === "npm" || head === "pnpm") && args[0] === "publish" || head === "terraform" && args[0] === "apply") {
|
|
15846
16051
|
return [
|
|
15847
|
-
|
|
16052
|
+
processRequirement(head, "spawn", segment, ["tier0_external"]),
|
|
15848
16053
|
requirement2(
|
|
15849
16054
|
"network.connect",
|
|
15850
16055
|
"network.connect",
|
|
15851
16056
|
{
|
|
15852
16057
|
kind: "network",
|
|
15853
|
-
host: "
|
|
15854
|
-
protocol:
|
|
15855
|
-
mode: "
|
|
16058
|
+
host: "control-plane",
|
|
16059
|
+
protocol: head,
|
|
16060
|
+
mode: "mutate",
|
|
15856
16061
|
payload: "present"
|
|
15857
16062
|
},
|
|
15858
16063
|
segment,
|
|
15859
|
-
["
|
|
15860
|
-
)
|
|
15861
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15862
|
-
"prisma.database_endpoint_unknown"
|
|
15863
|
-
])
|
|
16064
|
+
["tier0_external"]
|
|
16065
|
+
)
|
|
15864
16066
|
];
|
|
15865
16067
|
}
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
[
|
|
15877
|
-
|
|
15878
|
-
if (
|
|
15879
|
-
return [
|
|
15880
|
-
}
|
|
15881
|
-
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
if (!isRedirectOperator(operator) || isFdDuplication(operator)) {
|
|
15893
|
-
continue;
|
|
15894
|
-
}
|
|
15895
|
-
const rawTarget = tokens[index + 1];
|
|
15896
|
-
if (!rawTarget) {
|
|
15897
|
-
requirements.push(
|
|
15898
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15899
|
-
"shell.redirect_target_missing"
|
|
15900
|
-
])
|
|
15901
|
-
);
|
|
15902
|
-
continue;
|
|
15903
|
-
}
|
|
15904
|
-
if (operator.includes("<<")) {
|
|
15905
|
-
requirements.push(
|
|
15906
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15907
|
-
"shell.heredoc_opaque"
|
|
15908
|
-
])
|
|
15909
|
-
);
|
|
15910
|
-
index += 1;
|
|
15911
|
-
continue;
|
|
15912
|
-
}
|
|
15913
|
-
const target = expandKnownVariables(rawTarget, env);
|
|
15914
|
-
const resolved = resolvePathOperand(target, context.cwd);
|
|
15915
|
-
if (resolved === "/dev/null") {
|
|
15916
|
-
index += 1;
|
|
15917
|
-
continue;
|
|
15918
|
-
}
|
|
15919
|
-
if (operator.includes("<")) {
|
|
15920
|
-
requirements.push(
|
|
15921
|
-
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
15922
|
-
"shell.input_redirect"
|
|
15923
|
-
])
|
|
15924
|
-
);
|
|
15925
|
-
addSecretRead(requirements, resolved, segment);
|
|
15926
|
-
}
|
|
15927
|
-
if (operator.includes(">")) {
|
|
15928
|
-
addWriteEffects(requirements, resolved, segment, ["shell.output_redirect"]);
|
|
15929
|
-
}
|
|
15930
|
-
index += 1;
|
|
15931
|
-
}
|
|
15932
|
-
}
|
|
15933
|
-
function addSubstitutionEffects(requirements, command, context, segment, signals) {
|
|
15934
|
-
const inners = structuralSubstitutionInners(command);
|
|
15935
|
-
for (const inner of inners) {
|
|
15936
|
-
signals.add("command_substitution");
|
|
15937
|
-
if (context.depth >= MAX_LOWER_DEPTH) {
|
|
15938
|
-
requirements.push(
|
|
15939
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15940
|
-
"shell.substitution_depth_exceeded"
|
|
15941
|
-
])
|
|
15942
|
-
);
|
|
15943
|
-
continue;
|
|
15944
|
-
}
|
|
15945
|
-
const nestedSegments = lowerTopLevelSegments(inner, {
|
|
15946
|
-
...context,
|
|
15947
|
-
command: inner,
|
|
15948
|
-
depth: context.depth + 1
|
|
15949
|
-
});
|
|
15950
|
-
for (const nested of nestedSegments) {
|
|
15951
|
-
requirements.push(
|
|
15952
|
-
...nested.requirements.map((entry) => {
|
|
15953
|
-
const outerProvenance = {
|
|
15954
|
-
segment,
|
|
15955
|
-
innerCommand: inner
|
|
15956
|
-
};
|
|
15957
|
-
const provenance = {
|
|
15958
|
-
...entry.provenance,
|
|
15959
|
-
segment,
|
|
15960
|
-
innerCommand: entry.provenance.innerCommand ?? inner
|
|
15961
|
-
};
|
|
15962
|
-
return withProvenances(entry, provenance, outerProvenance);
|
|
15963
|
-
})
|
|
15964
|
-
);
|
|
15965
|
-
}
|
|
15966
|
-
}
|
|
15967
|
-
}
|
|
15968
|
-
function extractEnvironment(tokens, inherited) {
|
|
15969
|
-
const env = { ...inherited };
|
|
15970
|
-
const changedNames = /* @__PURE__ */ new Set();
|
|
15971
|
-
if (tokens[0] === "env") {
|
|
15972
|
-
let index = 1;
|
|
15973
|
-
let malformed = false;
|
|
15974
|
-
while (index < tokens.length) {
|
|
15975
|
-
const option = tokens[index] ?? "";
|
|
15976
|
-
if (option === "-u" || option === "--unset") {
|
|
15977
|
-
const name = tokens[index + 1] ?? "";
|
|
15978
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
15979
|
-
malformed = true;
|
|
15980
|
-
index += 1;
|
|
15981
|
-
break;
|
|
15982
|
-
}
|
|
15983
|
-
delete env[name];
|
|
15984
|
-
changedNames.add(name);
|
|
15985
|
-
index += 2;
|
|
15986
|
-
continue;
|
|
15987
|
-
}
|
|
15988
|
-
if (option.startsWith("--unset=")) {
|
|
15989
|
-
const name = option.slice("--unset=".length);
|
|
15990
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
15991
|
-
malformed = true;
|
|
15992
|
-
index += 1;
|
|
15993
|
-
break;
|
|
15994
|
-
}
|
|
15995
|
-
delete env[name];
|
|
15996
|
-
changedNames.add(name);
|
|
15997
|
-
index += 1;
|
|
15998
|
-
continue;
|
|
15999
|
-
}
|
|
16000
|
-
if (option === "-i" || option === "--ignore-environment") {
|
|
16001
|
-
for (const name of Object.keys(env)) {
|
|
16002
|
-
delete env[name];
|
|
16003
|
-
}
|
|
16004
|
-
changedNames.add("*");
|
|
16005
|
-
index += 1;
|
|
16006
|
-
continue;
|
|
16007
|
-
}
|
|
16008
|
-
if (option === "--") {
|
|
16009
|
-
index += 1;
|
|
16010
|
-
break;
|
|
16011
|
-
}
|
|
16012
|
-
if (option.startsWith("-")) {
|
|
16013
|
-
malformed = true;
|
|
16014
|
-
index += 1;
|
|
16015
|
-
break;
|
|
16016
|
-
}
|
|
16017
|
-
break;
|
|
16018
|
-
}
|
|
16019
|
-
while (index < tokens.length) {
|
|
16020
|
-
const token = tokens[index] ?? "";
|
|
16021
|
-
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
16022
|
-
if (!match) {
|
|
16023
|
-
break;
|
|
16024
|
-
}
|
|
16025
|
-
const [, name, value] = match;
|
|
16026
|
-
if (name) {
|
|
16027
|
-
env[name] = expandKnownVariables(value ?? "", env);
|
|
16028
|
-
changedNames.add(name);
|
|
16029
|
-
}
|
|
16030
|
-
index += 1;
|
|
16031
|
-
}
|
|
16032
|
-
const commandTokens = tokens.slice(index);
|
|
16033
|
-
return {
|
|
16034
|
-
env,
|
|
16035
|
-
commandTokens,
|
|
16036
|
-
malformed: malformed || commandTokens.length === 0,
|
|
16037
|
-
changedNames
|
|
16038
|
-
};
|
|
16039
|
-
}
|
|
16040
|
-
for (const token of tokens) {
|
|
16041
|
-
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
16042
|
-
if (!match) {
|
|
16043
|
-
break;
|
|
16068
|
+
if (head === "cd") {
|
|
16069
|
+
return [];
|
|
16070
|
+
}
|
|
16071
|
+
if (head === "cp" || head === "mv") {
|
|
16072
|
+
return decodeCopyMove(head, args, cwd, segment);
|
|
16073
|
+
}
|
|
16074
|
+
if (head === "rm") {
|
|
16075
|
+
return decodeRm(args, cwd, repoRoot, segment);
|
|
16076
|
+
}
|
|
16077
|
+
if (head === "vitest" || head === "eslint" || head === "biome" || head === "belay") {
|
|
16078
|
+
return [processRequirement(head, "spawn", segment, ["process.known_local_spawn"])];
|
|
16079
|
+
}
|
|
16080
|
+
if (head === "pwd" || head === "which" || head === "whoami") {
|
|
16081
|
+
return [processRequirement(head, "inspect", segment, ["process.pure_inspection"])];
|
|
16082
|
+
}
|
|
16083
|
+
const readOperands = filesystemReadOperands(head, args);
|
|
16084
|
+
if (readOperands !== null) {
|
|
16085
|
+
const lowered = [processRequirement(head, "inspect", segment, ["process.filesystem_inspect"])];
|
|
16086
|
+
for (const operand of readOperands) {
|
|
16087
|
+
const resolved = resolvePathOperand(operand, cwd);
|
|
16088
|
+
lowered.push(
|
|
16089
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
16090
|
+
"filesystem.read"
|
|
16091
|
+
])
|
|
16092
|
+
);
|
|
16093
|
+
addSecretRead(lowered, resolved, segment);
|
|
16044
16094
|
}
|
|
16045
|
-
|
|
16046
|
-
|
|
16047
|
-
|
|
16048
|
-
|
|
16095
|
+
return lowered;
|
|
16096
|
+
}
|
|
16097
|
+
const writeOperands = filesystemWriteOperands(head, args);
|
|
16098
|
+
if (writeOperands !== null) {
|
|
16099
|
+
const lowered = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
16100
|
+
for (const operand of writeOperands) {
|
|
16101
|
+
addWriteEffects(lowered, resolvePathOperand(operand, cwd), segment, ["filesystem.write"]);
|
|
16049
16102
|
}
|
|
16103
|
+
return lowered;
|
|
16050
16104
|
}
|
|
16051
|
-
|
|
16105
|
+
if (head === "printf" || head === "echo" || head === "true" || head === "false" || head === ":") {
|
|
16106
|
+
return [];
|
|
16107
|
+
}
|
|
16108
|
+
if (!head) {
|
|
16109
|
+
return [
|
|
16110
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16111
|
+
"shell.segment_empty"
|
|
16112
|
+
])
|
|
16113
|
+
];
|
|
16114
|
+
}
|
|
16115
|
+
return unsupportedProcess(head, segment, "process.grammar_unknown");
|
|
16052
16116
|
}
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16117
|
+
|
|
16118
|
+
// src/core/effect-ir/shell-lower/decoders/decode-package-exec.ts
|
|
16119
|
+
function decodePackageExec(peel, cwd, repoRoot, segment) {
|
|
16120
|
+
if (peel.opaque) {
|
|
16121
|
+
return [
|
|
16122
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16123
|
+
peel.reason,
|
|
16124
|
+
...peel.signals
|
|
16125
|
+
])
|
|
16126
|
+
];
|
|
16127
|
+
}
|
|
16128
|
+
if (peel.reason === "npx_wrapper_readonly") {
|
|
16129
|
+
return [];
|
|
16130
|
+
}
|
|
16131
|
+
const binHead = peel.innerTokens[0] ?? "";
|
|
16132
|
+
const metadataOnly = packageExecInnerIsMetadata(peel);
|
|
16133
|
+
const local = !peel.forceAcquire ? resolveLocalBin(binHead, cwd, repoRoot) : null;
|
|
16134
|
+
if (local) {
|
|
16135
|
+
return metadataOnly ? [
|
|
16136
|
+
requirement2(
|
|
16137
|
+
"process.exec",
|
|
16138
|
+
"process.exec",
|
|
16139
|
+
{ kind: "executable", command: local.path, operation: "inspect" },
|
|
16140
|
+
segment,
|
|
16141
|
+
["package_exec.delegate", "package_exec.local_bin_resolved"]
|
|
16142
|
+
)
|
|
16143
|
+
] : [];
|
|
16144
|
+
}
|
|
16145
|
+
const networkResources = peel.acquisitionSpecs.map((spec) => classifyPackageAcquisitionSpec(spec)).filter((source) => source.kind !== "local").map(
|
|
16146
|
+
(source) => source.kind === "registry" ? {
|
|
16147
|
+
kind: "network",
|
|
16148
|
+
host: "registry.npmjs.org",
|
|
16149
|
+
protocol: "registry",
|
|
16150
|
+
mode: "read",
|
|
16151
|
+
payload: "none"
|
|
16152
|
+
} : {
|
|
16153
|
+
kind: "network",
|
|
16154
|
+
host: source.host,
|
|
16155
|
+
...source.port ? { port: source.port } : {},
|
|
16156
|
+
protocol: source.protocol,
|
|
16157
|
+
mode: "read",
|
|
16158
|
+
payload: "none"
|
|
16059
16159
|
}
|
|
16060
16160
|
);
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
}
|
|
16069
|
-
if (!isRedirectOperator(token)) {
|
|
16070
|
-
stripped.push(token);
|
|
16071
|
-
continue;
|
|
16072
|
-
}
|
|
16073
|
-
index += 1;
|
|
16161
|
+
if (networkResources.length === 0) {
|
|
16162
|
+
networkResources.push({
|
|
16163
|
+
kind: "network",
|
|
16164
|
+
host: "registry.npmjs.org",
|
|
16165
|
+
protocol: "registry",
|
|
16166
|
+
mode: "read",
|
|
16167
|
+
payload: "none"
|
|
16168
|
+
});
|
|
16074
16169
|
}
|
|
16075
|
-
return
|
|
16170
|
+
return [
|
|
16171
|
+
...networkResources.map(
|
|
16172
|
+
(resource) => requirement2("network.acquire", "network.connect", resource, segment, [
|
|
16173
|
+
"package_acquire_possible"
|
|
16174
|
+
])
|
|
16175
|
+
),
|
|
16176
|
+
requirement2(
|
|
16177
|
+
"fs.write",
|
|
16178
|
+
"fs.write",
|
|
16179
|
+
{ kind: "package-cache", manager: peel.launcher === "pnpm" ? "pnpm" : "npm" },
|
|
16180
|
+
segment,
|
|
16181
|
+
["package_cache_write"]
|
|
16182
|
+
),
|
|
16183
|
+
...metadataOnly ? [
|
|
16184
|
+
requirement2(
|
|
16185
|
+
"process.exec",
|
|
16186
|
+
"process.exec",
|
|
16187
|
+
{ kind: "executable", command: binHead || peel.launcher, operation: "inspect" },
|
|
16188
|
+
segment,
|
|
16189
|
+
["package_exec.delegate"]
|
|
16190
|
+
)
|
|
16191
|
+
] : []
|
|
16192
|
+
];
|
|
16076
16193
|
}
|
|
16077
|
-
function
|
|
16078
|
-
const
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16194
|
+
function packageExecInnerIsMetadata(peel) {
|
|
16195
|
+
const args = peel.innerTokens.slice(1);
|
|
16196
|
+
return args.length > 0 && args.every((arg) => ["--help", "--version", "-V", "-h", "-v"].includes(arg));
|
|
16197
|
+
}
|
|
16198
|
+
|
|
16199
|
+
// src/core/effect-ir/shell-lower/segment.ts
|
|
16200
|
+
init_shell_tokenizer();
|
|
16201
|
+
import path47 from "node:path";
|
|
16202
|
+
var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
|
|
16203
|
+
var SHELL_GLOB_PATTERN = /[*?[]/;
|
|
16204
|
+
function requiresKnownCwd(requirementValue) {
|
|
16205
|
+
if (requirementValue.action === "fs.write" || requirementValue.action === "git.ref.write" || requirementValue.action === "control_plane.write") {
|
|
16206
|
+
return true;
|
|
16090
16207
|
}
|
|
16091
|
-
return
|
|
16208
|
+
return requirementValue.action === "process.exec" && requirementValue.resource.kind === "executable" && requirementValue.resource.operation === "spawn";
|
|
16092
16209
|
}
|
|
16093
|
-
function
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
|
|
16210
|
+
function joinNestedOpacity(outer, nested) {
|
|
16211
|
+
const nestedOpacity = nested.completeness === "partial" && nested.opacity === "transparent" ? "recursive" : nested.opacity;
|
|
16212
|
+
return joinEffectOpacity(outer, nestedOpacity);
|
|
16213
|
+
}
|
|
16214
|
+
function startsLocalPostgresService(command) {
|
|
16215
|
+
const tokens = tokenizeShell(command);
|
|
16216
|
+
return path47.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
16217
|
+
}
|
|
16218
|
+
function resolveCdTransition(command, currentCwd) {
|
|
16219
|
+
const tokens = tokenizeShell(command);
|
|
16220
|
+
if (path47.basename(tokens[0] ?? "") !== "cd") {
|
|
16221
|
+
return null;
|
|
16100
16222
|
}
|
|
16101
|
-
|
|
16223
|
+
const target = tokens[1] ?? "~";
|
|
16224
|
+
if (!target || target === "-" || target.includes("$") || target.includes("`")) {
|
|
16225
|
+
return { cwd: currentCwd, known: false };
|
|
16226
|
+
}
|
|
16227
|
+
return { cwd: resolvePathOperand(target, currentCwd), known: true };
|
|
16102
16228
|
}
|
|
16103
16229
|
function shellSegment(commandRedacted, segmentHead, requirements, opacity, signals) {
|
|
16104
16230
|
const normalizedRequirements = requirements.flatMap((entry) => {
|
|
@@ -16115,69 +16241,19 @@ function shellSegment(commandRedacted, segmentHead, requirements, opacity, signa
|
|
|
16115
16241
|
)
|
|
16116
16242
|
];
|
|
16117
16243
|
}
|
|
16118
|
-
return [entry];
|
|
16119
|
-
});
|
|
16120
|
-
const partial = normalizedRequirements.some(
|
|
16121
|
-
(entry) => entry.tag === "indeterminate" || entry.action === "indeterminate"
|
|
16122
|
-
);
|
|
16123
|
-
return {
|
|
16124
|
-
commandRedacted,
|
|
16125
|
-
segmentHead,
|
|
16126
|
-
requirements: normalizedRequirements,
|
|
16127
|
-
completeness: partial ? "partial" : "complete",
|
|
16128
|
-
opacity,
|
|
16129
|
-
signals: [...signals].sort()
|
|
16130
|
-
};
|
|
16131
|
-
}
|
|
16132
|
-
var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
|
|
16133
|
-
var SHELL_GLOB_PATTERN = /[*?[]/;
|
|
16134
|
-
function effectChangingEnvironmentSignals(head, env, changedNames) {
|
|
16135
|
-
if (head === "curl" && (env.CURL_HOME || changedNames.has("CURL_HOME") || changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME"))) {
|
|
16136
|
-
return ["egress.curl.environment_config_override"];
|
|
16137
|
-
}
|
|
16138
|
-
if (head === "wget" && (env.WGETRC || changedNames.has("WGETRC") || changedNames.has("HOME"))) {
|
|
16139
|
-
return ["egress.wget.environment_config_override"];
|
|
16140
|
-
}
|
|
16141
|
-
if (head !== "git") {
|
|
16142
|
-
return [];
|
|
16143
|
-
}
|
|
16144
|
-
const hazardousNames = /* @__PURE__ */ new Set([
|
|
16145
|
-
"GIT_ASKPASS",
|
|
16146
|
-
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
16147
|
-
"GIT_CEILING_DIRECTORIES",
|
|
16148
|
-
"GIT_COMMON_DIR",
|
|
16149
|
-
"GIT_CONFIG",
|
|
16150
|
-
"GIT_CONFIG_GLOBAL",
|
|
16151
|
-
"GIT_CONFIG_SYSTEM",
|
|
16152
|
-
"GIT_DIR",
|
|
16153
|
-
"GIT_DISCOVERY_ACROSS_FILESYSTEM",
|
|
16154
|
-
"GIT_EDITOR",
|
|
16155
|
-
"GIT_EXEC_PATH",
|
|
16156
|
-
"GIT_EXTERNAL_DIFF",
|
|
16157
|
-
"GIT_INDEX_FILE",
|
|
16158
|
-
"GIT_NAMESPACE",
|
|
16159
|
-
"GIT_OBJECT_DIRECTORY",
|
|
16160
|
-
"GIT_PAGER",
|
|
16161
|
-
"GIT_PROXY_COMMAND",
|
|
16162
|
-
"GIT_QUARANTINE_PATH",
|
|
16163
|
-
"GIT_SEQUENCE_EDITOR",
|
|
16164
|
-
"GIT_SHALLOW_FILE",
|
|
16165
|
-
"GIT_SSH",
|
|
16166
|
-
"GIT_SSH_COMMAND",
|
|
16167
|
-
"GIT_TEMPLATE_DIR",
|
|
16168
|
-
"GIT_WORK_TREE",
|
|
16169
|
-
"SSH_ASKPASS"
|
|
16170
|
-
]);
|
|
16171
|
-
const overridden = changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME") || Object.entries(env).some(([name, value]) => {
|
|
16172
|
-
if (!value) {
|
|
16173
|
-
return false;
|
|
16174
|
-
}
|
|
16175
|
-
if (hazardousNames.has(name) || /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(name) || /^GIT_TRACE/.test(name)) {
|
|
16176
|
-
return true;
|
|
16177
|
-
}
|
|
16178
|
-
return name === "GIT_CONFIG_COUNT" && value !== "0";
|
|
16244
|
+
return [entry];
|
|
16179
16245
|
});
|
|
16180
|
-
|
|
16246
|
+
const partial = normalizedRequirements.some(
|
|
16247
|
+
(entry) => entry.tag === "indeterminate" || entry.action === "indeterminate"
|
|
16248
|
+
);
|
|
16249
|
+
return {
|
|
16250
|
+
commandRedacted,
|
|
16251
|
+
segmentHead,
|
|
16252
|
+
requirements: normalizedRequirements,
|
|
16253
|
+
completeness: partial ? "partial" : "complete",
|
|
16254
|
+
opacity,
|
|
16255
|
+
signals: [...signals].sort()
|
|
16256
|
+
};
|
|
16181
16257
|
}
|
|
16182
16258
|
function dynamicResourceSignal(resource) {
|
|
16183
16259
|
const expanded = (value) => Boolean(value && DYNAMIC_SHELL_VALUE_PATTERN.test(value));
|
|
@@ -16197,362 +16273,502 @@ function dynamicResourceSignal(resource) {
|
|
|
16197
16273
|
return null;
|
|
16198
16274
|
}
|
|
16199
16275
|
}
|
|
16200
|
-
|
|
16201
|
-
|
|
16202
|
-
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
processRequirement(command, "spawn", segment, [signal]),
|
|
16212
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [signal])
|
|
16213
|
-
];
|
|
16276
|
+
|
|
16277
|
+
// src/core/effect-ir/shell-lower.ts
|
|
16278
|
+
var MAX_LOWER_DEPTH = 8;
|
|
16279
|
+
function lowerShellEffectPlan(params) {
|
|
16280
|
+
const context = { ...params, depth: 0 };
|
|
16281
|
+
const segments = lowerTopLevelSegments(params.command, context);
|
|
16282
|
+
return buildShellEffectPlan({
|
|
16283
|
+
inputFingerprint: params.inputFingerprint,
|
|
16284
|
+
segments,
|
|
16285
|
+
signals: pipeToShell(params.command) ? ["pipe_to_shell"] : []
|
|
16286
|
+
});
|
|
16214
16287
|
}
|
|
16215
|
-
function
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16288
|
+
function lowerTopLevelSegments(command, context) {
|
|
16289
|
+
const commands = splitStructuralShellSegments(command);
|
|
16290
|
+
if (commands.length === 0 && command.trim()) {
|
|
16291
|
+
commands.push(command.trim());
|
|
16292
|
+
}
|
|
16293
|
+
const pipedToShell = pipeToShell(command);
|
|
16294
|
+
const lowered = [];
|
|
16295
|
+
let cwd = context.cwd;
|
|
16296
|
+
let cwdKnown = true;
|
|
16297
|
+
let inferredEnv = { ...context.env };
|
|
16298
|
+
for (const segment of commands) {
|
|
16299
|
+
let result = lowerSegment(segment, {
|
|
16300
|
+
...context,
|
|
16301
|
+
cwd,
|
|
16302
|
+
env: inferredEnv,
|
|
16303
|
+
command: segment,
|
|
16304
|
+
depth: context.depth,
|
|
16305
|
+
inputFingerprint: context.inputFingerprint,
|
|
16306
|
+
...pipedToShell && isShellHead(parseSegment(segment).head) ? { pipeToShellSegment: true } : {}
|
|
16307
|
+
});
|
|
16308
|
+
if (!cwdKnown) {
|
|
16309
|
+
const requiresCwd = result.requirements.some(requiresKnownCwd);
|
|
16310
|
+
const requirements = [...result.requirements];
|
|
16311
|
+
if (requiresCwd) {
|
|
16312
|
+
requirements.push(
|
|
16313
|
+
requirement2(
|
|
16314
|
+
"indeterminate",
|
|
16315
|
+
"indeterminate",
|
|
16316
|
+
{ kind: "unknown" },
|
|
16317
|
+
result.commandRedacted,
|
|
16318
|
+
["shell.cwd_unknown"]
|
|
16319
|
+
)
|
|
16320
|
+
);
|
|
16321
|
+
}
|
|
16322
|
+
result = {
|
|
16323
|
+
...result,
|
|
16324
|
+
requirements,
|
|
16325
|
+
...requiresCwd ? {
|
|
16326
|
+
completeness: "partial",
|
|
16327
|
+
opacity: joinEffectOpacity(result.opacity, "opaque")
|
|
16328
|
+
} : {},
|
|
16329
|
+
signals: [.../* @__PURE__ */ new Set([...result.signals, "shell.cwd_unknown"])]
|
|
16330
|
+
};
|
|
16331
|
+
}
|
|
16332
|
+
lowered.push(result);
|
|
16333
|
+
if (!inferredEnv.DATABASE_URL && startsLocalPostgresService(segment)) {
|
|
16334
|
+
inferredEnv = {
|
|
16335
|
+
...inferredEnv,
|
|
16336
|
+
DATABASE_URL: "postgresql://127.0.0.1:5432/local"
|
|
16337
|
+
};
|
|
16338
|
+
}
|
|
16339
|
+
const nextCwd = resolveCdTransition(segment, cwd);
|
|
16340
|
+
if (nextCwd) {
|
|
16341
|
+
cwd = nextCwd.cwd;
|
|
16342
|
+
cwdKnown = nextCwd.known;
|
|
16343
|
+
}
|
|
16344
|
+
}
|
|
16345
|
+
if (commands.length > 1 && /[\r\n]/.test(command) && lowered.some(
|
|
16346
|
+
(segment) => segment.requirements.some((entry) => entry.action === "network.connect")
|
|
16347
|
+
)) {
|
|
16348
|
+
lowered.push(
|
|
16349
|
+
shellSegment(
|
|
16350
|
+
"[multiline network boundary]",
|
|
16351
|
+
"shell-boundary",
|
|
16352
|
+
[
|
|
16353
|
+
requirement2(
|
|
16354
|
+
"indeterminate",
|
|
16355
|
+
"indeterminate",
|
|
16356
|
+
{ kind: "unknown" },
|
|
16357
|
+
"[multiline network boundary]",
|
|
16358
|
+
["shell.multiline_network_boundary"]
|
|
16359
|
+
)
|
|
16360
|
+
],
|
|
16361
|
+
"opaque",
|
|
16362
|
+
/* @__PURE__ */ new Set(["shell.multiline_network_boundary"])
|
|
16227
16363
|
)
|
|
16228
16364
|
);
|
|
16229
16365
|
}
|
|
16366
|
+
return lowered;
|
|
16230
16367
|
}
|
|
16231
|
-
function
|
|
16232
|
-
|
|
16368
|
+
function lowerSegment(command, context) {
|
|
16369
|
+
const commandRedacted = redactCommand(command);
|
|
16370
|
+
const lexed = lexShell(command);
|
|
16371
|
+
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
16372
|
+
const environment = extractEnvironment(rawTokens, context.env);
|
|
16373
|
+
const env = environment.env;
|
|
16374
|
+
const parsed = parseSegment(command);
|
|
16375
|
+
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
16376
|
+
const tokens = stripRedirects(
|
|
16377
|
+
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
16378
|
+
).map((token) => expandKnownVariables(token, env));
|
|
16379
|
+
const decoderTokens = alignStructuredTokens(
|
|
16380
|
+
stripStructuredRedirects(lexed.tokens),
|
|
16381
|
+
stripRedirects(parsedTokens)
|
|
16382
|
+
);
|
|
16383
|
+
const head = path48.basename(tokens[0] ?? parsed.head);
|
|
16384
|
+
let opacity = segmentOpacity(command);
|
|
16385
|
+
const signals = /* @__PURE__ */ new Set();
|
|
16386
|
+
const requirements = [];
|
|
16387
|
+
if (!lexed.complete) {
|
|
16233
16388
|
requirements.push(
|
|
16234
|
-
requirement2("
|
|
16235
|
-
"
|
|
16389
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16390
|
+
"shell.grammar_incomplete"
|
|
16236
16391
|
])
|
|
16237
16392
|
);
|
|
16393
|
+
signals.add("shell.grammar_incomplete");
|
|
16394
|
+
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
16238
16395
|
}
|
|
16239
|
-
|
|
16240
|
-
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
case "cat":
|
|
16249
|
-
case "head":
|
|
16250
|
-
case "tail":
|
|
16251
|
-
case "less":
|
|
16252
|
-
case "stat":
|
|
16253
|
-
case "file":
|
|
16254
|
-
case "du":
|
|
16255
|
-
case "wc":
|
|
16256
|
-
return args.filter((arg) => arg && !arg.startsWith("-"));
|
|
16257
|
-
case "grep":
|
|
16258
|
-
case "rg":
|
|
16259
|
-
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
16260
|
-
case "jq":
|
|
16261
|
-
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
16262
|
-
default:
|
|
16263
|
-
return null;
|
|
16264
|
-
}
|
|
16265
|
-
}
|
|
16266
|
-
function findReadOperands(args) {
|
|
16267
|
-
const mutatingPrimaries = /* @__PURE__ */ new Set([
|
|
16268
|
-
"-delete",
|
|
16269
|
-
"-exec",
|
|
16270
|
-
"-execdir",
|
|
16271
|
-
"-fls",
|
|
16272
|
-
"-fprint",
|
|
16273
|
-
"-fprintf",
|
|
16274
|
-
"-ok",
|
|
16275
|
-
"-okdir"
|
|
16276
|
-
]);
|
|
16277
|
-
if (args.some(
|
|
16278
|
-
(arg) => mutatingPrimaries.has(arg) || [...mutatingPrimaries].some((primary) => arg.startsWith(`${primary}=`))
|
|
16279
|
-
)) {
|
|
16280
|
-
return null;
|
|
16281
|
-
}
|
|
16282
|
-
const paths = [];
|
|
16283
|
-
for (const arg of args) {
|
|
16284
|
-
if (arg.startsWith("-") || arg === "!" || arg === "(") {
|
|
16285
|
-
break;
|
|
16286
|
-
}
|
|
16287
|
-
paths.push(arg);
|
|
16288
|
-
}
|
|
16289
|
-
return paths.length > 0 ? paths : ["."];
|
|
16290
|
-
}
|
|
16291
|
-
function filesystemWriteOperands(head, args) {
|
|
16292
|
-
const positional = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
16293
|
-
switch (head) {
|
|
16294
|
-
case "touch":
|
|
16295
|
-
case "mkdir":
|
|
16296
|
-
case "rm":
|
|
16297
|
-
case "truncate":
|
|
16298
|
-
case "chmod":
|
|
16299
|
-
return positional;
|
|
16300
|
-
case "cp":
|
|
16301
|
-
case "mv":
|
|
16302
|
-
return positional.length > 0 ? [positional[positional.length - 1] ?? ""] : [];
|
|
16303
|
-
case "tee":
|
|
16304
|
-
return positional;
|
|
16305
|
-
default:
|
|
16306
|
-
return null;
|
|
16396
|
+
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
16397
|
+
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
16398
|
+
if (environment.malformed) {
|
|
16399
|
+
requirements.push(
|
|
16400
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16401
|
+
"shell.env_wrapper_incomplete"
|
|
16402
|
+
])
|
|
16403
|
+
);
|
|
16404
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16307
16405
|
}
|
|
16308
|
-
|
|
16309
|
-
|
|
16310
|
-
|
|
16311
|
-
|
|
16312
|
-
|
|
16313
|
-
|
|
16314
|
-
|
|
16315
|
-
|
|
16316
|
-
}
|
|
16317
|
-
if (flagsWithValues.has(arg)) {
|
|
16318
|
-
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
16319
|
-
return false;
|
|
16320
|
-
}
|
|
16321
|
-
index += 1;
|
|
16322
|
-
continue;
|
|
16323
|
-
}
|
|
16324
|
-
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)) {
|
|
16325
|
-
continue;
|
|
16326
|
-
}
|
|
16327
|
-
return false;
|
|
16406
|
+
if (parsed.encounteredXargs) {
|
|
16407
|
+
requirements.push(
|
|
16408
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16409
|
+
"shell.xargs_stdin_dynamic"
|
|
16410
|
+
])
|
|
16411
|
+
);
|
|
16412
|
+
signals.add("shell.xargs_stdin_dynamic");
|
|
16413
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16328
16414
|
}
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
|
|
16338
|
-
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
return false;
|
|
16351
|
-
}
|
|
16352
|
-
index += 1;
|
|
16353
|
-
continue;
|
|
16415
|
+
if (context.depth > MAX_LOWER_DEPTH) {
|
|
16416
|
+
requirements.push(
|
|
16417
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16418
|
+
"shell.lower_depth_exceeded"
|
|
16419
|
+
])
|
|
16420
|
+
);
|
|
16421
|
+
return shellSegment(
|
|
16422
|
+
commandRedacted,
|
|
16423
|
+
head,
|
|
16424
|
+
requirements,
|
|
16425
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16426
|
+
signals
|
|
16427
|
+
);
|
|
16428
|
+
}
|
|
16429
|
+
const packageExec = peelPackageExecArgv(tokens);
|
|
16430
|
+
if (packageExec) {
|
|
16431
|
+
requirements.push(
|
|
16432
|
+
...decodePackageExec(packageExec, context.cwd, context.repoRoot, commandRedacted)
|
|
16433
|
+
);
|
|
16434
|
+
for (const signal of packageExec.signals) {
|
|
16435
|
+
signals.add(signal);
|
|
16354
16436
|
}
|
|
16355
|
-
if (
|
|
16356
|
-
|
|
16437
|
+
if (packageExec.opaque) {
|
|
16438
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16357
16439
|
}
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
const
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
}
|
|
16375
|
-
break;
|
|
16440
|
+
const innerRecipe = packageExecInnerIsMetadata(packageExec) ? null : innerRecipeFromPeel(packageExec);
|
|
16441
|
+
if (innerRecipe) {
|
|
16442
|
+
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
16443
|
+
...context,
|
|
16444
|
+
command: innerRecipe,
|
|
16445
|
+
env,
|
|
16446
|
+
depth: context.depth + 1
|
|
16447
|
+
});
|
|
16448
|
+
for (const nestedSegment of nested) {
|
|
16449
|
+
requirements.push(
|
|
16450
|
+
...nestedSegment.requirements.map(
|
|
16451
|
+
(entry) => withInnerProvenance(entry, innerRecipe, packageExec.launcher, commandRedacted)
|
|
16452
|
+
)
|
|
16453
|
+
);
|
|
16454
|
+
for (const signal of nestedSegment.signals) {
|
|
16455
|
+
signals.add(signal);
|
|
16376
16456
|
}
|
|
16377
|
-
|
|
16378
|
-
break;
|
|
16379
|
-
}
|
|
16380
|
-
if (valid) {
|
|
16381
|
-
continue;
|
|
16457
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16382
16458
|
}
|
|
16383
16459
|
}
|
|
16384
|
-
return
|
|
16385
|
-
}
|
|
16386
|
-
return true;
|
|
16387
|
-
}
|
|
16388
|
-
function validFilesystemTest(head, args) {
|
|
16389
|
-
const operands = head === "[" && args.at(-1) === "]" ? args.slice(0, -1) : args;
|
|
16390
|
-
if (head === "[" && args.at(-1) !== "]") {
|
|
16391
|
-
return false;
|
|
16460
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16392
16461
|
}
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
|
|
16405
|
-
|
|
16462
|
+
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
16463
|
+
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
16464
|
+
requirements.push(
|
|
16465
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
16466
|
+
"shell.recursive_wrapper",
|
|
16467
|
+
"dynamic_shell_evaluation"
|
|
16468
|
+
])
|
|
16469
|
+
);
|
|
16470
|
+
if (recursive.script !== "") {
|
|
16471
|
+
const nested = lowerTopLevelSegments(recursive.script, {
|
|
16472
|
+
...context,
|
|
16473
|
+
command: recursive.script,
|
|
16474
|
+
env,
|
|
16475
|
+
depth: context.depth + 1
|
|
16476
|
+
});
|
|
16477
|
+
for (const nestedSegment of nested) {
|
|
16478
|
+
requirements.push(
|
|
16479
|
+
...nestedSegment.requirements.map(
|
|
16480
|
+
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
16481
|
+
)
|
|
16482
|
+
);
|
|
16483
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
16406
16484
|
}
|
|
16407
|
-
index += 1;
|
|
16408
|
-
continue;
|
|
16409
16485
|
}
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16486
|
+
signals.add("shell.recursive_wrapper");
|
|
16487
|
+
signals.add("dynamic_shell_evaluation");
|
|
16488
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
16489
|
+
}
|
|
16490
|
+
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
16491
|
+
const recursiveSignals = [
|
|
16492
|
+
recursive.signal,
|
|
16493
|
+
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
16494
|
+
];
|
|
16495
|
+
requirements.push(
|
|
16496
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
16497
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16498
|
+
...recursiveSignals
|
|
16499
|
+
])
|
|
16500
|
+
);
|
|
16501
|
+
for (const signal of recursiveSignals) signals.add(signal);
|
|
16502
|
+
return shellSegment(
|
|
16503
|
+
commandRedacted,
|
|
16504
|
+
head,
|
|
16505
|
+
requirements,
|
|
16506
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16507
|
+
signals
|
|
16508
|
+
);
|
|
16509
|
+
}
|
|
16510
|
+
const compose = decodeDockerComposeRun(decoderTokens);
|
|
16511
|
+
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
16512
|
+
requirements.push(
|
|
16513
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
16514
|
+
);
|
|
16515
|
+
if (compose.script !== "") {
|
|
16516
|
+
const nested = lowerTopLevelSegments(compose.script, {
|
|
16517
|
+
...context,
|
|
16518
|
+
command: compose.script,
|
|
16519
|
+
env,
|
|
16520
|
+
depth: context.depth + 1
|
|
16521
|
+
});
|
|
16522
|
+
for (const nestedSegment of nested) {
|
|
16523
|
+
requirements.push(
|
|
16524
|
+
...nestedSegment.requirements.map(
|
|
16525
|
+
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
16526
|
+
)
|
|
16527
|
+
);
|
|
16528
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
16529
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16413
16530
|
}
|
|
16414
|
-
continue;
|
|
16415
16531
|
}
|
|
16416
|
-
|
|
16532
|
+
signals.add("process.docker_compose_run");
|
|
16533
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
16417
16534
|
}
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
"
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
|
|
16433
|
-
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
|
|
16442
|
-
}
|
|
16443
|
-
|
|
16444
|
-
|
|
16445
|
-
|
|
16535
|
+
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
16536
|
+
requirements.push(
|
|
16537
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
16538
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16539
|
+
compose.signal
|
|
16540
|
+
])
|
|
16541
|
+
);
|
|
16542
|
+
signals.add("process.docker_compose_run");
|
|
16543
|
+
signals.add(compose.signal);
|
|
16544
|
+
return shellSegment(
|
|
16545
|
+
commandRedacted,
|
|
16546
|
+
head,
|
|
16547
|
+
requirements,
|
|
16548
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16549
|
+
signals
|
|
16550
|
+
);
|
|
16551
|
+
}
|
|
16552
|
+
const launcher = resolveLauncherRecipe({
|
|
16553
|
+
tokens,
|
|
16554
|
+
cwd: context.cwd,
|
|
16555
|
+
repoRoot: context.repoRoot,
|
|
16556
|
+
depth: context.depth
|
|
16557
|
+
});
|
|
16558
|
+
if (launcher) {
|
|
16559
|
+
signals.add(`launcher.${launcher.reason}`);
|
|
16560
|
+
requirements.push(
|
|
16561
|
+
requirement2(
|
|
16562
|
+
"process.exec",
|
|
16563
|
+
"process.exec",
|
|
16564
|
+
{ kind: "executable", command: head, operation: "spawn" },
|
|
16565
|
+
commandRedacted,
|
|
16566
|
+
["launcher.invoke"]
|
|
16567
|
+
)
|
|
16568
|
+
);
|
|
16569
|
+
for (const recipe of launcher.recipes) {
|
|
16570
|
+
const nested = lowerTopLevelSegments(recipe, {
|
|
16571
|
+
...context,
|
|
16572
|
+
command: recipe,
|
|
16573
|
+
env,
|
|
16574
|
+
depth: context.depth + 1
|
|
16575
|
+
});
|
|
16576
|
+
for (const nestedSegment of nested) {
|
|
16577
|
+
requirements.push(
|
|
16578
|
+
...nestedSegment.requirements.map(
|
|
16579
|
+
(entry) => withInnerProvenance(entry, recipe, head, commandRedacted)
|
|
16580
|
+
)
|
|
16581
|
+
);
|
|
16582
|
+
for (const signal of nestedSegment.signals) {
|
|
16583
|
+
signals.add(signal);
|
|
16584
|
+
}
|
|
16585
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16446
16586
|
}
|
|
16447
|
-
index += 1;
|
|
16448
|
-
continue;
|
|
16449
16587
|
}
|
|
16450
|
-
if (
|
|
16451
|
-
|
|
16588
|
+
if (launcher.opaque || launcher.recipes.length === 0) {
|
|
16589
|
+
requirements.push(
|
|
16590
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16591
|
+
`launcher.${launcher.reason}`
|
|
16592
|
+
])
|
|
16593
|
+
);
|
|
16594
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16452
16595
|
}
|
|
16453
|
-
|
|
16454
|
-
|
|
16596
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16597
|
+
}
|
|
16598
|
+
const egress = decodeEgressEffects({
|
|
16599
|
+
tokens,
|
|
16600
|
+
cwd: context.cwd,
|
|
16601
|
+
segment: commandRedacted
|
|
16602
|
+
});
|
|
16603
|
+
if (egress) {
|
|
16604
|
+
requirements.push(...egress);
|
|
16605
|
+
for (const signal of egress.flatMap((entry) => entry.evidence.signals)) {
|
|
16606
|
+
signals.add(signal);
|
|
16455
16607
|
}
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16608
|
+
} else {
|
|
16609
|
+
const git = decodeGitEffects({
|
|
16610
|
+
tokens,
|
|
16611
|
+
cwd: context.cwd,
|
|
16612
|
+
repoRoot: context.repoRoot,
|
|
16613
|
+
segment: commandRedacted
|
|
16614
|
+
});
|
|
16615
|
+
if (git) {
|
|
16616
|
+
requirements.push(...git);
|
|
16617
|
+
for (const signal of git.flatMap((entry) => entry.evidence.signals)) {
|
|
16618
|
+
signals.add(signal);
|
|
16460
16619
|
}
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16620
|
+
} else {
|
|
16621
|
+
const processRequirements = decodeProcessOrFilesystem({
|
|
16622
|
+
tokens,
|
|
16623
|
+
head,
|
|
16624
|
+
env,
|
|
16625
|
+
cwd: context.cwd,
|
|
16626
|
+
repoRoot: context.repoRoot,
|
|
16627
|
+
segment: commandRedacted
|
|
16628
|
+
});
|
|
16629
|
+
if (isGrammarUnknownOnly(processRequirements, head)) {
|
|
16630
|
+
const argvDelegate = peelArgvDelegateArgv(tokens);
|
|
16631
|
+
if (argvDelegate && !argvDelegate.opaque && shouldApplyArgvDelegate(head, argvDelegate.innerTokens, context.depth)) {
|
|
16632
|
+
const innerRecipe = innerRecipeFromArgvDelegate(argvDelegate);
|
|
16633
|
+
if (innerRecipe) {
|
|
16634
|
+
requirements.push(
|
|
16635
|
+
processRequirement(head, "inspect", commandRedacted, [
|
|
16636
|
+
"process.argv_delegate",
|
|
16637
|
+
...argvDelegate.signals
|
|
16638
|
+
])
|
|
16639
|
+
);
|
|
16640
|
+
for (const signal of argvDelegate.signals) {
|
|
16641
|
+
signals.add(signal);
|
|
16642
|
+
}
|
|
16643
|
+
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
16644
|
+
...context,
|
|
16645
|
+
command: innerRecipe,
|
|
16646
|
+
env,
|
|
16647
|
+
depth: context.depth + 1
|
|
16648
|
+
});
|
|
16649
|
+
for (const nestedSegment of nested) {
|
|
16650
|
+
requirements.push(
|
|
16651
|
+
...nestedSegment.requirements.map(
|
|
16652
|
+
(entry) => withInnerProvenance(entry, innerRecipe, head, commandRedacted)
|
|
16653
|
+
)
|
|
16654
|
+
);
|
|
16655
|
+
for (const signal of nestedSegment.signals) {
|
|
16656
|
+
signals.add(signal);
|
|
16657
|
+
}
|
|
16658
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16659
|
+
}
|
|
16660
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16661
|
+
}
|
|
16662
|
+
}
|
|
16663
|
+
if (argvDelegate?.opaque) {
|
|
16664
|
+
requirements.push(
|
|
16665
|
+
processRequirement(head, "spawn", commandRedacted, [
|
|
16666
|
+
"process.argv_delegate",
|
|
16667
|
+
argvDelegate.reason,
|
|
16668
|
+
...argvDelegate.signals
|
|
16669
|
+
]),
|
|
16670
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16671
|
+
argvDelegate.reason,
|
|
16672
|
+
"process.argv_delegate_opaque"
|
|
16673
|
+
])
|
|
16674
|
+
);
|
|
16675
|
+
for (const signal of argvDelegate.signals) {
|
|
16676
|
+
signals.add(signal);
|
|
16677
|
+
}
|
|
16678
|
+
signals.add("process.argv_delegate_opaque");
|
|
16679
|
+
return shellSegment(
|
|
16680
|
+
commandRedacted,
|
|
16681
|
+
head,
|
|
16682
|
+
requirements,
|
|
16683
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16684
|
+
signals
|
|
16685
|
+
);
|
|
16686
|
+
}
|
|
16687
|
+
}
|
|
16688
|
+
requirements.push(...processRequirements);
|
|
16470
16689
|
}
|
|
16471
|
-
script = arg;
|
|
16472
|
-
break;
|
|
16473
|
-
}
|
|
16474
|
-
return syntaxOnly ? script : null;
|
|
16475
|
-
}
|
|
16476
|
-
function isOptionToken(value) {
|
|
16477
|
-
return value.startsWith("-") || value.startsWith("+");
|
|
16478
|
-
}
|
|
16479
|
-
function databaseEndpoint(raw) {
|
|
16480
|
-
if (!raw || raw.includes("$")) {
|
|
16481
|
-
return null;
|
|
16482
16690
|
}
|
|
16483
|
-
|
|
16484
|
-
|
|
16485
|
-
|
|
16486
|
-
|
|
16691
|
+
const environmentSignals = effectChangingEnvironmentSignals(head, env, environment.changedNames);
|
|
16692
|
+
if (environmentSignals.length > 0) {
|
|
16693
|
+
requirements.push(
|
|
16694
|
+
requirement2(
|
|
16695
|
+
"indeterminate",
|
|
16696
|
+
"indeterminate",
|
|
16697
|
+
{ kind: "unknown" },
|
|
16698
|
+
commandRedacted,
|
|
16699
|
+
environmentSignals
|
|
16700
|
+
)
|
|
16701
|
+
);
|
|
16702
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16703
|
+
for (const signal of environmentSignals) {
|
|
16704
|
+
signals.add(signal);
|
|
16487
16705
|
}
|
|
16488
|
-
return {
|
|
16489
|
-
host: url.hostname.toLowerCase(),
|
|
16490
|
-
protocol: url.protocol.slice(0, -1),
|
|
16491
|
-
...url.port ? { port: Number(url.port) } : {}
|
|
16492
|
-
};
|
|
16493
|
-
} catch {
|
|
16494
|
-
return null;
|
|
16495
16706
|
}
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16707
|
+
if (context.pipeToShellSegment) {
|
|
16708
|
+
signals.add("pipe_to_shell");
|
|
16709
|
+
ensureRequirement(
|
|
16710
|
+
requirements,
|
|
16711
|
+
requirement2(
|
|
16712
|
+
"process.exec",
|
|
16713
|
+
"process.exec",
|
|
16714
|
+
{ kind: "executable", command: head || "sh", operation: "spawn" },
|
|
16715
|
+
commandRedacted,
|
|
16716
|
+
["pipe_to_shell"]
|
|
16717
|
+
)
|
|
16718
|
+
);
|
|
16719
|
+
ensureRequirement(
|
|
16720
|
+
requirements,
|
|
16721
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16722
|
+
"pipe_to_shell"
|
|
16723
|
+
])
|
|
16724
|
+
);
|
|
16725
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16500
16726
|
}
|
|
16501
|
-
if (
|
|
16502
|
-
|
|
16727
|
+
if (opacity === "unparseable" || opacity === "opaque") {
|
|
16728
|
+
ensureRequirement(
|
|
16729
|
+
requirements,
|
|
16730
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16731
|
+
`shell.${opacity}`
|
|
16732
|
+
])
|
|
16733
|
+
);
|
|
16503
16734
|
}
|
|
16504
|
-
return
|
|
16505
|
-
}
|
|
16506
|
-
function isShellHead(head) {
|
|
16507
|
-
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
16508
|
-
}
|
|
16509
|
-
function pipeToShell(command) {
|
|
16510
|
-
return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
|
|
16511
|
-
}
|
|
16512
|
-
function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegment) {
|
|
16513
|
-
const provenance = {
|
|
16514
|
-
...requirementValue.provenance,
|
|
16515
|
-
segment: outerSegment,
|
|
16516
|
-
innerCommand: requirementValue.provenance.innerCommand ?? innerCommand,
|
|
16517
|
-
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
16518
|
-
};
|
|
16519
|
-
const launcherProvenance = {
|
|
16520
|
-
segment: outerSegment,
|
|
16521
|
-
innerCommand,
|
|
16522
|
-
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
16523
|
-
};
|
|
16524
|
-
return withProvenances(requirementValue, provenance, launcherProvenance);
|
|
16525
|
-
}
|
|
16526
|
-
function withProvenances(requirementValue, provenance, contributing) {
|
|
16527
|
-
const provenances = [
|
|
16528
|
-
...requirementValue.provenances ?? [requirementValue.provenance],
|
|
16529
|
-
contributing,
|
|
16530
|
-
provenance
|
|
16531
|
-
].filter(
|
|
16532
|
-
(candidate, index, all) => all.findIndex((entry) => JSON.stringify(entry) === JSON.stringify(candidate)) === index
|
|
16533
|
-
);
|
|
16534
|
-
return { ...requirementValue, provenance, provenances };
|
|
16735
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16535
16736
|
}
|
|
16536
|
-
function
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16737
|
+
function addSubstitutionEffects(requirements, command, context, segment, signals) {
|
|
16738
|
+
const inners = structuralSubstitutionInners(command);
|
|
16739
|
+
for (const inner of inners) {
|
|
16740
|
+
signals.add("command_substitution");
|
|
16741
|
+
if (context.depth >= MAX_LOWER_DEPTH) {
|
|
16742
|
+
requirements.push(
|
|
16743
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16744
|
+
"shell.substitution_depth_exceeded"
|
|
16745
|
+
])
|
|
16746
|
+
);
|
|
16747
|
+
continue;
|
|
16748
|
+
}
|
|
16749
|
+
const nestedSegments = lowerTopLevelSegments(inner, {
|
|
16750
|
+
...context,
|
|
16751
|
+
command: inner,
|
|
16752
|
+
depth: context.depth + 1
|
|
16753
|
+
});
|
|
16754
|
+
for (const nested of nestedSegments) {
|
|
16755
|
+
requirements.push(
|
|
16756
|
+
...nested.requirements.map((entry) => {
|
|
16757
|
+
const outerProvenance = {
|
|
16758
|
+
segment,
|
|
16759
|
+
innerCommand: inner
|
|
16760
|
+
};
|
|
16761
|
+
const provenance = {
|
|
16762
|
+
...entry.provenance,
|
|
16763
|
+
segment,
|
|
16764
|
+
innerCommand: entry.provenance.innerCommand ?? inner
|
|
16765
|
+
};
|
|
16766
|
+
return withProvenances(entry, provenance, outerProvenance);
|
|
16767
|
+
})
|
|
16768
|
+
);
|
|
16769
|
+
}
|
|
16541
16770
|
}
|
|
16542
16771
|
}
|
|
16543
|
-
function requirement2(tag, action, resource, segment, signals) {
|
|
16544
|
-
return {
|
|
16545
|
-
tag,
|
|
16546
|
-
action,
|
|
16547
|
-
resource,
|
|
16548
|
-
evidence: {
|
|
16549
|
-
level: tag === "indeterminate" ? "indeterminate" : "certain",
|
|
16550
|
-
signals: [...new Set(signals)].sort(),
|
|
16551
|
-
basis: ["shell_semantic_lowering"]
|
|
16552
|
-
},
|
|
16553
|
-
provenance: { segment }
|
|
16554
|
-
};
|
|
16555
|
-
}
|
|
16556
16772
|
|
|
16557
16773
|
// src/core/verdict/verdict.ts
|
|
16558
16774
|
init_path_utils();
|
|
@@ -16772,6 +16988,13 @@ function policyAuth(options) {
|
|
|
16772
16988
|
function scrubPayload(value, options) {
|
|
16773
16989
|
return scrubValue(value, options.scrubOptions);
|
|
16774
16990
|
}
|
|
16991
|
+
function fingerprintPayload(payload, options) {
|
|
16992
|
+
const toolInput = fingerprintToolInputSource(payload);
|
|
16993
|
+
if (Object.keys(toolInput).length > 0) {
|
|
16994
|
+
return toolInput;
|
|
16995
|
+
}
|
|
16996
|
+
return scrubPayload(payload.tool_input ?? {}, options);
|
|
16997
|
+
}
|
|
16775
16998
|
function extractFilePath(payload) {
|
|
16776
16999
|
const toolInput = payload.tool_input;
|
|
16777
17000
|
if (!toolInput || typeof toolInput !== "object") {
|
|
@@ -16946,11 +17169,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16946
17169
|
verdict: "deny_pending_approval",
|
|
16947
17170
|
reason: "tool_shell_missing_command",
|
|
16948
17171
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
16949
|
-
fingerprint: toolFingerprint(
|
|
16950
|
-
toolName,
|
|
16951
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
16952
|
-
repoRoot
|
|
16953
|
-
),
|
|
17172
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
16954
17173
|
assessment: {
|
|
16955
17174
|
reversibility: "irreversible",
|
|
16956
17175
|
external: false,
|
|
@@ -16964,11 +17183,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16964
17183
|
verdict: "allow_flagged",
|
|
16965
17184
|
reason: "tool_shell_missing_command",
|
|
16966
17185
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
16967
|
-
fingerprint: toolFingerprint(
|
|
16968
|
-
toolName,
|
|
16969
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
16970
|
-
repoRoot
|
|
16971
|
-
),
|
|
17186
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
16972
17187
|
assessment: {
|
|
16973
17188
|
reversibility: "recoverable_with_cost",
|
|
16974
17189
|
external: false,
|
|
@@ -16992,11 +17207,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16992
17207
|
verdict: "deny_pending_approval",
|
|
16993
17208
|
reason: "file_mutation_missing_path",
|
|
16994
17209
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
16995
|
-
fingerprint: toolFingerprint(
|
|
16996
|
-
toolName,
|
|
16997
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
16998
|
-
repoRoot
|
|
16999
|
-
),
|
|
17210
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17000
17211
|
assessment: {
|
|
17001
17212
|
reversibility: "irreversible",
|
|
17002
17213
|
external: false,
|
|
@@ -17010,11 +17221,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17010
17221
|
verdict: "allow_flagged",
|
|
17011
17222
|
reason: "file_mutation_missing_path",
|
|
17012
17223
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17013
|
-
fingerprint: toolFingerprint(
|
|
17014
|
-
toolName,
|
|
17015
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17016
|
-
repoRoot
|
|
17017
|
-
),
|
|
17224
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17018
17225
|
assessment: {
|
|
17019
17226
|
reversibility: "recoverable_with_cost",
|
|
17020
17227
|
external: false,
|
|
@@ -17025,7 +17232,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17025
17232
|
};
|
|
17026
17233
|
}
|
|
17027
17234
|
const signals = [];
|
|
17028
|
-
const resolvedPath =
|
|
17235
|
+
const resolvedPath = path49.isAbsolute(filePath) ? filePath : path49.resolve(cwd, filePath);
|
|
17029
17236
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17030
17237
|
if (hitsProtectedRoot) {
|
|
17031
17238
|
signals.push("control_plane_path");
|
|
@@ -17164,11 +17371,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17164
17371
|
verdict: "deny_pending_approval",
|
|
17165
17372
|
reason: "apply_patch_missing_path",
|
|
17166
17373
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17167
|
-
fingerprint: toolFingerprint(
|
|
17168
|
-
toolName,
|
|
17169
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17170
|
-
repoRoot
|
|
17171
|
-
),
|
|
17374
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17172
17375
|
assessment: {
|
|
17173
17376
|
reversibility: "irreversible",
|
|
17174
17377
|
external: false,
|
|
@@ -17182,11 +17385,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17182
17385
|
verdict: "allow_flagged",
|
|
17183
17386
|
reason: "apply_patch_missing_path",
|
|
17184
17387
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17185
|
-
fingerprint: toolFingerprint(
|
|
17186
|
-
toolName,
|
|
17187
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17188
|
-
repoRoot
|
|
17189
|
-
),
|
|
17388
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17190
17389
|
assessment: {
|
|
17191
17390
|
reversibility: "recoverable_with_cost",
|
|
17192
17391
|
external: false,
|
|
@@ -17217,11 +17416,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17217
17416
|
verdict: "allow_flagged",
|
|
17218
17417
|
reason: sawDelete ? "file_delete" : "file_mutation",
|
|
17219
17418
|
summary: targets.map((target) => target.path).join(", "),
|
|
17220
|
-
fingerprint: toolFingerprint(
|
|
17221
|
-
toolName,
|
|
17222
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17223
|
-
repoRoot
|
|
17224
|
-
),
|
|
17419
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17225
17420
|
assessment: {
|
|
17226
17421
|
reversibility: "recoverable_with_cost",
|
|
17227
17422
|
external: false,
|
|
@@ -17235,11 +17430,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17235
17430
|
verdict: "allow",
|
|
17236
17431
|
reason: "unclassified_tool",
|
|
17237
17432
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17238
|
-
fingerprint: toolFingerprint(
|
|
17239
|
-
toolName,
|
|
17240
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17241
|
-
repoRoot
|
|
17242
|
-
),
|
|
17433
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17243
17434
|
assessment: {
|
|
17244
17435
|
reversibility: "reversible",
|
|
17245
17436
|
external: false,
|
|
@@ -17627,7 +17818,7 @@ function hashDecisionConfig(config) {
|
|
|
17627
17818
|
init_fingerprint2();
|
|
17628
17819
|
|
|
17629
17820
|
// src/version.ts
|
|
17630
|
-
var PACKAGE_VERSION = "0.9.
|
|
17821
|
+
var PACKAGE_VERSION = "0.9.4";
|
|
17631
17822
|
|
|
17632
17823
|
// src/runtime-provenance.ts
|
|
17633
17824
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -17702,7 +17893,7 @@ init_path_utils();
|
|
|
17702
17893
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17703
17894
|
import { existsSync as existsSync15 } from "node:fs";
|
|
17704
17895
|
import { mkdir as mkdir11, readdir as readdir3, readFile as readFile12, rename as rename3, rm as rm6 } from "node:fs/promises";
|
|
17705
|
-
import
|
|
17896
|
+
import path54 from "node:path";
|
|
17706
17897
|
|
|
17707
17898
|
// src/core/recovery/artifact-store.ts
|
|
17708
17899
|
init_fingerprint2();
|
|
@@ -17710,7 +17901,7 @@ init_path_utils();
|
|
|
17710
17901
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
17711
17902
|
import { existsSync as existsSync13 } from "node:fs";
|
|
17712
17903
|
import { lstat as lstat7, mkdir as mkdir10, open as open5, readdir as readdir2, readFile as readFile9, rename as rename2, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
|
|
17713
|
-
import
|
|
17904
|
+
import path51 from "node:path";
|
|
17714
17905
|
|
|
17715
17906
|
// src/core/recovery/snapshot-node.ts
|
|
17716
17907
|
init_fingerprint2();
|
|
@@ -17730,25 +17921,25 @@ import {
|
|
|
17730
17921
|
symlink as symlink3,
|
|
17731
17922
|
writeFile as writeFile6
|
|
17732
17923
|
} from "node:fs/promises";
|
|
17733
|
-
import
|
|
17924
|
+
import path50 from "node:path";
|
|
17734
17925
|
var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
|
|
17735
17926
|
function validRecoveryRelativePath(relativePath) {
|
|
17736
|
-
if (!relativePath || relativePath.includes("\0") ||
|
|
17737
|
-
const normalized =
|
|
17738
|
-
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${
|
|
17927
|
+
if (!relativePath || relativePath.includes("\0") || path50.isAbsolute(relativePath)) return false;
|
|
17928
|
+
const normalized = path50.normalize(relativePath);
|
|
17929
|
+
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path50.sep}`);
|
|
17739
17930
|
}
|
|
17740
17931
|
async function assertRecoverySafeTarget(resourceRoot, relativePath) {
|
|
17741
17932
|
if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
|
|
17742
17933
|
const root = canonicalPath(resourceRoot);
|
|
17743
|
-
const target =
|
|
17744
|
-
const relative =
|
|
17745
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
17934
|
+
const target = path50.resolve(root, relativePath);
|
|
17935
|
+
const relative = path50.relative(root, target);
|
|
17936
|
+
if (relative === ".." || relative.startsWith(`..${path50.sep}`) || path50.isAbsolute(relative)) {
|
|
17746
17937
|
throw new Error("recovery_path_escape");
|
|
17747
17938
|
}
|
|
17748
17939
|
let current = root;
|
|
17749
|
-
const parentParts =
|
|
17940
|
+
const parentParts = path50.relative(root, path50.dirname(target)).split(path50.sep).filter(Boolean);
|
|
17750
17941
|
for (const part of parentParts) {
|
|
17751
|
-
current =
|
|
17942
|
+
current = path50.join(current, part);
|
|
17752
17943
|
if (!existsSync12(current)) break;
|
|
17753
17944
|
const info = await lstat6(current);
|
|
17754
17945
|
if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
|
|
@@ -17804,7 +17995,7 @@ async function captureRecoverySnapshot(filePath, options) {
|
|
|
17804
17995
|
let blob;
|
|
17805
17996
|
if (options?.blobDir) {
|
|
17806
17997
|
await mkdir9(options.blobDir, { recursive: true, mode: 448 });
|
|
17807
|
-
const blobPath =
|
|
17998
|
+
const blobPath = path50.join(options.blobDir, hash);
|
|
17808
17999
|
if (!existsSync12(blobPath)) {
|
|
17809
18000
|
await writeFile6(blobPath, content, { mode: 384 });
|
|
17810
18001
|
await fsyncPath(blobPath);
|
|
@@ -17859,7 +18050,7 @@ async function validateRecoverySnapshot(params) {
|
|
|
17859
18050
|
if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
|
|
17860
18051
|
let content;
|
|
17861
18052
|
try {
|
|
17862
|
-
content = await readFile8(
|
|
18053
|
+
content = await readFile8(path50.join(params.artifactDir, record.blob));
|
|
17863
18054
|
} catch {
|
|
17864
18055
|
throw new Error(params.corruptReason);
|
|
17865
18056
|
}
|
|
@@ -17887,13 +18078,13 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
|
|
|
17887
18078
|
]);
|
|
17888
18079
|
var STAGING_STALE_MS = 5 * 6e4;
|
|
17889
18080
|
function checkpointsRoot(stateDir) {
|
|
17890
|
-
return
|
|
18081
|
+
return path51.join(stateDir, "recovery", "checkpoints");
|
|
17891
18082
|
}
|
|
17892
18083
|
function checkpointDir(stateDir, checkpointId) {
|
|
17893
18084
|
if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
|
|
17894
18085
|
throw new Error("invalid_recovery_checkpoint_id");
|
|
17895
18086
|
}
|
|
17896
|
-
return
|
|
18087
|
+
return path51.join(checkpointsRoot(stateDir), checkpointId);
|
|
17897
18088
|
}
|
|
17898
18089
|
async function fsyncPath2(filePath) {
|
|
17899
18090
|
const handle = await open5(filePath, "r");
|
|
@@ -17904,13 +18095,13 @@ async function fsyncPath2(filePath) {
|
|
|
17904
18095
|
}
|
|
17905
18096
|
}
|
|
17906
18097
|
async function atomicWriteJson(filePath, value) {
|
|
17907
|
-
await mkdir10(
|
|
18098
|
+
await mkdir10(path51.dirname(filePath), { recursive: true, mode: 448 });
|
|
17908
18099
|
const temporary = `${filePath}.tmp-${randomUUID4()}`;
|
|
17909
18100
|
await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
|
|
17910
18101
|
`, { mode: 384 });
|
|
17911
18102
|
await fsyncPath2(temporary);
|
|
17912
18103
|
await rename2(temporary, filePath);
|
|
17913
|
-
await fsyncPath2(
|
|
18104
|
+
await fsyncPath2(path51.dirname(filePath));
|
|
17914
18105
|
}
|
|
17915
18106
|
async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
17916
18107
|
const value = {
|
|
@@ -17920,13 +18111,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
|
17920
18111
|
manifestHash,
|
|
17921
18112
|
...detail ? { detail } : {}
|
|
17922
18113
|
};
|
|
17923
|
-
await atomicWriteJson(
|
|
18114
|
+
await atomicWriteJson(path51.join(artifactDir, "state.json"), value);
|
|
17924
18115
|
}
|
|
17925
18116
|
async function directorySize(root) {
|
|
17926
18117
|
if (!existsSync13(root)) return 0;
|
|
17927
18118
|
let total = 0;
|
|
17928
18119
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17929
|
-
const entryPath =
|
|
18120
|
+
const entryPath = path51.join(root, entry.name);
|
|
17930
18121
|
if (entry.isDirectory()) total += await directorySize(entryPath);
|
|
17931
18122
|
else total += (await lstat7(entryPath)).size;
|
|
17932
18123
|
}
|
|
@@ -17971,9 +18162,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17971
18162
|
let rawManifest;
|
|
17972
18163
|
let state;
|
|
17973
18164
|
try {
|
|
17974
|
-
rawManifest = JSON.parse(await readFile9(
|
|
18165
|
+
rawManifest = JSON.parse(await readFile9(path51.join(artifactDir, "manifest.json"), "utf8"));
|
|
17975
18166
|
state = JSON.parse(
|
|
17976
|
-
await readFile9(
|
|
18167
|
+
await readFile9(path51.join(artifactDir, "state.json"), "utf8")
|
|
17977
18168
|
);
|
|
17978
18169
|
} catch {
|
|
17979
18170
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
@@ -17989,10 +18180,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17989
18180
|
}
|
|
17990
18181
|
const entryPaths = /* @__PURE__ */ new Set();
|
|
17991
18182
|
for (const entry of manifest.entries) {
|
|
17992
|
-
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(
|
|
18183
|
+
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(path51.normalize(entry.path))) {
|
|
17993
18184
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17994
18185
|
}
|
|
17995
|
-
entryPaths.add(
|
|
18186
|
+
entryPaths.add(path51.normalize(entry.path));
|
|
17996
18187
|
for (const [side, snapshot] of [
|
|
17997
18188
|
["before", entry.before],
|
|
17998
18189
|
["after", entry.after]
|
|
@@ -18006,7 +18197,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18006
18197
|
});
|
|
18007
18198
|
}
|
|
18008
18199
|
}
|
|
18009
|
-
const receiptPath =
|
|
18200
|
+
const receiptPath = path51.join(artifactDir, "receipt.json");
|
|
18010
18201
|
let receipt;
|
|
18011
18202
|
if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
|
|
18012
18203
|
receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
@@ -18016,7 +18207,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18016
18207
|
async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
18017
18208
|
let rawReceipt;
|
|
18018
18209
|
try {
|
|
18019
|
-
rawReceipt = JSON.parse(await readFile9(
|
|
18210
|
+
rawReceipt = JSON.parse(await readFile9(path51.join(artifactDir, "receipt.json"), "utf8"));
|
|
18020
18211
|
} catch {
|
|
18021
18212
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
18022
18213
|
}
|
|
@@ -18039,7 +18230,7 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
|
|
|
18039
18230
|
return receipt;
|
|
18040
18231
|
}
|
|
18041
18232
|
async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
18042
|
-
const receiptPath =
|
|
18233
|
+
const receiptPath = path51.join(artifactDir, "receipt.json");
|
|
18043
18234
|
if (existsSync13(receiptPath)) {
|
|
18044
18235
|
return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
18045
18236
|
}
|
|
@@ -18064,7 +18255,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
18064
18255
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
18065
18256
|
try {
|
|
18066
18257
|
const manifest = JSON.parse(
|
|
18067
|
-
await readFile9(
|
|
18258
|
+
await readFile9(path51.join(artifactDir, "manifest.json"), "utf8")
|
|
18068
18259
|
);
|
|
18069
18260
|
if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
|
|
18070
18261
|
return canonicalPath(manifest.repoRoot);
|
|
@@ -18072,7 +18263,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
18072
18263
|
} catch {
|
|
18073
18264
|
}
|
|
18074
18265
|
try {
|
|
18075
|
-
const owner = JSON.parse(await readFile9(
|
|
18266
|
+
const owner = JSON.parse(await readFile9(path51.join(artifactDir, "owner.json"), "utf8"));
|
|
18076
18267
|
return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
|
|
18077
18268
|
} catch {
|
|
18078
18269
|
return null;
|
|
@@ -18092,10 +18283,10 @@ async function cleanupOrphanedStaging(stateDir) {
|
|
|
18092
18283
|
const now = Date.now();
|
|
18093
18284
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
18094
18285
|
if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
|
|
18095
|
-
const stagingPath =
|
|
18286
|
+
const stagingPath = path51.join(root, entry.name);
|
|
18096
18287
|
let stale = false;
|
|
18097
18288
|
try {
|
|
18098
|
-
const owner = JSON.parse(await readFile9(
|
|
18289
|
+
const owner = JSON.parse(await readFile9(path51.join(stagingPath, "owner.json"), "utf8"));
|
|
18099
18290
|
const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
|
|
18100
18291
|
const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
|
|
18101
18292
|
let alive = false;
|
|
@@ -18137,7 +18328,7 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
|
|
|
18137
18328
|
init_fingerprint2();
|
|
18138
18329
|
import { existsSync as existsSync14 } from "node:fs";
|
|
18139
18330
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
18140
|
-
import
|
|
18331
|
+
import path52 from "node:path";
|
|
18141
18332
|
async function matchRecoverySide(resourceRoot, entries, side) {
|
|
18142
18333
|
for (const entry of entries) {
|
|
18143
18334
|
const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
|
|
@@ -18152,7 +18343,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
18152
18343
|
} catch {
|
|
18153
18344
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
18154
18345
|
if (existsSync14(artifactDir)) {
|
|
18155
|
-
const manifestPath =
|
|
18346
|
+
const manifestPath = path52.join(artifactDir, "manifest.json");
|
|
18156
18347
|
const hash = existsSync14(manifestPath) ? hashValue(await readFile10(manifestPath, "utf8")) : "unavailable";
|
|
18157
18348
|
await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
|
|
18158
18349
|
}
|
|
@@ -18189,7 +18380,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
18189
18380
|
// src/core/recovery/resource-identity.ts
|
|
18190
18381
|
init_fingerprint2();
|
|
18191
18382
|
import { lstat as lstat8, readFile as readFile11, realpath as realpath3 } from "node:fs/promises";
|
|
18192
|
-
import
|
|
18383
|
+
import path53 from "node:path";
|
|
18193
18384
|
async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
18194
18385
|
const resolvedRoot = await realpath3(resourceRoot);
|
|
18195
18386
|
if (resourceKind === "directory") {
|
|
@@ -18197,13 +18388,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
|
18197
18388
|
if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
|
|
18198
18389
|
return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
|
|
18199
18390
|
}
|
|
18200
|
-
const dotGit =
|
|
18391
|
+
const dotGit = path53.join(resolvedRoot, ".git");
|
|
18201
18392
|
const gitInfo = await lstat8(dotGit);
|
|
18202
18393
|
let gitMetadataPath = dotGit;
|
|
18203
18394
|
if (gitInfo.isFile()) {
|
|
18204
18395
|
const marker = (await readFile11(dotGit, "utf8")).trim();
|
|
18205
18396
|
if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
|
|
18206
|
-
gitMetadataPath =
|
|
18397
|
+
gitMetadataPath = path53.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
|
|
18207
18398
|
} else if (!gitInfo.isDirectory()) {
|
|
18208
18399
|
throw new Error("recovery_repo_identity_unavailable");
|
|
18209
18400
|
}
|
|
@@ -18276,16 +18467,16 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18276
18467
|
throw new Error(RECOVERY_CHECKPOINT_QUOTA);
|
|
18277
18468
|
}
|
|
18278
18469
|
const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
|
|
18279
|
-
const temporary =
|
|
18470
|
+
const temporary = path54.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
|
|
18280
18471
|
const finalDir = checkpointDir(params.stateDir, checkpointId);
|
|
18281
18472
|
await mkdir11(temporary, { recursive: true, mode: 448 });
|
|
18282
|
-
await atomicWriteJson(
|
|
18473
|
+
await atomicWriteJson(path54.join(temporary, "owner.json"), {
|
|
18283
18474
|
version: 1,
|
|
18284
18475
|
pid: process.pid,
|
|
18285
18476
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18286
18477
|
repoRoot: canonicalPath(params.repoRoot)
|
|
18287
18478
|
});
|
|
18288
|
-
await mkdir11(
|
|
18479
|
+
await mkdir11(path54.join(temporary, "blobs"), { recursive: true, mode: 448 });
|
|
18289
18480
|
try {
|
|
18290
18481
|
const entries = [];
|
|
18291
18482
|
const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
|
|
@@ -18294,8 +18485,8 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18294
18485
|
)) {
|
|
18295
18486
|
const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
|
|
18296
18487
|
if (protectedRoots.some((root) => {
|
|
18297
|
-
const relative =
|
|
18298
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18488
|
+
const relative = path54.relative(root, target);
|
|
18489
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path54.sep}`) && !path54.isAbsolute(relative);
|
|
18299
18490
|
})) {
|
|
18300
18491
|
throw new Error("recovery_protected_path");
|
|
18301
18492
|
}
|
|
@@ -18307,7 +18498,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18307
18498
|
entries.push({
|
|
18308
18499
|
path: change.relativePath,
|
|
18309
18500
|
before: await captureRecoverySnapshot(baseline, {
|
|
18310
|
-
blobDir:
|
|
18501
|
+
blobDir: path54.join(temporary, "blobs")
|
|
18311
18502
|
}),
|
|
18312
18503
|
after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
|
|
18313
18504
|
});
|
|
@@ -18344,7 +18535,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18344
18535
|
entries
|
|
18345
18536
|
};
|
|
18346
18537
|
const manifestHash = hashValue(canonicalStringify(manifest));
|
|
18347
|
-
await atomicWriteJson(
|
|
18538
|
+
await atomicWriteJson(path54.join(temporary, "manifest.json"), manifest);
|
|
18348
18539
|
await writeRecoveryState(temporary, "prepared", manifestHash);
|
|
18349
18540
|
await fsyncPath2(temporary);
|
|
18350
18541
|
const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
|
|
@@ -18387,7 +18578,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
18387
18578
|
} catch {
|
|
18388
18579
|
try {
|
|
18389
18580
|
const raw = JSON.parse(
|
|
18390
|
-
await readFile12(
|
|
18581
|
+
await readFile12(path54.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
18391
18582
|
);
|
|
18392
18583
|
rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
|
|
18393
18584
|
} catch {
|
|
@@ -18421,7 +18612,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
18421
18612
|
} catch {
|
|
18422
18613
|
try {
|
|
18423
18614
|
const manifest = JSON.parse(
|
|
18424
|
-
await readFile12(
|
|
18615
|
+
await readFile12(path54.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
18425
18616
|
);
|
|
18426
18617
|
if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
|
|
18427
18618
|
if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
|
|
@@ -18451,7 +18642,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
18451
18642
|
let total = 0;
|
|
18452
18643
|
for (const entry of await readdir3(root, { withFileTypes: true })) {
|
|
18453
18644
|
if (!entry.isDirectory()) continue;
|
|
18454
|
-
const entryPath =
|
|
18645
|
+
const entryPath = path54.join(root, entry.name);
|
|
18455
18646
|
if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
18456
18647
|
if (await artifactRepoRoot(stateDir, entry.name) === expected) {
|
|
18457
18648
|
total += await directorySize(entryPath);
|
|
@@ -18460,7 +18651,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
18460
18651
|
}
|
|
18461
18652
|
if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
18462
18653
|
try {
|
|
18463
|
-
const owner = JSON.parse(await readFile12(
|
|
18654
|
+
const owner = JSON.parse(await readFile12(path54.join(entryPath, "owner.json"), "utf8"));
|
|
18464
18655
|
if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
|
|
18465
18656
|
total += await directorySize(entryPath);
|
|
18466
18657
|
}
|
|
@@ -18504,14 +18695,14 @@ init_scrub();
|
|
|
18504
18695
|
// src/core/transactional/file-checkpoint-backend.ts
|
|
18505
18696
|
import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
|
|
18506
18697
|
import os5 from "node:os";
|
|
18507
|
-
import
|
|
18698
|
+
import path58 from "node:path";
|
|
18508
18699
|
|
|
18509
18700
|
// src/core/transactional/file-checkpoint-git.ts
|
|
18510
18701
|
init_path_utils();
|
|
18511
18702
|
import { spawn as spawn8 } from "node:child_process";
|
|
18512
18703
|
import { createHash as createHash13 } from "node:crypto";
|
|
18513
18704
|
import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile13 } from "node:fs/promises";
|
|
18514
|
-
import
|
|
18705
|
+
import path55 from "node:path";
|
|
18515
18706
|
var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
|
|
18516
18707
|
var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
|
|
18517
18708
|
var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
|
|
@@ -18545,7 +18736,7 @@ function rethrowStableFileCheckpointError(error) {
|
|
|
18545
18736
|
}
|
|
18546
18737
|
async function rootGitMetadataPresent(repoRoot) {
|
|
18547
18738
|
try {
|
|
18548
|
-
await lstat9(
|
|
18739
|
+
await lstat9(path55.join(repoRoot, ".git"));
|
|
18549
18740
|
return true;
|
|
18550
18741
|
} catch {
|
|
18551
18742
|
return false;
|
|
@@ -18594,10 +18785,10 @@ function execGit2(repoRoot, args) {
|
|
|
18594
18785
|
}
|
|
18595
18786
|
async function resolveGitPath(repoRoot, gitPath) {
|
|
18596
18787
|
const trimmed = gitPath.trim();
|
|
18597
|
-
if (
|
|
18788
|
+
if (path55.isAbsolute(trimmed)) {
|
|
18598
18789
|
return trimmed;
|
|
18599
18790
|
}
|
|
18600
|
-
return
|
|
18791
|
+
return path55.join(repoRoot, trimmed);
|
|
18601
18792
|
}
|
|
18602
18793
|
async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
|
|
18603
18794
|
await execGit2(sourceRoot, [
|
|
@@ -18639,7 +18830,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18639
18830
|
destinationRoot,
|
|
18640
18831
|
await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
|
|
18641
18832
|
);
|
|
18642
|
-
const destinationShared =
|
|
18833
|
+
const destinationShared = path55.join(destinationGitDir, path55.basename(sourceShared));
|
|
18643
18834
|
try {
|
|
18644
18835
|
await copyFile3(sourceShared, destinationShared);
|
|
18645
18836
|
} catch (error) {
|
|
@@ -18648,7 +18839,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18648
18839
|
}
|
|
18649
18840
|
async function readGitFile(gitDir, relativePath) {
|
|
18650
18841
|
try {
|
|
18651
|
-
return await readFile13(
|
|
18842
|
+
return await readFile13(path55.join(gitDir, relativePath));
|
|
18652
18843
|
} catch {
|
|
18653
18844
|
return null;
|
|
18654
18845
|
}
|
|
@@ -18672,8 +18863,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18672
18863
|
repoRoot,
|
|
18673
18864
|
await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
|
|
18674
18865
|
);
|
|
18675
|
-
const relative =
|
|
18676
|
-
const content = typeof relative === "string" && !relative.startsWith("..") && !
|
|
18866
|
+
const relative = path55.resolve(resolved).startsWith(path55.resolve(gitDir)) ? path55.relative(gitDir, resolved) : resolved;
|
|
18867
|
+
const content = typeof relative === "string" && !relative.startsWith("..") && !path55.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18677
18868
|
if (content !== null) {
|
|
18678
18869
|
hashGitFileContent(hash, gitPath, content);
|
|
18679
18870
|
}
|
|
@@ -18683,13 +18874,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18683
18874
|
async function hashGitTree(gitDir, relativeDir, hash) {
|
|
18684
18875
|
let names;
|
|
18685
18876
|
try {
|
|
18686
|
-
names = await readdir4(
|
|
18877
|
+
names = await readdir4(path55.join(gitDir, relativeDir));
|
|
18687
18878
|
} catch {
|
|
18688
18879
|
return;
|
|
18689
18880
|
}
|
|
18690
18881
|
for (const name of names.sort()) {
|
|
18691
|
-
const relativePath = relativeDir ?
|
|
18692
|
-
const absolutePath =
|
|
18882
|
+
const relativePath = relativeDir ? path55.join(relativeDir, name) : name;
|
|
18883
|
+
const absolutePath = path55.join(gitDir, relativePath);
|
|
18693
18884
|
let childNames = null;
|
|
18694
18885
|
try {
|
|
18695
18886
|
childNames = await readdir4(absolutePath);
|
|
@@ -18711,7 +18902,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
|
|
|
18711
18902
|
}
|
|
18712
18903
|
async function computeGitMetadataFingerprint(repoRoot) {
|
|
18713
18904
|
const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18714
|
-
const gitDir =
|
|
18905
|
+
const gitDir = path55.isAbsolute(gitDirRel) ? gitDirRel : path55.join(repoRoot, gitDirRel);
|
|
18715
18906
|
const hash = createHash13("sha256");
|
|
18716
18907
|
for (const file of [
|
|
18717
18908
|
"HEAD",
|
|
@@ -18734,8 +18925,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18734
18925
|
const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
|
|
18735
18926
|
if (sharedIndex) {
|
|
18736
18927
|
const resolved = await resolveGitPath(repoRoot, sharedIndex);
|
|
18737
|
-
const relative =
|
|
18738
|
-
const content = relative && !relative.startsWith("..") && !
|
|
18928
|
+
const relative = path55.relative(gitDir, resolved);
|
|
18929
|
+
const content = relative && !relative.startsWith("..") && !path55.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18739
18930
|
if (content !== null) {
|
|
18740
18931
|
hashGitFileContent(hash, "shared-index", content);
|
|
18741
18932
|
}
|
|
@@ -18746,7 +18937,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18746
18937
|
await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
|
|
18747
18938
|
}
|
|
18748
18939
|
try {
|
|
18749
|
-
const rootGitPath =
|
|
18940
|
+
const rootGitPath = path55.join(repoRoot, ".git");
|
|
18750
18941
|
const rootGitInfo = await lstat9(rootGitPath);
|
|
18751
18942
|
if (rootGitInfo.isFile()) {
|
|
18752
18943
|
const content = await readAbsoluteGitFile(rootGitPath);
|
|
@@ -18762,14 +18953,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18762
18953
|
function resolveExecutionCwdRelative(resourceRoot, cwd) {
|
|
18763
18954
|
const resolvedCwd = canonicalPath(cwd);
|
|
18764
18955
|
const resourceCanonical = canonicalPath(resourceRoot);
|
|
18765
|
-
const relative =
|
|
18956
|
+
const relative = path55.relative(resourceCanonical, resolvedCwd);
|
|
18766
18957
|
if (relative === "" || relative === ".") {
|
|
18767
18958
|
return "";
|
|
18768
18959
|
}
|
|
18769
|
-
if (relative.startsWith("..") ||
|
|
18960
|
+
if (relative.startsWith("..") || path55.isAbsolute(relative)) {
|
|
18770
18961
|
throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
|
|
18771
18962
|
}
|
|
18772
|
-
return relative.split(
|
|
18963
|
+
return relative.split(path55.sep).join("/");
|
|
18773
18964
|
}
|
|
18774
18965
|
|
|
18775
18966
|
// src/core/transactional/file-checkpoint-isolation.ts
|
|
@@ -18791,7 +18982,7 @@ function fileCheckpointIsolationReason(context) {
|
|
|
18791
18982
|
|
|
18792
18983
|
// src/core/transactional/file-checkpoint-staging.ts
|
|
18793
18984
|
import { readdir as readdir5, readFile as readFile14, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
|
|
18794
|
-
import
|
|
18985
|
+
import path56 from "node:path";
|
|
18795
18986
|
function isOwnerProcessAlive(pid) {
|
|
18796
18987
|
try {
|
|
18797
18988
|
process.kill(pid, 0);
|
|
@@ -18801,12 +18992,12 @@ function isOwnerProcessAlive(pid) {
|
|
|
18801
18992
|
}
|
|
18802
18993
|
}
|
|
18803
18994
|
async function writeOwnerMarker(stagingRoot, marker) {
|
|
18804
|
-
await writeFile8(
|
|
18995
|
+
await writeFile8(path56.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
|
|
18805
18996
|
`, "utf8");
|
|
18806
18997
|
}
|
|
18807
18998
|
async function readOwnerMarker(stagingRoot) {
|
|
18808
18999
|
try {
|
|
18809
|
-
const raw = await readFile14(
|
|
19000
|
+
const raw = await readFile14(path56.join(stagingRoot, "owner.json"), "utf8");
|
|
18810
19001
|
return JSON.parse(raw.trim());
|
|
18811
19002
|
} catch {
|
|
18812
19003
|
return null;
|
|
@@ -18824,7 +19015,7 @@ async function collectDeadOwnerStaging(parentDir) {
|
|
|
18824
19015
|
if (!name.startsWith("belay-file-checkpoint-")) {
|
|
18825
19016
|
continue;
|
|
18826
19017
|
}
|
|
18827
|
-
const stagingRoot =
|
|
19018
|
+
const stagingRoot = path56.join(parentDir, name);
|
|
18828
19019
|
const marker = await readOwnerMarker(stagingRoot);
|
|
18829
19020
|
if (!marker) {
|
|
18830
19021
|
dead.push(stagingRoot);
|
|
@@ -18856,7 +19047,7 @@ import {
|
|
|
18856
19047
|
writeFile as writeFile9
|
|
18857
19048
|
} from "node:fs/promises";
|
|
18858
19049
|
import os4 from "node:os";
|
|
18859
|
-
import
|
|
19050
|
+
import path57 from "node:path";
|
|
18860
19051
|
var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
|
|
18861
19052
|
async function chmodSafe2(target, mode) {
|
|
18862
19053
|
try {
|
|
@@ -18866,7 +19057,7 @@ async function chmodSafe2(target, mode) {
|
|
|
18866
19057
|
}
|
|
18867
19058
|
}
|
|
18868
19059
|
async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
|
|
18869
|
-
await mkdir12(
|
|
19060
|
+
await mkdir12(path57.dirname(destinationPath), { recursive: true });
|
|
18870
19061
|
if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
|
|
18871
19062
|
try {
|
|
18872
19063
|
await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
|
|
@@ -18892,7 +19083,7 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
|
|
|
18892
19083
|
return strategy;
|
|
18893
19084
|
}
|
|
18894
19085
|
if (info.isSymbolicLink()) {
|
|
18895
|
-
await mkdir12(
|
|
19086
|
+
await mkdir12(path57.dirname(destinationPath), { recursive: true });
|
|
18896
19087
|
await symlink4(await readlink5(sourcePath), destinationPath);
|
|
18897
19088
|
return strategy;
|
|
18898
19089
|
}
|
|
@@ -18948,9 +19139,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
|
|
|
18948
19139
|
async function probeFileCloneStrategy() {
|
|
18949
19140
|
let tempDir = null;
|
|
18950
19141
|
try {
|
|
18951
|
-
tempDir = await mkdtemp4(
|
|
18952
|
-
const source =
|
|
18953
|
-
const destination =
|
|
19142
|
+
tempDir = await mkdtemp4(path57.join(os4.tmpdir(), "belay-clone-probe-"));
|
|
19143
|
+
const source = path57.join(tempDir, "source.txt");
|
|
19144
|
+
const destination = path57.join(tempDir, "dest.txt");
|
|
18954
19145
|
await writeFile9(source, "probe\n");
|
|
18955
19146
|
if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
|
|
18956
19147
|
try {
|
|
@@ -19103,11 +19294,11 @@ async function protectedRootState(root) {
|
|
|
19103
19294
|
return `directory:${node.hash}:${index.treeHash}`;
|
|
19104
19295
|
}
|
|
19105
19296
|
function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
|
|
19106
|
-
const relative =
|
|
19107
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
19297
|
+
const relative = path58.relative(path58.resolve(resourceRoot), path58.resolve(protectedRoot));
|
|
19298
|
+
if (relative === "" || relative.startsWith("..") || path58.isAbsolute(relative)) {
|
|
19108
19299
|
return null;
|
|
19109
19300
|
}
|
|
19110
|
-
return
|
|
19301
|
+
return path58.join(executionRoot, relative);
|
|
19111
19302
|
}
|
|
19112
19303
|
async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
|
|
19113
19304
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -19132,15 +19323,15 @@ async function directoryByteSize(root, deadlineMs) {
|
|
|
19132
19323
|
}
|
|
19133
19324
|
let total = 0;
|
|
19134
19325
|
for (const name of await readdir6(root)) {
|
|
19135
|
-
total += await directoryByteSize(
|
|
19326
|
+
total += await directoryByteSize(path58.join(root, name), deadlineMs);
|
|
19136
19327
|
}
|
|
19137
19328
|
return total;
|
|
19138
19329
|
}
|
|
19139
19330
|
async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
|
|
19140
19331
|
const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
|
|
19141
|
-
const sourceGitDir =
|
|
19142
|
-
const relativeGitDir =
|
|
19143
|
-
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ?
|
|
19332
|
+
const sourceGitDir = path58.isAbsolute(gitDirRel) ? gitDirRel : path58.join(sourceRoot, gitDirRel);
|
|
19333
|
+
const relativeGitDir = path58.relative(path58.resolve(sourceRoot), path58.resolve(sourceGitDir));
|
|
19334
|
+
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path58.join(destinationRoot, relativeGitDir) : path58.join(destinationRoot, ".git");
|
|
19144
19335
|
await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
|
|
19145
19336
|
}
|
|
19146
19337
|
async function prepareDirtyGitSnapshot(context) {
|
|
@@ -19149,7 +19340,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19149
19340
|
const quotas = context.fileCheckpoint;
|
|
19150
19341
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
19151
19342
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
19152
|
-
const stagingRoot = await mkdtemp5(
|
|
19343
|
+
const stagingRoot = await mkdtemp5(path58.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
19153
19344
|
await writeOwnerMarker(stagingRoot, {
|
|
19154
19345
|
version: 1,
|
|
19155
19346
|
pid: process.pid,
|
|
@@ -19157,8 +19348,8 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19157
19348
|
resourceRoot: context.repoRoot,
|
|
19158
19349
|
backend: "file_checkpoint"
|
|
19159
19350
|
});
|
|
19160
|
-
const baselineRoot =
|
|
19161
|
-
const executionRoot =
|
|
19351
|
+
const baselineRoot = path58.join(stagingRoot, "baseline");
|
|
19352
|
+
const executionRoot = path58.join(stagingRoot, "execution");
|
|
19162
19353
|
try {
|
|
19163
19354
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
19164
19355
|
const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
|
|
@@ -19192,7 +19383,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19192
19383
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
19193
19384
|
}
|
|
19194
19385
|
await writeFile10(
|
|
19195
|
-
|
|
19386
|
+
path58.join(stagingRoot, "baseline-index.json"),
|
|
19196
19387
|
`${JSON.stringify(baselineIndex)}
|
|
19197
19388
|
`,
|
|
19198
19389
|
"utf8"
|
|
@@ -19242,7 +19433,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19242
19433
|
const quotas = context.fileCheckpoint;
|
|
19243
19434
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
19244
19435
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
19245
|
-
const stagingRoot = await mkdtemp5(
|
|
19436
|
+
const stagingRoot = await mkdtemp5(path58.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
19246
19437
|
await writeOwnerMarker(stagingRoot, {
|
|
19247
19438
|
version: 1,
|
|
19248
19439
|
pid: process.pid,
|
|
@@ -19250,8 +19441,8 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19250
19441
|
resourceRoot: context.repoRoot,
|
|
19251
19442
|
backend: "file_checkpoint"
|
|
19252
19443
|
});
|
|
19253
|
-
const baselineRoot =
|
|
19254
|
-
const executionRoot =
|
|
19444
|
+
const baselineRoot = path58.join(stagingRoot, "baseline");
|
|
19445
|
+
const executionRoot = path58.join(stagingRoot, "execution");
|
|
19255
19446
|
try {
|
|
19256
19447
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
19257
19448
|
const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
|
|
@@ -19280,7 +19471,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19280
19471
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
19281
19472
|
}
|
|
19282
19473
|
await writeFile10(
|
|
19283
|
-
|
|
19474
|
+
path58.join(stagingRoot, "baseline-index.json"),
|
|
19284
19475
|
`${JSON.stringify(baselineIndex)}
|
|
19285
19476
|
`,
|
|
19286
19477
|
"utf8"
|
|
@@ -19633,10 +19824,10 @@ async function selectTransactionalBackend(context) {
|
|
|
19633
19824
|
}
|
|
19634
19825
|
|
|
19635
19826
|
// src/core/transactional/diff-evaluator.ts
|
|
19636
|
-
import
|
|
19827
|
+
import path59 from "node:path";
|
|
19637
19828
|
init_path_utils();
|
|
19638
19829
|
function categorizeChange(change, ctx) {
|
|
19639
|
-
const absolutePath = canonicalPath(
|
|
19830
|
+
const absolutePath = canonicalPath(path59.join(ctx.repoRoot, change.relativePath));
|
|
19640
19831
|
if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
|
|
19641
19832
|
return "repo_outside";
|
|
19642
19833
|
}
|
|
@@ -20230,7 +20421,7 @@ async function notifyDeny(config, event) {
|
|
|
20230
20421
|
init_path_utils();
|
|
20231
20422
|
|
|
20232
20423
|
// src/adapters/layouts/protected-paths.ts
|
|
20233
|
-
import
|
|
20424
|
+
import path60 from "node:path";
|
|
20234
20425
|
function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
20235
20426
|
const roots = [
|
|
20236
20427
|
layout.configPath(repoRoot),
|
|
@@ -20242,7 +20433,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
|
20242
20433
|
if (controlPlaneDir) {
|
|
20243
20434
|
roots.push(controlPlaneDir);
|
|
20244
20435
|
}
|
|
20245
|
-
return roots.map((entry) =>
|
|
20436
|
+
return roots.map((entry) => path60.resolve(entry));
|
|
20246
20437
|
}
|
|
20247
20438
|
|
|
20248
20439
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -20295,8 +20486,8 @@ function createDefaultGateRuntimeDeps() {
|
|
|
20295
20486
|
return loadJsonFile(configPath, {});
|
|
20296
20487
|
},
|
|
20297
20488
|
async appendAudit(ctx, event) {
|
|
20298
|
-
const auditPath =
|
|
20299
|
-
await mkdir14(
|
|
20489
|
+
const auditPath = path61.join(ctx.repoRoot, ctx.config.audit.logPath);
|
|
20490
|
+
await mkdir14(path61.dirname(auditPath), { recursive: true });
|
|
20300
20491
|
const provenance = auditProvenance(ctx.config);
|
|
20301
20492
|
const record = {
|
|
20302
20493
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -20329,7 +20520,7 @@ function createDefaultGateRuntimeDeps() {
|
|
|
20329
20520
|
};
|
|
20330
20521
|
},
|
|
20331
20522
|
async writeApprovals(filePath, state) {
|
|
20332
|
-
await mkdir14(
|
|
20523
|
+
await mkdir14(path61.dirname(filePath), { recursive: true });
|
|
20333
20524
|
await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
|
|
20334
20525
|
`, "utf8");
|
|
20335
20526
|
},
|
|
@@ -20491,7 +20682,7 @@ function deriveWorkspaceRootScopeHint(params) {
|
|
|
20491
20682
|
if (!targetPath) {
|
|
20492
20683
|
return void 0;
|
|
20493
20684
|
}
|
|
20494
|
-
const candidateRoot = canonicalPath(
|
|
20685
|
+
const candidateRoot = canonicalPath(path61.dirname(targetPath));
|
|
20495
20686
|
const validation = validateTrustedWorkspaceRootCandidate({
|
|
20496
20687
|
candidatePath: candidateRoot,
|
|
20497
20688
|
repoRoot: action.repoRoot,
|
|
@@ -21101,6 +21292,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
21101
21292
|
event: auditEvent,
|
|
21102
21293
|
sourceEvent,
|
|
21103
21294
|
kind,
|
|
21295
|
+
repoLabel: path61.basename(ctx.repoRoot),
|
|
21104
21296
|
...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
|
|
21105
21297
|
fingerprint: result.fingerprint,
|
|
21106
21298
|
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 path62 from "node:path";
|
|
21575
21767
|
function belayConfigPath(current, adapterName) {
|
|
21576
21768
|
if (adapterName === "cursor") {
|
|
21577
|
-
return
|
|
21769
|
+
return path62.join(current, ".cursor", "belay.config.json");
|
|
21578
21770
|
}
|
|
21579
21771
|
if (adapterName === "claude") {
|
|
21580
|
-
return
|
|
21772
|
+
return path62.join(current, ".claude", "belay.config.json");
|
|
21581
21773
|
}
|
|
21582
|
-
return
|
|
21774
|
+
return path62.join(current, ".codex", "belay.config.json");
|
|
21583
21775
|
}
|
|
21584
21776
|
function markerMatches(current, marker, layout) {
|
|
21585
|
-
const markerPath =
|
|
21777
|
+
const markerPath = path62.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 = path62.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 = path62.dirname(current);
|
|
21603
21795
|
if (parent === current) {
|
|
21604
|
-
return
|
|
21796
|
+
return path62.resolve(startPath);
|
|
21605
21797
|
}
|
|
21606
21798
|
current = parent;
|
|
21607
21799
|
}
|
|
@@ -21635,7 +21827,7 @@ function resolveCodexActionCwd(payload, fallbackCwd = process2.cwd(), options =
|
|
|
21635
21827
|
const nestedCwd = options.includeToolInputCwd ? nonEmptyPathString(toolInput?.working_directory) ?? nonEmptyPathString(toolInput?.cwd) : void 0;
|
|
21636
21828
|
const payloadCwd = nonEmptyPathString(payload.cwd);
|
|
21637
21829
|
const workspaceRoot = Array.isArray(payload.workspace_roots) ? payload.workspace_roots.map(nonEmptyPathString).find(Boolean) : void 0;
|
|
21638
|
-
return
|
|
21830
|
+
return path63.resolve(nestedCwd ?? payloadCwd ?? workspaceRoot ?? fallbackCwd);
|
|
21639
21831
|
}
|
|
21640
21832
|
async function loadRuntimeContext(cwd) {
|
|
21641
21833
|
const repoRoot = findRepoRoot(cwd, codexLayout);
|