@openclaw/mxc-sandbox 2026.9.8 → 2026.9.33

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.
Files changed (3) hide show
  1. package/README.md +32 -5
  2. package/dist/index.js +48 -23
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -38,7 +38,9 @@ readiness behavior to change as MXC host support matures.
38
38
 
39
39
  - Plugin id: `mxc`
40
40
  - Package: `@openclaw/mxc-sandbox`
41
- - Minimum OpenClaw host: `2026.6.11`
41
+ - Minimum OpenClaw install host: `2026.6.11`
42
+ - Plugin API host requirement: `2026.9.6` or newer. An older host cannot run
43
+ the current plugin even if the MXC executor is updated.
42
44
 
43
45
  ## Plugin config
44
46
 
@@ -48,7 +50,7 @@ and out-of-range values fail plugin activation with an actionable error
48
50
 
49
51
  | Field | Type | Default | Notes |
50
52
  | ---------------- | --------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
51
- | `mxcBinaryPath` | `string` | unset | Non-empty override for the `wxc-exec.exe` executor path; see [SDK-only executor discovery](#supported). |
53
+ | `mxcBinaryPath` | `string` | unset | Non-empty override for a compatible `wxc-exec.exe` supporting `--probe`; see [Host readiness](#host-readiness). |
52
54
  | `containment` | `"process" \| "processcontainer"` | `"process"` | Both currently resolve to Windows ProcessContainer. |
53
55
  | `network` | `"none" \| "default"` | `"none"` | `"default"` allows outbound network via the `internetClient` capability. |
54
56
  | `timeoutSeconds` | `number` | unset (baseline default `300` applies) | Must be `>= 1` and `<= 2147000` (the largest Node-safe `setTimeout` delay in whole seconds). Capped to the sandbox policy baseline timeout when both are set. |
@@ -86,7 +88,7 @@ help stay in sync with plugin runtime validation.
86
88
  - OpenClaw passes per-run command, environment, and filesystem config to the
87
89
  plugin's Node launcher through a short-lived local payload file, and deletes
88
90
  that file and its temp directory when the launcher or run finishes.
89
- - `@microsoft/mxc-sdk@0.7.0` then carries the full base64 request envelope on
91
+ - `@microsoft/mxc-sdk@0.8.0` then carries the full base64 request envelope on
90
92
  the native `wxc-exec` process argv. A host user with process-inspection rights
91
93
  can observe that command, environment, and policy data while the process is
92
94
  running. Do not put secrets in MXC command arguments or environment values
@@ -257,8 +259,33 @@ agents may still use them.
257
259
 
258
260
  ## Host readiness
259
261
 
260
- IsoEnvBroker must be available on the host OS. The plugin checks this before
261
- registering the sandbox backend.
262
+ Before registering the sandbox backend, the plugin runs the MXC executor's own
263
+ host probe (`wxc-exec --probe`) and requires it to select an isolation tier
264
+ (`base-container`, `appcontainer-bfs`, or `appcontainer-dacl`). It probes the
265
+ same executor it launches, including an `mxcBinaryPath` override. MXC's tier
266
+ degradation warnings are logged but do not block activation. To inspect a host,
267
+ run the executor directly:
268
+
269
+ ```powershell
270
+ & node_modules\@microsoft\mxc-sdk\bin\x64\wxc-exec.exe --probe
271
+ ```
272
+
273
+ Use `bin\arm64` on Arm64 hosts.
274
+
275
+ An existing `mxcBinaryPath` override must point to an MXC 0.8.0-compatible
276
+ executor that supports `--probe`. An older executor stops plugin activation;
277
+ the plugin cannot safely infer readiness from a Windows service name or probe a
278
+ different binary. If the override fails, run that exact executable with
279
+ `--probe` to see its error. Update the override to a compatible executor, or
280
+ remove it to use the `@microsoft/mxc-sdk@0.8.0` executor installed with the
281
+ plugin:
282
+
283
+ ```powershell
284
+ openclaw config unset plugins.entries.mxc.config.mxcBinaryPath
285
+ ```
286
+
287
+ Restart the Gateway after changing the override. If the SDK executor also
288
+ fails `--probe`, address the reported host-readiness error before retrying.
262
289
 
263
290
  Host preparation is advisory. If directory listing inside the sandbox fails with
264
291
  `Access is denied`, run this once from an elevated prompt:
package/dist/index.js CHANGED
@@ -509,7 +509,6 @@ function buildLauncherEnv(hostEnv = process.env) {
509
509
  //#endregion
510
510
  //#region extensions/mxc/src/mxc-container-config.ts
511
511
  const MXC_SCHEMA_VERSION = "0.7.0-alpha";
512
- const PROCESS_CONTAINER_NAME_MAX_LEN = 64;
513
512
  function resolveCurrentBaselineContext(projectDir) {
514
513
  return {
515
514
  projectDir: path.resolve(projectDir),
@@ -559,7 +558,10 @@ function buildMxcContainerConfig(params) {
559
558
  version: MXC_SCHEMA_VERSION,
560
559
  containerId: params.containerId,
561
560
  containment: params.config.containment,
562
- lifecycle: { destroyOnExit: true },
561
+ lifecycle: {
562
+ destroyOnExit: true,
563
+ preservePolicy: false
564
+ },
563
565
  process: {
564
566
  commandLine: buildCommandLine(params.command, params.args ?? []),
565
567
  cwd: params.workdir,
@@ -577,7 +579,6 @@ function buildMxcContainerConfig(params) {
577
579
  enforcementMode: "capabilities"
578
580
  },
579
581
  processContainer: {
580
- name: processContainerName(params.runtimeId),
581
582
  leastPrivilege: true,
582
583
  capabilities: networkAllowed ? ["internetClient"] : [],
583
584
  ui: {
@@ -617,8 +618,7 @@ function buildFilesystemConfig(params) {
617
618
  return {
618
619
  readonlyPaths,
619
620
  deniedPaths: void 0,
620
- readwritePaths,
621
- clearPolicyOnExit: true
621
+ readwritePaths
622
622
  };
623
623
  }
624
624
  function resolveWorkspaceReadwritePathSpecs(workspace) {
@@ -698,11 +698,6 @@ function buildMissingFilesystemPathMessage(pathValue, accessLabel, sources) {
698
698
  if (sourceLabel) return `MXC sandbox ${accessLabel} path ${pathValue} configured by ${sourceLabel} is missing on the host. Recreate the path or update the policy file before launching the sandbox.`;
699
699
  return `MXC sandbox ${accessLabel} path ${pathValue} does not exist on the host.`;
700
700
  }
701
- function processContainerName(runtimeId) {
702
- if (runtimeId.length <= PROCESS_CONTAINER_NAME_MAX_LEN) return runtimeId;
703
- const hash = createHash("sha256").update(runtimeId).digest("hex").slice(0, 8);
704
- return `${runtimeId.slice(0, PROCESS_CONTAINER_NAME_MAX_LEN - hash.length - 1)}-${hash}`;
705
- }
706
701
  function resolveProcessTimeoutSeconds(config, baseline) {
707
702
  if (config.timeoutSecondsConfigured === true) return Math.min(config.timeoutSeconds, baseline.process.timeoutSeconds);
708
703
  return baseline.process.timeoutSeconds;
@@ -904,7 +899,7 @@ function isNodeError(err) {
904
899
  }
905
900
  //#endregion
906
901
  //#region extensions/mxc/src/mxc-backend.ts
907
- const CONTAINER_ID_MAX_LEN = 80;
902
+ const CONTAINER_ID_MAX_LEN = 64;
908
903
  function uniqueContainerId(runtimeId) {
909
904
  const suffix = randomBytes(4).toString("hex");
910
905
  return `${runtimeId.length + suffix.length + 1 > CONTAINER_ID_MAX_LEN ? runtimeId.slice(0, CONTAINER_ID_MAX_LEN - suffix.length - 1) : runtimeId}-${suffix}`;
@@ -1028,7 +1023,6 @@ function createMxcSandboxBackendHandle(params) {
1028
1023
  config: params.config,
1029
1024
  baseline,
1030
1025
  baselineContext,
1031
- runtimeId: params.runtimeId,
1032
1026
  containerId: uniqueContainerId(params.runtimeId),
1033
1027
  command,
1034
1028
  sandboxTempDir,
@@ -1083,7 +1077,6 @@ function createMxcSandboxBackendHandle(params) {
1083
1077
  config: restrictiveConfig,
1084
1078
  baseline,
1085
1079
  baselineContext,
1086
- runtimeId: params.runtimeId,
1087
1080
  containerId: uniqueContainerId(params.runtimeId),
1088
1081
  command: commandBridge.command,
1089
1082
  args: cmdParams.args,
@@ -1173,22 +1166,46 @@ function createMxcSandboxBackendFactory(config) {
1173
1166
  //#endregion
1174
1167
  //#region extensions/mxc/src/readiness.ts
1175
1168
  const DEFAULT_DEPS = { execFileSync };
1169
+ const MxcProbeOutputSchema = z.object({
1170
+ tier: z.enum([
1171
+ "base-container",
1172
+ "appcontainer-bfs",
1173
+ "appcontainer-dacl"
1174
+ ]).optional(),
1175
+ warnings: z.array(z.string()).default([]),
1176
+ error: z.string().optional()
1177
+ });
1176
1178
  function resolveWindowsSystemExecutable(name) {
1177
1179
  const systemRoot = process.env.SystemRoot || process.env.WINDIR;
1178
1180
  return path.win32.join(systemRoot || "C:\\Windows", "System32", name);
1179
1181
  }
1180
- function assertWindowsIsoEnvBrokerInstalled(deps) {
1182
+ function probeMxcIsolationTier(executablePath, deps) {
1183
+ const notReady = (reason, cause) => new Error(`[mxc] MXC Windows ProcessContainer sandbox is not ready: ${reason}. Run "${executablePath}" --probe for host details. The selected executor must be compatible with MXC 0.8.0 and support --probe. If mxcBinaryPath points to an older executor, update it or unset plugins.entries.mxc.config.mxcBinaryPath and restart the Gateway to use the bundled SDK executor.`, cause === void 0 ? void 0 : { cause });
1184
+ let output;
1181
1185
  try {
1182
- deps.execFileSync(resolveWindowsSystemExecutable("sc.exe"), ["query", "IsoEnvBroker"], {
1186
+ output = deps.execFileSync(executablePath, ["--probe"], {
1183
1187
  encoding: "utf-8",
1184
1188
  stdio: "pipe",
1185
- timeout: 5e3,
1189
+ timeout: 15e3,
1186
1190
  windowsHide: true
1187
1191
  });
1188
1192
  } catch (error) {
1189
- const detail = error instanceof Error && error.message ? `: ${error.message.trim()}` : "";
1190
- throw new Error(`[mxc] MXC Windows ProcessContainer sandbox is not ready: IsoEnvBroker service is not installed${detail}. Install the IsoEnvBroker service before enabling MXC sandbox execution.`, { cause: error });
1193
+ throw notReady(`the MXC host probe failed${error instanceof Error && error.message ? `: ${error.message.trim()}` : ""}`, error);
1191
1194
  }
1195
+ let probe;
1196
+ try {
1197
+ probe = JSON.parse(output);
1198
+ } catch (error) {
1199
+ throw notReady("the MXC host probe did not return JSON", error);
1200
+ }
1201
+ const parsed = MxcProbeOutputSchema.safeParse(probe);
1202
+ if (!parsed.success) throw notReady("the MXC host probe returned an unexpected result", parsed.error);
1203
+ const { tier, warnings, error } = parsed.data;
1204
+ if (!tier) throw notReady(`MXC cannot select an isolation tier on this host (${error || "the probe reported no isolation tier"})`);
1205
+ return {
1206
+ tier,
1207
+ warnings
1208
+ };
1192
1209
  }
1193
1210
  function isSystemDrivePrepared(deps) {
1194
1211
  const systemDrive = process.env.SystemDrive || "C:";
@@ -1219,12 +1236,19 @@ function warnMxcHostPrepIfNeeded(params = {}) {
1219
1236
  ...params.deps
1220
1237
  })) (params.warn ?? ((message) => console.warn(message)))(systemDrivePrepWarning(process.env.SystemDrive || "C:"));
1221
1238
  }
1222
- function assertMxcReadiness(params = {}) {
1239
+ /**
1240
+ * Fails plugin activation unless MXC's host probe selects an isolation tier for
1241
+ * `executablePath`. Degradation warnings from the probe are reported but do not
1242
+ * block activation.
1243
+ */
1244
+ function assertMxcReadiness(params) {
1223
1245
  if ((params.platform ?? process.platform) !== "win32") return;
1224
- assertWindowsIsoEnvBrokerInstalled({
1246
+ const deps = {
1225
1247
  ...DEFAULT_DEPS,
1226
1248
  ...params.deps
1227
- });
1249
+ };
1250
+ const probe = probeMxcIsolationTier(params.executablePath, deps);
1251
+ if (probe.warnings.length > 0) (params.warn ?? ((message) => console.warn(message)))(`[mxc] MXC sandbox is using the ${probe.tier} isolation tier: ${probe.warnings.join("; ")}`);
1228
1252
  }
1229
1253
  //#endregion
1230
1254
  //#region extensions/mxc/src/plugin.ts
@@ -1235,13 +1259,14 @@ function registerMxcPlugin(api) {
1235
1259
  console.warn(`[mxc] Sandbox backend is Windows-only and not available on ${process.platform}. Plugin will be dormant.`);
1236
1260
  return;
1237
1261
  }
1262
+ let mxcBinaryPath;
1238
1263
  try {
1239
- resolveMxcBinaryPath(config.mxcBinaryPath);
1264
+ mxcBinaryPath = resolveMxcBinaryPath(config.mxcBinaryPath);
1240
1265
  } catch (err) {
1241
1266
  const reason = err instanceof Error ? err.message : String(err);
1242
1267
  throw new Error(`[mxc] MXC sandbox backend cannot load: ${reason}. Install @microsoft/mxc-sdk or set mxcBinaryPath.`, { cause: err });
1243
1268
  }
1244
- assertMxcReadiness();
1269
+ assertMxcReadiness({ executablePath: mxcBinaryPath });
1245
1270
  warnMxcHostPrepIfNeeded();
1246
1271
  const unregister = registerSandboxBackend("mxc", {
1247
1272
  factory: createMxcSandboxBackendFactory(config),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/mxc-sandbox",
3
- "version": "2026.9.8",
3
+ "version": "2026.9.33",
4
4
  "description": "OpenClaw MXC sandbox execution plugin for MXC-capable hosts",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,10 +22,10 @@
22
22
  "minHostVersion": ">=2026.6.11"
23
23
  },
24
24
  "compat": {
25
- "pluginApi": ">=2026.9.8"
25
+ "pluginApi": ">=2026.9.33"
26
26
  },
27
27
  "build": {
28
- "openclawVersion": "2026.9.8",
28
+ "openclawVersion": "2026.9.33",
29
29
  "bundledDist": false,
30
30
  "staticAssets": [
31
31
  {
@@ -50,7 +50,7 @@
50
50
  "assets/activity.svg"
51
51
  ],
52
52
  "peerDependencies": {
53
- "openclaw": ">=2026.9.8"
53
+ "openclaw": ">=2026.9.33"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "openclaw": {