@opengeni/runtime 0.14.0 → 0.14.3

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.
@@ -10647,17 +10647,27 @@ function getHostDockerUser() {
10647
10647
  }
10648
10648
 
10649
10649
  // src/sandbox/providers/docker.ts
10650
+ import { isAbsolute as isAbsolute4 } from "path";
10650
10651
  var dockerProvider = {
10651
10652
  backend: "docker",
10652
10653
  descriptor: CAPABILITY_DESCRIPTORS.docker,
10653
10654
  // Local dev container — no credentials. (The dockerNetwork decoration is
10654
10655
  // applied by the factory, not here: it wraps the constructed client.)
10655
- validateCredentials() {
10656
+ validateCredentials(settings) {
10657
+ const workspaceBaseDir = settings.dockerWorkspaceBaseDir?.trim();
10658
+ if (workspaceBaseDir && !isAbsolute4(workspaceBaseDir)) {
10659
+ throw new SandboxConfigError(
10660
+ "docker",
10661
+ "OPENGENI_DOCKER_WORKSPACE_BASE_DIR must be an absolute path"
10662
+ );
10663
+ }
10656
10664
  },
10657
10665
  build({ settings, exposedPorts }) {
10666
+ const workspaceBaseDir = settings.dockerWorkspaceBaseDir?.trim();
10658
10667
  return new DockerSandboxClient({
10659
10668
  image: settings.dockerImage,
10660
- exposedPorts
10669
+ exposedPorts,
10670
+ ...workspaceBaseDir ? { workspaceBaseDir } : {}
10661
10671
  });
10662
10672
  }
10663
10673
  };
@@ -19458,6 +19468,7 @@ function withRunCredentialsClient(client, sessionId, onSessionReady) {
19458
19468
  import { createHash as createHash5 } from "crypto";
19459
19469
  import { posix as posixPath } from "path";
19460
19470
  var MAX_TOOLSPACE_SESSION_ID_BYTES = 512;
19471
+ var HOME_RELATIVE_TOOLSPACE_PREFIX = "$HOME/";
19461
19472
  var ToolspaceTokenPathError = class extends Error {
19462
19473
  constructor(message) {
19463
19474
  super(message);
@@ -19473,11 +19484,29 @@ function assertToolspaceSessionId(sessionId) {
19473
19484
  }
19474
19485
  return sessionId;
19475
19486
  }
19476
- function toolspaceTokenFileForSession(manifestTokenFile, sessionId) {
19477
- if (!manifestTokenFile || manifestTokenFile.includes("\0") || !posixPath.isAbsolute(manifestTokenFile)) {
19478
- throw new ToolspaceTokenPathError("Toolspace manifest token file must be absolute");
19487
+ function isHomeRelativeToolspacePath(value) {
19488
+ if (!value.startsWith(HOME_RELATIVE_TOOLSPACE_PREFIX)) return false;
19489
+ const relative4 = value.slice(HOME_RELATIVE_TOOLSPACE_PREFIX.length);
19490
+ const segments = relative4.split("/");
19491
+ return relative4.length > 0 && !relative4.includes("\0") && segments.every(
19492
+ (segment) => segment !== "." && segment !== ".." && /^[A-Za-z0-9._-]+$/.test(segment)
19493
+ ) && posixPath.normalize(relative4) === relative4;
19494
+ }
19495
+ function assertToolspaceFilePath(value, label) {
19496
+ if (!value || value.includes("\0") || !posixPath.isAbsolute(value) && !isHomeRelativeToolspacePath(value)) {
19497
+ throw new ToolspaceTokenPathError(`${label} must be absolute or use the trusted $HOME/ prefix`);
19479
19498
  }
19480
- const normalizedManifestFile = posixPath.normalize(manifestTokenFile);
19499
+ return posixPath.isAbsolute(value) ? posixPath.normalize(value) : value;
19500
+ }
19501
+ function shellToolspacePath(value) {
19502
+ const validated = assertToolspaceFilePath(value, "Toolspace token file");
19503
+ return isHomeRelativeToolspacePath(validated) ? `"${validated}"` : shellQuote5(validated);
19504
+ }
19505
+ function toolspaceTokenFileForSession(manifestTokenFile, sessionId) {
19506
+ const normalizedManifestFile = assertToolspaceFilePath(
19507
+ manifestTokenFile,
19508
+ "Toolspace manifest token file"
19509
+ );
19481
19510
  const digest = createHash5("sha256").update(assertToolspaceSessionId(sessionId)).digest("hex");
19482
19511
  return posixPath.join(posixPath.dirname(normalizedManifestFile), "toolspace-tokens", digest);
19483
19512
  }
@@ -19486,10 +19515,7 @@ function toolspaceTokenFileFromEnvironment(environment, sessionId) {
19486
19515
  return toolspaceTokenFileForSession(manifestTokenFile, sessionId);
19487
19516
  }
19488
19517
  function withToolspaceTokenEnvironment(cmd, tokenFile) {
19489
- if (!tokenFile || tokenFile.includes("\0") || !posixPath.isAbsolute(tokenFile)) {
19490
- throw new ToolspaceTokenPathError("Toolspace token file must be absolute");
19491
- }
19492
- return [`export OPENGENI_TOOLSPACE_TOKEN_FILE=${shellQuote5(tokenFile)}`, cmd].join("\n");
19518
+ return [`export OPENGENI_TOOLSPACE_TOKEN_FILE=${shellToolspacePath(tokenFile)}`, cmd].join("\n");
19493
19519
  }
19494
19520
  function withToolspaceTokenSession(session, tokenFile) {
19495
19521
  return new Proxy(session, {
@@ -20509,7 +20535,11 @@ var RoutingSandboxSession = class {
20509
20535
  if (!s.materializeEntry) {
20510
20536
  throw new RoutingUnsupportedError("materializeEntry", this.cached?.kind ?? "unknown");
20511
20537
  }
20512
- return s.materializeEntry(args);
20538
+ await s.materializeEntry(args);
20539
+ const path = args && typeof args === "object" && typeof args.path === "string" ? args.path : null;
20540
+ if (path) {
20541
+ await assertProviderCanSeeMaterializedPath(s, path);
20542
+ }
20513
20543
  });
20514
20544
  }
20515
20545
  /** PTY support reflects the LAST-resolved backend (a synchronous probe; the SDK
@@ -20573,6 +20603,39 @@ var RoutingSandboxSession = class {
20573
20603
  return this.resolve();
20574
20604
  }
20575
20605
  };
20606
+ var MATERIALIZED_PATH_MARKER = "__OPENGENI_MATERIALIZED_PATH_VISIBLE__";
20607
+ async function assertProviderCanSeeMaterializedPath(session, path) {
20608
+ const command = `test -e ${shellSingleQuote(path)} && printf %s ${shellSingleQuote(
20609
+ MATERIALIZED_PATH_MARKER
20610
+ )}`;
20611
+ const args = {
20612
+ cmd: command,
20613
+ workdir: providerManifestRoot(session) ?? "/workspace",
20614
+ shell: "sh",
20615
+ login: false,
20616
+ tty: false
20617
+ };
20618
+ let output;
20619
+ if (session.execCommand) {
20620
+ output = await session.execCommand(args);
20621
+ } else if (session.exec) {
20622
+ output = formatExecResult(await session.exec(args));
20623
+ } else {
20624
+ throw new RoutingUnsupportedError("materializeEntry.verify", "unknown");
20625
+ }
20626
+ if (!output.includes(MATERIALIZED_PATH_MARKER)) {
20627
+ throw new Error(
20628
+ `Sandbox materialization completed but the provider cannot read the destination path: ${path}`
20629
+ );
20630
+ }
20631
+ }
20632
+ function providerManifestRoot(session) {
20633
+ const root = session.state?.manifest?.root;
20634
+ return typeof root === "string" && root.length > 0 ? root : null;
20635
+ }
20636
+ function shellSingleQuote(value) {
20637
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
20638
+ }
20576
20639
 
20577
20640
  // src/sandbox/turn-tool-cancellation.ts
20578
20641
  var TURN_EXEC_YIELD_MS = 250;
@@ -23984,6 +24047,7 @@ export {
23984
24047
  withRunCredentialsSession,
23985
24048
  withRunCredentialsClient,
23986
24049
  ToolspaceTokenPathError,
24050
+ shellToolspacePath,
23987
24051
  toolspaceTokenFileForSession,
23988
24052
  toolspaceTokenFileFromEnvironment,
23989
24053
  withToolspaceTokenEnvironment,
@@ -24048,4 +24112,4 @@ export {
24048
24112
  collectSandboxEnvironment2 as collectSandboxEnvironment,
24049
24113
  parseExposedPorts2 as parseExposedPorts
24050
24114
  };
24051
- //# sourceMappingURL=chunk-3NUSY22C.js.map
24115
+ //# sourceMappingURL=chunk-GQIFSLAC.js.map