@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
|
@@ -4232,7 +4232,7 @@ init_approval_replay();
|
|
|
4232
4232
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
4233
4233
|
import { existsSync as existsSync16 } from "node:fs";
|
|
4234
4234
|
import { mkdir as mkdir14, readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
|
|
4235
|
-
import
|
|
4235
|
+
import path61 from "node:path";
|
|
4236
4236
|
|
|
4237
4237
|
// src/core/approval-service.ts
|
|
4238
4238
|
init_config_io();
|
|
@@ -7239,31 +7239,44 @@ import { randomUUID as randomUUID3 } from "node:crypto";
|
|
|
7239
7239
|
import path22 from "node:path";
|
|
7240
7240
|
|
|
7241
7241
|
// src/core/glob.ts
|
|
7242
|
+
init_approval();
|
|
7243
|
+
function globPatternToRegexSource(pattern) {
|
|
7244
|
+
let result = "";
|
|
7245
|
+
let index = 0;
|
|
7246
|
+
while (index < pattern.length) {
|
|
7247
|
+
const char = pattern[index];
|
|
7248
|
+
if (char === "*" && pattern[index + 1] === "*") {
|
|
7249
|
+
index += 2;
|
|
7250
|
+
if (pattern[index] === "/") {
|
|
7251
|
+
result += "(?:.*/)?";
|
|
7252
|
+
index += 1;
|
|
7253
|
+
} else {
|
|
7254
|
+
result += ".*";
|
|
7255
|
+
}
|
|
7256
|
+
continue;
|
|
7257
|
+
}
|
|
7258
|
+
if (char === "*") {
|
|
7259
|
+
result += "[^/]*";
|
|
7260
|
+
index += 1;
|
|
7261
|
+
continue;
|
|
7262
|
+
}
|
|
7263
|
+
result += escapeRegex(char);
|
|
7264
|
+
index += 1;
|
|
7265
|
+
}
|
|
7266
|
+
return result;
|
|
7267
|
+
}
|
|
7268
|
+
function globPatternMatches(pattern, normalized, baseName) {
|
|
7269
|
+
const regex = new RegExp(`^${globPatternToRegexSource(pattern)}$`);
|
|
7270
|
+
return regex.test(normalized) || regex.test(baseName);
|
|
7271
|
+
}
|
|
7242
7272
|
function matchesSensitivePath(filePath, patterns) {
|
|
7243
7273
|
const normalized = filePath.replaceAll("\\", "/");
|
|
7244
7274
|
const segments = normalized.split("/");
|
|
7245
7275
|
const baseName = segments.at(-1) ?? normalized;
|
|
7246
7276
|
for (const pattern of patterns) {
|
|
7247
7277
|
const normalizedPattern = pattern.replaceAll("\\", "/");
|
|
7248
|
-
if (normalizedPattern.includes("**")) {
|
|
7249
|
-
const parts = normalizedPattern.split("**").map((part) => part.replace(/^\/+|\/+$/g, ""));
|
|
7250
|
-
const prefix = parts[0]?.replace(/\/+$/, "") ?? "";
|
|
7251
|
-
const suffix = parts[1]?.replace(/^\/+/, "") ?? "";
|
|
7252
|
-
if (prefix && !normalized.startsWith(prefix)) {
|
|
7253
|
-
continue;
|
|
7254
|
-
}
|
|
7255
|
-
if (suffix && !normalized.includes(suffix)) {
|
|
7256
|
-
continue;
|
|
7257
|
-
}
|
|
7258
|
-
if (prefix || suffix) {
|
|
7259
|
-
return true;
|
|
7260
|
-
}
|
|
7261
|
-
}
|
|
7262
7278
|
if (normalizedPattern.includes("*")) {
|
|
7263
|
-
|
|
7264
|
-
`^${normalizedPattern.replaceAll(".", "\\.").replaceAll("*", ".*")}$`
|
|
7265
|
-
);
|
|
7266
|
-
if (regex.test(normalized) || regex.test(baseName)) {
|
|
7279
|
+
if (globPatternMatches(normalizedPattern, normalized, baseName)) {
|
|
7267
7280
|
return true;
|
|
7268
7281
|
}
|
|
7269
7282
|
continue;
|
|
@@ -11020,6 +11033,16 @@ function subagentFingerprintSource(payload, scrubOptions) {
|
|
|
11020
11033
|
}
|
|
11021
11034
|
return scrubValue(payload, scrubOptions);
|
|
11022
11035
|
}
|
|
11036
|
+
function fingerprintToolInputSource(payload) {
|
|
11037
|
+
const toolInput = payload.tool_input;
|
|
11038
|
+
if (!toolInput || typeof toolInput !== "object") {
|
|
11039
|
+
return {};
|
|
11040
|
+
}
|
|
11041
|
+
return redactToolInvocationId(
|
|
11042
|
+
toolInput,
|
|
11043
|
+
typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0
|
|
11044
|
+
);
|
|
11045
|
+
}
|
|
11023
11046
|
function fingerprintReplayPayload(kind, payload, scrubOptions) {
|
|
11024
11047
|
if (!payload) {
|
|
11025
11048
|
return void 0;
|
|
@@ -11129,7 +11152,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
|
|
|
11129
11152
|
}
|
|
11130
11153
|
|
|
11131
11154
|
// src/core/classify-tool.ts
|
|
11132
|
-
import
|
|
11155
|
+
import path49 from "node:path";
|
|
11133
11156
|
init_fingerprint2();
|
|
11134
11157
|
init_path_utils();
|
|
11135
11158
|
init_scrub();
|
|
@@ -11248,11 +11271,8 @@ function worstEffectDecision(decisions) {
|
|
|
11248
11271
|
}
|
|
11249
11272
|
|
|
11250
11273
|
// src/core/effect-ir/shell-lower.ts
|
|
11251
|
-
init_git_resource_identity();
|
|
11252
|
-
init_path_utils();
|
|
11253
11274
|
init_shell_tokenizer();
|
|
11254
|
-
import
|
|
11255
|
-
import path41 from "node:path";
|
|
11275
|
+
import path48 from "node:path";
|
|
11256
11276
|
|
|
11257
11277
|
// src/core/verdict/docker-compose-run.ts
|
|
11258
11278
|
import path36 from "node:path";
|
|
@@ -11592,6 +11612,17 @@ function decodeDockerComposeRun(tokens) {
|
|
|
11592
11612
|
|
|
11593
11613
|
// src/core/verdict/egress-classify.ts
|
|
11594
11614
|
import path37 from "node:path";
|
|
11615
|
+
var EGRESS_TOOL_HEADS = /* @__PURE__ */ new Set([
|
|
11616
|
+
"aws",
|
|
11617
|
+
"curl",
|
|
11618
|
+
"gh",
|
|
11619
|
+
"gcloud",
|
|
11620
|
+
"heroku",
|
|
11621
|
+
"kubectl",
|
|
11622
|
+
"netlify",
|
|
11623
|
+
"vercel",
|
|
11624
|
+
"wget"
|
|
11625
|
+
]);
|
|
11595
11626
|
var CURL_EFFECT_NEUTRAL_FLAGS = /* @__PURE__ */ new Set([
|
|
11596
11627
|
"-f",
|
|
11597
11628
|
"-L",
|
|
@@ -11625,6 +11656,9 @@ var GH_READ_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11625
11656
|
"workflow list",
|
|
11626
11657
|
"workflow view"
|
|
11627
11658
|
]);
|
|
11659
|
+
function isEgressToolHead(head) {
|
|
11660
|
+
return EGRESS_TOOL_HEADS.has(head);
|
|
11661
|
+
}
|
|
11628
11662
|
function decodeEgressEffects(params) {
|
|
11629
11663
|
const head = path37.basename(params.tokens[0] ?? "");
|
|
11630
11664
|
if (head !== "curl" && head !== "wget" && head !== "gh") {
|
|
@@ -13887,7 +13921,7 @@ function extractBalancedParenContent(command, start) {
|
|
|
13887
13921
|
index += 1;
|
|
13888
13922
|
continue;
|
|
13889
13923
|
}
|
|
13890
|
-
if (char === "\\" &&
|
|
13924
|
+
if (char === "\\" && inDouble) {
|
|
13891
13925
|
escaping = true;
|
|
13892
13926
|
index += 1;
|
|
13893
13927
|
continue;
|
|
@@ -13965,7 +13999,9 @@ function hasUnclosedQuote(command) {
|
|
|
13965
13999
|
continue;
|
|
13966
14000
|
}
|
|
13967
14001
|
if (char === "\\") {
|
|
13968
|
-
|
|
14002
|
+
if (quote !== "'") {
|
|
14003
|
+
escaping = true;
|
|
14004
|
+
}
|
|
13969
14005
|
continue;
|
|
13970
14006
|
}
|
|
13971
14007
|
if (quote) {
|
|
@@ -14482,6 +14518,50 @@ function redactCommand(command) {
|
|
|
14482
14518
|
return command.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]").replace(/sk-[A-Za-z0-9]{8,}/g, "sk-[REDACTED]").trim();
|
|
14483
14519
|
}
|
|
14484
14520
|
|
|
14521
|
+
// src/core/effect-ir/argv-delegate.ts
|
|
14522
|
+
function innerRecipeFromArgvDelegate(peel) {
|
|
14523
|
+
if (peel.opaque || peel.innerTokens.length === 0) {
|
|
14524
|
+
return null;
|
|
14525
|
+
}
|
|
14526
|
+
return peel.innerTokens.join(" ");
|
|
14527
|
+
}
|
|
14528
|
+
function peelArgvDelegateArgv(tokens) {
|
|
14529
|
+
const launcher = tokens[0] ?? "";
|
|
14530
|
+
if (!launcher || tokens.length < 2) {
|
|
14531
|
+
return null;
|
|
14532
|
+
}
|
|
14533
|
+
const signals = ["process.argv_delegate"];
|
|
14534
|
+
let index = 1;
|
|
14535
|
+
while (index < tokens.length) {
|
|
14536
|
+
const token = tokens[index] ?? "";
|
|
14537
|
+
if (token === "--") {
|
|
14538
|
+
index += 1;
|
|
14539
|
+
break;
|
|
14540
|
+
}
|
|
14541
|
+
if (token.startsWith("-")) {
|
|
14542
|
+
return {
|
|
14543
|
+
launcher,
|
|
14544
|
+
innerTokens: [],
|
|
14545
|
+
opaque: true,
|
|
14546
|
+
reason: "argv_delegate_wrapper_options",
|
|
14547
|
+
signals: [...signals, "argv_delegate_wrapper_options"]
|
|
14548
|
+
};
|
|
14549
|
+
}
|
|
14550
|
+
break;
|
|
14551
|
+
}
|
|
14552
|
+
const innerTokens = tokens.slice(index);
|
|
14553
|
+
if (innerTokens.length === 0) {
|
|
14554
|
+
return null;
|
|
14555
|
+
}
|
|
14556
|
+
return {
|
|
14557
|
+
launcher,
|
|
14558
|
+
innerTokens,
|
|
14559
|
+
opaque: false,
|
|
14560
|
+
reason: "argv_delegate_peel",
|
|
14561
|
+
signals
|
|
14562
|
+
};
|
|
14563
|
+
}
|
|
14564
|
+
|
|
14485
14565
|
// src/core/effect-ir/shell-build.ts
|
|
14486
14566
|
function buildShellEffectPlan(params) {
|
|
14487
14567
|
const nodes = params.segments.map(buildSegmentNode);
|
|
@@ -14539,933 +14619,416 @@ function mergeNodes(nodes) {
|
|
|
14539
14619
|
return { kind: "merge", children: nodes };
|
|
14540
14620
|
}
|
|
14541
14621
|
|
|
14542
|
-
// src/core/effect-ir/shell-lower.ts
|
|
14543
|
-
|
|
14544
|
-
var
|
|
14545
|
-
|
|
14622
|
+
// src/core/effect-ir/shell-lower/argv-delegate-gate.ts
|
|
14623
|
+
import path41 from "node:path";
|
|
14624
|
+
var ARGV_DELEGATE_INNER_BLOCKLIST = /* @__PURE__ */ new Set([
|
|
14625
|
+
"sudo",
|
|
14626
|
+
"env",
|
|
14627
|
+
"command",
|
|
14628
|
+
"builtin",
|
|
14629
|
+
"exec",
|
|
14630
|
+
"time",
|
|
14631
|
+
"nice",
|
|
14632
|
+
"nohup",
|
|
14633
|
+
"stdbuf",
|
|
14634
|
+
"setsid",
|
|
14635
|
+
"("
|
|
14636
|
+
]);
|
|
14637
|
+
function shouldApplyArgvDelegate(head, innerTokens, depth) {
|
|
14638
|
+
if (depth > 0 || isEgressToolHead(head) || head === "bundle") {
|
|
14639
|
+
return false;
|
|
14640
|
+
}
|
|
14641
|
+
if (ARGV_DELEGATE_INNER_BLOCKLIST.has(head)) {
|
|
14642
|
+
return false;
|
|
14643
|
+
}
|
|
14644
|
+
const innerHead = path41.basename(innerTokens[0] ?? "");
|
|
14645
|
+
if (ARGV_DELEGATE_INNER_BLOCKLIST.has(innerHead)) {
|
|
14646
|
+
return false;
|
|
14647
|
+
}
|
|
14648
|
+
return innerTokens.length >= 2;
|
|
14649
|
+
}
|
|
14650
|
+
function isGrammarUnknownOnly(requirements, head) {
|
|
14651
|
+
if (requirements.length !== 2) {
|
|
14652
|
+
return false;
|
|
14653
|
+
}
|
|
14654
|
+
const [spawn9, indeterminate] = requirements;
|
|
14655
|
+
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");
|
|
14656
|
+
}
|
|
14657
|
+
|
|
14658
|
+
// src/core/effect-ir/shell-lower/augment.ts
|
|
14659
|
+
init_shell_tokenizer();
|
|
14660
|
+
|
|
14661
|
+
// src/core/effect-ir/shell-lower/requirement.ts
|
|
14546
14662
|
var SECRET_PATH_PATTERN = /(?:^|[/\\])(?:\.env(?:\..*)?|credentials?|secrets?|id_rsa)(?:$|[/\\])/i;
|
|
14547
14663
|
var CONTROL_PLANE_PATH_PATTERN = /^(?:\/etc(?:\/|$)|\/var\/run(?:\/|$)|.*(?:^|[/\\])\.(?:git|ssh|cursor|claude)(?:[/\\]|$))/;
|
|
14548
|
-
function
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14664
|
+
function requirement2(tag, action, resource, segment, signals) {
|
|
14665
|
+
return {
|
|
14666
|
+
tag,
|
|
14667
|
+
action,
|
|
14668
|
+
resource,
|
|
14669
|
+
evidence: {
|
|
14670
|
+
level: tag === "indeterminate" ? "indeterminate" : "certain",
|
|
14671
|
+
signals: [...new Set(signals)].sort(),
|
|
14672
|
+
basis: ["shell_semantic_lowering"]
|
|
14673
|
+
},
|
|
14674
|
+
provenance: { segment }
|
|
14675
|
+
};
|
|
14556
14676
|
}
|
|
14557
|
-
function
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
"indeterminate",
|
|
14585
|
-
{ kind: "unknown" },
|
|
14586
|
-
result.commandRedacted,
|
|
14587
|
-
["shell.cwd_unknown"]
|
|
14588
|
-
)
|
|
14589
|
-
);
|
|
14590
|
-
}
|
|
14591
|
-
result = {
|
|
14592
|
-
...result,
|
|
14593
|
-
requirements,
|
|
14594
|
-
...requiresCwd ? {
|
|
14595
|
-
completeness: "partial",
|
|
14596
|
-
opacity: joinEffectOpacity(result.opacity, "opaque")
|
|
14597
|
-
} : {},
|
|
14598
|
-
signals: [.../* @__PURE__ */ new Set([...result.signals, "shell.cwd_unknown"])]
|
|
14599
|
-
};
|
|
14600
|
-
}
|
|
14601
|
-
lowered.push(result);
|
|
14602
|
-
if (!inferredEnv.DATABASE_URL && startsLocalPostgresService(segment)) {
|
|
14603
|
-
inferredEnv = {
|
|
14604
|
-
...inferredEnv,
|
|
14605
|
-
DATABASE_URL: "postgresql://127.0.0.1:5432/local"
|
|
14606
|
-
};
|
|
14607
|
-
}
|
|
14608
|
-
const nextCwd = resolveCdTransition(segment, cwd);
|
|
14609
|
-
if (nextCwd) {
|
|
14610
|
-
cwd = nextCwd.cwd;
|
|
14611
|
-
cwdKnown = nextCwd.known;
|
|
14612
|
-
}
|
|
14613
|
-
}
|
|
14614
|
-
if (commands.length > 1 && /[\r\n]/.test(command) && lowered.some(
|
|
14615
|
-
(segment) => segment.requirements.some((entry) => entry.action === "network.connect")
|
|
14616
|
-
)) {
|
|
14617
|
-
lowered.push(
|
|
14618
|
-
shellSegment(
|
|
14619
|
-
"[multiline network boundary]",
|
|
14620
|
-
"shell-boundary",
|
|
14621
|
-
[
|
|
14622
|
-
requirement2(
|
|
14623
|
-
"indeterminate",
|
|
14624
|
-
"indeterminate",
|
|
14625
|
-
{ kind: "unknown" },
|
|
14626
|
-
"[multiline network boundary]",
|
|
14627
|
-
["shell.multiline_network_boundary"]
|
|
14628
|
-
)
|
|
14629
|
-
],
|
|
14630
|
-
"opaque",
|
|
14631
|
-
/* @__PURE__ */ new Set(["shell.multiline_network_boundary"])
|
|
14677
|
+
function processRequirement(command, operation, segment, signals) {
|
|
14678
|
+
return requirement2(
|
|
14679
|
+
"process.exec",
|
|
14680
|
+
"process.exec",
|
|
14681
|
+
{ kind: "executable", command, operation },
|
|
14682
|
+
segment,
|
|
14683
|
+
signals
|
|
14684
|
+
);
|
|
14685
|
+
}
|
|
14686
|
+
function unsupportedProcess(command, segment, signal) {
|
|
14687
|
+
return [
|
|
14688
|
+
processRequirement(command, "spawn", segment, [signal]),
|
|
14689
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [signal])
|
|
14690
|
+
];
|
|
14691
|
+
}
|
|
14692
|
+
function addWriteEffects(requirements, resolved, segment, signals) {
|
|
14693
|
+
requirements.push(
|
|
14694
|
+
requirement2("fs.write", "fs.write", { kind: "path", path: resolved }, segment, signals)
|
|
14695
|
+
);
|
|
14696
|
+
if (CONTROL_PLANE_PATH_PATTERN.test(resolved)) {
|
|
14697
|
+
requirements.push(
|
|
14698
|
+
requirement2(
|
|
14699
|
+
"control_plane.write",
|
|
14700
|
+
"control_plane.write",
|
|
14701
|
+
{ kind: "path", path: resolved },
|
|
14702
|
+
segment,
|
|
14703
|
+
[...signals, "protected_path"]
|
|
14632
14704
|
)
|
|
14633
14705
|
);
|
|
14634
14706
|
}
|
|
14635
|
-
return lowered;
|
|
14636
|
-
}
|
|
14637
|
-
function startsLocalPostgresService(command) {
|
|
14638
|
-
const tokens = tokenizeShell(command);
|
|
14639
|
-
return path41.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
14640
14707
|
}
|
|
14641
|
-
function
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
|
|
14646
|
-
|
|
14647
|
-
|
|
14648
|
-
return { cwd: currentCwd, known: false };
|
|
14708
|
+
function addSecretRead(requirements, resolved, segment) {
|
|
14709
|
+
if (SECRET_PATH_PATTERN.test(resolved)) {
|
|
14710
|
+
requirements.push(
|
|
14711
|
+
requirement2("secret.read", "secret.read", { kind: "path", path: resolved }, segment, [
|
|
14712
|
+
"secret_path_read"
|
|
14713
|
+
])
|
|
14714
|
+
);
|
|
14649
14715
|
}
|
|
14650
|
-
return { cwd: resolvePathOperand(target, currentCwd), known: true };
|
|
14651
14716
|
}
|
|
14652
|
-
function
|
|
14653
|
-
if (
|
|
14654
|
-
|
|
14717
|
+
function ensureRequirement(requirements, candidate) {
|
|
14718
|
+
if (!requirements.some(
|
|
14719
|
+
(entry) => entry.action === candidate.action && JSON.stringify(entry.resource) === JSON.stringify(candidate.resource)
|
|
14720
|
+
)) {
|
|
14721
|
+
requirements.push(candidate);
|
|
14655
14722
|
}
|
|
14656
|
-
return requirementValue.action === "process.exec" && requirementValue.resource.kind === "executable" && requirementValue.resource.operation === "spawn";
|
|
14657
14723
|
}
|
|
14658
|
-
function
|
|
14659
|
-
const
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
14666
|
-
const environment = extractEnvironment(rawTokens, context.env);
|
|
14667
|
-
const env = environment.env;
|
|
14668
|
-
const parsed = parseSegment(command);
|
|
14669
|
-
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
14670
|
-
const tokens = stripRedirects(
|
|
14671
|
-
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
14672
|
-
).map((token) => expandKnownVariables(token, env));
|
|
14673
|
-
const decoderTokens = alignStructuredTokens(
|
|
14674
|
-
stripStructuredRedirects(lexed.tokens),
|
|
14675
|
-
stripRedirects(parsedTokens)
|
|
14676
|
-
);
|
|
14677
|
-
const head = path41.basename(tokens[0] ?? parsed.head);
|
|
14678
|
-
let opacity = segmentOpacity(command);
|
|
14679
|
-
const signals = /* @__PURE__ */ new Set();
|
|
14680
|
-
const requirements = [];
|
|
14681
|
-
if (!lexed.complete) {
|
|
14682
|
-
requirements.push(
|
|
14683
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14684
|
-
"shell.grammar_incomplete"
|
|
14685
|
-
])
|
|
14686
|
-
);
|
|
14687
|
-
signals.add("shell.grammar_incomplete");
|
|
14688
|
-
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
14689
|
-
}
|
|
14690
|
-
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
14691
|
-
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
14692
|
-
if (environment.malformed) {
|
|
14693
|
-
requirements.push(
|
|
14694
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14695
|
-
"shell.env_wrapper_incomplete"
|
|
14696
|
-
])
|
|
14697
|
-
);
|
|
14698
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14699
|
-
}
|
|
14700
|
-
if (parsed.encounteredXargs) {
|
|
14701
|
-
requirements.push(
|
|
14702
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14703
|
-
"shell.xargs_stdin_dynamic"
|
|
14704
|
-
])
|
|
14705
|
-
);
|
|
14706
|
-
signals.add("shell.xargs_stdin_dynamic");
|
|
14707
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14708
|
-
}
|
|
14709
|
-
if (context.depth > MAX_LOWER_DEPTH) {
|
|
14710
|
-
requirements.push(
|
|
14711
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14712
|
-
"shell.lower_depth_exceeded"
|
|
14713
|
-
])
|
|
14714
|
-
);
|
|
14715
|
-
return shellSegment(
|
|
14716
|
-
commandRedacted,
|
|
14717
|
-
head,
|
|
14718
|
-
requirements,
|
|
14719
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14720
|
-
signals
|
|
14721
|
-
);
|
|
14722
|
-
}
|
|
14723
|
-
const packageExec = peelPackageExecArgv(tokens);
|
|
14724
|
-
if (packageExec) {
|
|
14725
|
-
requirements.push(
|
|
14726
|
-
...decodePackageExec(packageExec, context.cwd, context.repoRoot, commandRedacted)
|
|
14727
|
-
);
|
|
14728
|
-
for (const signal of packageExec.signals) {
|
|
14729
|
-
signals.add(signal);
|
|
14730
|
-
}
|
|
14731
|
-
if (packageExec.opaque) {
|
|
14732
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14733
|
-
}
|
|
14734
|
-
const innerRecipe = packageExecInnerIsMetadata(packageExec) ? null : innerRecipeFromPeel(packageExec);
|
|
14735
|
-
if (innerRecipe) {
|
|
14736
|
-
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
14737
|
-
...context,
|
|
14738
|
-
command: innerRecipe,
|
|
14739
|
-
env,
|
|
14740
|
-
depth: context.depth + 1
|
|
14741
|
-
});
|
|
14742
|
-
for (const nestedSegment of nested) {
|
|
14743
|
-
requirements.push(
|
|
14744
|
-
...nestedSegment.requirements.map(
|
|
14745
|
-
(entry) => withInnerProvenance(entry, innerRecipe, packageExec.launcher, commandRedacted)
|
|
14746
|
-
)
|
|
14747
|
-
);
|
|
14748
|
-
for (const signal of nestedSegment.signals) {
|
|
14749
|
-
signals.add(signal);
|
|
14750
|
-
}
|
|
14751
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14752
|
-
}
|
|
14753
|
-
}
|
|
14754
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14755
|
-
}
|
|
14756
|
-
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
14757
|
-
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14758
|
-
requirements.push(
|
|
14759
|
-
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
14760
|
-
"shell.recursive_wrapper",
|
|
14761
|
-
"dynamic_shell_evaluation"
|
|
14762
|
-
])
|
|
14763
|
-
);
|
|
14764
|
-
if (recursive.script !== "") {
|
|
14765
|
-
const nested = lowerTopLevelSegments(recursive.script, {
|
|
14766
|
-
...context,
|
|
14767
|
-
command: recursive.script,
|
|
14768
|
-
env,
|
|
14769
|
-
depth: context.depth + 1
|
|
14770
|
-
});
|
|
14771
|
-
for (const nestedSegment of nested) {
|
|
14772
|
-
requirements.push(
|
|
14773
|
-
...nestedSegment.requirements.map(
|
|
14774
|
-
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
14775
|
-
)
|
|
14776
|
-
);
|
|
14777
|
-
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14778
|
-
}
|
|
14779
|
-
}
|
|
14780
|
-
signals.add("shell.recursive_wrapper");
|
|
14781
|
-
signals.add("dynamic_shell_evaluation");
|
|
14782
|
-
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14783
|
-
}
|
|
14784
|
-
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
14785
|
-
const recursiveSignals = [
|
|
14786
|
-
recursive.signal,
|
|
14787
|
-
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
14788
|
-
];
|
|
14789
|
-
requirements.push(
|
|
14790
|
-
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
14791
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14792
|
-
...recursiveSignals
|
|
14793
|
-
])
|
|
14794
|
-
);
|
|
14795
|
-
for (const signal of recursiveSignals) signals.add(signal);
|
|
14796
|
-
return shellSegment(
|
|
14797
|
-
commandRedacted,
|
|
14798
|
-
head,
|
|
14799
|
-
requirements,
|
|
14800
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14801
|
-
signals
|
|
14802
|
-
);
|
|
14803
|
-
}
|
|
14804
|
-
const compose = decodeDockerComposeRun(decoderTokens);
|
|
14805
|
-
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14806
|
-
requirements.push(
|
|
14807
|
-
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
14808
|
-
);
|
|
14809
|
-
if (compose.script !== "") {
|
|
14810
|
-
const nested = lowerTopLevelSegments(compose.script, {
|
|
14811
|
-
...context,
|
|
14812
|
-
command: compose.script,
|
|
14813
|
-
env,
|
|
14814
|
-
depth: context.depth + 1
|
|
14815
|
-
});
|
|
14816
|
-
for (const nestedSegment of nested) {
|
|
14817
|
-
requirements.push(
|
|
14818
|
-
...nestedSegment.requirements.map(
|
|
14819
|
-
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
14820
|
-
)
|
|
14821
|
-
);
|
|
14822
|
-
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14823
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14824
|
-
}
|
|
14825
|
-
}
|
|
14826
|
-
signals.add("process.docker_compose_run");
|
|
14827
|
-
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14828
|
-
}
|
|
14829
|
-
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
14830
|
-
requirements.push(
|
|
14831
|
-
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
14832
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14833
|
-
compose.signal
|
|
14834
|
-
])
|
|
14835
|
-
);
|
|
14836
|
-
signals.add("process.docker_compose_run");
|
|
14837
|
-
signals.add(compose.signal);
|
|
14838
|
-
return shellSegment(
|
|
14839
|
-
commandRedacted,
|
|
14840
|
-
head,
|
|
14841
|
-
requirements,
|
|
14842
|
-
joinEffectOpacity(opacity, "opaque"),
|
|
14843
|
-
signals
|
|
14844
|
-
);
|
|
14845
|
-
}
|
|
14846
|
-
const launcher = resolveLauncherRecipe({
|
|
14847
|
-
tokens,
|
|
14848
|
-
cwd: context.cwd,
|
|
14849
|
-
repoRoot: context.repoRoot,
|
|
14850
|
-
depth: context.depth
|
|
14851
|
-
});
|
|
14852
|
-
if (launcher) {
|
|
14853
|
-
signals.add(`launcher.${launcher.reason}`);
|
|
14854
|
-
requirements.push(
|
|
14855
|
-
requirement2(
|
|
14856
|
-
"process.exec",
|
|
14857
|
-
"process.exec",
|
|
14858
|
-
{ kind: "executable", command: head, operation: "spawn" },
|
|
14859
|
-
commandRedacted,
|
|
14860
|
-
["launcher.invoke"]
|
|
14861
|
-
)
|
|
14862
|
-
);
|
|
14863
|
-
for (const recipe of launcher.recipes) {
|
|
14864
|
-
const nested = lowerTopLevelSegments(recipe, {
|
|
14865
|
-
...context,
|
|
14866
|
-
command: recipe,
|
|
14867
|
-
env,
|
|
14868
|
-
depth: context.depth + 1
|
|
14869
|
-
});
|
|
14870
|
-
for (const nestedSegment of nested) {
|
|
14871
|
-
requirements.push(
|
|
14872
|
-
...nestedSegment.requirements.map(
|
|
14873
|
-
(entry) => withInnerProvenance(entry, recipe, head, commandRedacted)
|
|
14874
|
-
)
|
|
14875
|
-
);
|
|
14876
|
-
for (const signal of nestedSegment.signals) {
|
|
14877
|
-
signals.add(signal);
|
|
14878
|
-
}
|
|
14879
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14880
|
-
}
|
|
14881
|
-
}
|
|
14882
|
-
if (launcher.opaque || launcher.recipes.length === 0) {
|
|
14883
|
-
requirements.push(
|
|
14884
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14885
|
-
`launcher.${launcher.reason}`
|
|
14886
|
-
])
|
|
14887
|
-
);
|
|
14888
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14889
|
-
}
|
|
14890
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14891
|
-
}
|
|
14892
|
-
const egress = decodeEgressEffects({
|
|
14893
|
-
tokens,
|
|
14894
|
-
cwd: context.cwd,
|
|
14895
|
-
segment: commandRedacted
|
|
14896
|
-
});
|
|
14897
|
-
if (egress) {
|
|
14898
|
-
requirements.push(...egress);
|
|
14899
|
-
for (const signal of egress.flatMap((entry) => entry.evidence.signals)) {
|
|
14900
|
-
signals.add(signal);
|
|
14901
|
-
}
|
|
14902
|
-
} else {
|
|
14903
|
-
const git = decodeGitEffects({
|
|
14904
|
-
tokens,
|
|
14905
|
-
cwd: context.cwd,
|
|
14906
|
-
repoRoot: context.repoRoot,
|
|
14907
|
-
segment: commandRedacted
|
|
14908
|
-
});
|
|
14909
|
-
if (git) {
|
|
14910
|
-
requirements.push(...git);
|
|
14911
|
-
for (const signal of git.flatMap((entry) => entry.evidence.signals)) {
|
|
14912
|
-
signals.add(signal);
|
|
14913
|
-
}
|
|
14914
|
-
} else {
|
|
14915
|
-
requirements.push(
|
|
14916
|
-
...decodeProcessOrFilesystem({
|
|
14917
|
-
tokens,
|
|
14918
|
-
head,
|
|
14919
|
-
env,
|
|
14920
|
-
cwd: context.cwd,
|
|
14921
|
-
repoRoot: context.repoRoot,
|
|
14922
|
-
segment: commandRedacted
|
|
14923
|
-
})
|
|
14924
|
-
);
|
|
14925
|
-
}
|
|
14926
|
-
}
|
|
14927
|
-
const environmentSignals = effectChangingEnvironmentSignals(head, env, environment.changedNames);
|
|
14928
|
-
if (environmentSignals.length > 0) {
|
|
14929
|
-
requirements.push(
|
|
14930
|
-
requirement2(
|
|
14931
|
-
"indeterminate",
|
|
14932
|
-
"indeterminate",
|
|
14933
|
-
{ kind: "unknown" },
|
|
14934
|
-
commandRedacted,
|
|
14935
|
-
environmentSignals
|
|
14936
|
-
)
|
|
14937
|
-
);
|
|
14938
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14939
|
-
for (const signal of environmentSignals) {
|
|
14940
|
-
signals.add(signal);
|
|
14941
|
-
}
|
|
14942
|
-
}
|
|
14943
|
-
if (context.pipeToShellSegment) {
|
|
14944
|
-
signals.add("pipe_to_shell");
|
|
14945
|
-
ensureRequirement(
|
|
14946
|
-
requirements,
|
|
14947
|
-
requirement2(
|
|
14948
|
-
"process.exec",
|
|
14949
|
-
"process.exec",
|
|
14950
|
-
{ kind: "executable", command: head || "sh", operation: "spawn" },
|
|
14951
|
-
commandRedacted,
|
|
14952
|
-
["pipe_to_shell"]
|
|
14953
|
-
)
|
|
14954
|
-
);
|
|
14955
|
-
ensureRequirement(
|
|
14956
|
-
requirements,
|
|
14957
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14958
|
-
"pipe_to_shell"
|
|
14959
|
-
])
|
|
14960
|
-
);
|
|
14961
|
-
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14962
|
-
}
|
|
14963
|
-
if (opacity === "unparseable" || opacity === "opaque") {
|
|
14964
|
-
ensureRequirement(
|
|
14965
|
-
requirements,
|
|
14966
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14967
|
-
`shell.${opacity}`
|
|
14968
|
-
])
|
|
14969
|
-
);
|
|
14970
|
-
}
|
|
14971
|
-
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14972
|
-
}
|
|
14973
|
-
function decodePackageExec(peel, cwd, repoRoot, segment) {
|
|
14974
|
-
if (peel.opaque) {
|
|
14975
|
-
return [
|
|
14976
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14977
|
-
peel.reason,
|
|
14978
|
-
...peel.signals
|
|
14979
|
-
])
|
|
14980
|
-
];
|
|
14981
|
-
}
|
|
14982
|
-
if (peel.reason === "npx_wrapper_readonly") {
|
|
14983
|
-
return [];
|
|
14984
|
-
}
|
|
14985
|
-
const binHead = peel.innerTokens[0] ?? "";
|
|
14986
|
-
const metadataOnly = packageExecInnerIsMetadata(peel);
|
|
14987
|
-
const local = !peel.forceAcquire ? resolveLocalBin(binHead, cwd, repoRoot) : null;
|
|
14988
|
-
if (local) {
|
|
14989
|
-
return metadataOnly ? [
|
|
14990
|
-
requirement2(
|
|
14991
|
-
"process.exec",
|
|
14992
|
-
"process.exec",
|
|
14993
|
-
{ kind: "executable", command: local.path, operation: "inspect" },
|
|
14994
|
-
segment,
|
|
14995
|
-
["package_exec.delegate", "package_exec.local_bin_resolved"]
|
|
14996
|
-
)
|
|
14997
|
-
] : [];
|
|
14998
|
-
}
|
|
14999
|
-
const networkResources = peel.acquisitionSpecs.map((spec) => classifyPackageAcquisitionSpec(spec)).filter((source) => source.kind !== "local").map(
|
|
15000
|
-
(source) => source.kind === "registry" ? {
|
|
15001
|
-
kind: "network",
|
|
15002
|
-
host: "registry.npmjs.org",
|
|
15003
|
-
protocol: "registry",
|
|
15004
|
-
mode: "read",
|
|
15005
|
-
payload: "none"
|
|
15006
|
-
} : {
|
|
15007
|
-
kind: "network",
|
|
15008
|
-
host: source.host,
|
|
15009
|
-
...source.port ? { port: source.port } : {},
|
|
15010
|
-
protocol: source.protocol,
|
|
15011
|
-
mode: "read",
|
|
15012
|
-
payload: "none"
|
|
15013
|
-
}
|
|
14724
|
+
function withProvenances(requirementValue, provenance, contributing) {
|
|
14725
|
+
const provenances = [
|
|
14726
|
+
...requirementValue.provenances ?? [requirementValue.provenance],
|
|
14727
|
+
contributing,
|
|
14728
|
+
provenance
|
|
14729
|
+
].filter(
|
|
14730
|
+
(candidate, index, all) => all.findIndex((entry) => JSON.stringify(entry) === JSON.stringify(candidate)) === index
|
|
15014
14731
|
);
|
|
15015
|
-
|
|
15016
|
-
networkResources.push({
|
|
15017
|
-
kind: "network",
|
|
15018
|
-
host: "registry.npmjs.org",
|
|
15019
|
-
protocol: "registry",
|
|
15020
|
-
mode: "read",
|
|
15021
|
-
payload: "none"
|
|
15022
|
-
});
|
|
15023
|
-
}
|
|
15024
|
-
return [
|
|
15025
|
-
...networkResources.map(
|
|
15026
|
-
(resource) => requirement2("network.acquire", "network.connect", resource, segment, [
|
|
15027
|
-
"package_acquire_possible"
|
|
15028
|
-
])
|
|
15029
|
-
),
|
|
15030
|
-
requirement2(
|
|
15031
|
-
"fs.write",
|
|
15032
|
-
"fs.write",
|
|
15033
|
-
{ kind: "package-cache", manager: peel.launcher === "pnpm" ? "pnpm" : "npm" },
|
|
15034
|
-
segment,
|
|
15035
|
-
["package_cache_write"]
|
|
15036
|
-
),
|
|
15037
|
-
...metadataOnly ? [
|
|
15038
|
-
requirement2(
|
|
15039
|
-
"process.exec",
|
|
15040
|
-
"process.exec",
|
|
15041
|
-
{ kind: "executable", command: binHead || peel.launcher, operation: "inspect" },
|
|
15042
|
-
segment,
|
|
15043
|
-
["package_exec.delegate"]
|
|
15044
|
-
)
|
|
15045
|
-
] : []
|
|
15046
|
-
];
|
|
14732
|
+
return { ...requirementValue, provenance, provenances };
|
|
15047
14733
|
}
|
|
15048
|
-
function
|
|
15049
|
-
const
|
|
15050
|
-
|
|
14734
|
+
function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegment) {
|
|
14735
|
+
const provenance = {
|
|
14736
|
+
...requirementValue.provenance,
|
|
14737
|
+
segment: outerSegment,
|
|
14738
|
+
innerCommand: requirementValue.provenance.innerCommand ?? innerCommand,
|
|
14739
|
+
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
14740
|
+
};
|
|
14741
|
+
const launcherProvenance = {
|
|
14742
|
+
segment: outerSegment,
|
|
14743
|
+
innerCommand,
|
|
14744
|
+
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
14745
|
+
};
|
|
14746
|
+
return withProvenances(requirementValue, provenance, launcherProvenance);
|
|
15051
14747
|
}
|
|
14748
|
+
|
|
14749
|
+
// src/core/effect-ir/shell-lower/tokens.ts
|
|
14750
|
+
init_shell_tokenizer();
|
|
14751
|
+
import path42 from "node:path";
|
|
14752
|
+
var ENV_PREFIX_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
14753
|
+
var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "0:0:0:0:0:0:0:1"]);
|
|
15052
14754
|
var METADATA_ONLY_FLAGS = /* @__PURE__ */ new Set(["--version", "-v", "-V", "--help", "-h"]);
|
|
15053
|
-
function
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
const includePaths = [];
|
|
15073
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
15074
|
-
const arg = args[index] ?? "";
|
|
15075
|
-
if (arg === "-e" || arg === "-r") {
|
|
15076
|
-
return null;
|
|
15077
|
-
}
|
|
15078
|
-
if (arg === "-I") {
|
|
15079
|
-
const includePath = args[index + 1];
|
|
15080
|
-
if (!includePath) {
|
|
15081
|
-
return null;
|
|
14755
|
+
function extractEnvironment(tokens, inherited) {
|
|
14756
|
+
const env = { ...inherited };
|
|
14757
|
+
const changedNames = /* @__PURE__ */ new Set();
|
|
14758
|
+
if (tokens[0] === "env") {
|
|
14759
|
+
let index = 1;
|
|
14760
|
+
let malformed = false;
|
|
14761
|
+
while (index < tokens.length) {
|
|
14762
|
+
const option = tokens[index] ?? "";
|
|
14763
|
+
if (option === "-u" || option === "--unset") {
|
|
14764
|
+
const name = tokens[index + 1] ?? "";
|
|
14765
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
14766
|
+
malformed = true;
|
|
14767
|
+
index += 1;
|
|
14768
|
+
break;
|
|
14769
|
+
}
|
|
14770
|
+
delete env[name];
|
|
14771
|
+
changedNames.add(name);
|
|
14772
|
+
index += 2;
|
|
14773
|
+
continue;
|
|
15082
14774
|
}
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15089
|
-
continue;
|
|
15090
|
-
}
|
|
15091
|
-
if (arg.startsWith("-")) {
|
|
15092
|
-
if (arg === "-n") {
|
|
15093
|
-
if (!args[index + 1]) {
|
|
15094
|
-
return null;
|
|
14775
|
+
if (option.startsWith("--unset=")) {
|
|
14776
|
+
const name = option.slice("--unset=".length);
|
|
14777
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
14778
|
+
malformed = true;
|
|
14779
|
+
index += 1;
|
|
14780
|
+
break;
|
|
15095
14781
|
}
|
|
14782
|
+
delete env[name];
|
|
14783
|
+
changedNames.add(name);
|
|
15096
14784
|
index += 1;
|
|
15097
14785
|
continue;
|
|
15098
14786
|
}
|
|
15099
|
-
if (
|
|
14787
|
+
if (option === "-i" || option === "--ignore-environment") {
|
|
14788
|
+
for (const name of Object.keys(env)) {
|
|
14789
|
+
delete env[name];
|
|
14790
|
+
}
|
|
14791
|
+
changedNames.add("*");
|
|
14792
|
+
index += 1;
|
|
15100
14793
|
continue;
|
|
15101
14794
|
}
|
|
15102
|
-
|
|
14795
|
+
if (option === "--") {
|
|
14796
|
+
index += 1;
|
|
14797
|
+
break;
|
|
14798
|
+
}
|
|
14799
|
+
if (option.startsWith("-")) {
|
|
14800
|
+
malformed = true;
|
|
14801
|
+
index += 1;
|
|
14802
|
+
break;
|
|
14803
|
+
}
|
|
14804
|
+
break;
|
|
15103
14805
|
}
|
|
15104
|
-
|
|
15105
|
-
|
|
14806
|
+
while (index < tokens.length) {
|
|
14807
|
+
const token = tokens[index] ?? "";
|
|
14808
|
+
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
14809
|
+
if (!match) {
|
|
14810
|
+
break;
|
|
14811
|
+
}
|
|
14812
|
+
const [, name, value] = match;
|
|
14813
|
+
if (name) {
|
|
14814
|
+
env[name] = expandKnownVariables(value ?? "", env);
|
|
14815
|
+
changedNames.add(name);
|
|
14816
|
+
}
|
|
14817
|
+
index += 1;
|
|
15106
14818
|
}
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
);
|
|
15115
|
-
}
|
|
15116
|
-
function decodeBundleExecInner(innerHead, innerArgs, segment) {
|
|
15117
|
-
const innerBase = executableBaseName(innerHead);
|
|
15118
|
-
if (innerBase === "rubocop") {
|
|
15119
|
-
const mutating = isRubocopMutating(innerArgs);
|
|
15120
|
-
return [
|
|
15121
|
-
processRequirement(
|
|
15122
|
-
innerHead,
|
|
15123
|
-
mutating ? "spawn" : "inspect",
|
|
15124
|
-
segment,
|
|
15125
|
-
mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
|
|
15126
|
-
)
|
|
15127
|
-
];
|
|
14819
|
+
const commandTokens = tokens.slice(index);
|
|
14820
|
+
return {
|
|
14821
|
+
env,
|
|
14822
|
+
commandTokens,
|
|
14823
|
+
malformed: malformed || commandTokens.length === 0,
|
|
14824
|
+
changedNames
|
|
14825
|
+
};
|
|
15128
14826
|
}
|
|
15129
|
-
|
|
15130
|
-
const
|
|
15131
|
-
if (
|
|
15132
|
-
|
|
14827
|
+
for (const token of tokens) {
|
|
14828
|
+
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
14829
|
+
if (!match) {
|
|
14830
|
+
break;
|
|
14831
|
+
}
|
|
14832
|
+
const [, name, value] = match;
|
|
14833
|
+
if (name) {
|
|
14834
|
+
env[name] = expandKnownVariables(value ?? "", env);
|
|
14835
|
+
changedNames.add(name);
|
|
15133
14836
|
}
|
|
15134
|
-
return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
|
|
15135
14837
|
}
|
|
15136
|
-
return
|
|
14838
|
+
return { env, malformed: false, changedNames };
|
|
15137
14839
|
}
|
|
15138
|
-
function
|
|
15139
|
-
|
|
15140
|
-
|
|
15141
|
-
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15145
|
-
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15146
|
-
}
|
|
15147
|
-
for (const includePath of parsed.includePaths) {
|
|
15148
|
-
const resolvedInclude = resolvePathOperand(includePath, cwd);
|
|
15149
|
-
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
|
|
15150
|
-
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
14840
|
+
function expandKnownVariables(token, env) {
|
|
14841
|
+
return token.replace(
|
|
14842
|
+
/\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g,
|
|
14843
|
+
(raw, a, b) => {
|
|
14844
|
+
const value = env[a ?? b];
|
|
14845
|
+
return value === void 0 ? raw : value;
|
|
15151
14846
|
}
|
|
15152
|
-
|
|
15153
|
-
const lowered = [
|
|
15154
|
-
processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
|
|
15155
|
-
requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
|
|
15156
|
-
"ruby.minitest_script_read"
|
|
15157
|
-
])
|
|
15158
|
-
];
|
|
15159
|
-
for (const includePath of parsed.includePaths) {
|
|
15160
|
-
lowered.push(
|
|
15161
|
-
requirement2(
|
|
15162
|
-
"fs.read",
|
|
15163
|
-
"fs.read",
|
|
15164
|
-
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15165
|
-
segment,
|
|
15166
|
-
["ruby.minitest_load_path_read"]
|
|
15167
|
-
)
|
|
15168
|
-
);
|
|
15169
|
-
}
|
|
15170
|
-
return lowered;
|
|
14847
|
+
);
|
|
15171
14848
|
}
|
|
15172
|
-
function
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
14849
|
+
function stripRedirects(tokens) {
|
|
14850
|
+
const stripped = [];
|
|
14851
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14852
|
+
const token = tokens[index] ?? "";
|
|
14853
|
+
if (isFdDuplication(token)) {
|
|
14854
|
+
continue;
|
|
15176
14855
|
}
|
|
15177
|
-
if (
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
const innerBase = executableBaseName(innerHead);
|
|
15181
|
-
if ((innerBase === "rails" || innerBase === "rake") && railsReadOnlySubcommand(innerArgs)) {
|
|
15182
|
-
return [
|
|
15183
|
-
processRequirement(innerHead, "inspect", segment, ["process.inspect.rails_read_only"])
|
|
15184
|
-
];
|
|
15185
|
-
}
|
|
15186
|
-
if (isMetadataOnlyArgv(innerArgs)) {
|
|
15187
|
-
return [
|
|
15188
|
-
processRequirement(innerHead, "inspect", segment, [
|
|
15189
|
-
"process.inspect.bundle_exec_metadata"
|
|
15190
|
-
])
|
|
15191
|
-
];
|
|
15192
|
-
}
|
|
15193
|
-
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15194
|
-
if (bundleExecInner) {
|
|
15195
|
-
return bundleExecInner;
|
|
15196
|
-
}
|
|
14856
|
+
if (!isRedirectOperator(token)) {
|
|
14857
|
+
stripped.push(token);
|
|
14858
|
+
continue;
|
|
15197
14859
|
}
|
|
15198
|
-
|
|
15199
|
-
}
|
|
15200
|
-
if ((head === "ruby" || head === "yarn") && args.length >= 1 && isMetadataOnlyArgv(args)) {
|
|
15201
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15202
|
-
}
|
|
15203
|
-
if (head === "make" && args.includes("-n")) {
|
|
15204
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.make_dry_run"])];
|
|
15205
|
-
}
|
|
15206
|
-
const base = executableBaseName(head);
|
|
15207
|
-
if ((base === "rails" || base === "rake") && railsReadOnlySubcommand(args)) {
|
|
15208
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.rails_read_only"])];
|
|
14860
|
+
index += 1;
|
|
15209
14861
|
}
|
|
15210
|
-
return
|
|
14862
|
+
return stripped;
|
|
15211
14863
|
}
|
|
15212
|
-
function
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
const
|
|
15216
|
-
if (
|
|
15217
|
-
|
|
14864
|
+
function stripStructuredRedirects(tokens) {
|
|
14865
|
+
const stripped = [];
|
|
14866
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14867
|
+
const token = tokens[index];
|
|
14868
|
+
if (!token) continue;
|
|
14869
|
+
if (isFdDuplication(token.value)) {
|
|
15218
14870
|
continue;
|
|
15219
14871
|
}
|
|
15220
|
-
if (
|
|
15221
|
-
|
|
15222
|
-
return false;
|
|
15223
|
-
}
|
|
15224
|
-
index += 2;
|
|
14872
|
+
if (!isRedirectOperator(token.value)) {
|
|
14873
|
+
stripped.push(token);
|
|
15225
14874
|
continue;
|
|
15226
14875
|
}
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
14876
|
+
index += 1;
|
|
14877
|
+
}
|
|
14878
|
+
return stripped;
|
|
14879
|
+
}
|
|
14880
|
+
function alignStructuredTokens(tokens, values) {
|
|
14881
|
+
if (values.length === 0) return [];
|
|
14882
|
+
for (let start = tokens.length - values.length; start >= 0; start -= 1) {
|
|
14883
|
+
const candidate = tokens.slice(start);
|
|
14884
|
+
if (candidate.length === values.length && candidate.every((token, index) => token.value === values[index])) {
|
|
14885
|
+
return candidate;
|
|
15230
14886
|
}
|
|
15231
|
-
return false;
|
|
15232
14887
|
}
|
|
15233
|
-
return
|
|
14888
|
+
return [];
|
|
15234
14889
|
}
|
|
15235
|
-
function
|
|
15236
|
-
if (
|
|
15237
|
-
return
|
|
14890
|
+
function resolvePathOperand(operand, cwd) {
|
|
14891
|
+
if (operand === "~") {
|
|
14892
|
+
return process.env.HOME ?? operand;
|
|
15238
14893
|
}
|
|
15239
|
-
if (
|
|
15240
|
-
|
|
15241
|
-
|
|
15242
|
-
|
|
14894
|
+
if (operand.startsWith("~/")) {
|
|
14895
|
+
return path42.join(process.env.HOME ?? "~", operand.slice(2));
|
|
14896
|
+
}
|
|
14897
|
+
return path42.resolve(cwd, operand);
|
|
14898
|
+
}
|
|
14899
|
+
function isOptionToken(value) {
|
|
14900
|
+
return value.startsWith("-") || value.startsWith("+");
|
|
14901
|
+
}
|
|
14902
|
+
function isShellHead(head) {
|
|
14903
|
+
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
14904
|
+
}
|
|
14905
|
+
function pipeToShell(command) {
|
|
14906
|
+
return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
|
|
14907
|
+
}
|
|
14908
|
+
function executableBaseName(head) {
|
|
14909
|
+
return path42.basename(head);
|
|
14910
|
+
}
|
|
14911
|
+
function isMetadataOnlyArgv(argv) {
|
|
14912
|
+
return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
|
|
14913
|
+
}
|
|
14914
|
+
function databaseEndpoint(raw) {
|
|
14915
|
+
if (!raw || raw.includes("$")) {
|
|
15243
14916
|
return null;
|
|
15244
14917
|
}
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
14918
|
+
try {
|
|
14919
|
+
const url = new URL(raw);
|
|
14920
|
+
if (!url.hostname || !url.protocol) {
|
|
14921
|
+
return null;
|
|
15248
14922
|
}
|
|
14923
|
+
return {
|
|
14924
|
+
host: url.hostname.toLowerCase(),
|
|
14925
|
+
protocol: url.protocol.slice(0, -1),
|
|
14926
|
+
...url.port ? { port: Number(url.port) } : {}
|
|
14927
|
+
};
|
|
14928
|
+
} catch {
|
|
15249
14929
|
return null;
|
|
15250
14930
|
}
|
|
15251
|
-
return null;
|
|
15252
|
-
}
|
|
15253
|
-
function decodeDockerComposeRun2(head, args, segment) {
|
|
15254
|
-
let composeArgs = null;
|
|
15255
|
-
let command = head;
|
|
15256
|
-
if (head === "docker-compose") {
|
|
15257
|
-
composeArgs = args;
|
|
15258
|
-
} else if (head === "docker" && args[0] === "compose") {
|
|
15259
|
-
composeArgs = args.slice(1);
|
|
15260
|
-
command = "docker";
|
|
15261
|
-
}
|
|
15262
|
-
if (!composeArgs) {
|
|
15263
|
-
return null;
|
|
15264
|
-
}
|
|
15265
|
-
if (composeArgs.includes("run")) {
|
|
15266
|
-
return [processRequirement(command, "spawn", segment, ["process.docker_compose_run"])];
|
|
15267
|
-
}
|
|
15268
|
-
return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
|
|
15269
14931
|
}
|
|
15270
|
-
|
|
15271
|
-
|
|
15272
|
-
|
|
15273
|
-
|
|
15274
|
-
|
|
15275
|
-
|
|
15276
|
-
|
|
15277
|
-
if (shellControl) {
|
|
15278
|
-
return shellControl;
|
|
15279
|
-
}
|
|
15280
|
-
if (isCommandInspection(tokens)) {
|
|
15281
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
15282
|
-
}
|
|
15283
|
-
if (head === "lsof") {
|
|
15284
|
-
return validLsof(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.lsof"])] : unsupportedProcess(head, segment, "process.lsof_grammar_incomplete");
|
|
15285
|
-
}
|
|
15286
|
-
if (head === "ps") {
|
|
15287
|
-
return validPs(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.ps"])] : unsupportedProcess(head, segment, "process.ps_grammar_incomplete");
|
|
15288
|
-
}
|
|
15289
|
-
if (head === "test" || head === "[") {
|
|
15290
|
-
return validFilesystemTest(head, args) ? [processRequirement(head, "inspect", segment, ["process.inspect.filesystem_test"])] : unsupportedProcess(head, segment, "process.filesystem_test_grammar_incomplete");
|
|
15291
|
-
}
|
|
15292
|
-
if (head === "docker") {
|
|
15293
|
-
if (args[0] === "info") {
|
|
15294
|
-
return validDockerInfo(args.slice(1)) ? [processRequirement(head, "inspect", segment, ["process.inspect.docker_info"])] : unsupportedProcess(head, segment, "process.docker_info_grammar_incomplete");
|
|
14932
|
+
|
|
14933
|
+
// src/core/effect-ir/shell-lower/augment.ts
|
|
14934
|
+
function addRedirectEffects(requirements, tokens, env, context, segment) {
|
|
14935
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
14936
|
+
const operator = tokens[index] ?? "";
|
|
14937
|
+
if (!isRedirectOperator(operator) || isFdDuplication(operator)) {
|
|
14938
|
+
continue;
|
|
15295
14939
|
}
|
|
15296
|
-
|
|
15297
|
-
|
|
14940
|
+
const rawTarget = tokens[index + 1];
|
|
14941
|
+
if (!rawTarget) {
|
|
14942
|
+
requirements.push(
|
|
14943
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14944
|
+
"shell.redirect_target_missing"
|
|
14945
|
+
])
|
|
14946
|
+
);
|
|
14947
|
+
continue;
|
|
15298
14948
|
}
|
|
15299
|
-
if (
|
|
15300
|
-
|
|
15301
|
-
|
|
15302
|
-
|
|
15303
|
-
|
|
15304
|
-
|
|
15305
|
-
|
|
15306
|
-
|
|
15307
|
-
{
|
|
15308
|
-
kind: "network",
|
|
15309
|
-
host: "registry",
|
|
15310
|
-
protocol: "container-registry",
|
|
15311
|
-
mode: "mutate",
|
|
15312
|
-
payload: "present"
|
|
15313
|
-
},
|
|
15314
|
-
segment,
|
|
15315
|
-
["tier0_external", "docker.remote_mutation"]
|
|
15316
|
-
)
|
|
15317
|
-
];
|
|
14949
|
+
if (operator.includes("<<")) {
|
|
14950
|
+
requirements.push(
|
|
14951
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
14952
|
+
"shell.heredoc_opaque"
|
|
14953
|
+
])
|
|
14954
|
+
);
|
|
14955
|
+
index += 1;
|
|
14956
|
+
continue;
|
|
15318
14957
|
}
|
|
15319
|
-
|
|
15320
|
-
|
|
15321
|
-
|
|
15322
|
-
|
|
15323
|
-
|
|
15324
|
-
"network.connect",
|
|
15325
|
-
{
|
|
15326
|
-
kind: "network",
|
|
15327
|
-
host: "unknown",
|
|
15328
|
-
protocol: "container-registry",
|
|
15329
|
-
mode: "ambiguous",
|
|
15330
|
-
payload: "none"
|
|
15331
|
-
},
|
|
15332
|
-
segment,
|
|
15333
|
-
["docker.image_acquisition_possible"]
|
|
15334
|
-
)
|
|
15335
|
-
];
|
|
14958
|
+
const target = expandKnownVariables(rawTarget, env);
|
|
14959
|
+
const resolved = resolvePathOperand(target, context.cwd);
|
|
14960
|
+
if (resolved === "/dev/null") {
|
|
14961
|
+
index += 1;
|
|
14962
|
+
continue;
|
|
15336
14963
|
}
|
|
15337
|
-
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
|
|
15341
|
-
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
requirement2(
|
|
15345
|
-
"fs.read",
|
|
15346
|
-
"fs.read",
|
|
15347
|
-
{ kind: "path", path: path41.resolve(cwd, syntax) },
|
|
15348
|
-
segment,
|
|
15349
|
-
["shell.syntax_source_read"]
|
|
15350
|
-
)
|
|
15351
|
-
];
|
|
14964
|
+
if (operator.includes("<")) {
|
|
14965
|
+
requirements.push(
|
|
14966
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
14967
|
+
"shell.input_redirect"
|
|
14968
|
+
])
|
|
14969
|
+
);
|
|
14970
|
+
addSecretRead(requirements, resolved, segment);
|
|
15352
14971
|
}
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
if (head === "prisma") {
|
|
15356
|
-
return decodePrisma(args, env, repoRoot, segment);
|
|
15357
|
-
}
|
|
15358
|
-
const runtimeMetadata = decodeRuntimeMetadataProcess(head, args, segment);
|
|
15359
|
-
if (runtimeMetadata) {
|
|
15360
|
-
return runtimeMetadata;
|
|
15361
|
-
}
|
|
15362
|
-
if (head === "ruby") {
|
|
15363
|
-
return decodeRuby(args, cwd, repoRoot, segment);
|
|
15364
|
-
}
|
|
15365
|
-
if (head === "rubocop" || head === "rspec") {
|
|
15366
|
-
const decoded = decodeBundleExecInner(head, args, segment);
|
|
15367
|
-
if (decoded) {
|
|
15368
|
-
return decoded;
|
|
14972
|
+
if (operator.includes(">")) {
|
|
14973
|
+
addWriteEffects(requirements, resolved, segment, ["shell.output_redirect"]);
|
|
15369
14974
|
}
|
|
14975
|
+
index += 1;
|
|
15370
14976
|
}
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
15376
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
15377
|
-
}
|
|
15378
|
-
if (head === "belay") {
|
|
15379
|
-
return decodeBelay(args, repoRoot, segment);
|
|
15380
|
-
}
|
|
15381
|
-
if (head === "tsc") {
|
|
15382
|
-
return decodeTsc(args, cwd, segment);
|
|
15383
|
-
}
|
|
15384
|
-
if (head === "go") {
|
|
15385
|
-
return decodeGo(args, segment);
|
|
15386
|
-
}
|
|
15387
|
-
if (head === "rsync") {
|
|
15388
|
-
return decodeRsync(args, cwd, segment);
|
|
15389
|
-
}
|
|
15390
|
-
if (head === "sed") {
|
|
15391
|
-
return decodeSed(args, cwd, segment);
|
|
15392
|
-
}
|
|
15393
|
-
if (head === "base64" && args.length === 1 && ["-d", "-D", "--decode"].includes(args[0] ?? "")) {
|
|
15394
|
-
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
15395
|
-
}
|
|
15396
|
-
if (head === "node") {
|
|
15397
|
-
return decodeNode2(args, cwd, segment);
|
|
15398
|
-
}
|
|
15399
|
-
if (head === "vite" || head === "vite-node") {
|
|
15400
|
-
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
14977
|
+
}
|
|
14978
|
+
function effectChangingEnvironmentSignals(head, env, changedNames) {
|
|
14979
|
+
if (head === "curl" && (env.CURL_HOME || changedNames.has("CURL_HOME") || changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME"))) {
|
|
14980
|
+
return ["egress.curl.environment_config_override"];
|
|
15401
14981
|
}
|
|
15402
|
-
if (
|
|
15403
|
-
return [
|
|
15404
|
-
processRequirement(head, "spawn", segment, ["tier0_external"]),
|
|
15405
|
-
requirement2(
|
|
15406
|
-
"network.connect",
|
|
15407
|
-
"network.connect",
|
|
15408
|
-
{
|
|
15409
|
-
kind: "network",
|
|
15410
|
-
host: "control-plane",
|
|
15411
|
-
protocol: head,
|
|
15412
|
-
mode: "mutate",
|
|
15413
|
-
payload: "present"
|
|
15414
|
-
},
|
|
15415
|
-
segment,
|
|
15416
|
-
["tier0_external"]
|
|
15417
|
-
)
|
|
15418
|
-
];
|
|
14982
|
+
if (head === "wget" && (env.WGETRC || changedNames.has("WGETRC") || changedNames.has("HOME"))) {
|
|
14983
|
+
return ["egress.wget.environment_config_override"];
|
|
15419
14984
|
}
|
|
15420
|
-
if (head
|
|
14985
|
+
if (head !== "git") {
|
|
15421
14986
|
return [];
|
|
15422
14987
|
}
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15440
|
-
|
|
15441
|
-
|
|
15442
|
-
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
|
|
14988
|
+
const hazardousNames = /* @__PURE__ */ new Set([
|
|
14989
|
+
"GIT_ASKPASS",
|
|
14990
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
14991
|
+
"GIT_CEILING_DIRECTORIES",
|
|
14992
|
+
"GIT_COMMON_DIR",
|
|
14993
|
+
"GIT_CONFIG",
|
|
14994
|
+
"GIT_CONFIG_GLOBAL",
|
|
14995
|
+
"GIT_CONFIG_SYSTEM",
|
|
14996
|
+
"GIT_DIR",
|
|
14997
|
+
"GIT_DISCOVERY_ACROSS_FILESYSTEM",
|
|
14998
|
+
"GIT_EDITOR",
|
|
14999
|
+
"GIT_EXEC_PATH",
|
|
15000
|
+
"GIT_EXTERNAL_DIFF",
|
|
15001
|
+
"GIT_INDEX_FILE",
|
|
15002
|
+
"GIT_NAMESPACE",
|
|
15003
|
+
"GIT_OBJECT_DIRECTORY",
|
|
15004
|
+
"GIT_PAGER",
|
|
15005
|
+
"GIT_PROXY_COMMAND",
|
|
15006
|
+
"GIT_QUARANTINE_PATH",
|
|
15007
|
+
"GIT_SEQUENCE_EDITOR",
|
|
15008
|
+
"GIT_SHALLOW_FILE",
|
|
15009
|
+
"GIT_SSH",
|
|
15010
|
+
"GIT_SSH_COMMAND",
|
|
15011
|
+
"GIT_TEMPLATE_DIR",
|
|
15012
|
+
"GIT_WORK_TREE",
|
|
15013
|
+
"SSH_ASKPASS"
|
|
15014
|
+
]);
|
|
15015
|
+
const overridden = changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME") || Object.entries(env).some(([name, value]) => {
|
|
15016
|
+
if (!value) {
|
|
15017
|
+
return false;
|
|
15446
15018
|
}
|
|
15447
|
-
|
|
15448
|
-
|
|
15449
|
-
const writeOperands = filesystemWriteOperands(head, args);
|
|
15450
|
-
if (writeOperands !== null) {
|
|
15451
|
-
const lowered = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
15452
|
-
for (const operand of writeOperands) {
|
|
15453
|
-
addWriteEffects(lowered, resolvePathOperand(operand, cwd), segment, ["filesystem.write"]);
|
|
15019
|
+
if (hazardousNames.has(name) || /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(name) || /^GIT_TRACE/.test(name)) {
|
|
15020
|
+
return true;
|
|
15454
15021
|
}
|
|
15455
|
-
return
|
|
15456
|
-
}
|
|
15457
|
-
|
|
15458
|
-
return [];
|
|
15459
|
-
}
|
|
15460
|
-
if (!head) {
|
|
15461
|
-
return [
|
|
15462
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15463
|
-
"shell.segment_empty"
|
|
15464
|
-
])
|
|
15465
|
-
];
|
|
15466
|
-
}
|
|
15467
|
-
return unsupportedProcess(head, segment, "process.grammar_unknown");
|
|
15022
|
+
return name === "GIT_CONFIG_COUNT" && value !== "0";
|
|
15023
|
+
});
|
|
15024
|
+
return overridden ? ["git.environment_execution_or_config_override"] : [];
|
|
15468
15025
|
}
|
|
15026
|
+
|
|
15027
|
+
// src/core/effect-ir/shell-lower/decode-process.ts
|
|
15028
|
+
import path46 from "node:path";
|
|
15029
|
+
|
|
15030
|
+
// src/core/effect-ir/shell-lower/decoders/belay.ts
|
|
15031
|
+
import path43 from "node:path";
|
|
15469
15032
|
function decodeBelay(args, repoRoot, segment) {
|
|
15470
15033
|
const [section, operation, key] = args;
|
|
15471
15034
|
const judgeCommand = section === "judge" && operation !== void 0 && ["consent", "list", "status", "test", "use"].includes(operation);
|
|
@@ -15484,7 +15047,7 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
15484
15047
|
requirement2(
|
|
15485
15048
|
"control_plane.write",
|
|
15486
15049
|
"control_plane.write",
|
|
15487
|
-
{ kind: "path", path:
|
|
15050
|
+
{ kind: "path", path: path43.join(repoRoot, ".belay-control-plane") },
|
|
15488
15051
|
segment,
|
|
15489
15052
|
["belay.config_non_judge_mutation"]
|
|
15490
15053
|
)
|
|
@@ -15492,33 +15055,240 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
15492
15055
|
}
|
|
15493
15056
|
return [processRequirement("belay", "spawn", segment, ["process.known_local_spawn"])];
|
|
15494
15057
|
}
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
let
|
|
15058
|
+
|
|
15059
|
+
// src/core/effect-ir/shell-lower/decoders/builtins.ts
|
|
15060
|
+
function decodeSetBuiltin(args) {
|
|
15061
|
+
let index = 0;
|
|
15062
|
+
while (index < args.length) {
|
|
15063
|
+
const arg = args[index] ?? "";
|
|
15064
|
+
if (arg === "--") {
|
|
15065
|
+
index += 1;
|
|
15066
|
+
continue;
|
|
15067
|
+
}
|
|
15068
|
+
if (arg === "-o" || arg === "+o") {
|
|
15069
|
+
if (!args[index + 1]) {
|
|
15070
|
+
return false;
|
|
15071
|
+
}
|
|
15072
|
+
index += 2;
|
|
15073
|
+
continue;
|
|
15074
|
+
}
|
|
15075
|
+
if (/^[-+][A-Za-z0-9]+$/.test(arg)) {
|
|
15076
|
+
index += 1;
|
|
15077
|
+
continue;
|
|
15078
|
+
}
|
|
15079
|
+
return false;
|
|
15080
|
+
}
|
|
15081
|
+
return true;
|
|
15082
|
+
}
|
|
15083
|
+
function decodeShellControlBuiltin(head, args) {
|
|
15084
|
+
if (head === "set") {
|
|
15085
|
+
return decodeSetBuiltin(args) ? [] : null;
|
|
15086
|
+
}
|
|
15087
|
+
if (head === "wait") {
|
|
15088
|
+
if (args.length === 0 || args.every((arg) => /^\d+$/.test(arg))) {
|
|
15089
|
+
return [];
|
|
15090
|
+
}
|
|
15091
|
+
return null;
|
|
15092
|
+
}
|
|
15093
|
+
if (head === "exit") {
|
|
15094
|
+
if (args.length === 0 || args.length === 1 && /^-?\d+$/.test(args[0] ?? "")) {
|
|
15095
|
+
return [];
|
|
15096
|
+
}
|
|
15097
|
+
return null;
|
|
15098
|
+
}
|
|
15099
|
+
return null;
|
|
15100
|
+
}
|
|
15101
|
+
function validLsof(args) {
|
|
15102
|
+
const flagsWithoutValues = /* @__PURE__ */ new Set(["-a", "-b", "-l", "-n", "-P", "-R", "-t", "-V"]);
|
|
15103
|
+
const flagsWithValues = /* @__PURE__ */ new Set(["-c", "-d", "-F", "-g", "-p", "-T", "-u", "+d", "+D"]);
|
|
15499
15104
|
for (let index = 0; index < args.length; index += 1) {
|
|
15500
15105
|
const arg = args[index] ?? "";
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
if (
|
|
15106
|
+
if (flagsWithoutValues.has(arg) || arg === "-i") {
|
|
15107
|
+
continue;
|
|
15108
|
+
}
|
|
15109
|
+
if (flagsWithValues.has(arg)) {
|
|
15110
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15111
|
+
return false;
|
|
15112
|
+
}
|
|
15113
|
+
index += 1;
|
|
15114
|
+
continue;
|
|
15115
|
+
}
|
|
15116
|
+
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)) {
|
|
15117
|
+
continue;
|
|
15118
|
+
}
|
|
15119
|
+
return false;
|
|
15120
|
+
}
|
|
15121
|
+
return true;
|
|
15122
|
+
}
|
|
15123
|
+
function validPs(args) {
|
|
15124
|
+
const bareForms = /* @__PURE__ */ new Set(["aux", "ax", "x", "u"]);
|
|
15125
|
+
const flagsWithoutValues = /* @__PURE__ */ new Set(["-A", "-a", "-d", "-e", "-f", "-j", "-l", "-T", "-x"]);
|
|
15126
|
+
const flagsWithValues = /* @__PURE__ */ new Set([
|
|
15127
|
+
"--format",
|
|
15128
|
+
"--group",
|
|
15129
|
+
"--pid",
|
|
15130
|
+
"--ppid",
|
|
15131
|
+
"--sort",
|
|
15132
|
+
"--tty",
|
|
15133
|
+
"--user"
|
|
15134
|
+
]);
|
|
15135
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15136
|
+
const arg = args[index] ?? "";
|
|
15137
|
+
if (bareForms.has(arg) || flagsWithoutValues.has(arg)) {
|
|
15138
|
+
continue;
|
|
15139
|
+
}
|
|
15140
|
+
if (flagsWithValues.has(arg)) {
|
|
15141
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15142
|
+
return false;
|
|
15143
|
+
}
|
|
15144
|
+
index += 1;
|
|
15145
|
+
continue;
|
|
15146
|
+
}
|
|
15147
|
+
if (/^(?:--format|--group|--pid|--ppid|--sort|--tty|--user)=.+$/.test(arg)) {
|
|
15148
|
+
continue;
|
|
15149
|
+
}
|
|
15150
|
+
if (/^-[^-]/.test(arg)) {
|
|
15151
|
+
const noValue = /* @__PURE__ */ new Set(["A", "a", "d", "e", "f", "j", "l", "T", "x"]);
|
|
15152
|
+
const withValue = /* @__PURE__ */ new Set(["G", "g", "N", "o", "p", "t", "U", "u"]);
|
|
15153
|
+
const characters = arg.slice(1);
|
|
15154
|
+
let valid = true;
|
|
15155
|
+
for (let optionIndex = 0; optionIndex < characters.length; optionIndex += 1) {
|
|
15156
|
+
const option = characters[optionIndex] ?? "";
|
|
15157
|
+
if (noValue.has(option)) {
|
|
15158
|
+
continue;
|
|
15159
|
+
}
|
|
15160
|
+
if (withValue.has(option)) {
|
|
15161
|
+
if (optionIndex === characters.length - 1) {
|
|
15162
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15163
|
+
return false;
|
|
15164
|
+
}
|
|
15165
|
+
index += 1;
|
|
15166
|
+
}
|
|
15167
|
+
break;
|
|
15168
|
+
}
|
|
15169
|
+
valid = false;
|
|
15170
|
+
break;
|
|
15171
|
+
}
|
|
15172
|
+
if (valid) {
|
|
15173
|
+
continue;
|
|
15174
|
+
}
|
|
15175
|
+
}
|
|
15176
|
+
return false;
|
|
15177
|
+
}
|
|
15178
|
+
return true;
|
|
15179
|
+
}
|
|
15180
|
+
function validFilesystemTest(head, args) {
|
|
15181
|
+
const operands = head === "[" && args.at(-1) === "]" ? args.slice(0, -1) : args;
|
|
15182
|
+
if (head === "[" && args.at(-1) !== "]") {
|
|
15183
|
+
return false;
|
|
15184
|
+
}
|
|
15185
|
+
return operands.length === 2 && (/* @__PURE__ */ new Set(["-b", "-c", "-d", "-e", "-f", "-h", "-L", "-r", "-s", "-w", "-x"])).has(
|
|
15186
|
+
operands[0] ?? ""
|
|
15187
|
+
) && Boolean(operands[1]);
|
|
15188
|
+
}
|
|
15189
|
+
function bashSyntaxTarget(args) {
|
|
15190
|
+
let syntaxOnly = false;
|
|
15191
|
+
let script = null;
|
|
15192
|
+
const shortFlags = new Set("abefhkmnptuvxBCEHPT".split(""));
|
|
15193
|
+
const longFlags = /* @__PURE__ */ new Set([
|
|
15194
|
+
"--debugger",
|
|
15195
|
+
"--dump-po-strings",
|
|
15196
|
+
"--dump-strings",
|
|
15197
|
+
"--help",
|
|
15198
|
+
"--login",
|
|
15199
|
+
"--noediting",
|
|
15200
|
+
"--noprofile",
|
|
15201
|
+
"--norc",
|
|
15202
|
+
"--posix",
|
|
15203
|
+
"--restricted",
|
|
15204
|
+
"--verbose",
|
|
15205
|
+
"--version"
|
|
15206
|
+
]);
|
|
15207
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15208
|
+
const arg = args[index] ?? "";
|
|
15209
|
+
if (arg === "-c" || arg === "-lc") {
|
|
15210
|
+
return null;
|
|
15211
|
+
}
|
|
15212
|
+
if (arg === "-O" || arg === "+O" || arg === "--rcfile" || arg === "--init-file") {
|
|
15213
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15214
|
+
return null;
|
|
15215
|
+
}
|
|
15216
|
+
index += 1;
|
|
15217
|
+
continue;
|
|
15218
|
+
}
|
|
15219
|
+
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) {
|
|
15220
|
+
continue;
|
|
15221
|
+
}
|
|
15222
|
+
if (longFlags.has(arg)) {
|
|
15223
|
+
continue;
|
|
15224
|
+
}
|
|
15225
|
+
if (/^[+-][A-Za-z]+$/.test(arg)) {
|
|
15226
|
+
const options = arg.slice(1);
|
|
15227
|
+
if ([...options].some((option) => !shortFlags.has(option))) {
|
|
15228
|
+
return null;
|
|
15229
|
+
}
|
|
15230
|
+
syntaxOnly ||= options.includes("n");
|
|
15231
|
+
continue;
|
|
15232
|
+
}
|
|
15233
|
+
if (arg === "--") {
|
|
15234
|
+
script = args[index + 1] ?? null;
|
|
15235
|
+
break;
|
|
15236
|
+
}
|
|
15237
|
+
if (arg.startsWith("-") || arg.startsWith("+")) {
|
|
15238
|
+
return null;
|
|
15239
|
+
}
|
|
15240
|
+
script = arg;
|
|
15241
|
+
break;
|
|
15242
|
+
}
|
|
15243
|
+
return syntaxOnly ? script : null;
|
|
15244
|
+
}
|
|
15245
|
+
|
|
15246
|
+
// src/core/effect-ir/shell-lower/decoders/docker.ts
|
|
15247
|
+
function decodeDockerComposeRun2(head, args, segment) {
|
|
15248
|
+
let composeArgs = null;
|
|
15249
|
+
let command = head;
|
|
15250
|
+
if (head === "docker-compose") {
|
|
15251
|
+
composeArgs = args;
|
|
15252
|
+
} else if (head === "docker" && args[0] === "compose") {
|
|
15253
|
+
composeArgs = args.slice(1);
|
|
15254
|
+
command = "docker";
|
|
15255
|
+
}
|
|
15256
|
+
if (!composeArgs) {
|
|
15257
|
+
return null;
|
|
15258
|
+
}
|
|
15259
|
+
if (composeArgs.includes("run")) {
|
|
15260
|
+
return [processRequirement(command, "spawn", segment, ["process.docker_compose_run"])];
|
|
15261
|
+
}
|
|
15262
|
+
return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
|
|
15263
|
+
}
|
|
15264
|
+
function validDockerInfo(args) {
|
|
15265
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15266
|
+
const arg = args[index] ?? "";
|
|
15267
|
+
if (arg === "--help") {
|
|
15505
15268
|
continue;
|
|
15506
15269
|
}
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15270
|
+
if (arg === "--format" || arg === "-f") {
|
|
15271
|
+
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
15272
|
+
return false;
|
|
15273
|
+
}
|
|
15510
15274
|
index += 1;
|
|
15275
|
+
continue;
|
|
15276
|
+
}
|
|
15277
|
+
if (arg.startsWith("--format=")) {
|
|
15278
|
+
if (arg.slice("--format=".length).length === 0) {
|
|
15279
|
+
return false;
|
|
15280
|
+
}
|
|
15281
|
+
continue;
|
|
15511
15282
|
}
|
|
15283
|
+
return false;
|
|
15512
15284
|
}
|
|
15513
|
-
|
|
15514
|
-
const inspect = metadataOnly || typecheckOnly;
|
|
15515
|
-
requirements.unshift(
|
|
15516
|
-
processRequirement("tsc", inspect ? "inspect" : "spawn", segment, [
|
|
15517
|
-
metadataOnly ? "process.inspect.tsc_metadata" : typecheckOnly ? "process.inspect.tsc_typecheck" : "process.known_local_spawn"
|
|
15518
|
-
])
|
|
15519
|
-
);
|
|
15520
|
-
return requirements;
|
|
15285
|
+
return true;
|
|
15521
15286
|
}
|
|
15287
|
+
|
|
15288
|
+
// src/core/effect-ir/shell-lower/decoders/filesystem.ts
|
|
15289
|
+
init_git_resource_identity();
|
|
15290
|
+
import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
15291
|
+
import path44 from "node:path";
|
|
15522
15292
|
function decodeCopyMove(head, args, cwd, segment) {
|
|
15523
15293
|
const requirements = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
15524
15294
|
const operands = [];
|
|
@@ -15641,28 +15411,349 @@ function decodeRm(args, cwd, repoRoot, segment) {
|
|
|
15641
15411
|
);
|
|
15642
15412
|
}
|
|
15643
15413
|
}
|
|
15644
|
-
return requirements;
|
|
15414
|
+
return requirements;
|
|
15415
|
+
}
|
|
15416
|
+
function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
|
|
15417
|
+
try {
|
|
15418
|
+
if (finalOperandIsSymlink) {
|
|
15419
|
+
return path44.join(realpathSync4.native(path44.dirname(targetPath)), path44.basename(targetPath));
|
|
15420
|
+
}
|
|
15421
|
+
return realpathSync4.native(targetPath);
|
|
15422
|
+
} catch {
|
|
15423
|
+
return path44.resolve(targetPath);
|
|
15424
|
+
}
|
|
15425
|
+
}
|
|
15426
|
+
function isSymbolicLink(targetPath) {
|
|
15427
|
+
try {
|
|
15428
|
+
return lstatSync2(targetPath).isSymbolicLink();
|
|
15429
|
+
} catch {
|
|
15430
|
+
return false;
|
|
15431
|
+
}
|
|
15432
|
+
}
|
|
15433
|
+
function pathContains(ancestor, candidate) {
|
|
15434
|
+
const relative = path44.relative(path44.resolve(ancestor), path44.resolve(candidate));
|
|
15435
|
+
return relative === "" || !relative.startsWith("..") && !path44.isAbsolute(relative);
|
|
15436
|
+
}
|
|
15437
|
+
function filesystemReadOperands(head, args) {
|
|
15438
|
+
switch (head) {
|
|
15439
|
+
case "ls": {
|
|
15440
|
+
const operands = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15441
|
+
return operands.length > 0 ? operands : ["."];
|
|
15442
|
+
}
|
|
15443
|
+
case "find":
|
|
15444
|
+
return findReadOperands(args);
|
|
15445
|
+
case "cat":
|
|
15446
|
+
case "head":
|
|
15447
|
+
case "tail":
|
|
15448
|
+
case "less":
|
|
15449
|
+
case "stat":
|
|
15450
|
+
case "file":
|
|
15451
|
+
case "du":
|
|
15452
|
+
case "wc":
|
|
15453
|
+
return args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15454
|
+
case "grep":
|
|
15455
|
+
case "rg":
|
|
15456
|
+
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
15457
|
+
case "jq":
|
|
15458
|
+
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
15459
|
+
default:
|
|
15460
|
+
return null;
|
|
15461
|
+
}
|
|
15462
|
+
}
|
|
15463
|
+
function findReadOperands(args) {
|
|
15464
|
+
const mutatingPrimaries = /* @__PURE__ */ new Set([
|
|
15465
|
+
"-delete",
|
|
15466
|
+
"-exec",
|
|
15467
|
+
"-execdir",
|
|
15468
|
+
"-fls",
|
|
15469
|
+
"-fprint",
|
|
15470
|
+
"-fprintf",
|
|
15471
|
+
"-ok",
|
|
15472
|
+
"-okdir"
|
|
15473
|
+
]);
|
|
15474
|
+
if (args.some(
|
|
15475
|
+
(arg) => mutatingPrimaries.has(arg) || [...mutatingPrimaries].some((primary) => arg.startsWith(`${primary}=`))
|
|
15476
|
+
)) {
|
|
15477
|
+
return null;
|
|
15478
|
+
}
|
|
15479
|
+
const paths = [];
|
|
15480
|
+
for (const arg of args) {
|
|
15481
|
+
if (arg.startsWith("-") || arg === "!" || arg === "(") {
|
|
15482
|
+
break;
|
|
15483
|
+
}
|
|
15484
|
+
paths.push(arg);
|
|
15485
|
+
}
|
|
15486
|
+
return paths.length > 0 ? paths : ["."];
|
|
15487
|
+
}
|
|
15488
|
+
function filesystemWriteOperands(head, args) {
|
|
15489
|
+
const positional = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
15490
|
+
switch (head) {
|
|
15491
|
+
case "touch":
|
|
15492
|
+
case "mkdir":
|
|
15493
|
+
case "rm":
|
|
15494
|
+
case "truncate":
|
|
15495
|
+
case "chmod":
|
|
15496
|
+
return positional;
|
|
15497
|
+
case "cp":
|
|
15498
|
+
case "mv":
|
|
15499
|
+
return positional.length > 0 ? [positional[positional.length - 1] ?? ""] : [];
|
|
15500
|
+
case "tee":
|
|
15501
|
+
return positional;
|
|
15502
|
+
default:
|
|
15503
|
+
return null;
|
|
15504
|
+
}
|
|
15505
|
+
}
|
|
15506
|
+
|
|
15507
|
+
// src/core/effect-ir/shell-lower/decoders/prisma.ts
|
|
15508
|
+
function decodePrisma(args, env, repoRoot, segment) {
|
|
15509
|
+
const processEffect = processRequirement("prisma", "spawn", segment, ["process.prisma"]);
|
|
15510
|
+
if (args[0] === "generate") {
|
|
15511
|
+
return [
|
|
15512
|
+
processEffect,
|
|
15513
|
+
requirement2("fs.write", "fs.write", { kind: "path", path: repoRoot }, segment, [
|
|
15514
|
+
"prisma.generate.repo_local"
|
|
15515
|
+
])
|
|
15516
|
+
];
|
|
15517
|
+
}
|
|
15518
|
+
const databaseMutation = args[0] === "migrate" || args[0] === "db" && args[1] === "seed" || args[0] === "seed";
|
|
15519
|
+
if (!databaseMutation) {
|
|
15520
|
+
return [
|
|
15521
|
+
processEffect,
|
|
15522
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15523
|
+
"prisma.grammar_incomplete"
|
|
15524
|
+
])
|
|
15525
|
+
];
|
|
15526
|
+
}
|
|
15527
|
+
const endpoint = databaseEndpoint(env.DATABASE_URL);
|
|
15528
|
+
if (!endpoint) {
|
|
15529
|
+
return [
|
|
15530
|
+
processEffect,
|
|
15531
|
+
requirement2(
|
|
15532
|
+
"network.connect",
|
|
15533
|
+
"network.connect",
|
|
15534
|
+
{
|
|
15535
|
+
kind: "network",
|
|
15536
|
+
host: "unknown",
|
|
15537
|
+
protocol: "database",
|
|
15538
|
+
mode: "ambiguous",
|
|
15539
|
+
payload: "present"
|
|
15540
|
+
},
|
|
15541
|
+
segment,
|
|
15542
|
+
["prisma.database_endpoint_unknown"]
|
|
15543
|
+
),
|
|
15544
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15545
|
+
"prisma.database_endpoint_unknown"
|
|
15546
|
+
])
|
|
15547
|
+
];
|
|
15548
|
+
}
|
|
15549
|
+
const network = requirement2(
|
|
15550
|
+
"network.connect",
|
|
15551
|
+
"network.connect",
|
|
15552
|
+
{
|
|
15553
|
+
kind: "network",
|
|
15554
|
+
...endpoint,
|
|
15555
|
+
mode: "mutate",
|
|
15556
|
+
payload: "present"
|
|
15557
|
+
},
|
|
15558
|
+
segment,
|
|
15559
|
+
[LOOPBACK_HOSTS2.has(endpoint.host) ? "prisma.database_local" : "prisma.database_remote"]
|
|
15560
|
+
);
|
|
15561
|
+
if (LOOPBACK_HOSTS2.has(endpoint.host)) {
|
|
15562
|
+
return [processEffect, network];
|
|
15563
|
+
}
|
|
15564
|
+
return [
|
|
15565
|
+
processEffect,
|
|
15566
|
+
network,
|
|
15567
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15568
|
+
"prisma.remote_database_mutation"
|
|
15569
|
+
])
|
|
15570
|
+
];
|
|
15571
|
+
}
|
|
15572
|
+
|
|
15573
|
+
// src/core/effect-ir/shell-lower/decoders/ruby.ts
|
|
15574
|
+
init_path_utils();
|
|
15575
|
+
import path45 from "node:path";
|
|
15576
|
+
var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
|
|
15577
|
+
function railsReadOnlySubcommand(args) {
|
|
15578
|
+
const subcommand = args[0];
|
|
15579
|
+
if (!subcommand || subcommand.startsWith("-")) {
|
|
15580
|
+
return false;
|
|
15581
|
+
}
|
|
15582
|
+
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
15583
|
+
}
|
|
15584
|
+
function isRubyTestScript(scriptPath) {
|
|
15585
|
+
const base = path45.basename(scriptPath);
|
|
15586
|
+
return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
|
|
15587
|
+
}
|
|
15588
|
+
function parseRubyTestInvocation(args) {
|
|
15589
|
+
const includePaths = [];
|
|
15590
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15591
|
+
const arg = args[index] ?? "";
|
|
15592
|
+
if (arg === "-e" || arg === "-r") {
|
|
15593
|
+
return null;
|
|
15594
|
+
}
|
|
15595
|
+
if (arg === "-I") {
|
|
15596
|
+
const includePath = args[index + 1];
|
|
15597
|
+
if (!includePath) {
|
|
15598
|
+
return null;
|
|
15599
|
+
}
|
|
15600
|
+
includePaths.push(includePath);
|
|
15601
|
+
index += 1;
|
|
15602
|
+
continue;
|
|
15603
|
+
}
|
|
15604
|
+
if (arg.startsWith("-I") && arg.length > 2) {
|
|
15605
|
+
includePaths.push(arg.slice(2));
|
|
15606
|
+
continue;
|
|
15607
|
+
}
|
|
15608
|
+
if (arg.startsWith("-")) {
|
|
15609
|
+
if (arg === "-n") {
|
|
15610
|
+
if (!args[index + 1]) {
|
|
15611
|
+
return null;
|
|
15612
|
+
}
|
|
15613
|
+
index += 1;
|
|
15614
|
+
continue;
|
|
15615
|
+
}
|
|
15616
|
+
if (arg.startsWith("-n")) {
|
|
15617
|
+
continue;
|
|
15618
|
+
}
|
|
15619
|
+
return null;
|
|
15620
|
+
}
|
|
15621
|
+
if (isRubyTestScript(arg)) {
|
|
15622
|
+
return { includePaths, scriptPath: arg };
|
|
15623
|
+
}
|
|
15624
|
+
return null;
|
|
15625
|
+
}
|
|
15626
|
+
return null;
|
|
15627
|
+
}
|
|
15628
|
+
function isRubocopMutating(args) {
|
|
15629
|
+
return args.some(
|
|
15630
|
+
(arg) => arg === "-A" || arg === "-a" || arg === "--auto-correct" || arg === "--autocorrect" || arg.startsWith("--auto-correct-all") || arg.startsWith("--autocorrect-all")
|
|
15631
|
+
);
|
|
15632
|
+
}
|
|
15633
|
+
function decodeBundleExecInner(innerHead, innerArgs, segment) {
|
|
15634
|
+
const innerBase = executableBaseName(innerHead);
|
|
15635
|
+
if (innerBase === "rubocop") {
|
|
15636
|
+
const mutating = isRubocopMutating(innerArgs);
|
|
15637
|
+
return [
|
|
15638
|
+
processRequirement(
|
|
15639
|
+
innerHead,
|
|
15640
|
+
mutating ? "spawn" : "inspect",
|
|
15641
|
+
segment,
|
|
15642
|
+
mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
|
|
15643
|
+
)
|
|
15644
|
+
];
|
|
15645
|
+
}
|
|
15646
|
+
if (innerBase === "rspec") {
|
|
15647
|
+
const targetArgs = innerArgs.filter((arg) => !arg.startsWith("-"));
|
|
15648
|
+
if (targetArgs.length === 0) {
|
|
15649
|
+
return null;
|
|
15650
|
+
}
|
|
15651
|
+
return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
|
|
15652
|
+
}
|
|
15653
|
+
return null;
|
|
15645
15654
|
}
|
|
15646
|
-
function
|
|
15647
|
-
|
|
15648
|
-
|
|
15649
|
-
|
|
15655
|
+
function decodeRuby(args, cwd, repoRoot, segment) {
|
|
15656
|
+
const parsed = parseRubyTestInvocation(args);
|
|
15657
|
+
if (!parsed) {
|
|
15658
|
+
return unsupportedProcess("ruby", segment, "process.ruby_grammar_incomplete");
|
|
15659
|
+
}
|
|
15660
|
+
const scriptPath = resolvePathOperand(parsed.scriptPath, cwd);
|
|
15661
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15662
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15663
|
+
}
|
|
15664
|
+
for (const includePath of parsed.includePaths) {
|
|
15665
|
+
const resolvedInclude = resolvePathOperand(includePath, cwd);
|
|
15666
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
|
|
15667
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15650
15668
|
}
|
|
15651
|
-
return realpathSync4.native(targetPath);
|
|
15652
|
-
} catch {
|
|
15653
|
-
return path41.resolve(targetPath);
|
|
15654
15669
|
}
|
|
15670
|
+
const lowered = [
|
|
15671
|
+
processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
|
|
15672
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
|
|
15673
|
+
"ruby.minitest_script_read"
|
|
15674
|
+
])
|
|
15675
|
+
];
|
|
15676
|
+
for (const includePath of parsed.includePaths) {
|
|
15677
|
+
lowered.push(
|
|
15678
|
+
requirement2(
|
|
15679
|
+
"fs.read",
|
|
15680
|
+
"fs.read",
|
|
15681
|
+
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15682
|
+
segment,
|
|
15683
|
+
["ruby.minitest_load_path_read"]
|
|
15684
|
+
)
|
|
15685
|
+
);
|
|
15686
|
+
}
|
|
15687
|
+
return lowered;
|
|
15655
15688
|
}
|
|
15656
|
-
function
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15689
|
+
function decodeRuntimeMetadataProcess(head, args, segment) {
|
|
15690
|
+
if (head === "bundle") {
|
|
15691
|
+
if (args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
15692
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15693
|
+
}
|
|
15694
|
+
if (args[0] === "exec" && args.length >= 2) {
|
|
15695
|
+
const innerHead = args[1] ?? "";
|
|
15696
|
+
const innerArgs = args.slice(2);
|
|
15697
|
+
const innerBase = executableBaseName(innerHead);
|
|
15698
|
+
if ((innerBase === "rails" || innerBase === "rake") && railsReadOnlySubcommand(innerArgs)) {
|
|
15699
|
+
return [
|
|
15700
|
+
processRequirement(innerHead, "inspect", segment, ["process.inspect.rails_read_only"])
|
|
15701
|
+
];
|
|
15702
|
+
}
|
|
15703
|
+
if (isMetadataOnlyArgv(innerArgs)) {
|
|
15704
|
+
return [
|
|
15705
|
+
processRequirement(innerHead, "inspect", segment, [
|
|
15706
|
+
"process.inspect.bundle_exec_metadata"
|
|
15707
|
+
])
|
|
15708
|
+
];
|
|
15709
|
+
}
|
|
15710
|
+
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15711
|
+
if (bundleExecInner) {
|
|
15712
|
+
return bundleExecInner;
|
|
15713
|
+
}
|
|
15714
|
+
}
|
|
15715
|
+
return null;
|
|
15716
|
+
}
|
|
15717
|
+
if ((head === "ruby" || head === "yarn") && args.length >= 1 && isMetadataOnlyArgv(args)) {
|
|
15718
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.runtime_metadata"])];
|
|
15719
|
+
}
|
|
15720
|
+
if (head === "make" && args.includes("-n")) {
|
|
15721
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.make_dry_run"])];
|
|
15722
|
+
}
|
|
15723
|
+
const base = executableBaseName(head);
|
|
15724
|
+
if ((base === "rails" || base === "rake") && railsReadOnlySubcommand(args)) {
|
|
15725
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.rails_read_only"])];
|
|
15661
15726
|
}
|
|
15727
|
+
return null;
|
|
15662
15728
|
}
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15729
|
+
|
|
15730
|
+
// src/core/effect-ir/shell-lower/decoders/toolchain.ts
|
|
15731
|
+
function decodeTsc(args, cwd, segment) {
|
|
15732
|
+
const metadataOnly = args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg));
|
|
15733
|
+
const requirements = [];
|
|
15734
|
+
let hasOutput = false;
|
|
15735
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15736
|
+
const arg = args[index] ?? "";
|
|
15737
|
+
const inline = arg.match(/^--(?:outDir|outFile)=(.+)$/)?.[1];
|
|
15738
|
+
const separate = (arg === "--outDir" || arg === "--outFile") && args[index + 1] ? args[index + 1] : null;
|
|
15739
|
+
const output = inline ?? separate;
|
|
15740
|
+
if (!output) {
|
|
15741
|
+
continue;
|
|
15742
|
+
}
|
|
15743
|
+
hasOutput = true;
|
|
15744
|
+
addWriteEffects(requirements, resolvePathOperand(output, cwd), segment, ["tsc.output"]);
|
|
15745
|
+
if (separate) {
|
|
15746
|
+
index += 1;
|
|
15747
|
+
}
|
|
15748
|
+
}
|
|
15749
|
+
const typecheckOnly = args.includes("--noEmit") && !hasOutput;
|
|
15750
|
+
const inspect = metadataOnly || typecheckOnly;
|
|
15751
|
+
requirements.unshift(
|
|
15752
|
+
processRequirement("tsc", inspect ? "inspect" : "spawn", segment, [
|
|
15753
|
+
metadataOnly ? "process.inspect.tsc_metadata" : typecheckOnly ? "process.inspect.tsc_typecheck" : "process.known_local_spawn"
|
|
15754
|
+
])
|
|
15755
|
+
);
|
|
15756
|
+
return requirements;
|
|
15666
15757
|
}
|
|
15667
15758
|
function decodeGo(args, segment) {
|
|
15668
15759
|
if (["test", "list", "vet"].includes(args[0] ?? "")) {
|
|
@@ -15793,316 +15884,351 @@ function decodeSed(args, cwd, segment) {
|
|
|
15793
15884
|
}
|
|
15794
15885
|
files.push(arg);
|
|
15795
15886
|
}
|
|
15796
|
-
const operation = inline ? "spawn" : "inspect";
|
|
15797
|
-
const lowered = [processRequirement("sed", operation, segment, ["process.sed"])];
|
|
15798
|
-
for (const file of files) {
|
|
15799
|
-
lowered.push(
|
|
15800
|
-
requirement2(
|
|
15801
|
-
inline ? "fs.write" : "fs.read",
|
|
15802
|
-
inline ? "fs.write" : "fs.read",
|
|
15803
|
-
{ kind: "path", path: resolvePathOperand(file, cwd) },
|
|
15804
|
-
segment,
|
|
15805
|
-
[inline ? "sed.in_place_write" : "sed.file_read"]
|
|
15806
|
-
)
|
|
15807
|
-
);
|
|
15887
|
+
const operation = inline ? "spawn" : "inspect";
|
|
15888
|
+
const lowered = [processRequirement("sed", operation, segment, ["process.sed"])];
|
|
15889
|
+
for (const file of files) {
|
|
15890
|
+
lowered.push(
|
|
15891
|
+
requirement2(
|
|
15892
|
+
inline ? "fs.write" : "fs.read",
|
|
15893
|
+
inline ? "fs.write" : "fs.read",
|
|
15894
|
+
{ kind: "path", path: resolvePathOperand(file, cwd) },
|
|
15895
|
+
segment,
|
|
15896
|
+
[inline ? "sed.in_place_write" : "sed.file_read"]
|
|
15897
|
+
)
|
|
15898
|
+
);
|
|
15899
|
+
}
|
|
15900
|
+
return lowered;
|
|
15901
|
+
}
|
|
15902
|
+
function decodeNode2(args, cwd, segment) {
|
|
15903
|
+
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
15904
|
+
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
15905
|
+
}
|
|
15906
|
+
if ((args[0] === "--check" || args[0] === "-c") && args.length === 2 && args[1]) {
|
|
15907
|
+
return [
|
|
15908
|
+
processRequirement("node", "inspect", segment, ["process.inspect.node_syntax"]),
|
|
15909
|
+
requirement2(
|
|
15910
|
+
"fs.read",
|
|
15911
|
+
"fs.read",
|
|
15912
|
+
{ kind: "path", path: resolvePathOperand(args[1], cwd) },
|
|
15913
|
+
segment,
|
|
15914
|
+
["node.syntax_source_read"]
|
|
15915
|
+
)
|
|
15916
|
+
];
|
|
15917
|
+
}
|
|
15918
|
+
return unsupportedProcess("node", segment, "process.node_grammar_incomplete");
|
|
15919
|
+
}
|
|
15920
|
+
|
|
15921
|
+
// src/core/effect-ir/shell-lower/decode-process.ts
|
|
15922
|
+
function decodeProcessOrFilesystem(params) {
|
|
15923
|
+
const { tokens, head, env, cwd, repoRoot, segment } = params;
|
|
15924
|
+
const args = tokens.slice(1);
|
|
15925
|
+
if (tokens.length > 0 && tokens.every((token) => ENV_PREFIX_PATTERN2.test(token))) {
|
|
15926
|
+
return [];
|
|
15927
|
+
}
|
|
15928
|
+
const shellControl = decodeShellControlBuiltin(head, args);
|
|
15929
|
+
if (shellControl) {
|
|
15930
|
+
return shellControl;
|
|
15931
|
+
}
|
|
15932
|
+
if (isCommandInspection(tokens)) {
|
|
15933
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
15934
|
+
}
|
|
15935
|
+
if (head === "lsof") {
|
|
15936
|
+
return validLsof(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.lsof"])] : unsupportedProcess(head, segment, "process.lsof_grammar_incomplete");
|
|
15937
|
+
}
|
|
15938
|
+
if (head === "ps") {
|
|
15939
|
+
return validPs(args) ? [processRequirement(head, "inspect", segment, ["process.inspect.ps"])] : unsupportedProcess(head, segment, "process.ps_grammar_incomplete");
|
|
15940
|
+
}
|
|
15941
|
+
if (head === "test" || head === "[") {
|
|
15942
|
+
return validFilesystemTest(head, args) ? [processRequirement(head, "inspect", segment, ["process.inspect.filesystem_test"])] : unsupportedProcess(head, segment, "process.filesystem_test_grammar_incomplete");
|
|
15943
|
+
}
|
|
15944
|
+
if (head === "docker") {
|
|
15945
|
+
if (args[0] === "info") {
|
|
15946
|
+
return validDockerInfo(args.slice(1)) ? [processRequirement(head, "inspect", segment, ["process.inspect.docker_info"])] : unsupportedProcess(head, segment, "process.docker_info_grammar_incomplete");
|
|
15947
|
+
}
|
|
15948
|
+
if (args[0] === "compose" && ["up", "down", "start", "stop", "restart", "create", "rm"].includes(args[1] ?? "")) {
|
|
15949
|
+
return [processRequirement(head, "spawn", segment, ["service.local_mutation"])];
|
|
15950
|
+
}
|
|
15951
|
+
if (args[0] === "push" || args[0] === "build" && args.includes("--push") || args[0] === "buildx" && args[1] === "build" && (args.includes("--push") || args.some(
|
|
15952
|
+
(arg) => arg.startsWith("--output=type=registry") || arg.startsWith("-o=type=registry")
|
|
15953
|
+
))) {
|
|
15954
|
+
return [
|
|
15955
|
+
processRequirement(head, "spawn", segment, ["tier0_external", "docker.remote_mutation"]),
|
|
15956
|
+
requirement2(
|
|
15957
|
+
"network.connect",
|
|
15958
|
+
"network.connect",
|
|
15959
|
+
{
|
|
15960
|
+
kind: "network",
|
|
15961
|
+
host: "registry",
|
|
15962
|
+
protocol: "container-registry",
|
|
15963
|
+
mode: "mutate",
|
|
15964
|
+
payload: "present"
|
|
15965
|
+
},
|
|
15966
|
+
segment,
|
|
15967
|
+
["tier0_external", "docker.remote_mutation"]
|
|
15968
|
+
)
|
|
15969
|
+
];
|
|
15970
|
+
}
|
|
15971
|
+
if (args[0] === "run" || args[0] === "create" || args[0] === "pull" || args[0] === "build" || args[0] === "buildx" && args[1] === "build") {
|
|
15972
|
+
return [
|
|
15973
|
+
processRequirement(head, "spawn", segment, ["process.docker_spawn"]),
|
|
15974
|
+
requirement2(
|
|
15975
|
+
"network.acquire",
|
|
15976
|
+
"network.connect",
|
|
15977
|
+
{
|
|
15978
|
+
kind: "network",
|
|
15979
|
+
host: "unknown",
|
|
15980
|
+
protocol: "container-registry",
|
|
15981
|
+
mode: "ambiguous",
|
|
15982
|
+
payload: "none"
|
|
15983
|
+
},
|
|
15984
|
+
segment,
|
|
15985
|
+
["docker.image_acquisition_possible"]
|
|
15986
|
+
)
|
|
15987
|
+
];
|
|
15988
|
+
}
|
|
15989
|
+
return [processRequirement(head, "spawn", segment, ["process.docker_spawn"])];
|
|
15990
|
+
}
|
|
15991
|
+
if (isShellHead(head)) {
|
|
15992
|
+
const syntax = bashSyntaxTarget(args);
|
|
15993
|
+
if (syntax) {
|
|
15994
|
+
return [
|
|
15995
|
+
processRequirement(head, "inspect", segment, ["process.inspect.shell_syntax"]),
|
|
15996
|
+
requirement2(
|
|
15997
|
+
"fs.read",
|
|
15998
|
+
"fs.read",
|
|
15999
|
+
{ kind: "path", path: path46.resolve(cwd, syntax) },
|
|
16000
|
+
segment,
|
|
16001
|
+
["shell.syntax_source_read"]
|
|
16002
|
+
)
|
|
16003
|
+
];
|
|
16004
|
+
}
|
|
16005
|
+
return unsupportedProcess(head, segment, "process.shell_grammar_incomplete");
|
|
16006
|
+
}
|
|
16007
|
+
if (head === "prisma") {
|
|
16008
|
+
return decodePrisma(args, env, repoRoot, segment);
|
|
16009
|
+
}
|
|
16010
|
+
const runtimeMetadata = decodeRuntimeMetadataProcess(head, args, segment);
|
|
16011
|
+
if (runtimeMetadata) {
|
|
16012
|
+
return runtimeMetadata;
|
|
16013
|
+
}
|
|
16014
|
+
if (head === "ruby") {
|
|
16015
|
+
return decodeRuby(args, cwd, repoRoot, segment);
|
|
16016
|
+
}
|
|
16017
|
+
if (head === "rubocop" || head === "rspec") {
|
|
16018
|
+
const decoded = decodeBundleExecInner(head, args, segment);
|
|
16019
|
+
if (decoded) {
|
|
16020
|
+
return decoded;
|
|
16021
|
+
}
|
|
16022
|
+
}
|
|
16023
|
+
const dockerCompose = decodeDockerComposeRun2(head, args, segment);
|
|
16024
|
+
if (dockerCompose) {
|
|
16025
|
+
return dockerCompose;
|
|
16026
|
+
}
|
|
16027
|
+
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
16028
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
16029
|
+
}
|
|
16030
|
+
if (head === "belay") {
|
|
16031
|
+
return decodeBelay(args, repoRoot, segment);
|
|
16032
|
+
}
|
|
16033
|
+
if (head === "tsc") {
|
|
16034
|
+
return decodeTsc(args, cwd, segment);
|
|
15808
16035
|
}
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
function decodeNode2(args, cwd, segment) {
|
|
15812
|
-
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
15813
|
-
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
16036
|
+
if (head === "go") {
|
|
16037
|
+
return decodeGo(args, segment);
|
|
15814
16038
|
}
|
|
15815
|
-
if (
|
|
15816
|
-
return
|
|
15817
|
-
processRequirement("node", "inspect", segment, ["process.inspect.node_syntax"]),
|
|
15818
|
-
requirement2(
|
|
15819
|
-
"fs.read",
|
|
15820
|
-
"fs.read",
|
|
15821
|
-
{ kind: "path", path: resolvePathOperand(args[1], cwd) },
|
|
15822
|
-
segment,
|
|
15823
|
-
["node.syntax_source_read"]
|
|
15824
|
-
)
|
|
15825
|
-
];
|
|
16039
|
+
if (head === "rsync") {
|
|
16040
|
+
return decodeRsync(args, cwd, segment);
|
|
15826
16041
|
}
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
function decodePrisma(args, env, repoRoot, segment) {
|
|
15830
|
-
const processEffect = processRequirement("prisma", "spawn", segment, ["process.prisma"]);
|
|
15831
|
-
if (args[0] === "generate") {
|
|
15832
|
-
return [
|
|
15833
|
-
processEffect,
|
|
15834
|
-
requirement2("fs.write", "fs.write", { kind: "path", path: repoRoot }, segment, [
|
|
15835
|
-
"prisma.generate.repo_local"
|
|
15836
|
-
])
|
|
15837
|
-
];
|
|
16042
|
+
if (head === "sed") {
|
|
16043
|
+
return decodeSed(args, cwd, segment);
|
|
15838
16044
|
}
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
return [
|
|
15842
|
-
processEffect,
|
|
15843
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15844
|
-
"prisma.grammar_incomplete"
|
|
15845
|
-
])
|
|
15846
|
-
];
|
|
16045
|
+
if (head === "base64" && args.length === 1 && ["-d", "-D", "--decode"].includes(args[0] ?? "")) {
|
|
16046
|
+
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
15847
16047
|
}
|
|
15848
|
-
|
|
15849
|
-
|
|
16048
|
+
if (head === "node") {
|
|
16049
|
+
return decodeNode2(args, cwd, segment);
|
|
16050
|
+
}
|
|
16051
|
+
if (head === "vite" || head === "vite-node") {
|
|
16052
|
+
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
16053
|
+
}
|
|
16054
|
+
if ((head === "npm" || head === "pnpm") && args[0] === "publish" || head === "terraform" && args[0] === "apply") {
|
|
15850
16055
|
return [
|
|
15851
|
-
|
|
16056
|
+
processRequirement(head, "spawn", segment, ["tier0_external"]),
|
|
15852
16057
|
requirement2(
|
|
15853
16058
|
"network.connect",
|
|
15854
16059
|
"network.connect",
|
|
15855
16060
|
{
|
|
15856
16061
|
kind: "network",
|
|
15857
|
-
host: "
|
|
15858
|
-
protocol:
|
|
15859
|
-
mode: "
|
|
16062
|
+
host: "control-plane",
|
|
16063
|
+
protocol: head,
|
|
16064
|
+
mode: "mutate",
|
|
15860
16065
|
payload: "present"
|
|
15861
16066
|
},
|
|
15862
16067
|
segment,
|
|
15863
|
-
["
|
|
15864
|
-
)
|
|
15865
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15866
|
-
"prisma.database_endpoint_unknown"
|
|
15867
|
-
])
|
|
16068
|
+
["tier0_external"]
|
|
16069
|
+
)
|
|
15868
16070
|
];
|
|
15869
16071
|
}
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
"network.connect",
|
|
15873
|
-
{
|
|
15874
|
-
kind: "network",
|
|
15875
|
-
...endpoint,
|
|
15876
|
-
mode: "mutate",
|
|
15877
|
-
payload: "present"
|
|
15878
|
-
},
|
|
15879
|
-
segment,
|
|
15880
|
-
[LOOPBACK_HOSTS2.has(endpoint.host) ? "prisma.database_local" : "prisma.database_remote"]
|
|
15881
|
-
);
|
|
15882
|
-
if (LOOPBACK_HOSTS2.has(endpoint.host)) {
|
|
15883
|
-
return [processEffect, network];
|
|
15884
|
-
}
|
|
15885
|
-
return [
|
|
15886
|
-
processEffect,
|
|
15887
|
-
network,
|
|
15888
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15889
|
-
"prisma.remote_database_mutation"
|
|
15890
|
-
])
|
|
15891
|
-
];
|
|
15892
|
-
}
|
|
15893
|
-
function addRedirectEffects(requirements, tokens, env, context, segment) {
|
|
15894
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
15895
|
-
const operator = tokens[index] ?? "";
|
|
15896
|
-
if (!isRedirectOperator(operator) || isFdDuplication(operator)) {
|
|
15897
|
-
continue;
|
|
15898
|
-
}
|
|
15899
|
-
const rawTarget = tokens[index + 1];
|
|
15900
|
-
if (!rawTarget) {
|
|
15901
|
-
requirements.push(
|
|
15902
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15903
|
-
"shell.redirect_target_missing"
|
|
15904
|
-
])
|
|
15905
|
-
);
|
|
15906
|
-
continue;
|
|
15907
|
-
}
|
|
15908
|
-
if (operator.includes("<<")) {
|
|
15909
|
-
requirements.push(
|
|
15910
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15911
|
-
"shell.heredoc_opaque"
|
|
15912
|
-
])
|
|
15913
|
-
);
|
|
15914
|
-
index += 1;
|
|
15915
|
-
continue;
|
|
15916
|
-
}
|
|
15917
|
-
const target = expandKnownVariables(rawTarget, env);
|
|
15918
|
-
const resolved = resolvePathOperand(target, context.cwd);
|
|
15919
|
-
if (resolved === "/dev/null") {
|
|
15920
|
-
index += 1;
|
|
15921
|
-
continue;
|
|
15922
|
-
}
|
|
15923
|
-
if (operator.includes("<")) {
|
|
15924
|
-
requirements.push(
|
|
15925
|
-
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
15926
|
-
"shell.input_redirect"
|
|
15927
|
-
])
|
|
15928
|
-
);
|
|
15929
|
-
addSecretRead(requirements, resolved, segment);
|
|
15930
|
-
}
|
|
15931
|
-
if (operator.includes(">")) {
|
|
15932
|
-
addWriteEffects(requirements, resolved, segment, ["shell.output_redirect"]);
|
|
15933
|
-
}
|
|
15934
|
-
index += 1;
|
|
15935
|
-
}
|
|
15936
|
-
}
|
|
15937
|
-
function addSubstitutionEffects(requirements, command, context, segment, signals) {
|
|
15938
|
-
const inners = structuralSubstitutionInners(command);
|
|
15939
|
-
for (const inner of inners) {
|
|
15940
|
-
signals.add("command_substitution");
|
|
15941
|
-
if (context.depth >= MAX_LOWER_DEPTH) {
|
|
15942
|
-
requirements.push(
|
|
15943
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
15944
|
-
"shell.substitution_depth_exceeded"
|
|
15945
|
-
])
|
|
15946
|
-
);
|
|
15947
|
-
continue;
|
|
15948
|
-
}
|
|
15949
|
-
const nestedSegments = lowerTopLevelSegments(inner, {
|
|
15950
|
-
...context,
|
|
15951
|
-
command: inner,
|
|
15952
|
-
depth: context.depth + 1
|
|
15953
|
-
});
|
|
15954
|
-
for (const nested of nestedSegments) {
|
|
15955
|
-
requirements.push(
|
|
15956
|
-
...nested.requirements.map((entry) => {
|
|
15957
|
-
const outerProvenance = {
|
|
15958
|
-
segment,
|
|
15959
|
-
innerCommand: inner
|
|
15960
|
-
};
|
|
15961
|
-
const provenance = {
|
|
15962
|
-
...entry.provenance,
|
|
15963
|
-
segment,
|
|
15964
|
-
innerCommand: entry.provenance.innerCommand ?? inner
|
|
15965
|
-
};
|
|
15966
|
-
return withProvenances(entry, provenance, outerProvenance);
|
|
15967
|
-
})
|
|
15968
|
-
);
|
|
15969
|
-
}
|
|
15970
|
-
}
|
|
15971
|
-
}
|
|
15972
|
-
function extractEnvironment(tokens, inherited) {
|
|
15973
|
-
const env = { ...inherited };
|
|
15974
|
-
const changedNames = /* @__PURE__ */ new Set();
|
|
15975
|
-
if (tokens[0] === "env") {
|
|
15976
|
-
let index = 1;
|
|
15977
|
-
let malformed = false;
|
|
15978
|
-
while (index < tokens.length) {
|
|
15979
|
-
const option = tokens[index] ?? "";
|
|
15980
|
-
if (option === "-u" || option === "--unset") {
|
|
15981
|
-
const name = tokens[index + 1] ?? "";
|
|
15982
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
15983
|
-
malformed = true;
|
|
15984
|
-
index += 1;
|
|
15985
|
-
break;
|
|
15986
|
-
}
|
|
15987
|
-
delete env[name];
|
|
15988
|
-
changedNames.add(name);
|
|
15989
|
-
index += 2;
|
|
15990
|
-
continue;
|
|
15991
|
-
}
|
|
15992
|
-
if (option.startsWith("--unset=")) {
|
|
15993
|
-
const name = option.slice("--unset=".length);
|
|
15994
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
15995
|
-
malformed = true;
|
|
15996
|
-
index += 1;
|
|
15997
|
-
break;
|
|
15998
|
-
}
|
|
15999
|
-
delete env[name];
|
|
16000
|
-
changedNames.add(name);
|
|
16001
|
-
index += 1;
|
|
16002
|
-
continue;
|
|
16003
|
-
}
|
|
16004
|
-
if (option === "-i" || option === "--ignore-environment") {
|
|
16005
|
-
for (const name of Object.keys(env)) {
|
|
16006
|
-
delete env[name];
|
|
16007
|
-
}
|
|
16008
|
-
changedNames.add("*");
|
|
16009
|
-
index += 1;
|
|
16010
|
-
continue;
|
|
16011
|
-
}
|
|
16012
|
-
if (option === "--") {
|
|
16013
|
-
index += 1;
|
|
16014
|
-
break;
|
|
16015
|
-
}
|
|
16016
|
-
if (option.startsWith("-")) {
|
|
16017
|
-
malformed = true;
|
|
16018
|
-
index += 1;
|
|
16019
|
-
break;
|
|
16020
|
-
}
|
|
16021
|
-
break;
|
|
16022
|
-
}
|
|
16023
|
-
while (index < tokens.length) {
|
|
16024
|
-
const token = tokens[index] ?? "";
|
|
16025
|
-
const match = ENV_PREFIX_PATTERN2.exec(token);
|
|
16026
|
-
if (!match) {
|
|
16027
|
-
break;
|
|
16028
|
-
}
|
|
16029
|
-
const [, name, value] = match;
|
|
16030
|
-
if (name) {
|
|
16031
|
-
env[name] = expandKnownVariables(value ?? "", env);
|
|
16032
|
-
changedNames.add(name);
|
|
16033
|
-
}
|
|
16034
|
-
index += 1;
|
|
16035
|
-
}
|
|
16036
|
-
const commandTokens = tokens.slice(index);
|
|
16037
|
-
return {
|
|
16038
|
-
env,
|
|
16039
|
-
commandTokens,
|
|
16040
|
-
malformed: malformed || commandTokens.length === 0,
|
|
16041
|
-
changedNames
|
|
16042
|
-
};
|
|
16072
|
+
if (head === "cd") {
|
|
16073
|
+
return [];
|
|
16043
16074
|
}
|
|
16044
|
-
|
|
16045
|
-
|
|
16046
|
-
|
|
16047
|
-
|
|
16075
|
+
if (head === "cp" || head === "mv") {
|
|
16076
|
+
return decodeCopyMove(head, args, cwd, segment);
|
|
16077
|
+
}
|
|
16078
|
+
if (head === "rm") {
|
|
16079
|
+
return decodeRm(args, cwd, repoRoot, segment);
|
|
16080
|
+
}
|
|
16081
|
+
if (head === "vitest" || head === "eslint" || head === "biome" || head === "belay") {
|
|
16082
|
+
return [processRequirement(head, "spawn", segment, ["process.known_local_spawn"])];
|
|
16083
|
+
}
|
|
16084
|
+
if (head === "pwd" || head === "which" || head === "whoami") {
|
|
16085
|
+
return [processRequirement(head, "inspect", segment, ["process.pure_inspection"])];
|
|
16086
|
+
}
|
|
16087
|
+
const readOperands = filesystemReadOperands(head, args);
|
|
16088
|
+
if (readOperands !== null) {
|
|
16089
|
+
const lowered = [processRequirement(head, "inspect", segment, ["process.filesystem_inspect"])];
|
|
16090
|
+
for (const operand of readOperands) {
|
|
16091
|
+
const resolved = resolvePathOperand(operand, cwd);
|
|
16092
|
+
lowered.push(
|
|
16093
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: resolved }, segment, [
|
|
16094
|
+
"filesystem.read"
|
|
16095
|
+
])
|
|
16096
|
+
);
|
|
16097
|
+
addSecretRead(lowered, resolved, segment);
|
|
16048
16098
|
}
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16099
|
+
return lowered;
|
|
16100
|
+
}
|
|
16101
|
+
const writeOperands = filesystemWriteOperands(head, args);
|
|
16102
|
+
if (writeOperands !== null) {
|
|
16103
|
+
const lowered = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
|
|
16104
|
+
for (const operand of writeOperands) {
|
|
16105
|
+
addWriteEffects(lowered, resolvePathOperand(operand, cwd), segment, ["filesystem.write"]);
|
|
16053
16106
|
}
|
|
16107
|
+
return lowered;
|
|
16054
16108
|
}
|
|
16055
|
-
|
|
16109
|
+
if (head === "printf" || head === "echo" || head === "true" || head === "false" || head === ":") {
|
|
16110
|
+
return [];
|
|
16111
|
+
}
|
|
16112
|
+
if (!head) {
|
|
16113
|
+
return [
|
|
16114
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16115
|
+
"shell.segment_empty"
|
|
16116
|
+
])
|
|
16117
|
+
];
|
|
16118
|
+
}
|
|
16119
|
+
return unsupportedProcess(head, segment, "process.grammar_unknown");
|
|
16056
16120
|
}
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16121
|
+
|
|
16122
|
+
// src/core/effect-ir/shell-lower/decoders/decode-package-exec.ts
|
|
16123
|
+
function decodePackageExec(peel, cwd, repoRoot, segment) {
|
|
16124
|
+
if (peel.opaque) {
|
|
16125
|
+
return [
|
|
16126
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16127
|
+
peel.reason,
|
|
16128
|
+
...peel.signals
|
|
16129
|
+
])
|
|
16130
|
+
];
|
|
16131
|
+
}
|
|
16132
|
+
if (peel.reason === "npx_wrapper_readonly") {
|
|
16133
|
+
return [];
|
|
16134
|
+
}
|
|
16135
|
+
const binHead = peel.innerTokens[0] ?? "";
|
|
16136
|
+
const metadataOnly = packageExecInnerIsMetadata(peel);
|
|
16137
|
+
const local = !peel.forceAcquire ? resolveLocalBin(binHead, cwd, repoRoot) : null;
|
|
16138
|
+
if (local) {
|
|
16139
|
+
return metadataOnly ? [
|
|
16140
|
+
requirement2(
|
|
16141
|
+
"process.exec",
|
|
16142
|
+
"process.exec",
|
|
16143
|
+
{ kind: "executable", command: local.path, operation: "inspect" },
|
|
16144
|
+
segment,
|
|
16145
|
+
["package_exec.delegate", "package_exec.local_bin_resolved"]
|
|
16146
|
+
)
|
|
16147
|
+
] : [];
|
|
16148
|
+
}
|
|
16149
|
+
const networkResources = peel.acquisitionSpecs.map((spec) => classifyPackageAcquisitionSpec(spec)).filter((source) => source.kind !== "local").map(
|
|
16150
|
+
(source) => source.kind === "registry" ? {
|
|
16151
|
+
kind: "network",
|
|
16152
|
+
host: "registry.npmjs.org",
|
|
16153
|
+
protocol: "registry",
|
|
16154
|
+
mode: "read",
|
|
16155
|
+
payload: "none"
|
|
16156
|
+
} : {
|
|
16157
|
+
kind: "network",
|
|
16158
|
+
host: source.host,
|
|
16159
|
+
...source.port ? { port: source.port } : {},
|
|
16160
|
+
protocol: source.protocol,
|
|
16161
|
+
mode: "read",
|
|
16162
|
+
payload: "none"
|
|
16063
16163
|
}
|
|
16064
16164
|
);
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
}
|
|
16073
|
-
if (!isRedirectOperator(token)) {
|
|
16074
|
-
stripped.push(token);
|
|
16075
|
-
continue;
|
|
16076
|
-
}
|
|
16077
|
-
index += 1;
|
|
16165
|
+
if (networkResources.length === 0) {
|
|
16166
|
+
networkResources.push({
|
|
16167
|
+
kind: "network",
|
|
16168
|
+
host: "registry.npmjs.org",
|
|
16169
|
+
protocol: "registry",
|
|
16170
|
+
mode: "read",
|
|
16171
|
+
payload: "none"
|
|
16172
|
+
});
|
|
16078
16173
|
}
|
|
16079
|
-
return
|
|
16174
|
+
return [
|
|
16175
|
+
...networkResources.map(
|
|
16176
|
+
(resource) => requirement2("network.acquire", "network.connect", resource, segment, [
|
|
16177
|
+
"package_acquire_possible"
|
|
16178
|
+
])
|
|
16179
|
+
),
|
|
16180
|
+
requirement2(
|
|
16181
|
+
"fs.write",
|
|
16182
|
+
"fs.write",
|
|
16183
|
+
{ kind: "package-cache", manager: peel.launcher === "pnpm" ? "pnpm" : "npm" },
|
|
16184
|
+
segment,
|
|
16185
|
+
["package_cache_write"]
|
|
16186
|
+
),
|
|
16187
|
+
...metadataOnly ? [
|
|
16188
|
+
requirement2(
|
|
16189
|
+
"process.exec",
|
|
16190
|
+
"process.exec",
|
|
16191
|
+
{ kind: "executable", command: binHead || peel.launcher, operation: "inspect" },
|
|
16192
|
+
segment,
|
|
16193
|
+
["package_exec.delegate"]
|
|
16194
|
+
)
|
|
16195
|
+
] : []
|
|
16196
|
+
];
|
|
16080
16197
|
}
|
|
16081
|
-
function
|
|
16082
|
-
const
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16198
|
+
function packageExecInnerIsMetadata(peel) {
|
|
16199
|
+
const args = peel.innerTokens.slice(1);
|
|
16200
|
+
return args.length > 0 && args.every((arg) => ["--help", "--version", "-V", "-h", "-v"].includes(arg));
|
|
16201
|
+
}
|
|
16202
|
+
|
|
16203
|
+
// src/core/effect-ir/shell-lower/segment.ts
|
|
16204
|
+
init_shell_tokenizer();
|
|
16205
|
+
import path47 from "node:path";
|
|
16206
|
+
var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
|
|
16207
|
+
var SHELL_GLOB_PATTERN = /[*?[]/;
|
|
16208
|
+
function requiresKnownCwd(requirementValue) {
|
|
16209
|
+
if (requirementValue.action === "fs.write" || requirementValue.action === "git.ref.write" || requirementValue.action === "control_plane.write") {
|
|
16210
|
+
return true;
|
|
16094
16211
|
}
|
|
16095
|
-
return
|
|
16212
|
+
return requirementValue.action === "process.exec" && requirementValue.resource.kind === "executable" && requirementValue.resource.operation === "spawn";
|
|
16096
16213
|
}
|
|
16097
|
-
function
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16214
|
+
function joinNestedOpacity(outer, nested) {
|
|
16215
|
+
const nestedOpacity = nested.completeness === "partial" && nested.opacity === "transparent" ? "recursive" : nested.opacity;
|
|
16216
|
+
return joinEffectOpacity(outer, nestedOpacity);
|
|
16217
|
+
}
|
|
16218
|
+
function startsLocalPostgresService(command) {
|
|
16219
|
+
const tokens = tokenizeShell(command);
|
|
16220
|
+
return path47.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
16221
|
+
}
|
|
16222
|
+
function resolveCdTransition(command, currentCwd) {
|
|
16223
|
+
const tokens = tokenizeShell(command);
|
|
16224
|
+
if (path47.basename(tokens[0] ?? "") !== "cd") {
|
|
16225
|
+
return null;
|
|
16104
16226
|
}
|
|
16105
|
-
|
|
16227
|
+
const target = tokens[1] ?? "~";
|
|
16228
|
+
if (!target || target === "-" || target.includes("$") || target.includes("`")) {
|
|
16229
|
+
return { cwd: currentCwd, known: false };
|
|
16230
|
+
}
|
|
16231
|
+
return { cwd: resolvePathOperand(target, currentCwd), known: true };
|
|
16106
16232
|
}
|
|
16107
16233
|
function shellSegment(commandRedacted, segmentHead, requirements, opacity, signals) {
|
|
16108
16234
|
const normalizedRequirements = requirements.flatMap((entry) => {
|
|
@@ -16117,71 +16243,21 @@ function shellSegment(commandRedacted, segmentHead, requirements, opacity, signa
|
|
|
16117
16243
|
entry.provenance.segment ?? commandRedacted,
|
|
16118
16244
|
[...entry.evidence.signals, dynamicSignal]
|
|
16119
16245
|
)
|
|
16120
|
-
];
|
|
16121
|
-
}
|
|
16122
|
-
return [entry];
|
|
16123
|
-
});
|
|
16124
|
-
const partial = normalizedRequirements.some(
|
|
16125
|
-
(entry) => entry.tag === "indeterminate" || entry.action === "indeterminate"
|
|
16126
|
-
);
|
|
16127
|
-
return {
|
|
16128
|
-
commandRedacted,
|
|
16129
|
-
segmentHead,
|
|
16130
|
-
requirements: normalizedRequirements,
|
|
16131
|
-
completeness: partial ? "partial" : "complete",
|
|
16132
|
-
opacity,
|
|
16133
|
-
signals: [...signals].sort()
|
|
16134
|
-
};
|
|
16135
|
-
}
|
|
16136
|
-
var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
|
|
16137
|
-
var SHELL_GLOB_PATTERN = /[*?[]/;
|
|
16138
|
-
function effectChangingEnvironmentSignals(head, env, changedNames) {
|
|
16139
|
-
if (head === "curl" && (env.CURL_HOME || changedNames.has("CURL_HOME") || changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME"))) {
|
|
16140
|
-
return ["egress.curl.environment_config_override"];
|
|
16141
|
-
}
|
|
16142
|
-
if (head === "wget" && (env.WGETRC || changedNames.has("WGETRC") || changedNames.has("HOME"))) {
|
|
16143
|
-
return ["egress.wget.environment_config_override"];
|
|
16144
|
-
}
|
|
16145
|
-
if (head !== "git") {
|
|
16146
|
-
return [];
|
|
16147
|
-
}
|
|
16148
|
-
const hazardousNames = /* @__PURE__ */ new Set([
|
|
16149
|
-
"GIT_ASKPASS",
|
|
16150
|
-
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
16151
|
-
"GIT_CEILING_DIRECTORIES",
|
|
16152
|
-
"GIT_COMMON_DIR",
|
|
16153
|
-
"GIT_CONFIG",
|
|
16154
|
-
"GIT_CONFIG_GLOBAL",
|
|
16155
|
-
"GIT_CONFIG_SYSTEM",
|
|
16156
|
-
"GIT_DIR",
|
|
16157
|
-
"GIT_DISCOVERY_ACROSS_FILESYSTEM",
|
|
16158
|
-
"GIT_EDITOR",
|
|
16159
|
-
"GIT_EXEC_PATH",
|
|
16160
|
-
"GIT_EXTERNAL_DIFF",
|
|
16161
|
-
"GIT_INDEX_FILE",
|
|
16162
|
-
"GIT_NAMESPACE",
|
|
16163
|
-
"GIT_OBJECT_DIRECTORY",
|
|
16164
|
-
"GIT_PAGER",
|
|
16165
|
-
"GIT_PROXY_COMMAND",
|
|
16166
|
-
"GIT_QUARANTINE_PATH",
|
|
16167
|
-
"GIT_SEQUENCE_EDITOR",
|
|
16168
|
-
"GIT_SHALLOW_FILE",
|
|
16169
|
-
"GIT_SSH",
|
|
16170
|
-
"GIT_SSH_COMMAND",
|
|
16171
|
-
"GIT_TEMPLATE_DIR",
|
|
16172
|
-
"GIT_WORK_TREE",
|
|
16173
|
-
"SSH_ASKPASS"
|
|
16174
|
-
]);
|
|
16175
|
-
const overridden = changedNames.has("HOME") || changedNames.has("XDG_CONFIG_HOME") || Object.entries(env).some(([name, value]) => {
|
|
16176
|
-
if (!value) {
|
|
16177
|
-
return false;
|
|
16178
|
-
}
|
|
16179
|
-
if (hazardousNames.has(name) || /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(name) || /^GIT_TRACE/.test(name)) {
|
|
16180
|
-
return true;
|
|
16246
|
+
];
|
|
16181
16247
|
}
|
|
16182
|
-
return
|
|
16248
|
+
return [entry];
|
|
16183
16249
|
});
|
|
16184
|
-
|
|
16250
|
+
const partial = normalizedRequirements.some(
|
|
16251
|
+
(entry) => entry.tag === "indeterminate" || entry.action === "indeterminate"
|
|
16252
|
+
);
|
|
16253
|
+
return {
|
|
16254
|
+
commandRedacted,
|
|
16255
|
+
segmentHead,
|
|
16256
|
+
requirements: normalizedRequirements,
|
|
16257
|
+
completeness: partial ? "partial" : "complete",
|
|
16258
|
+
opacity,
|
|
16259
|
+
signals: [...signals].sort()
|
|
16260
|
+
};
|
|
16185
16261
|
}
|
|
16186
16262
|
function dynamicResourceSignal(resource) {
|
|
16187
16263
|
const expanded = (value) => Boolean(value && DYNAMIC_SHELL_VALUE_PATTERN.test(value));
|
|
@@ -16201,362 +16277,502 @@ function dynamicResourceSignal(resource) {
|
|
|
16201
16277
|
return null;
|
|
16202
16278
|
}
|
|
16203
16279
|
}
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
|
|
16214
|
-
|
|
16215
|
-
processRequirement(command, "spawn", segment, [signal]),
|
|
16216
|
-
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [signal])
|
|
16217
|
-
];
|
|
16280
|
+
|
|
16281
|
+
// src/core/effect-ir/shell-lower.ts
|
|
16282
|
+
var MAX_LOWER_DEPTH = 8;
|
|
16283
|
+
function lowerShellEffectPlan(params) {
|
|
16284
|
+
const context = { ...params, depth: 0 };
|
|
16285
|
+
const segments = lowerTopLevelSegments(params.command, context);
|
|
16286
|
+
return buildShellEffectPlan({
|
|
16287
|
+
inputFingerprint: params.inputFingerprint,
|
|
16288
|
+
segments,
|
|
16289
|
+
signals: pipeToShell(params.command) ? ["pipe_to_shell"] : []
|
|
16290
|
+
});
|
|
16218
16291
|
}
|
|
16219
|
-
function
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16292
|
+
function lowerTopLevelSegments(command, context) {
|
|
16293
|
+
const commands = splitStructuralShellSegments(command);
|
|
16294
|
+
if (commands.length === 0 && command.trim()) {
|
|
16295
|
+
commands.push(command.trim());
|
|
16296
|
+
}
|
|
16297
|
+
const pipedToShell = pipeToShell(command);
|
|
16298
|
+
const lowered = [];
|
|
16299
|
+
let cwd = context.cwd;
|
|
16300
|
+
let cwdKnown = true;
|
|
16301
|
+
let inferredEnv = { ...context.env };
|
|
16302
|
+
for (const segment of commands) {
|
|
16303
|
+
let result = lowerSegment(segment, {
|
|
16304
|
+
...context,
|
|
16305
|
+
cwd,
|
|
16306
|
+
env: inferredEnv,
|
|
16307
|
+
command: segment,
|
|
16308
|
+
depth: context.depth,
|
|
16309
|
+
inputFingerprint: context.inputFingerprint,
|
|
16310
|
+
...pipedToShell && isShellHead(parseSegment(segment).head) ? { pipeToShellSegment: true } : {}
|
|
16311
|
+
});
|
|
16312
|
+
if (!cwdKnown) {
|
|
16313
|
+
const requiresCwd = result.requirements.some(requiresKnownCwd);
|
|
16314
|
+
const requirements = [...result.requirements];
|
|
16315
|
+
if (requiresCwd) {
|
|
16316
|
+
requirements.push(
|
|
16317
|
+
requirement2(
|
|
16318
|
+
"indeterminate",
|
|
16319
|
+
"indeterminate",
|
|
16320
|
+
{ kind: "unknown" },
|
|
16321
|
+
result.commandRedacted,
|
|
16322
|
+
["shell.cwd_unknown"]
|
|
16323
|
+
)
|
|
16324
|
+
);
|
|
16325
|
+
}
|
|
16326
|
+
result = {
|
|
16327
|
+
...result,
|
|
16328
|
+
requirements,
|
|
16329
|
+
...requiresCwd ? {
|
|
16330
|
+
completeness: "partial",
|
|
16331
|
+
opacity: joinEffectOpacity(result.opacity, "opaque")
|
|
16332
|
+
} : {},
|
|
16333
|
+
signals: [.../* @__PURE__ */ new Set([...result.signals, "shell.cwd_unknown"])]
|
|
16334
|
+
};
|
|
16335
|
+
}
|
|
16336
|
+
lowered.push(result);
|
|
16337
|
+
if (!inferredEnv.DATABASE_URL && startsLocalPostgresService(segment)) {
|
|
16338
|
+
inferredEnv = {
|
|
16339
|
+
...inferredEnv,
|
|
16340
|
+
DATABASE_URL: "postgresql://127.0.0.1:5432/local"
|
|
16341
|
+
};
|
|
16342
|
+
}
|
|
16343
|
+
const nextCwd = resolveCdTransition(segment, cwd);
|
|
16344
|
+
if (nextCwd) {
|
|
16345
|
+
cwd = nextCwd.cwd;
|
|
16346
|
+
cwdKnown = nextCwd.known;
|
|
16347
|
+
}
|
|
16348
|
+
}
|
|
16349
|
+
if (commands.length > 1 && /[\r\n]/.test(command) && lowered.some(
|
|
16350
|
+
(segment) => segment.requirements.some((entry) => entry.action === "network.connect")
|
|
16351
|
+
)) {
|
|
16352
|
+
lowered.push(
|
|
16353
|
+
shellSegment(
|
|
16354
|
+
"[multiline network boundary]",
|
|
16355
|
+
"shell-boundary",
|
|
16356
|
+
[
|
|
16357
|
+
requirement2(
|
|
16358
|
+
"indeterminate",
|
|
16359
|
+
"indeterminate",
|
|
16360
|
+
{ kind: "unknown" },
|
|
16361
|
+
"[multiline network boundary]",
|
|
16362
|
+
["shell.multiline_network_boundary"]
|
|
16363
|
+
)
|
|
16364
|
+
],
|
|
16365
|
+
"opaque",
|
|
16366
|
+
/* @__PURE__ */ new Set(["shell.multiline_network_boundary"])
|
|
16231
16367
|
)
|
|
16232
16368
|
);
|
|
16233
16369
|
}
|
|
16370
|
+
return lowered;
|
|
16234
16371
|
}
|
|
16235
|
-
function
|
|
16236
|
-
|
|
16372
|
+
function lowerSegment(command, context) {
|
|
16373
|
+
const commandRedacted = redactCommand(command);
|
|
16374
|
+
const lexed = lexShell(command);
|
|
16375
|
+
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
16376
|
+
const environment = extractEnvironment(rawTokens, context.env);
|
|
16377
|
+
const env = environment.env;
|
|
16378
|
+
const parsed = parseSegment(command);
|
|
16379
|
+
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
16380
|
+
const tokens = stripRedirects(
|
|
16381
|
+
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
16382
|
+
).map((token) => expandKnownVariables(token, env));
|
|
16383
|
+
const decoderTokens = alignStructuredTokens(
|
|
16384
|
+
stripStructuredRedirects(lexed.tokens),
|
|
16385
|
+
stripRedirects(parsedTokens)
|
|
16386
|
+
);
|
|
16387
|
+
const head = path48.basename(tokens[0] ?? parsed.head);
|
|
16388
|
+
let opacity = segmentOpacity(command);
|
|
16389
|
+
const signals = /* @__PURE__ */ new Set();
|
|
16390
|
+
const requirements = [];
|
|
16391
|
+
if (!lexed.complete) {
|
|
16237
16392
|
requirements.push(
|
|
16238
|
-
requirement2("
|
|
16239
|
-
"
|
|
16393
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16394
|
+
"shell.grammar_incomplete"
|
|
16240
16395
|
])
|
|
16241
16396
|
);
|
|
16397
|
+
signals.add("shell.grammar_incomplete");
|
|
16398
|
+
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
16242
16399
|
}
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
|
|
16249
|
-
|
|
16250
|
-
|
|
16251
|
-
|
|
16252
|
-
case "cat":
|
|
16253
|
-
case "head":
|
|
16254
|
-
case "tail":
|
|
16255
|
-
case "less":
|
|
16256
|
-
case "stat":
|
|
16257
|
-
case "file":
|
|
16258
|
-
case "du":
|
|
16259
|
-
case "wc":
|
|
16260
|
-
return args.filter((arg) => arg && !arg.startsWith("-"));
|
|
16261
|
-
case "grep":
|
|
16262
|
-
case "rg":
|
|
16263
|
-
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
16264
|
-
case "jq":
|
|
16265
|
-
return args.slice(1).filter((arg) => arg && !arg.startsWith("-"));
|
|
16266
|
-
default:
|
|
16267
|
-
return null;
|
|
16268
|
-
}
|
|
16269
|
-
}
|
|
16270
|
-
function findReadOperands(args) {
|
|
16271
|
-
const mutatingPrimaries = /* @__PURE__ */ new Set([
|
|
16272
|
-
"-delete",
|
|
16273
|
-
"-exec",
|
|
16274
|
-
"-execdir",
|
|
16275
|
-
"-fls",
|
|
16276
|
-
"-fprint",
|
|
16277
|
-
"-fprintf",
|
|
16278
|
-
"-ok",
|
|
16279
|
-
"-okdir"
|
|
16280
|
-
]);
|
|
16281
|
-
if (args.some(
|
|
16282
|
-
(arg) => mutatingPrimaries.has(arg) || [...mutatingPrimaries].some((primary) => arg.startsWith(`${primary}=`))
|
|
16283
|
-
)) {
|
|
16284
|
-
return null;
|
|
16285
|
-
}
|
|
16286
|
-
const paths = [];
|
|
16287
|
-
for (const arg of args) {
|
|
16288
|
-
if (arg.startsWith("-") || arg === "!" || arg === "(") {
|
|
16289
|
-
break;
|
|
16290
|
-
}
|
|
16291
|
-
paths.push(arg);
|
|
16292
|
-
}
|
|
16293
|
-
return paths.length > 0 ? paths : ["."];
|
|
16294
|
-
}
|
|
16295
|
-
function filesystemWriteOperands(head, args) {
|
|
16296
|
-
const positional = args.filter((arg) => arg && !arg.startsWith("-"));
|
|
16297
|
-
switch (head) {
|
|
16298
|
-
case "touch":
|
|
16299
|
-
case "mkdir":
|
|
16300
|
-
case "rm":
|
|
16301
|
-
case "truncate":
|
|
16302
|
-
case "chmod":
|
|
16303
|
-
return positional;
|
|
16304
|
-
case "cp":
|
|
16305
|
-
case "mv":
|
|
16306
|
-
return positional.length > 0 ? [positional[positional.length - 1] ?? ""] : [];
|
|
16307
|
-
case "tee":
|
|
16308
|
-
return positional;
|
|
16309
|
-
default:
|
|
16310
|
-
return null;
|
|
16400
|
+
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
16401
|
+
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
16402
|
+
if (environment.malformed) {
|
|
16403
|
+
requirements.push(
|
|
16404
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16405
|
+
"shell.env_wrapper_incomplete"
|
|
16406
|
+
])
|
|
16407
|
+
);
|
|
16408
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16311
16409
|
}
|
|
16312
|
-
|
|
16313
|
-
|
|
16314
|
-
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
}
|
|
16321
|
-
if (flagsWithValues.has(arg)) {
|
|
16322
|
-
if (!args[index + 1] || isOptionToken(args[index + 1] ?? "")) {
|
|
16323
|
-
return false;
|
|
16324
|
-
}
|
|
16325
|
-
index += 1;
|
|
16326
|
-
continue;
|
|
16327
|
-
}
|
|
16328
|
-
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)) {
|
|
16329
|
-
continue;
|
|
16330
|
-
}
|
|
16331
|
-
return false;
|
|
16410
|
+
if (parsed.encounteredXargs) {
|
|
16411
|
+
requirements.push(
|
|
16412
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16413
|
+
"shell.xargs_stdin_dynamic"
|
|
16414
|
+
])
|
|
16415
|
+
);
|
|
16416
|
+
signals.add("shell.xargs_stdin_dynamic");
|
|
16417
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16332
16418
|
}
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
|
|
16338
|
-
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
return false;
|
|
16355
|
-
}
|
|
16356
|
-
index += 1;
|
|
16357
|
-
continue;
|
|
16419
|
+
if (context.depth > MAX_LOWER_DEPTH) {
|
|
16420
|
+
requirements.push(
|
|
16421
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16422
|
+
"shell.lower_depth_exceeded"
|
|
16423
|
+
])
|
|
16424
|
+
);
|
|
16425
|
+
return shellSegment(
|
|
16426
|
+
commandRedacted,
|
|
16427
|
+
head,
|
|
16428
|
+
requirements,
|
|
16429
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16430
|
+
signals
|
|
16431
|
+
);
|
|
16432
|
+
}
|
|
16433
|
+
const packageExec = peelPackageExecArgv(tokens);
|
|
16434
|
+
if (packageExec) {
|
|
16435
|
+
requirements.push(
|
|
16436
|
+
...decodePackageExec(packageExec, context.cwd, context.repoRoot, commandRedacted)
|
|
16437
|
+
);
|
|
16438
|
+
for (const signal of packageExec.signals) {
|
|
16439
|
+
signals.add(signal);
|
|
16358
16440
|
}
|
|
16359
|
-
if (
|
|
16360
|
-
|
|
16441
|
+
if (packageExec.opaque) {
|
|
16442
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16361
16443
|
}
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
const
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
}
|
|
16379
|
-
break;
|
|
16444
|
+
const innerRecipe = packageExecInnerIsMetadata(packageExec) ? null : innerRecipeFromPeel(packageExec);
|
|
16445
|
+
if (innerRecipe) {
|
|
16446
|
+
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
16447
|
+
...context,
|
|
16448
|
+
command: innerRecipe,
|
|
16449
|
+
env,
|
|
16450
|
+
depth: context.depth + 1
|
|
16451
|
+
});
|
|
16452
|
+
for (const nestedSegment of nested) {
|
|
16453
|
+
requirements.push(
|
|
16454
|
+
...nestedSegment.requirements.map(
|
|
16455
|
+
(entry) => withInnerProvenance(entry, innerRecipe, packageExec.launcher, commandRedacted)
|
|
16456
|
+
)
|
|
16457
|
+
);
|
|
16458
|
+
for (const signal of nestedSegment.signals) {
|
|
16459
|
+
signals.add(signal);
|
|
16380
16460
|
}
|
|
16381
|
-
|
|
16382
|
-
break;
|
|
16383
|
-
}
|
|
16384
|
-
if (valid) {
|
|
16385
|
-
continue;
|
|
16461
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16386
16462
|
}
|
|
16387
16463
|
}
|
|
16388
|
-
return
|
|
16389
|
-
}
|
|
16390
|
-
return true;
|
|
16391
|
-
}
|
|
16392
|
-
function validFilesystemTest(head, args) {
|
|
16393
|
-
const operands = head === "[" && args.at(-1) === "]" ? args.slice(0, -1) : args;
|
|
16394
|
-
if (head === "[" && args.at(-1) !== "]") {
|
|
16395
|
-
return false;
|
|
16464
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16396
16465
|
}
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
|
|
16405
|
-
|
|
16406
|
-
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
|
|
16466
|
+
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
16467
|
+
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
16468
|
+
requirements.push(
|
|
16469
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
16470
|
+
"shell.recursive_wrapper",
|
|
16471
|
+
"dynamic_shell_evaluation"
|
|
16472
|
+
])
|
|
16473
|
+
);
|
|
16474
|
+
if (recursive.script !== "") {
|
|
16475
|
+
const nested = lowerTopLevelSegments(recursive.script, {
|
|
16476
|
+
...context,
|
|
16477
|
+
command: recursive.script,
|
|
16478
|
+
env,
|
|
16479
|
+
depth: context.depth + 1
|
|
16480
|
+
});
|
|
16481
|
+
for (const nestedSegment of nested) {
|
|
16482
|
+
requirements.push(
|
|
16483
|
+
...nestedSegment.requirements.map(
|
|
16484
|
+
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
16485
|
+
)
|
|
16486
|
+
);
|
|
16487
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
16410
16488
|
}
|
|
16411
|
-
index += 1;
|
|
16412
|
-
continue;
|
|
16413
16489
|
}
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16490
|
+
signals.add("shell.recursive_wrapper");
|
|
16491
|
+
signals.add("dynamic_shell_evaluation");
|
|
16492
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
16493
|
+
}
|
|
16494
|
+
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
16495
|
+
const recursiveSignals = [
|
|
16496
|
+
recursive.signal,
|
|
16497
|
+
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
16498
|
+
];
|
|
16499
|
+
requirements.push(
|
|
16500
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
16501
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16502
|
+
...recursiveSignals
|
|
16503
|
+
])
|
|
16504
|
+
);
|
|
16505
|
+
for (const signal of recursiveSignals) signals.add(signal);
|
|
16506
|
+
return shellSegment(
|
|
16507
|
+
commandRedacted,
|
|
16508
|
+
head,
|
|
16509
|
+
requirements,
|
|
16510
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16511
|
+
signals
|
|
16512
|
+
);
|
|
16513
|
+
}
|
|
16514
|
+
const compose = decodeDockerComposeRun(decoderTokens);
|
|
16515
|
+
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
16516
|
+
requirements.push(
|
|
16517
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
16518
|
+
);
|
|
16519
|
+
if (compose.script !== "") {
|
|
16520
|
+
const nested = lowerTopLevelSegments(compose.script, {
|
|
16521
|
+
...context,
|
|
16522
|
+
command: compose.script,
|
|
16523
|
+
env,
|
|
16524
|
+
depth: context.depth + 1
|
|
16525
|
+
});
|
|
16526
|
+
for (const nestedSegment of nested) {
|
|
16527
|
+
requirements.push(
|
|
16528
|
+
...nestedSegment.requirements.map(
|
|
16529
|
+
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
16530
|
+
)
|
|
16531
|
+
);
|
|
16532
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
16533
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16417
16534
|
}
|
|
16418
|
-
continue;
|
|
16419
16535
|
}
|
|
16420
|
-
|
|
16536
|
+
signals.add("process.docker_compose_run");
|
|
16537
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
16421
16538
|
}
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
"
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
|
|
16433
|
-
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
|
|
16442
|
-
|
|
16443
|
-
|
|
16444
|
-
|
|
16445
|
-
|
|
16446
|
-
}
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16539
|
+
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
16540
|
+
requirements.push(
|
|
16541
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
16542
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16543
|
+
compose.signal
|
|
16544
|
+
])
|
|
16545
|
+
);
|
|
16546
|
+
signals.add("process.docker_compose_run");
|
|
16547
|
+
signals.add(compose.signal);
|
|
16548
|
+
return shellSegment(
|
|
16549
|
+
commandRedacted,
|
|
16550
|
+
head,
|
|
16551
|
+
requirements,
|
|
16552
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16553
|
+
signals
|
|
16554
|
+
);
|
|
16555
|
+
}
|
|
16556
|
+
const launcher = resolveLauncherRecipe({
|
|
16557
|
+
tokens,
|
|
16558
|
+
cwd: context.cwd,
|
|
16559
|
+
repoRoot: context.repoRoot,
|
|
16560
|
+
depth: context.depth
|
|
16561
|
+
});
|
|
16562
|
+
if (launcher) {
|
|
16563
|
+
signals.add(`launcher.${launcher.reason}`);
|
|
16564
|
+
requirements.push(
|
|
16565
|
+
requirement2(
|
|
16566
|
+
"process.exec",
|
|
16567
|
+
"process.exec",
|
|
16568
|
+
{ kind: "executable", command: head, operation: "spawn" },
|
|
16569
|
+
commandRedacted,
|
|
16570
|
+
["launcher.invoke"]
|
|
16571
|
+
)
|
|
16572
|
+
);
|
|
16573
|
+
for (const recipe of launcher.recipes) {
|
|
16574
|
+
const nested = lowerTopLevelSegments(recipe, {
|
|
16575
|
+
...context,
|
|
16576
|
+
command: recipe,
|
|
16577
|
+
env,
|
|
16578
|
+
depth: context.depth + 1
|
|
16579
|
+
});
|
|
16580
|
+
for (const nestedSegment of nested) {
|
|
16581
|
+
requirements.push(
|
|
16582
|
+
...nestedSegment.requirements.map(
|
|
16583
|
+
(entry) => withInnerProvenance(entry, recipe, head, commandRedacted)
|
|
16584
|
+
)
|
|
16585
|
+
);
|
|
16586
|
+
for (const signal of nestedSegment.signals) {
|
|
16587
|
+
signals.add(signal);
|
|
16588
|
+
}
|
|
16589
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16450
16590
|
}
|
|
16451
|
-
index += 1;
|
|
16452
|
-
continue;
|
|
16453
16591
|
}
|
|
16454
|
-
if (
|
|
16455
|
-
|
|
16592
|
+
if (launcher.opaque || launcher.recipes.length === 0) {
|
|
16593
|
+
requirements.push(
|
|
16594
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16595
|
+
`launcher.${launcher.reason}`
|
|
16596
|
+
])
|
|
16597
|
+
);
|
|
16598
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16456
16599
|
}
|
|
16457
|
-
|
|
16458
|
-
|
|
16600
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16601
|
+
}
|
|
16602
|
+
const egress = decodeEgressEffects({
|
|
16603
|
+
tokens,
|
|
16604
|
+
cwd: context.cwd,
|
|
16605
|
+
segment: commandRedacted
|
|
16606
|
+
});
|
|
16607
|
+
if (egress) {
|
|
16608
|
+
requirements.push(...egress);
|
|
16609
|
+
for (const signal of egress.flatMap((entry) => entry.evidence.signals)) {
|
|
16610
|
+
signals.add(signal);
|
|
16459
16611
|
}
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16612
|
+
} else {
|
|
16613
|
+
const git = decodeGitEffects({
|
|
16614
|
+
tokens,
|
|
16615
|
+
cwd: context.cwd,
|
|
16616
|
+
repoRoot: context.repoRoot,
|
|
16617
|
+
segment: commandRedacted
|
|
16618
|
+
});
|
|
16619
|
+
if (git) {
|
|
16620
|
+
requirements.push(...git);
|
|
16621
|
+
for (const signal of git.flatMap((entry) => entry.evidence.signals)) {
|
|
16622
|
+
signals.add(signal);
|
|
16464
16623
|
}
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16624
|
+
} else {
|
|
16625
|
+
const processRequirements = decodeProcessOrFilesystem({
|
|
16626
|
+
tokens,
|
|
16627
|
+
head,
|
|
16628
|
+
env,
|
|
16629
|
+
cwd: context.cwd,
|
|
16630
|
+
repoRoot: context.repoRoot,
|
|
16631
|
+
segment: commandRedacted
|
|
16632
|
+
});
|
|
16633
|
+
if (isGrammarUnknownOnly(processRequirements, head)) {
|
|
16634
|
+
const argvDelegate = peelArgvDelegateArgv(tokens);
|
|
16635
|
+
if (argvDelegate && !argvDelegate.opaque && shouldApplyArgvDelegate(head, argvDelegate.innerTokens, context.depth)) {
|
|
16636
|
+
const innerRecipe = innerRecipeFromArgvDelegate(argvDelegate);
|
|
16637
|
+
if (innerRecipe) {
|
|
16638
|
+
requirements.push(
|
|
16639
|
+
processRequirement(head, "inspect", commandRedacted, [
|
|
16640
|
+
"process.argv_delegate",
|
|
16641
|
+
...argvDelegate.signals
|
|
16642
|
+
])
|
|
16643
|
+
);
|
|
16644
|
+
for (const signal of argvDelegate.signals) {
|
|
16645
|
+
signals.add(signal);
|
|
16646
|
+
}
|
|
16647
|
+
const nested = lowerTopLevelSegments(innerRecipe, {
|
|
16648
|
+
...context,
|
|
16649
|
+
command: innerRecipe,
|
|
16650
|
+
env,
|
|
16651
|
+
depth: context.depth + 1
|
|
16652
|
+
});
|
|
16653
|
+
for (const nestedSegment of nested) {
|
|
16654
|
+
requirements.push(
|
|
16655
|
+
...nestedSegment.requirements.map(
|
|
16656
|
+
(entry) => withInnerProvenance(entry, innerRecipe, head, commandRedacted)
|
|
16657
|
+
)
|
|
16658
|
+
);
|
|
16659
|
+
for (const signal of nestedSegment.signals) {
|
|
16660
|
+
signals.add(signal);
|
|
16661
|
+
}
|
|
16662
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
16663
|
+
}
|
|
16664
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16665
|
+
}
|
|
16666
|
+
}
|
|
16667
|
+
if (argvDelegate?.opaque) {
|
|
16668
|
+
requirements.push(
|
|
16669
|
+
processRequirement(head, "spawn", commandRedacted, [
|
|
16670
|
+
"process.argv_delegate",
|
|
16671
|
+
argvDelegate.reason,
|
|
16672
|
+
...argvDelegate.signals
|
|
16673
|
+
]),
|
|
16674
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16675
|
+
argvDelegate.reason,
|
|
16676
|
+
"process.argv_delegate_opaque"
|
|
16677
|
+
])
|
|
16678
|
+
);
|
|
16679
|
+
for (const signal of argvDelegate.signals) {
|
|
16680
|
+
signals.add(signal);
|
|
16681
|
+
}
|
|
16682
|
+
signals.add("process.argv_delegate_opaque");
|
|
16683
|
+
return shellSegment(
|
|
16684
|
+
commandRedacted,
|
|
16685
|
+
head,
|
|
16686
|
+
requirements,
|
|
16687
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
16688
|
+
signals
|
|
16689
|
+
);
|
|
16690
|
+
}
|
|
16691
|
+
}
|
|
16692
|
+
requirements.push(...processRequirements);
|
|
16474
16693
|
}
|
|
16475
|
-
script = arg;
|
|
16476
|
-
break;
|
|
16477
|
-
}
|
|
16478
|
-
return syntaxOnly ? script : null;
|
|
16479
|
-
}
|
|
16480
|
-
function isOptionToken(value) {
|
|
16481
|
-
return value.startsWith("-") || value.startsWith("+");
|
|
16482
|
-
}
|
|
16483
|
-
function databaseEndpoint(raw) {
|
|
16484
|
-
if (!raw || raw.includes("$")) {
|
|
16485
|
-
return null;
|
|
16486
16694
|
}
|
|
16487
|
-
|
|
16488
|
-
|
|
16489
|
-
|
|
16490
|
-
|
|
16695
|
+
const environmentSignals = effectChangingEnvironmentSignals(head, env, environment.changedNames);
|
|
16696
|
+
if (environmentSignals.length > 0) {
|
|
16697
|
+
requirements.push(
|
|
16698
|
+
requirement2(
|
|
16699
|
+
"indeterminate",
|
|
16700
|
+
"indeterminate",
|
|
16701
|
+
{ kind: "unknown" },
|
|
16702
|
+
commandRedacted,
|
|
16703
|
+
environmentSignals
|
|
16704
|
+
)
|
|
16705
|
+
);
|
|
16706
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16707
|
+
for (const signal of environmentSignals) {
|
|
16708
|
+
signals.add(signal);
|
|
16491
16709
|
}
|
|
16492
|
-
return {
|
|
16493
|
-
host: url.hostname.toLowerCase(),
|
|
16494
|
-
protocol: url.protocol.slice(0, -1),
|
|
16495
|
-
...url.port ? { port: Number(url.port) } : {}
|
|
16496
|
-
};
|
|
16497
|
-
} catch {
|
|
16498
|
-
return null;
|
|
16499
16710
|
}
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16711
|
+
if (context.pipeToShellSegment) {
|
|
16712
|
+
signals.add("pipe_to_shell");
|
|
16713
|
+
ensureRequirement(
|
|
16714
|
+
requirements,
|
|
16715
|
+
requirement2(
|
|
16716
|
+
"process.exec",
|
|
16717
|
+
"process.exec",
|
|
16718
|
+
{ kind: "executable", command: head || "sh", operation: "spawn" },
|
|
16719
|
+
commandRedacted,
|
|
16720
|
+
["pipe_to_shell"]
|
|
16721
|
+
)
|
|
16722
|
+
);
|
|
16723
|
+
ensureRequirement(
|
|
16724
|
+
requirements,
|
|
16725
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16726
|
+
"pipe_to_shell"
|
|
16727
|
+
])
|
|
16728
|
+
);
|
|
16729
|
+
opacity = joinEffectOpacity(opacity, "opaque");
|
|
16504
16730
|
}
|
|
16505
|
-
if (
|
|
16506
|
-
|
|
16731
|
+
if (opacity === "unparseable" || opacity === "opaque") {
|
|
16732
|
+
ensureRequirement(
|
|
16733
|
+
requirements,
|
|
16734
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
16735
|
+
`shell.${opacity}`
|
|
16736
|
+
])
|
|
16737
|
+
);
|
|
16507
16738
|
}
|
|
16508
|
-
return
|
|
16509
|
-
}
|
|
16510
|
-
function isShellHead(head) {
|
|
16511
|
-
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
16512
|
-
}
|
|
16513
|
-
function pipeToShell(command) {
|
|
16514
|
-
return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
|
|
16515
|
-
}
|
|
16516
|
-
function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegment) {
|
|
16517
|
-
const provenance = {
|
|
16518
|
-
...requirementValue.provenance,
|
|
16519
|
-
segment: outerSegment,
|
|
16520
|
-
innerCommand: requirementValue.provenance.innerCommand ?? innerCommand,
|
|
16521
|
-
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
16522
|
-
};
|
|
16523
|
-
const launcherProvenance = {
|
|
16524
|
-
segment: outerSegment,
|
|
16525
|
-
innerCommand,
|
|
16526
|
-
...launcher === "npm" || launcher === "pnpm" ? { launcher, phase: "delegate" } : {}
|
|
16527
|
-
};
|
|
16528
|
-
return withProvenances(requirementValue, provenance, launcherProvenance);
|
|
16529
|
-
}
|
|
16530
|
-
function withProvenances(requirementValue, provenance, contributing) {
|
|
16531
|
-
const provenances = [
|
|
16532
|
-
...requirementValue.provenances ?? [requirementValue.provenance],
|
|
16533
|
-
contributing,
|
|
16534
|
-
provenance
|
|
16535
|
-
].filter(
|
|
16536
|
-
(candidate, index, all) => all.findIndex((entry) => JSON.stringify(entry) === JSON.stringify(candidate)) === index
|
|
16537
|
-
);
|
|
16538
|
-
return { ...requirementValue, provenance, provenances };
|
|
16739
|
+
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
16539
16740
|
}
|
|
16540
|
-
function
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16741
|
+
function addSubstitutionEffects(requirements, command, context, segment, signals) {
|
|
16742
|
+
const inners = structuralSubstitutionInners(command);
|
|
16743
|
+
for (const inner of inners) {
|
|
16744
|
+
signals.add("command_substitution");
|
|
16745
|
+
if (context.depth >= MAX_LOWER_DEPTH) {
|
|
16746
|
+
requirements.push(
|
|
16747
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, segment, [
|
|
16748
|
+
"shell.substitution_depth_exceeded"
|
|
16749
|
+
])
|
|
16750
|
+
);
|
|
16751
|
+
continue;
|
|
16752
|
+
}
|
|
16753
|
+
const nestedSegments = lowerTopLevelSegments(inner, {
|
|
16754
|
+
...context,
|
|
16755
|
+
command: inner,
|
|
16756
|
+
depth: context.depth + 1
|
|
16757
|
+
});
|
|
16758
|
+
for (const nested of nestedSegments) {
|
|
16759
|
+
requirements.push(
|
|
16760
|
+
...nested.requirements.map((entry) => {
|
|
16761
|
+
const outerProvenance = {
|
|
16762
|
+
segment,
|
|
16763
|
+
innerCommand: inner
|
|
16764
|
+
};
|
|
16765
|
+
const provenance = {
|
|
16766
|
+
...entry.provenance,
|
|
16767
|
+
segment,
|
|
16768
|
+
innerCommand: entry.provenance.innerCommand ?? inner
|
|
16769
|
+
};
|
|
16770
|
+
return withProvenances(entry, provenance, outerProvenance);
|
|
16771
|
+
})
|
|
16772
|
+
);
|
|
16773
|
+
}
|
|
16545
16774
|
}
|
|
16546
16775
|
}
|
|
16547
|
-
function requirement2(tag, action, resource, segment, signals) {
|
|
16548
|
-
return {
|
|
16549
|
-
tag,
|
|
16550
|
-
action,
|
|
16551
|
-
resource,
|
|
16552
|
-
evidence: {
|
|
16553
|
-
level: tag === "indeterminate" ? "indeterminate" : "certain",
|
|
16554
|
-
signals: [...new Set(signals)].sort(),
|
|
16555
|
-
basis: ["shell_semantic_lowering"]
|
|
16556
|
-
},
|
|
16557
|
-
provenance: { segment }
|
|
16558
|
-
};
|
|
16559
|
-
}
|
|
16560
16776
|
|
|
16561
16777
|
// src/core/verdict/verdict.ts
|
|
16562
16778
|
init_path_utils();
|
|
@@ -16776,6 +16992,13 @@ function policyAuth(options) {
|
|
|
16776
16992
|
function scrubPayload(value, options) {
|
|
16777
16993
|
return scrubValue(value, options.scrubOptions);
|
|
16778
16994
|
}
|
|
16995
|
+
function fingerprintPayload(payload, options) {
|
|
16996
|
+
const toolInput = fingerprintToolInputSource(payload);
|
|
16997
|
+
if (Object.keys(toolInput).length > 0) {
|
|
16998
|
+
return toolInput;
|
|
16999
|
+
}
|
|
17000
|
+
return scrubPayload(payload.tool_input ?? {}, options);
|
|
17001
|
+
}
|
|
16779
17002
|
function extractFilePath(payload) {
|
|
16780
17003
|
const toolInput = payload.tool_input;
|
|
16781
17004
|
if (!toolInput || typeof toolInput !== "object") {
|
|
@@ -16950,11 +17173,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16950
17173
|
verdict: "deny_pending_approval",
|
|
16951
17174
|
reason: "tool_shell_missing_command",
|
|
16952
17175
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
16953
|
-
fingerprint: toolFingerprint(
|
|
16954
|
-
toolName,
|
|
16955
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
16956
|
-
repoRoot
|
|
16957
|
-
),
|
|
17176
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
16958
17177
|
assessment: {
|
|
16959
17178
|
reversibility: "irreversible",
|
|
16960
17179
|
external: false,
|
|
@@ -16968,11 +17187,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16968
17187
|
verdict: "allow_flagged",
|
|
16969
17188
|
reason: "tool_shell_missing_command",
|
|
16970
17189
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
16971
|
-
fingerprint: toolFingerprint(
|
|
16972
|
-
toolName,
|
|
16973
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
16974
|
-
repoRoot
|
|
16975
|
-
),
|
|
17190
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
16976
17191
|
assessment: {
|
|
16977
17192
|
reversibility: "recoverable_with_cost",
|
|
16978
17193
|
external: false,
|
|
@@ -16996,11 +17211,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16996
17211
|
verdict: "deny_pending_approval",
|
|
16997
17212
|
reason: "file_mutation_missing_path",
|
|
16998
17213
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
16999
|
-
fingerprint: toolFingerprint(
|
|
17000
|
-
toolName,
|
|
17001
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17002
|
-
repoRoot
|
|
17003
|
-
),
|
|
17214
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17004
17215
|
assessment: {
|
|
17005
17216
|
reversibility: "irreversible",
|
|
17006
17217
|
external: false,
|
|
@@ -17014,11 +17225,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17014
17225
|
verdict: "allow_flagged",
|
|
17015
17226
|
reason: "file_mutation_missing_path",
|
|
17016
17227
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17017
|
-
fingerprint: toolFingerprint(
|
|
17018
|
-
toolName,
|
|
17019
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17020
|
-
repoRoot
|
|
17021
|
-
),
|
|
17228
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17022
17229
|
assessment: {
|
|
17023
17230
|
reversibility: "recoverable_with_cost",
|
|
17024
17231
|
external: false,
|
|
@@ -17029,7 +17236,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17029
17236
|
};
|
|
17030
17237
|
}
|
|
17031
17238
|
const signals = [];
|
|
17032
|
-
const resolvedPath =
|
|
17239
|
+
const resolvedPath = path49.isAbsolute(filePath) ? filePath : path49.resolve(cwd, filePath);
|
|
17033
17240
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
17034
17241
|
if (hitsProtectedRoot) {
|
|
17035
17242
|
signals.push("control_plane_path");
|
|
@@ -17168,11 +17375,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17168
17375
|
verdict: "deny_pending_approval",
|
|
17169
17376
|
reason: "apply_patch_missing_path",
|
|
17170
17377
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17171
|
-
fingerprint: toolFingerprint(
|
|
17172
|
-
toolName,
|
|
17173
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17174
|
-
repoRoot
|
|
17175
|
-
),
|
|
17378
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17176
17379
|
assessment: {
|
|
17177
17380
|
reversibility: "irreversible",
|
|
17178
17381
|
external: false,
|
|
@@ -17186,11 +17389,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17186
17389
|
verdict: "allow_flagged",
|
|
17187
17390
|
reason: "apply_patch_missing_path",
|
|
17188
17391
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17189
|
-
fingerprint: toolFingerprint(
|
|
17190
|
-
toolName,
|
|
17191
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17192
|
-
repoRoot
|
|
17193
|
-
),
|
|
17392
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17194
17393
|
assessment: {
|
|
17195
17394
|
reversibility: "recoverable_with_cost",
|
|
17196
17395
|
external: false,
|
|
@@ -17221,11 +17420,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17221
17420
|
verdict: "allow_flagged",
|
|
17222
17421
|
reason: sawDelete ? "file_delete" : "file_mutation",
|
|
17223
17422
|
summary: targets.map((target) => target.path).join(", "),
|
|
17224
|
-
fingerprint: toolFingerprint(
|
|
17225
|
-
toolName,
|
|
17226
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17227
|
-
repoRoot
|
|
17228
|
-
),
|
|
17423
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17229
17424
|
assessment: {
|
|
17230
17425
|
reversibility: "recoverable_with_cost",
|
|
17231
17426
|
external: false,
|
|
@@ -17239,11 +17434,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
17239
17434
|
verdict: "allow",
|
|
17240
17435
|
reason: "unclassified_tool",
|
|
17241
17436
|
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
17242
|
-
fingerprint: toolFingerprint(
|
|
17243
|
-
toolName,
|
|
17244
|
-
scrubPayload(payload.tool_input ?? {}, options),
|
|
17245
|
-
repoRoot
|
|
17246
|
-
),
|
|
17437
|
+
fingerprint: toolFingerprint(toolName, fingerprintPayload(payload, options), repoRoot),
|
|
17247
17438
|
assessment: {
|
|
17248
17439
|
reversibility: "reversible",
|
|
17249
17440
|
external: false,
|
|
@@ -17631,7 +17822,7 @@ function hashDecisionConfig(config) {
|
|
|
17631
17822
|
init_fingerprint2();
|
|
17632
17823
|
|
|
17633
17824
|
// src/version.ts
|
|
17634
|
-
var PACKAGE_VERSION = "0.9.
|
|
17825
|
+
var PACKAGE_VERSION = "0.9.4";
|
|
17635
17826
|
|
|
17636
17827
|
// src/runtime-provenance.ts
|
|
17637
17828
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -17706,7 +17897,7 @@ init_path_utils();
|
|
|
17706
17897
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17707
17898
|
import { existsSync as existsSync15 } from "node:fs";
|
|
17708
17899
|
import { mkdir as mkdir11, readdir as readdir3, readFile as readFile12, rename as rename3, rm as rm6 } from "node:fs/promises";
|
|
17709
|
-
import
|
|
17900
|
+
import path54 from "node:path";
|
|
17710
17901
|
|
|
17711
17902
|
// src/core/recovery/artifact-store.ts
|
|
17712
17903
|
init_fingerprint2();
|
|
@@ -17714,7 +17905,7 @@ init_path_utils();
|
|
|
17714
17905
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
17715
17906
|
import { existsSync as existsSync13 } from "node:fs";
|
|
17716
17907
|
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";
|
|
17717
|
-
import
|
|
17908
|
+
import path51 from "node:path";
|
|
17718
17909
|
|
|
17719
17910
|
// src/core/recovery/snapshot-node.ts
|
|
17720
17911
|
init_fingerprint2();
|
|
@@ -17734,25 +17925,25 @@ import {
|
|
|
17734
17925
|
symlink as symlink3,
|
|
17735
17926
|
writeFile as writeFile6
|
|
17736
17927
|
} from "node:fs/promises";
|
|
17737
|
-
import
|
|
17928
|
+
import path50 from "node:path";
|
|
17738
17929
|
var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
|
|
17739
17930
|
function validRecoveryRelativePath(relativePath) {
|
|
17740
|
-
if (!relativePath || relativePath.includes("\0") ||
|
|
17741
|
-
const normalized =
|
|
17742
|
-
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${
|
|
17931
|
+
if (!relativePath || relativePath.includes("\0") || path50.isAbsolute(relativePath)) return false;
|
|
17932
|
+
const normalized = path50.normalize(relativePath);
|
|
17933
|
+
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path50.sep}`);
|
|
17743
17934
|
}
|
|
17744
17935
|
async function assertRecoverySafeTarget(resourceRoot, relativePath) {
|
|
17745
17936
|
if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
|
|
17746
17937
|
const root = canonicalPath(resourceRoot);
|
|
17747
|
-
const target =
|
|
17748
|
-
const relative =
|
|
17749
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
17938
|
+
const target = path50.resolve(root, relativePath);
|
|
17939
|
+
const relative = path50.relative(root, target);
|
|
17940
|
+
if (relative === ".." || relative.startsWith(`..${path50.sep}`) || path50.isAbsolute(relative)) {
|
|
17750
17941
|
throw new Error("recovery_path_escape");
|
|
17751
17942
|
}
|
|
17752
17943
|
let current = root;
|
|
17753
|
-
const parentParts =
|
|
17944
|
+
const parentParts = path50.relative(root, path50.dirname(target)).split(path50.sep).filter(Boolean);
|
|
17754
17945
|
for (const part of parentParts) {
|
|
17755
|
-
current =
|
|
17946
|
+
current = path50.join(current, part);
|
|
17756
17947
|
if (!existsSync12(current)) break;
|
|
17757
17948
|
const info = await lstat6(current);
|
|
17758
17949
|
if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
|
|
@@ -17808,7 +17999,7 @@ async function captureRecoverySnapshot(filePath, options) {
|
|
|
17808
17999
|
let blob;
|
|
17809
18000
|
if (options?.blobDir) {
|
|
17810
18001
|
await mkdir9(options.blobDir, { recursive: true, mode: 448 });
|
|
17811
|
-
const blobPath =
|
|
18002
|
+
const blobPath = path50.join(options.blobDir, hash);
|
|
17812
18003
|
if (!existsSync12(blobPath)) {
|
|
17813
18004
|
await writeFile6(blobPath, content, { mode: 384 });
|
|
17814
18005
|
await fsyncPath(blobPath);
|
|
@@ -17863,7 +18054,7 @@ async function validateRecoverySnapshot(params) {
|
|
|
17863
18054
|
if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
|
|
17864
18055
|
let content;
|
|
17865
18056
|
try {
|
|
17866
|
-
content = await readFile8(
|
|
18057
|
+
content = await readFile8(path50.join(params.artifactDir, record.blob));
|
|
17867
18058
|
} catch {
|
|
17868
18059
|
throw new Error(params.corruptReason);
|
|
17869
18060
|
}
|
|
@@ -17891,13 +18082,13 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
|
|
|
17891
18082
|
]);
|
|
17892
18083
|
var STAGING_STALE_MS = 5 * 6e4;
|
|
17893
18084
|
function checkpointsRoot(stateDir) {
|
|
17894
|
-
return
|
|
18085
|
+
return path51.join(stateDir, "recovery", "checkpoints");
|
|
17895
18086
|
}
|
|
17896
18087
|
function checkpointDir(stateDir, checkpointId) {
|
|
17897
18088
|
if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
|
|
17898
18089
|
throw new Error("invalid_recovery_checkpoint_id");
|
|
17899
18090
|
}
|
|
17900
|
-
return
|
|
18091
|
+
return path51.join(checkpointsRoot(stateDir), checkpointId);
|
|
17901
18092
|
}
|
|
17902
18093
|
async function fsyncPath2(filePath) {
|
|
17903
18094
|
const handle = await open5(filePath, "r");
|
|
@@ -17908,13 +18099,13 @@ async function fsyncPath2(filePath) {
|
|
|
17908
18099
|
}
|
|
17909
18100
|
}
|
|
17910
18101
|
async function atomicWriteJson(filePath, value) {
|
|
17911
|
-
await mkdir10(
|
|
18102
|
+
await mkdir10(path51.dirname(filePath), { recursive: true, mode: 448 });
|
|
17912
18103
|
const temporary = `${filePath}.tmp-${randomUUID4()}`;
|
|
17913
18104
|
await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
|
|
17914
18105
|
`, { mode: 384 });
|
|
17915
18106
|
await fsyncPath2(temporary);
|
|
17916
18107
|
await rename2(temporary, filePath);
|
|
17917
|
-
await fsyncPath2(
|
|
18108
|
+
await fsyncPath2(path51.dirname(filePath));
|
|
17918
18109
|
}
|
|
17919
18110
|
async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
17920
18111
|
const value = {
|
|
@@ -17924,13 +18115,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
|
17924
18115
|
manifestHash,
|
|
17925
18116
|
...detail ? { detail } : {}
|
|
17926
18117
|
};
|
|
17927
|
-
await atomicWriteJson(
|
|
18118
|
+
await atomicWriteJson(path51.join(artifactDir, "state.json"), value);
|
|
17928
18119
|
}
|
|
17929
18120
|
async function directorySize(root) {
|
|
17930
18121
|
if (!existsSync13(root)) return 0;
|
|
17931
18122
|
let total = 0;
|
|
17932
18123
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17933
|
-
const entryPath =
|
|
18124
|
+
const entryPath = path51.join(root, entry.name);
|
|
17934
18125
|
if (entry.isDirectory()) total += await directorySize(entryPath);
|
|
17935
18126
|
else total += (await lstat7(entryPath)).size;
|
|
17936
18127
|
}
|
|
@@ -17975,9 +18166,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17975
18166
|
let rawManifest;
|
|
17976
18167
|
let state;
|
|
17977
18168
|
try {
|
|
17978
|
-
rawManifest = JSON.parse(await readFile9(
|
|
18169
|
+
rawManifest = JSON.parse(await readFile9(path51.join(artifactDir, "manifest.json"), "utf8"));
|
|
17979
18170
|
state = JSON.parse(
|
|
17980
|
-
await readFile9(
|
|
18171
|
+
await readFile9(path51.join(artifactDir, "state.json"), "utf8")
|
|
17981
18172
|
);
|
|
17982
18173
|
} catch {
|
|
17983
18174
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
@@ -17993,10 +18184,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17993
18184
|
}
|
|
17994
18185
|
const entryPaths = /* @__PURE__ */ new Set();
|
|
17995
18186
|
for (const entry of manifest.entries) {
|
|
17996
|
-
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(
|
|
18187
|
+
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))) {
|
|
17997
18188
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17998
18189
|
}
|
|
17999
|
-
entryPaths.add(
|
|
18190
|
+
entryPaths.add(path51.normalize(entry.path));
|
|
18000
18191
|
for (const [side, snapshot] of [
|
|
18001
18192
|
["before", entry.before],
|
|
18002
18193
|
["after", entry.after]
|
|
@@ -18010,7 +18201,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18010
18201
|
});
|
|
18011
18202
|
}
|
|
18012
18203
|
}
|
|
18013
|
-
const receiptPath =
|
|
18204
|
+
const receiptPath = path51.join(artifactDir, "receipt.json");
|
|
18014
18205
|
let receipt;
|
|
18015
18206
|
if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
|
|
18016
18207
|
receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
@@ -18020,7 +18211,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
18020
18211
|
async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
18021
18212
|
let rawReceipt;
|
|
18022
18213
|
try {
|
|
18023
|
-
rawReceipt = JSON.parse(await readFile9(
|
|
18214
|
+
rawReceipt = JSON.parse(await readFile9(path51.join(artifactDir, "receipt.json"), "utf8"));
|
|
18024
18215
|
} catch {
|
|
18025
18216
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
18026
18217
|
}
|
|
@@ -18043,7 +18234,7 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
|
|
|
18043
18234
|
return receipt;
|
|
18044
18235
|
}
|
|
18045
18236
|
async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
18046
|
-
const receiptPath =
|
|
18237
|
+
const receiptPath = path51.join(artifactDir, "receipt.json");
|
|
18047
18238
|
if (existsSync13(receiptPath)) {
|
|
18048
18239
|
return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
18049
18240
|
}
|
|
@@ -18068,7 +18259,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
18068
18259
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
18069
18260
|
try {
|
|
18070
18261
|
const manifest = JSON.parse(
|
|
18071
|
-
await readFile9(
|
|
18262
|
+
await readFile9(path51.join(artifactDir, "manifest.json"), "utf8")
|
|
18072
18263
|
);
|
|
18073
18264
|
if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
|
|
18074
18265
|
return canonicalPath(manifest.repoRoot);
|
|
@@ -18076,7 +18267,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
18076
18267
|
} catch {
|
|
18077
18268
|
}
|
|
18078
18269
|
try {
|
|
18079
|
-
const owner = JSON.parse(await readFile9(
|
|
18270
|
+
const owner = JSON.parse(await readFile9(path51.join(artifactDir, "owner.json"), "utf8"));
|
|
18080
18271
|
return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
|
|
18081
18272
|
} catch {
|
|
18082
18273
|
return null;
|
|
@@ -18096,10 +18287,10 @@ async function cleanupOrphanedStaging(stateDir) {
|
|
|
18096
18287
|
const now = Date.now();
|
|
18097
18288
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
18098
18289
|
if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
|
|
18099
|
-
const stagingPath =
|
|
18290
|
+
const stagingPath = path51.join(root, entry.name);
|
|
18100
18291
|
let stale = false;
|
|
18101
18292
|
try {
|
|
18102
|
-
const owner = JSON.parse(await readFile9(
|
|
18293
|
+
const owner = JSON.parse(await readFile9(path51.join(stagingPath, "owner.json"), "utf8"));
|
|
18103
18294
|
const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
|
|
18104
18295
|
const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
|
|
18105
18296
|
let alive = false;
|
|
@@ -18141,7 +18332,7 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
|
|
|
18141
18332
|
init_fingerprint2();
|
|
18142
18333
|
import { existsSync as existsSync14 } from "node:fs";
|
|
18143
18334
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
18144
|
-
import
|
|
18335
|
+
import path52 from "node:path";
|
|
18145
18336
|
async function matchRecoverySide(resourceRoot, entries, side) {
|
|
18146
18337
|
for (const entry of entries) {
|
|
18147
18338
|
const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
|
|
@@ -18156,7 +18347,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
18156
18347
|
} catch {
|
|
18157
18348
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
18158
18349
|
if (existsSync14(artifactDir)) {
|
|
18159
|
-
const manifestPath =
|
|
18350
|
+
const manifestPath = path52.join(artifactDir, "manifest.json");
|
|
18160
18351
|
const hash = existsSync14(manifestPath) ? hashValue(await readFile10(manifestPath, "utf8")) : "unavailable";
|
|
18161
18352
|
await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
|
|
18162
18353
|
}
|
|
@@ -18193,7 +18384,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
18193
18384
|
// src/core/recovery/resource-identity.ts
|
|
18194
18385
|
init_fingerprint2();
|
|
18195
18386
|
import { lstat as lstat8, readFile as readFile11, realpath as realpath3 } from "node:fs/promises";
|
|
18196
|
-
import
|
|
18387
|
+
import path53 from "node:path";
|
|
18197
18388
|
async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
18198
18389
|
const resolvedRoot = await realpath3(resourceRoot);
|
|
18199
18390
|
if (resourceKind === "directory") {
|
|
@@ -18201,13 +18392,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
|
18201
18392
|
if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
|
|
18202
18393
|
return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
|
|
18203
18394
|
}
|
|
18204
|
-
const dotGit =
|
|
18395
|
+
const dotGit = path53.join(resolvedRoot, ".git");
|
|
18205
18396
|
const gitInfo = await lstat8(dotGit);
|
|
18206
18397
|
let gitMetadataPath = dotGit;
|
|
18207
18398
|
if (gitInfo.isFile()) {
|
|
18208
18399
|
const marker = (await readFile11(dotGit, "utf8")).trim();
|
|
18209
18400
|
if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
|
|
18210
|
-
gitMetadataPath =
|
|
18401
|
+
gitMetadataPath = path53.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
|
|
18211
18402
|
} else if (!gitInfo.isDirectory()) {
|
|
18212
18403
|
throw new Error("recovery_repo_identity_unavailable");
|
|
18213
18404
|
}
|
|
@@ -18280,16 +18471,16 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18280
18471
|
throw new Error(RECOVERY_CHECKPOINT_QUOTA);
|
|
18281
18472
|
}
|
|
18282
18473
|
const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
|
|
18283
|
-
const temporary =
|
|
18474
|
+
const temporary = path54.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
|
|
18284
18475
|
const finalDir = checkpointDir(params.stateDir, checkpointId);
|
|
18285
18476
|
await mkdir11(temporary, { recursive: true, mode: 448 });
|
|
18286
|
-
await atomicWriteJson(
|
|
18477
|
+
await atomicWriteJson(path54.join(temporary, "owner.json"), {
|
|
18287
18478
|
version: 1,
|
|
18288
18479
|
pid: process.pid,
|
|
18289
18480
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18290
18481
|
repoRoot: canonicalPath(params.repoRoot)
|
|
18291
18482
|
});
|
|
18292
|
-
await mkdir11(
|
|
18483
|
+
await mkdir11(path54.join(temporary, "blobs"), { recursive: true, mode: 448 });
|
|
18293
18484
|
try {
|
|
18294
18485
|
const entries = [];
|
|
18295
18486
|
const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
|
|
@@ -18298,8 +18489,8 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18298
18489
|
)) {
|
|
18299
18490
|
const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
|
|
18300
18491
|
if (protectedRoots.some((root) => {
|
|
18301
|
-
const relative =
|
|
18302
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18492
|
+
const relative = path54.relative(root, target);
|
|
18493
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path54.sep}`) && !path54.isAbsolute(relative);
|
|
18303
18494
|
})) {
|
|
18304
18495
|
throw new Error("recovery_protected_path");
|
|
18305
18496
|
}
|
|
@@ -18311,7 +18502,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18311
18502
|
entries.push({
|
|
18312
18503
|
path: change.relativePath,
|
|
18313
18504
|
before: await captureRecoverySnapshot(baseline, {
|
|
18314
|
-
blobDir:
|
|
18505
|
+
blobDir: path54.join(temporary, "blobs")
|
|
18315
18506
|
}),
|
|
18316
18507
|
after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
|
|
18317
18508
|
});
|
|
@@ -18348,7 +18539,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
18348
18539
|
entries
|
|
18349
18540
|
};
|
|
18350
18541
|
const manifestHash = hashValue(canonicalStringify(manifest));
|
|
18351
|
-
await atomicWriteJson(
|
|
18542
|
+
await atomicWriteJson(path54.join(temporary, "manifest.json"), manifest);
|
|
18352
18543
|
await writeRecoveryState(temporary, "prepared", manifestHash);
|
|
18353
18544
|
await fsyncPath2(temporary);
|
|
18354
18545
|
const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
|
|
@@ -18391,7 +18582,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
18391
18582
|
} catch {
|
|
18392
18583
|
try {
|
|
18393
18584
|
const raw = JSON.parse(
|
|
18394
|
-
await readFile12(
|
|
18585
|
+
await readFile12(path54.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
18395
18586
|
);
|
|
18396
18587
|
rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
|
|
18397
18588
|
} catch {
|
|
@@ -18425,7 +18616,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
18425
18616
|
} catch {
|
|
18426
18617
|
try {
|
|
18427
18618
|
const manifest = JSON.parse(
|
|
18428
|
-
await readFile12(
|
|
18619
|
+
await readFile12(path54.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
18429
18620
|
);
|
|
18430
18621
|
if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
|
|
18431
18622
|
if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
|
|
@@ -18455,7 +18646,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
18455
18646
|
let total = 0;
|
|
18456
18647
|
for (const entry of await readdir3(root, { withFileTypes: true })) {
|
|
18457
18648
|
if (!entry.isDirectory()) continue;
|
|
18458
|
-
const entryPath =
|
|
18649
|
+
const entryPath = path54.join(root, entry.name);
|
|
18459
18650
|
if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
18460
18651
|
if (await artifactRepoRoot(stateDir, entry.name) === expected) {
|
|
18461
18652
|
total += await directorySize(entryPath);
|
|
@@ -18464,7 +18655,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
18464
18655
|
}
|
|
18465
18656
|
if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
18466
18657
|
try {
|
|
18467
|
-
const owner = JSON.parse(await readFile12(
|
|
18658
|
+
const owner = JSON.parse(await readFile12(path54.join(entryPath, "owner.json"), "utf8"));
|
|
18468
18659
|
if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
|
|
18469
18660
|
total += await directorySize(entryPath);
|
|
18470
18661
|
}
|
|
@@ -18508,14 +18699,14 @@ init_scrub();
|
|
|
18508
18699
|
// src/core/transactional/file-checkpoint-backend.ts
|
|
18509
18700
|
import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
|
|
18510
18701
|
import os5 from "node:os";
|
|
18511
|
-
import
|
|
18702
|
+
import path58 from "node:path";
|
|
18512
18703
|
|
|
18513
18704
|
// src/core/transactional/file-checkpoint-git.ts
|
|
18514
18705
|
init_path_utils();
|
|
18515
18706
|
import { spawn as spawn8 } from "node:child_process";
|
|
18516
18707
|
import { createHash as createHash13 } from "node:crypto";
|
|
18517
18708
|
import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile13 } from "node:fs/promises";
|
|
18518
|
-
import
|
|
18709
|
+
import path55 from "node:path";
|
|
18519
18710
|
var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
|
|
18520
18711
|
var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
|
|
18521
18712
|
var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
|
|
@@ -18549,7 +18740,7 @@ function rethrowStableFileCheckpointError(error) {
|
|
|
18549
18740
|
}
|
|
18550
18741
|
async function rootGitMetadataPresent(repoRoot) {
|
|
18551
18742
|
try {
|
|
18552
|
-
await lstat9(
|
|
18743
|
+
await lstat9(path55.join(repoRoot, ".git"));
|
|
18553
18744
|
return true;
|
|
18554
18745
|
} catch {
|
|
18555
18746
|
return false;
|
|
@@ -18598,10 +18789,10 @@ function execGit2(repoRoot, args) {
|
|
|
18598
18789
|
}
|
|
18599
18790
|
async function resolveGitPath(repoRoot, gitPath) {
|
|
18600
18791
|
const trimmed = gitPath.trim();
|
|
18601
|
-
if (
|
|
18792
|
+
if (path55.isAbsolute(trimmed)) {
|
|
18602
18793
|
return trimmed;
|
|
18603
18794
|
}
|
|
18604
|
-
return
|
|
18795
|
+
return path55.join(repoRoot, trimmed);
|
|
18605
18796
|
}
|
|
18606
18797
|
async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
|
|
18607
18798
|
await execGit2(sourceRoot, [
|
|
@@ -18643,7 +18834,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18643
18834
|
destinationRoot,
|
|
18644
18835
|
await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
|
|
18645
18836
|
);
|
|
18646
|
-
const destinationShared =
|
|
18837
|
+
const destinationShared = path55.join(destinationGitDir, path55.basename(sourceShared));
|
|
18647
18838
|
try {
|
|
18648
18839
|
await copyFile3(sourceShared, destinationShared);
|
|
18649
18840
|
} catch (error) {
|
|
@@ -18652,7 +18843,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18652
18843
|
}
|
|
18653
18844
|
async function readGitFile(gitDir, relativePath) {
|
|
18654
18845
|
try {
|
|
18655
|
-
return await readFile13(
|
|
18846
|
+
return await readFile13(path55.join(gitDir, relativePath));
|
|
18656
18847
|
} catch {
|
|
18657
18848
|
return null;
|
|
18658
18849
|
}
|
|
@@ -18676,8 +18867,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18676
18867
|
repoRoot,
|
|
18677
18868
|
await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
|
|
18678
18869
|
);
|
|
18679
|
-
const relative =
|
|
18680
|
-
const content = typeof relative === "string" && !relative.startsWith("..") && !
|
|
18870
|
+
const relative = path55.resolve(resolved).startsWith(path55.resolve(gitDir)) ? path55.relative(gitDir, resolved) : resolved;
|
|
18871
|
+
const content = typeof relative === "string" && !relative.startsWith("..") && !path55.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18681
18872
|
if (content !== null) {
|
|
18682
18873
|
hashGitFileContent(hash, gitPath, content);
|
|
18683
18874
|
}
|
|
@@ -18687,13 +18878,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18687
18878
|
async function hashGitTree(gitDir, relativeDir, hash) {
|
|
18688
18879
|
let names;
|
|
18689
18880
|
try {
|
|
18690
|
-
names = await readdir4(
|
|
18881
|
+
names = await readdir4(path55.join(gitDir, relativeDir));
|
|
18691
18882
|
} catch {
|
|
18692
18883
|
return;
|
|
18693
18884
|
}
|
|
18694
18885
|
for (const name of names.sort()) {
|
|
18695
|
-
const relativePath = relativeDir ?
|
|
18696
|
-
const absolutePath =
|
|
18886
|
+
const relativePath = relativeDir ? path55.join(relativeDir, name) : name;
|
|
18887
|
+
const absolutePath = path55.join(gitDir, relativePath);
|
|
18697
18888
|
let childNames = null;
|
|
18698
18889
|
try {
|
|
18699
18890
|
childNames = await readdir4(absolutePath);
|
|
@@ -18715,7 +18906,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
|
|
|
18715
18906
|
}
|
|
18716
18907
|
async function computeGitMetadataFingerprint(repoRoot) {
|
|
18717
18908
|
const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18718
|
-
const gitDir =
|
|
18909
|
+
const gitDir = path55.isAbsolute(gitDirRel) ? gitDirRel : path55.join(repoRoot, gitDirRel);
|
|
18719
18910
|
const hash = createHash13("sha256");
|
|
18720
18911
|
for (const file of [
|
|
18721
18912
|
"HEAD",
|
|
@@ -18738,8 +18929,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18738
18929
|
const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
|
|
18739
18930
|
if (sharedIndex) {
|
|
18740
18931
|
const resolved = await resolveGitPath(repoRoot, sharedIndex);
|
|
18741
|
-
const relative =
|
|
18742
|
-
const content = relative && !relative.startsWith("..") && !
|
|
18932
|
+
const relative = path55.relative(gitDir, resolved);
|
|
18933
|
+
const content = relative && !relative.startsWith("..") && !path55.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18743
18934
|
if (content !== null) {
|
|
18744
18935
|
hashGitFileContent(hash, "shared-index", content);
|
|
18745
18936
|
}
|
|
@@ -18750,7 +18941,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18750
18941
|
await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
|
|
18751
18942
|
}
|
|
18752
18943
|
try {
|
|
18753
|
-
const rootGitPath =
|
|
18944
|
+
const rootGitPath = path55.join(repoRoot, ".git");
|
|
18754
18945
|
const rootGitInfo = await lstat9(rootGitPath);
|
|
18755
18946
|
if (rootGitInfo.isFile()) {
|
|
18756
18947
|
const content = await readAbsoluteGitFile(rootGitPath);
|
|
@@ -18766,14 +18957,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18766
18957
|
function resolveExecutionCwdRelative(resourceRoot, cwd) {
|
|
18767
18958
|
const resolvedCwd = canonicalPath(cwd);
|
|
18768
18959
|
const resourceCanonical = canonicalPath(resourceRoot);
|
|
18769
|
-
const relative =
|
|
18960
|
+
const relative = path55.relative(resourceCanonical, resolvedCwd);
|
|
18770
18961
|
if (relative === "" || relative === ".") {
|
|
18771
18962
|
return "";
|
|
18772
18963
|
}
|
|
18773
|
-
if (relative.startsWith("..") ||
|
|
18964
|
+
if (relative.startsWith("..") || path55.isAbsolute(relative)) {
|
|
18774
18965
|
throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
|
|
18775
18966
|
}
|
|
18776
|
-
return relative.split(
|
|
18967
|
+
return relative.split(path55.sep).join("/");
|
|
18777
18968
|
}
|
|
18778
18969
|
|
|
18779
18970
|
// src/core/transactional/file-checkpoint-isolation.ts
|
|
@@ -18795,7 +18986,7 @@ function fileCheckpointIsolationReason(context) {
|
|
|
18795
18986
|
|
|
18796
18987
|
// src/core/transactional/file-checkpoint-staging.ts
|
|
18797
18988
|
import { readdir as readdir5, readFile as readFile14, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
|
|
18798
|
-
import
|
|
18989
|
+
import path56 from "node:path";
|
|
18799
18990
|
function isOwnerProcessAlive(pid) {
|
|
18800
18991
|
try {
|
|
18801
18992
|
process.kill(pid, 0);
|
|
@@ -18805,12 +18996,12 @@ function isOwnerProcessAlive(pid) {
|
|
|
18805
18996
|
}
|
|
18806
18997
|
}
|
|
18807
18998
|
async function writeOwnerMarker(stagingRoot, marker) {
|
|
18808
|
-
await writeFile8(
|
|
18999
|
+
await writeFile8(path56.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
|
|
18809
19000
|
`, "utf8");
|
|
18810
19001
|
}
|
|
18811
19002
|
async function readOwnerMarker(stagingRoot) {
|
|
18812
19003
|
try {
|
|
18813
|
-
const raw = await readFile14(
|
|
19004
|
+
const raw = await readFile14(path56.join(stagingRoot, "owner.json"), "utf8");
|
|
18814
19005
|
return JSON.parse(raw.trim());
|
|
18815
19006
|
} catch {
|
|
18816
19007
|
return null;
|
|
@@ -18828,7 +19019,7 @@ async function collectDeadOwnerStaging(parentDir) {
|
|
|
18828
19019
|
if (!name.startsWith("belay-file-checkpoint-")) {
|
|
18829
19020
|
continue;
|
|
18830
19021
|
}
|
|
18831
|
-
const stagingRoot =
|
|
19022
|
+
const stagingRoot = path56.join(parentDir, name);
|
|
18832
19023
|
const marker = await readOwnerMarker(stagingRoot);
|
|
18833
19024
|
if (!marker) {
|
|
18834
19025
|
dead.push(stagingRoot);
|
|
@@ -18860,7 +19051,7 @@ import {
|
|
|
18860
19051
|
writeFile as writeFile9
|
|
18861
19052
|
} from "node:fs/promises";
|
|
18862
19053
|
import os4 from "node:os";
|
|
18863
|
-
import
|
|
19054
|
+
import path57 from "node:path";
|
|
18864
19055
|
var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
|
|
18865
19056
|
async function chmodSafe2(target, mode) {
|
|
18866
19057
|
try {
|
|
@@ -18870,7 +19061,7 @@ async function chmodSafe2(target, mode) {
|
|
|
18870
19061
|
}
|
|
18871
19062
|
}
|
|
18872
19063
|
async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
|
|
18873
|
-
await mkdir12(
|
|
19064
|
+
await mkdir12(path57.dirname(destinationPath), { recursive: true });
|
|
18874
19065
|
if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
|
|
18875
19066
|
try {
|
|
18876
19067
|
await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
|
|
@@ -18896,7 +19087,7 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
|
|
|
18896
19087
|
return strategy;
|
|
18897
19088
|
}
|
|
18898
19089
|
if (info.isSymbolicLink()) {
|
|
18899
|
-
await mkdir12(
|
|
19090
|
+
await mkdir12(path57.dirname(destinationPath), { recursive: true });
|
|
18900
19091
|
await symlink4(await readlink5(sourcePath), destinationPath);
|
|
18901
19092
|
return strategy;
|
|
18902
19093
|
}
|
|
@@ -18952,9 +19143,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
|
|
|
18952
19143
|
async function probeFileCloneStrategy() {
|
|
18953
19144
|
let tempDir = null;
|
|
18954
19145
|
try {
|
|
18955
|
-
tempDir = await mkdtemp4(
|
|
18956
|
-
const source =
|
|
18957
|
-
const destination =
|
|
19146
|
+
tempDir = await mkdtemp4(path57.join(os4.tmpdir(), "belay-clone-probe-"));
|
|
19147
|
+
const source = path57.join(tempDir, "source.txt");
|
|
19148
|
+
const destination = path57.join(tempDir, "dest.txt");
|
|
18958
19149
|
await writeFile9(source, "probe\n");
|
|
18959
19150
|
if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
|
|
18960
19151
|
try {
|
|
@@ -19107,11 +19298,11 @@ async function protectedRootState(root) {
|
|
|
19107
19298
|
return `directory:${node.hash}:${index.treeHash}`;
|
|
19108
19299
|
}
|
|
19109
19300
|
function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
|
|
19110
|
-
const relative =
|
|
19111
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
19301
|
+
const relative = path58.relative(path58.resolve(resourceRoot), path58.resolve(protectedRoot));
|
|
19302
|
+
if (relative === "" || relative.startsWith("..") || path58.isAbsolute(relative)) {
|
|
19112
19303
|
return null;
|
|
19113
19304
|
}
|
|
19114
|
-
return
|
|
19305
|
+
return path58.join(executionRoot, relative);
|
|
19115
19306
|
}
|
|
19116
19307
|
async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
|
|
19117
19308
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -19136,15 +19327,15 @@ async function directoryByteSize(root, deadlineMs) {
|
|
|
19136
19327
|
}
|
|
19137
19328
|
let total = 0;
|
|
19138
19329
|
for (const name of await readdir6(root)) {
|
|
19139
|
-
total += await directoryByteSize(
|
|
19330
|
+
total += await directoryByteSize(path58.join(root, name), deadlineMs);
|
|
19140
19331
|
}
|
|
19141
19332
|
return total;
|
|
19142
19333
|
}
|
|
19143
19334
|
async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
|
|
19144
19335
|
const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
|
|
19145
|
-
const sourceGitDir =
|
|
19146
|
-
const relativeGitDir =
|
|
19147
|
-
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ?
|
|
19336
|
+
const sourceGitDir = path58.isAbsolute(gitDirRel) ? gitDirRel : path58.join(sourceRoot, gitDirRel);
|
|
19337
|
+
const relativeGitDir = path58.relative(path58.resolve(sourceRoot), path58.resolve(sourceGitDir));
|
|
19338
|
+
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path58.join(destinationRoot, relativeGitDir) : path58.join(destinationRoot, ".git");
|
|
19148
19339
|
await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
|
|
19149
19340
|
}
|
|
19150
19341
|
async function prepareDirtyGitSnapshot(context) {
|
|
@@ -19153,7 +19344,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19153
19344
|
const quotas = context.fileCheckpoint;
|
|
19154
19345
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
19155
19346
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
19156
|
-
const stagingRoot = await mkdtemp5(
|
|
19347
|
+
const stagingRoot = await mkdtemp5(path58.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
19157
19348
|
await writeOwnerMarker(stagingRoot, {
|
|
19158
19349
|
version: 1,
|
|
19159
19350
|
pid: process.pid,
|
|
@@ -19161,8 +19352,8 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19161
19352
|
resourceRoot: context.repoRoot,
|
|
19162
19353
|
backend: "file_checkpoint"
|
|
19163
19354
|
});
|
|
19164
|
-
const baselineRoot =
|
|
19165
|
-
const executionRoot =
|
|
19355
|
+
const baselineRoot = path58.join(stagingRoot, "baseline");
|
|
19356
|
+
const executionRoot = path58.join(stagingRoot, "execution");
|
|
19166
19357
|
try {
|
|
19167
19358
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
19168
19359
|
const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
|
|
@@ -19196,7 +19387,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
19196
19387
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
19197
19388
|
}
|
|
19198
19389
|
await writeFile10(
|
|
19199
|
-
|
|
19390
|
+
path58.join(stagingRoot, "baseline-index.json"),
|
|
19200
19391
|
`${JSON.stringify(baselineIndex)}
|
|
19201
19392
|
`,
|
|
19202
19393
|
"utf8"
|
|
@@ -19246,7 +19437,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19246
19437
|
const quotas = context.fileCheckpoint;
|
|
19247
19438
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
19248
19439
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
19249
|
-
const stagingRoot = await mkdtemp5(
|
|
19440
|
+
const stagingRoot = await mkdtemp5(path58.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
19250
19441
|
await writeOwnerMarker(stagingRoot, {
|
|
19251
19442
|
version: 1,
|
|
19252
19443
|
pid: process.pid,
|
|
@@ -19254,8 +19445,8 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19254
19445
|
resourceRoot: context.repoRoot,
|
|
19255
19446
|
backend: "file_checkpoint"
|
|
19256
19447
|
});
|
|
19257
|
-
const baselineRoot =
|
|
19258
|
-
const executionRoot =
|
|
19448
|
+
const baselineRoot = path58.join(stagingRoot, "baseline");
|
|
19449
|
+
const executionRoot = path58.join(stagingRoot, "execution");
|
|
19259
19450
|
try {
|
|
19260
19451
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
19261
19452
|
const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
|
|
@@ -19284,7 +19475,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
19284
19475
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
19285
19476
|
}
|
|
19286
19477
|
await writeFile10(
|
|
19287
|
-
|
|
19478
|
+
path58.join(stagingRoot, "baseline-index.json"),
|
|
19288
19479
|
`${JSON.stringify(baselineIndex)}
|
|
19289
19480
|
`,
|
|
19290
19481
|
"utf8"
|
|
@@ -19637,10 +19828,10 @@ async function selectTransactionalBackend(context) {
|
|
|
19637
19828
|
}
|
|
19638
19829
|
|
|
19639
19830
|
// src/core/transactional/diff-evaluator.ts
|
|
19640
|
-
import
|
|
19831
|
+
import path59 from "node:path";
|
|
19641
19832
|
init_path_utils();
|
|
19642
19833
|
function categorizeChange(change, ctx) {
|
|
19643
|
-
const absolutePath = canonicalPath(
|
|
19834
|
+
const absolutePath = canonicalPath(path59.join(ctx.repoRoot, change.relativePath));
|
|
19644
19835
|
if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
|
|
19645
19836
|
return "repo_outside";
|
|
19646
19837
|
}
|
|
@@ -20234,7 +20425,7 @@ async function notifyDeny(config, event) {
|
|
|
20234
20425
|
init_path_utils();
|
|
20235
20426
|
|
|
20236
20427
|
// src/adapters/layouts/protected-paths.ts
|
|
20237
|
-
import
|
|
20428
|
+
import path60 from "node:path";
|
|
20238
20429
|
function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
20239
20430
|
const roots = [
|
|
20240
20431
|
layout.configPath(repoRoot),
|
|
@@ -20246,7 +20437,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
|
20246
20437
|
if (controlPlaneDir) {
|
|
20247
20438
|
roots.push(controlPlaneDir);
|
|
20248
20439
|
}
|
|
20249
|
-
return roots.map((entry) =>
|
|
20440
|
+
return roots.map((entry) => path60.resolve(entry));
|
|
20250
20441
|
}
|
|
20251
20442
|
|
|
20252
20443
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -20299,8 +20490,8 @@ function createDefaultGateRuntimeDeps() {
|
|
|
20299
20490
|
return loadJsonFile(configPath, {});
|
|
20300
20491
|
},
|
|
20301
20492
|
async appendAudit(ctx, event) {
|
|
20302
|
-
const auditPath =
|
|
20303
|
-
await mkdir14(
|
|
20493
|
+
const auditPath = path61.join(ctx.repoRoot, ctx.config.audit.logPath);
|
|
20494
|
+
await mkdir14(path61.dirname(auditPath), { recursive: true });
|
|
20304
20495
|
const provenance = auditProvenance(ctx.config);
|
|
20305
20496
|
const record = {
|
|
20306
20497
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -20333,7 +20524,7 @@ function createDefaultGateRuntimeDeps() {
|
|
|
20333
20524
|
};
|
|
20334
20525
|
},
|
|
20335
20526
|
async writeApprovals(filePath, state) {
|
|
20336
|
-
await mkdir14(
|
|
20527
|
+
await mkdir14(path61.dirname(filePath), { recursive: true });
|
|
20337
20528
|
await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
|
|
20338
20529
|
`, "utf8");
|
|
20339
20530
|
},
|
|
@@ -20495,7 +20686,7 @@ function deriveWorkspaceRootScopeHint(params) {
|
|
|
20495
20686
|
if (!targetPath) {
|
|
20496
20687
|
return void 0;
|
|
20497
20688
|
}
|
|
20498
|
-
const candidateRoot = canonicalPath(
|
|
20689
|
+
const candidateRoot = canonicalPath(path61.dirname(targetPath));
|
|
20499
20690
|
const validation = validateTrustedWorkspaceRootCandidate({
|
|
20500
20691
|
candidatePath: candidateRoot,
|
|
20501
20692
|
repoRoot: action.repoRoot,
|
|
@@ -21071,6 +21262,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
21071
21262
|
event: auditEvent,
|
|
21072
21263
|
sourceEvent,
|
|
21073
21264
|
kind,
|
|
21265
|
+
repoLabel: path61.basename(ctx.repoRoot),
|
|
21074
21266
|
...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
|
|
21075
21267
|
fingerprint: result.fingerprint,
|
|
21076
21268
|
summary: result.normalizedCommand ?? result.summary ?? "",
|
|
@@ -21537,18 +21729,18 @@ async function appendObservedAudit(ctx, deps, eventName, payload) {
|
|
|
21537
21729
|
|
|
21538
21730
|
// src/adapters/shared/repo-root.ts
|
|
21539
21731
|
import { existsSync as existsSync17 } from "node:fs";
|
|
21540
|
-
import
|
|
21732
|
+
import path62 from "node:path";
|
|
21541
21733
|
function belayConfigPath(current, adapterName) {
|
|
21542
21734
|
if (adapterName === "cursor") {
|
|
21543
|
-
return
|
|
21735
|
+
return path62.join(current, ".cursor", "belay.config.json");
|
|
21544
21736
|
}
|
|
21545
21737
|
if (adapterName === "claude") {
|
|
21546
|
-
return
|
|
21738
|
+
return path62.join(current, ".claude", "belay.config.json");
|
|
21547
21739
|
}
|
|
21548
|
-
return
|
|
21740
|
+
return path62.join(current, ".codex", "belay.config.json");
|
|
21549
21741
|
}
|
|
21550
21742
|
function markerMatches(current, marker, layout) {
|
|
21551
|
-
const markerPath =
|
|
21743
|
+
const markerPath = path62.join(current, marker);
|
|
21552
21744
|
if (!existsSync17(markerPath)) {
|
|
21553
21745
|
return false;
|
|
21554
21746
|
}
|
|
@@ -21558,16 +21750,16 @@ function markerMatches(current, marker, layout) {
|
|
|
21558
21750
|
return true;
|
|
21559
21751
|
}
|
|
21560
21752
|
function findRepoRoot(startPath, layout) {
|
|
21561
|
-
let current =
|
|
21753
|
+
let current = path62.resolve(startPath);
|
|
21562
21754
|
while (true) {
|
|
21563
21755
|
for (const marker of layout.repoRootMarkers) {
|
|
21564
21756
|
if (markerMatches(current, marker, layout)) {
|
|
21565
21757
|
return current;
|
|
21566
21758
|
}
|
|
21567
21759
|
}
|
|
21568
|
-
const parent =
|
|
21760
|
+
const parent = path62.dirname(current);
|
|
21569
21761
|
if (parent === current) {
|
|
21570
|
-
return
|
|
21762
|
+
return path62.resolve(startPath);
|
|
21571
21763
|
}
|
|
21572
21764
|
current = parent;
|
|
21573
21765
|
}
|