@vtxmacro/cli 2026.10.7 → 2026.10.9
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/bin/vtx-mcp.js +48 -13
- package/bin/vtx-service-bootstrap.js +48 -13
- package/bin/vtx-service-launcher.js +17 -8
- package/bin/vtx.js +3012 -692
- package/package.json +1 -1
package/bin/vtx-mcp.js
CHANGED
|
@@ -37,7 +37,7 @@ var init_define_VTX_PI_MODEL_POLICY = __esm({
|
|
|
37
37
|
var agent_cli_release_default;
|
|
38
38
|
var init_agent_cli_release = __esm({
|
|
39
39
|
"agent-cli-release.json"() {
|
|
40
|
-
agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.
|
|
40
|
+
agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.9", codex_package_name: "@openai/codex", codex_version: "0.155.0", copilot_sdk_package_name: "@github/copilot-sdk", copilot_sdk_version: "1.0.0-beta.8", copilot_cli_package_name: "@github/copilot", copilot_cli_version: "1.0.80", deepseek_harness_version: "0.1.1-rc.2", deepseek_harness_packages: ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-agent-instructions", "@deepseek-ai/dsh-agent-loop", "@deepseek-ai/dsh-agent-spine-demo", "@deepseek-ai/dsh-anonymous-user-id", "@deepseek-ai/dsh-atomic-write", "@deepseek-ai/dsh-attachment", "@deepseek-ai/dsh-brand", "@deepseek-ai/dsh-code-runtime", "@deepseek-ai/dsh-credentials", "@deepseek-ai/dsh-fs", "@deepseek-ai/dsh-goal", "@deepseek-ai/dsh-goal-round-driver", "@deepseek-ai/dsh-home-paths", "@deepseek-ai/dsh-invariants", "@deepseek-ai/dsh-jobs", "@deepseek-ai/dsh-jobs-local", "@deepseek-ai/dsh-launch-environment", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-llm-deepseek", "@deepseek-ai/dsh-llm-retry", "@deepseek-ai/dsh-output-retention", "@deepseek-ai/dsh-sandbox", "@deepseek-ai/dsh-sandbox-policy", "@deepseek-ai/dsh-scope", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-checkpoint-policy", "@deepseek-ai/dsh-session-persistence", "@deepseek-ai/dsh-session-persistence-jsonl", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-session-title", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-shell", "@deepseek-ai/dsh-shell-env", "@deepseek-ai/dsh-skill", "@deepseek-ai/dsh-skill-filesystem", "@deepseek-ai/dsh-subprocess", "@deepseek-ai/dsh-system-prompt", "@deepseek-ai/dsh-timeout", "@deepseek-ai/dsh-tool-bash", "@deepseek-ai/dsh-tool-goal", "@deepseek-ai/dsh-tool-jobs", "@deepseek-ai/dsh-tool-skill", "@deepseek-ai/dsh-tools", "@deepseek-ai/dsh-typert-protocol", "@deepseek-ai/dsh-user-approval"], deepseek_cordis_package_name: "@deepseek-ai/cordis", deepseek_cordis_version: "4.0.1", deepseek_support_packages: { "@deepseek-ai/cordis-plugin-timer": "1.1.3" }, platforms: { "linux-x64": { package_name: "@openai/codex-linux-x64", target: "x86_64-unknown-linux-musl", binary_name: "codex", sha256: "660e159a49e823ac8e5986cb238f73158ce4b957d40d9292f8de90862644b501" }, "win32-x64": { package_name: "@openai/codex-win32-x64", target: "x86_64-pc-windows-msvc", binary_name: "codex.exe", sha256: "e4c11374bd9de8ad5c3b7617fd4654bb7839901edb0863f9930666863c7a021b" } }, pi_coding_agent_package_name: "@earendil-works/pi-coding-agent", pi_ai_package_name: "@earendil-works/pi-ai", pi_version: "0.85.1", pi_support_packages: ["@earendil-works/pi-agent-core", "@earendil-works/pi-telemetry", "@earendil-works/pi-tui", "@earendil-works/chord"], grok_version: "1.0.30", grok_platforms: { "linux-x64": { package_name: "@xai-official/grok-linux-x64", binary_name: "grok", sha256: "504dd6546ab991b75d36698242875ce461489cd1f8cd84285873cb55bd5c7d54" }, "win32-x64": { package_name: "@xai-official/grok-win32-x64", binary_name: "grok.exe", sha256: "48736d1a4342a801ea26d0ecde4c516b653f791399065adaa55973f83abd8867" } } };
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
|
|
@@ -1199,7 +1199,7 @@ init_define_VTX_PI_MODEL_POLICY();
|
|
|
1199
1199
|
init_agent_cli_release();
|
|
1200
1200
|
import { spawn as spawn2 } from "node:child_process";
|
|
1201
1201
|
import { createHash, randomUUID } from "node:crypto";
|
|
1202
|
-
import { access, appendFile, chmod, lstat as lstat2,
|
|
1202
|
+
import { access, appendFile, chmod, lstat as lstat2, readFile as readFile3, readdir as readdir3, realpath as realpath2, rename as rename2, rm as rm3 } from "node:fs/promises";
|
|
1203
1203
|
import { constants as osConstants, homedir as homedir3 } from "node:os";
|
|
1204
1204
|
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve as resolve2, win32 as windowsPath2 } from "node:path";
|
|
1205
1205
|
|
|
@@ -1296,6 +1296,13 @@ var runtime_policy_generated_default = {
|
|
|
1296
1296
|
evidence_max_items: 32,
|
|
1297
1297
|
evidence_shared_read_seconds: 10
|
|
1298
1298
|
},
|
|
1299
|
+
protective_plan_set_lock: {
|
|
1300
|
+
wait_seconds: 120
|
|
1301
|
+
},
|
|
1302
|
+
execution_mutation_queue: {
|
|
1303
|
+
wait_seconds: 120,
|
|
1304
|
+
trade_submit_deadline_seconds: 360
|
|
1305
|
+
},
|
|
1299
1306
|
history_evidence: {
|
|
1300
1307
|
device_rounds_per_beat: 6,
|
|
1301
1308
|
device_retry_seconds: 60
|
|
@@ -1561,6 +1568,7 @@ var InferenceHostProcessLockBusyError = class extends Error {
|
|
|
1561
1568
|
}
|
|
1562
1569
|
};
|
|
1563
1570
|
var MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
|
|
1571
|
+
var WINDOWS_PRIVATE_ACL_MODES = ["harden", "verify", "verify-owner", "verify-private"];
|
|
1564
1572
|
var WINDOWS_PRIVATE_ACL_BROKER_SCRIPT = `$ErrorActionPreference='Stop'
|
|
1565
1573
|
$ProgressPreference='SilentlyContinue'
|
|
1566
1574
|
while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
@@ -1577,7 +1585,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
1577
1585
|
$kind=[string]$request.kind
|
|
1578
1586
|
$mode=[string]$request.mode
|
|
1579
1587
|
if($kind -ne 'directory' -and $kind -ne 'file') { throw 'invalid path kind' }
|
|
1580
|
-
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner') { throw 'invalid ACL mode' }
|
|
1588
|
+
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner' -and $mode -ne 'verify-private') { throw 'invalid ACL mode' }
|
|
1581
1589
|
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String([string]$request.path_b64))
|
|
1582
1590
|
if([string]::IsNullOrWhiteSpace($path) -or $path.Length -gt 32767 -or $path.Contains([char]0)) { throw 'invalid path' }
|
|
1583
1591
|
$failureStage='path_lookup'
|
|
@@ -1626,11 +1634,12 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
1626
1634
|
$owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
1627
1635
|
if($owner -ne $current.Value -and ($owner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
|
|
1628
1636
|
if($mode -ne 'verify-owner') {
|
|
1629
|
-
|
|
1637
|
+
$inheritedAllowed=$mode -eq 'verify-private'
|
|
1638
|
+
if(-not $inheritedAllowed -and -not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
|
|
1630
1639
|
$userFull=$false
|
|
1631
1640
|
foreach($rule in $actual.Access) {
|
|
1632
1641
|
$sid=$rule.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
|
|
1633
|
-
if($rule.IsInherited -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
1642
|
+
if(($rule.IsInherited -and -not $inheritedAllowed) -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
1634
1643
|
throw 'private ACL contains an unauthorized access rule'
|
|
1635
1644
|
}
|
|
1636
1645
|
if($sid -eq $current.Value -and (($rule.FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -eq [Security.AccessControl.FileSystemRights]::FullControl)) { $userFull=$true }
|
|
@@ -1766,9 +1775,9 @@ var WindowsPrivateAclBroker = class {
|
|
|
1766
1775
|
error.code = "ENOENT";
|
|
1767
1776
|
pending.reject(error);
|
|
1768
1777
|
} else {
|
|
1769
|
-
pending.reject(new Error(
|
|
1778
|
+
pending.reject(Object.assign(new Error(
|
|
1770
1779
|
`Windows private ACL ${pending.mode} failed (${response.error_code}).`
|
|
1771
|
-
));
|
|
1780
|
+
), { aclStage: response.error_code }));
|
|
1772
1781
|
}
|
|
1773
1782
|
this.scheduleIdleShutdown();
|
|
1774
1783
|
}
|
|
@@ -1873,7 +1882,7 @@ var secureWindowsPrivatePath = async (path, kind, mode, platform = process.platf
|
|
|
1873
1882
|
};
|
|
1874
1883
|
var invalidateWindowsAclCache = (path) => {
|
|
1875
1884
|
for (const kind of ["file", "directory"]) {
|
|
1876
|
-
for (const mode of
|
|
1885
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
1877
1886
|
windowsAclCache.delete(aclCacheKey(path, kind, mode));
|
|
1878
1887
|
}
|
|
1879
1888
|
}
|
|
@@ -1892,7 +1901,7 @@ var rebindHardenedWindowsAclAfterRename = async (source, destination, kind, expe
|
|
|
1892
1901
|
}
|
|
1893
1902
|
invalidateWindowsAclCache(source);
|
|
1894
1903
|
invalidateWindowsAclCache(destination);
|
|
1895
|
-
for (const mode of
|
|
1904
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
1896
1905
|
windowsAclCache.set(aclCacheKey(destination, kind, mode), published);
|
|
1897
1906
|
}
|
|
1898
1907
|
};
|
|
@@ -1903,10 +1912,11 @@ var rebindHardenedWindowsDirectoryAfterOwnedMutation = async (path, expected) =>
|
|
|
1903
1912
|
throw new Error("Windows private directory identity changed during atomic publication.");
|
|
1904
1913
|
}
|
|
1905
1914
|
invalidateWindowsAclCache(path);
|
|
1906
|
-
for (const mode of
|
|
1915
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
1907
1916
|
windowsAclCache.set(aclCacheKey(path, "directory", mode), current);
|
|
1908
1917
|
}
|
|
1909
1918
|
};
|
|
1919
|
+
var isWindowsPrivateAclVerificationFailure = (error) => error?.aclStage === "acl_verification";
|
|
1910
1920
|
var isDefaultWindowsPrivatePath = (path, root = resolve(homedir2(), ".vtx", "inference-host")) => {
|
|
1911
1921
|
const child = relative(root, resolve(path));
|
|
1912
1922
|
return child === "" || !child.startsWith("..") && !child.includes(":");
|
|
@@ -2740,7 +2750,32 @@ var cleanupInterruptedReleaseStaging = async (releasesPath) => {
|
|
|
2740
2750
|
};
|
|
2741
2751
|
var ensureUpdaterPrivateDirectory = async (path, root, dependencies = {}) => {
|
|
2742
2752
|
const platform = dependencies.platform ?? process.platform;
|
|
2743
|
-
if (platform
|
|
2753
|
+
if (platform === "win32") {
|
|
2754
|
+
const existing = await lstat2(path).catch((error) => {
|
|
2755
|
+
if (error.code === "ENOENT") return null;
|
|
2756
|
+
throw error;
|
|
2757
|
+
});
|
|
2758
|
+
if (!existing) {
|
|
2759
|
+
await ensureInferencePrivateDirectory(path, { ...dependencies, defaultRoot: root });
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
if (existing.isSymbolicLink() || !existing.isDirectory()) {
|
|
2763
|
+
throw new Error("Inference host state directory is unsafe.");
|
|
2764
|
+
}
|
|
2765
|
+
const runner = dependencies.runner ?? runWindowsPrivateAcl;
|
|
2766
|
+
try {
|
|
2767
|
+
await secureWindowsPrivatePath(path, "directory", "verify-private", platform, runner);
|
|
2768
|
+
} catch (error) {
|
|
2769
|
+
if (!isWindowsPrivateAclVerificationFailure(error)) throw error;
|
|
2770
|
+
if ((await readdir3(path)).length > 0) {
|
|
2771
|
+
const recovery = /\.service-releases$/u.test(path) ? "run 'vtx inference-host service uninstall' then 'install'" : "delete this directory; it is recreated private";
|
|
2772
|
+
throw new Error(`updater_dir_not_private: ${recovery} (${path})`, { cause: error });
|
|
2773
|
+
}
|
|
2774
|
+
await secureWindowsPrivatePath(path, "directory", "harden", platform, runner);
|
|
2775
|
+
}
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2778
|
+
if (resolve2(path) === resolve2(root) || isPathWithin(root, path)) {
|
|
2744
2779
|
const existing = await lstat2(path).catch(() => null);
|
|
2745
2780
|
if (existing && existing.isDirectory() && !existing.isSymbolicLink() && (existing.mode & 63) !== 0 && (typeof process.getuid !== "function" || existing.uid === process.getuid())) {
|
|
2746
2781
|
await chmod(path, 448);
|
|
@@ -2797,8 +2832,8 @@ var stageCliReleaseWithin = async (input) => {
|
|
|
2797
2832
|
} catch (error) {
|
|
2798
2833
|
if (error.code !== "ENOENT") throw error;
|
|
2799
2834
|
}
|
|
2800
|
-
await
|
|
2801
|
-
await
|
|
2835
|
+
await ensureUpdaterPrivateDirectory(stagingPath, input.privateRoot, { platform });
|
|
2836
|
+
await ensureUpdaterPrivateDirectory(downloadPath, input.privateRoot, { platform });
|
|
2802
2837
|
try {
|
|
2803
2838
|
const packed = await runCliReleaseNpmCommand(executable, [
|
|
2804
2839
|
"pack",
|
|
@@ -14,7 +14,7 @@ import { dirname as dirname4, relative as relative4, resolve as resolve4 } from
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
|
|
16
16
|
// agent-cli-release.json
|
|
17
|
-
var agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.
|
|
17
|
+
var agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.9", codex_package_name: "@openai/codex", codex_version: "0.155.0", copilot_sdk_package_name: "@github/copilot-sdk", copilot_sdk_version: "1.0.0-beta.8", copilot_cli_package_name: "@github/copilot", copilot_cli_version: "1.0.80", deepseek_harness_version: "0.1.1-rc.2", deepseek_harness_packages: ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-agent-instructions", "@deepseek-ai/dsh-agent-loop", "@deepseek-ai/dsh-agent-spine-demo", "@deepseek-ai/dsh-anonymous-user-id", "@deepseek-ai/dsh-atomic-write", "@deepseek-ai/dsh-attachment", "@deepseek-ai/dsh-brand", "@deepseek-ai/dsh-code-runtime", "@deepseek-ai/dsh-credentials", "@deepseek-ai/dsh-fs", "@deepseek-ai/dsh-goal", "@deepseek-ai/dsh-goal-round-driver", "@deepseek-ai/dsh-home-paths", "@deepseek-ai/dsh-invariants", "@deepseek-ai/dsh-jobs", "@deepseek-ai/dsh-jobs-local", "@deepseek-ai/dsh-launch-environment", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-llm-deepseek", "@deepseek-ai/dsh-llm-retry", "@deepseek-ai/dsh-output-retention", "@deepseek-ai/dsh-sandbox", "@deepseek-ai/dsh-sandbox-policy", "@deepseek-ai/dsh-scope", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-checkpoint-policy", "@deepseek-ai/dsh-session-persistence", "@deepseek-ai/dsh-session-persistence-jsonl", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-session-title", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-shell", "@deepseek-ai/dsh-shell-env", "@deepseek-ai/dsh-skill", "@deepseek-ai/dsh-skill-filesystem", "@deepseek-ai/dsh-subprocess", "@deepseek-ai/dsh-system-prompt", "@deepseek-ai/dsh-timeout", "@deepseek-ai/dsh-tool-bash", "@deepseek-ai/dsh-tool-goal", "@deepseek-ai/dsh-tool-jobs", "@deepseek-ai/dsh-tool-skill", "@deepseek-ai/dsh-tools", "@deepseek-ai/dsh-typert-protocol", "@deepseek-ai/dsh-user-approval"], deepseek_cordis_package_name: "@deepseek-ai/cordis", deepseek_cordis_version: "4.0.1", deepseek_support_packages: { "@deepseek-ai/cordis-plugin-timer": "1.1.3" }, platforms: { "linux-x64": { package_name: "@openai/codex-linux-x64", target: "x86_64-unknown-linux-musl", binary_name: "codex", sha256: "660e159a49e823ac8e5986cb238f73158ce4b957d40d9292f8de90862644b501" }, "win32-x64": { package_name: "@openai/codex-win32-x64", target: "x86_64-pc-windows-msvc", binary_name: "codex.exe", sha256: "e4c11374bd9de8ad5c3b7617fd4654bb7839901edb0863f9930666863c7a021b" } }, pi_coding_agent_package_name: "@earendil-works/pi-coding-agent", pi_ai_package_name: "@earendil-works/pi-ai", pi_version: "0.85.1", pi_support_packages: ["@earendil-works/pi-agent-core", "@earendil-works/pi-telemetry", "@earendil-works/pi-tui", "@earendil-works/chord"], grok_version: "1.0.30", grok_platforms: { "linux-x64": { package_name: "@xai-official/grok-linux-x64", binary_name: "grok", sha256: "504dd6546ab991b75d36698242875ce461489cd1f8cd84285873cb55bd5c7d54" }, "win32-x64": { package_name: "@xai-official/grok-win32-x64", binary_name: "grok.exe", sha256: "48736d1a4342a801ea26d0ecde4c516b653f791399065adaa55973f83abd8867" } } };
|
|
18
18
|
|
|
19
19
|
// lib/runtime-policy.generated.json
|
|
20
20
|
var runtime_policy_generated_default = {
|
|
@@ -109,6 +109,13 @@ var runtime_policy_generated_default = {
|
|
|
109
109
|
evidence_max_items: 32,
|
|
110
110
|
evidence_shared_read_seconds: 10
|
|
111
111
|
},
|
|
112
|
+
protective_plan_set_lock: {
|
|
113
|
+
wait_seconds: 120
|
|
114
|
+
},
|
|
115
|
+
execution_mutation_queue: {
|
|
116
|
+
wait_seconds: 120,
|
|
117
|
+
trade_submit_deadline_seconds: 360
|
|
118
|
+
},
|
|
112
119
|
history_evidence: {
|
|
113
120
|
device_rounds_per_beat: 6,
|
|
114
121
|
device_retry_seconds: 60
|
|
@@ -305,7 +312,7 @@ var runtime_policy_generated_default = {
|
|
|
305
312
|
// lib/cli-release/updater.ts
|
|
306
313
|
import { spawn as spawn2 } from "node:child_process";
|
|
307
314
|
import { createHash, randomUUID } from "node:crypto";
|
|
308
|
-
import { access, appendFile, chmod, lstat as lstat2,
|
|
315
|
+
import { access, appendFile, chmod, lstat as lstat2, readFile as readFile2, readdir as readdir2, realpath as realpath2, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
309
316
|
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2, win32 as windowsPath2 } from "node:path";
|
|
310
317
|
|
|
311
318
|
// lib/inference-host/config.ts
|
|
@@ -322,6 +329,7 @@ var InferenceHostProcessLockBusyError = class extends Error {
|
|
|
322
329
|
}
|
|
323
330
|
};
|
|
324
331
|
var MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
|
|
332
|
+
var WINDOWS_PRIVATE_ACL_MODES = ["harden", "verify", "verify-owner", "verify-private"];
|
|
325
333
|
var WINDOWS_PRIVATE_ACL_BROKER_SCRIPT = `$ErrorActionPreference='Stop'
|
|
326
334
|
$ProgressPreference='SilentlyContinue'
|
|
327
335
|
while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
@@ -338,7 +346,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
338
346
|
$kind=[string]$request.kind
|
|
339
347
|
$mode=[string]$request.mode
|
|
340
348
|
if($kind -ne 'directory' -and $kind -ne 'file') { throw 'invalid path kind' }
|
|
341
|
-
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner') { throw 'invalid ACL mode' }
|
|
349
|
+
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner' -and $mode -ne 'verify-private') { throw 'invalid ACL mode' }
|
|
342
350
|
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String([string]$request.path_b64))
|
|
343
351
|
if([string]::IsNullOrWhiteSpace($path) -or $path.Length -gt 32767 -or $path.Contains([char]0)) { throw 'invalid path' }
|
|
344
352
|
$failureStage='path_lookup'
|
|
@@ -387,11 +395,12 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
387
395
|
$owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
388
396
|
if($owner -ne $current.Value -and ($owner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
|
|
389
397
|
if($mode -ne 'verify-owner') {
|
|
390
|
-
|
|
398
|
+
$inheritedAllowed=$mode -eq 'verify-private'
|
|
399
|
+
if(-not $inheritedAllowed -and -not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
|
|
391
400
|
$userFull=$false
|
|
392
401
|
foreach($rule in $actual.Access) {
|
|
393
402
|
$sid=$rule.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
|
|
394
|
-
if($rule.IsInherited -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
403
|
+
if(($rule.IsInherited -and -not $inheritedAllowed) -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
395
404
|
throw 'private ACL contains an unauthorized access rule'
|
|
396
405
|
}
|
|
397
406
|
if($sid -eq $current.Value -and (($rule.FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -eq [Security.AccessControl.FileSystemRights]::FullControl)) { $userFull=$true }
|
|
@@ -527,9 +536,9 @@ var WindowsPrivateAclBroker = class {
|
|
|
527
536
|
error.code = "ENOENT";
|
|
528
537
|
pending.reject(error);
|
|
529
538
|
} else {
|
|
530
|
-
pending.reject(new Error(
|
|
539
|
+
pending.reject(Object.assign(new Error(
|
|
531
540
|
`Windows private ACL ${pending.mode} failed (${response.error_code}).`
|
|
532
|
-
));
|
|
541
|
+
), { aclStage: response.error_code }));
|
|
533
542
|
}
|
|
534
543
|
this.scheduleIdleShutdown();
|
|
535
544
|
}
|
|
@@ -634,7 +643,7 @@ var secureWindowsPrivatePath = async (path, kind, mode, platform = process.platf
|
|
|
634
643
|
};
|
|
635
644
|
var invalidateWindowsAclCache = (path) => {
|
|
636
645
|
for (const kind of ["file", "directory"]) {
|
|
637
|
-
for (const mode of
|
|
646
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
638
647
|
windowsAclCache.delete(aclCacheKey(path, kind, mode));
|
|
639
648
|
}
|
|
640
649
|
}
|
|
@@ -653,7 +662,7 @@ var rebindHardenedWindowsAclAfterRename = async (source, destination, kind, expe
|
|
|
653
662
|
}
|
|
654
663
|
invalidateWindowsAclCache(source);
|
|
655
664
|
invalidateWindowsAclCache(destination);
|
|
656
|
-
for (const mode of
|
|
665
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
657
666
|
windowsAclCache.set(aclCacheKey(destination, kind, mode), published);
|
|
658
667
|
}
|
|
659
668
|
};
|
|
@@ -664,10 +673,11 @@ var rebindHardenedWindowsDirectoryAfterOwnedMutation = async (path, expected) =>
|
|
|
664
673
|
throw new Error("Windows private directory identity changed during atomic publication.");
|
|
665
674
|
}
|
|
666
675
|
invalidateWindowsAclCache(path);
|
|
667
|
-
for (const mode of
|
|
676
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
668
677
|
windowsAclCache.set(aclCacheKey(path, "directory", mode), current);
|
|
669
678
|
}
|
|
670
679
|
};
|
|
680
|
+
var isWindowsPrivateAclVerificationFailure = (error) => error?.aclStage === "acl_verification";
|
|
671
681
|
var isDefaultWindowsPrivatePath = (path, root = resolve(homedir(), ".vtx", "inference-host")) => {
|
|
672
682
|
const child = relative(root, resolve(path));
|
|
673
683
|
return child === "" || !child.startsWith("..") && !child.includes(":");
|
|
@@ -1464,7 +1474,32 @@ var cleanupInterruptedReleaseStaging = async (releasesPath) => {
|
|
|
1464
1474
|
};
|
|
1465
1475
|
var ensureUpdaterPrivateDirectory = async (path, root, dependencies = {}) => {
|
|
1466
1476
|
const platform = dependencies.platform ?? process.platform;
|
|
1467
|
-
if (platform
|
|
1477
|
+
if (platform === "win32") {
|
|
1478
|
+
const existing = await lstat2(path).catch((error) => {
|
|
1479
|
+
if (error.code === "ENOENT") return null;
|
|
1480
|
+
throw error;
|
|
1481
|
+
});
|
|
1482
|
+
if (!existing) {
|
|
1483
|
+
await ensureInferencePrivateDirectory(path, { ...dependencies, defaultRoot: root });
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
if (existing.isSymbolicLink() || !existing.isDirectory()) {
|
|
1487
|
+
throw new Error("Inference host state directory is unsafe.");
|
|
1488
|
+
}
|
|
1489
|
+
const runner = dependencies.runner ?? runWindowsPrivateAcl;
|
|
1490
|
+
try {
|
|
1491
|
+
await secureWindowsPrivatePath(path, "directory", "verify-private", platform, runner);
|
|
1492
|
+
} catch (error) {
|
|
1493
|
+
if (!isWindowsPrivateAclVerificationFailure(error)) throw error;
|
|
1494
|
+
if ((await readdir2(path)).length > 0) {
|
|
1495
|
+
const recovery = /\.service-releases$/u.test(path) ? "run 'vtx inference-host service uninstall' then 'install'" : "delete this directory; it is recreated private";
|
|
1496
|
+
throw new Error(`updater_dir_not_private: ${recovery} (${path})`, { cause: error });
|
|
1497
|
+
}
|
|
1498
|
+
await secureWindowsPrivatePath(path, "directory", "harden", platform, runner);
|
|
1499
|
+
}
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
if (resolve2(path) === resolve2(root) || isPathWithin(root, path)) {
|
|
1468
1503
|
const existing = await lstat2(path).catch(() => null);
|
|
1469
1504
|
if (existing && existing.isDirectory() && !existing.isSymbolicLink() && (existing.mode & 63) !== 0 && (typeof process.getuid !== "function" || existing.uid === process.getuid())) {
|
|
1470
1505
|
await chmod(path, 448);
|
|
@@ -1521,8 +1556,8 @@ var stageCliReleaseWithin = async (input) => {
|
|
|
1521
1556
|
} catch (error) {
|
|
1522
1557
|
if (error.code !== "ENOENT") throw error;
|
|
1523
1558
|
}
|
|
1524
|
-
await
|
|
1525
|
-
await
|
|
1559
|
+
await ensureUpdaterPrivateDirectory(stagingPath, input.privateRoot, { platform });
|
|
1560
|
+
await ensureUpdaterPrivateDirectory(downloadPath, input.privateRoot, { platform });
|
|
1526
1561
|
try {
|
|
1527
1562
|
const packed = await runCliReleaseNpmCommand(executable, [
|
|
1528
1563
|
"pack",
|
|
@@ -93,6 +93,13 @@ var runtime_policy_generated_default = {
|
|
|
93
93
|
evidence_max_items: 32,
|
|
94
94
|
evidence_shared_read_seconds: 10
|
|
95
95
|
},
|
|
96
|
+
protective_plan_set_lock: {
|
|
97
|
+
wait_seconds: 120
|
|
98
|
+
},
|
|
99
|
+
execution_mutation_queue: {
|
|
100
|
+
wait_seconds: 120,
|
|
101
|
+
trade_submit_deadline_seconds: 360
|
|
102
|
+
},
|
|
96
103
|
history_evidence: {
|
|
97
104
|
device_rounds_per_beat: 6,
|
|
98
105
|
device_retry_seconds: 60
|
|
@@ -306,6 +313,7 @@ var InferenceHostProcessLockBusyError = class extends Error {
|
|
|
306
313
|
}
|
|
307
314
|
};
|
|
308
315
|
var MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
|
|
316
|
+
var WINDOWS_PRIVATE_ACL_MODES = ["harden", "verify", "verify-owner", "verify-private"];
|
|
309
317
|
var WINDOWS_PRIVATE_ACL_BROKER_SCRIPT = `$ErrorActionPreference='Stop'
|
|
310
318
|
$ProgressPreference='SilentlyContinue'
|
|
311
319
|
while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
@@ -322,7 +330,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
322
330
|
$kind=[string]$request.kind
|
|
323
331
|
$mode=[string]$request.mode
|
|
324
332
|
if($kind -ne 'directory' -and $kind -ne 'file') { throw 'invalid path kind' }
|
|
325
|
-
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner') { throw 'invalid ACL mode' }
|
|
333
|
+
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner' -and $mode -ne 'verify-private') { throw 'invalid ACL mode' }
|
|
326
334
|
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String([string]$request.path_b64))
|
|
327
335
|
if([string]::IsNullOrWhiteSpace($path) -or $path.Length -gt 32767 -or $path.Contains([char]0)) { throw 'invalid path' }
|
|
328
336
|
$failureStage='path_lookup'
|
|
@@ -371,11 +379,12 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
371
379
|
$owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
372
380
|
if($owner -ne $current.Value -and ($owner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
|
|
373
381
|
if($mode -ne 'verify-owner') {
|
|
374
|
-
|
|
382
|
+
$inheritedAllowed=$mode -eq 'verify-private'
|
|
383
|
+
if(-not $inheritedAllowed -and -not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
|
|
375
384
|
$userFull=$false
|
|
376
385
|
foreach($rule in $actual.Access) {
|
|
377
386
|
$sid=$rule.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
|
|
378
|
-
if($rule.IsInherited -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
387
|
+
if(($rule.IsInherited -and -not $inheritedAllowed) -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
379
388
|
throw 'private ACL contains an unauthorized access rule'
|
|
380
389
|
}
|
|
381
390
|
if($sid -eq $current.Value -and (($rule.FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -eq [Security.AccessControl.FileSystemRights]::FullControl)) { $userFull=$true }
|
|
@@ -511,9 +520,9 @@ var WindowsPrivateAclBroker = class {
|
|
|
511
520
|
error.code = "ENOENT";
|
|
512
521
|
pending.reject(error);
|
|
513
522
|
} else {
|
|
514
|
-
pending.reject(new Error(
|
|
523
|
+
pending.reject(Object.assign(new Error(
|
|
515
524
|
`Windows private ACL ${pending.mode} failed (${response.error_code}).`
|
|
516
|
-
));
|
|
525
|
+
), { aclStage: response.error_code }));
|
|
517
526
|
}
|
|
518
527
|
this.scheduleIdleShutdown();
|
|
519
528
|
}
|
|
@@ -618,7 +627,7 @@ var secureWindowsPrivatePath = async (path, kind, mode, platform = process.platf
|
|
|
618
627
|
};
|
|
619
628
|
var invalidateWindowsAclCache = (path) => {
|
|
620
629
|
for (const kind of ["file", "directory"]) {
|
|
621
|
-
for (const mode of
|
|
630
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
622
631
|
windowsAclCache.delete(aclCacheKey(path, kind, mode));
|
|
623
632
|
}
|
|
624
633
|
}
|
|
@@ -637,7 +646,7 @@ var rebindHardenedWindowsAclAfterRename = async (source, destination, kind, expe
|
|
|
637
646
|
}
|
|
638
647
|
invalidateWindowsAclCache(source);
|
|
639
648
|
invalidateWindowsAclCache(destination);
|
|
640
|
-
for (const mode of
|
|
649
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
641
650
|
windowsAclCache.set(aclCacheKey(destination, kind, mode), published);
|
|
642
651
|
}
|
|
643
652
|
};
|
|
@@ -648,7 +657,7 @@ var rebindHardenedWindowsDirectoryAfterOwnedMutation = async (path, expected) =>
|
|
|
648
657
|
throw new Error("Windows private directory identity changed during atomic publication.");
|
|
649
658
|
}
|
|
650
659
|
invalidateWindowsAclCache(path);
|
|
651
|
-
for (const mode of
|
|
660
|
+
for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
|
|
652
661
|
windowsAclCache.set(aclCacheKey(path, "directory", mode), current);
|
|
653
662
|
}
|
|
654
663
|
};
|