@opengeni/runtime 0.14.3 → 0.14.15
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/dist/{chunk-4YJ5Z52Z.js → chunk-7E2ZSCZK.js} +6 -6
- package/dist/{chunk-4YJ5Z52Z.js.map → chunk-7E2ZSCZK.js.map} +1 -1
- package/dist/{chunk-GQIFSLAC.js → chunk-GNEGANUF.js} +892 -297
- package/dist/chunk-GNEGANUF.js.map +1 -0
- package/dist/codex-tool-search.d.ts +100 -0
- package/dist/context-compaction.d.ts +236 -0
- package/dist/history-sanitizer.d.ts +320 -0
- package/dist/index.d.ts +186 -718
- package/dist/index.js +612 -126
- package/dist/index.js.map +1 -1
- package/dist/{localSources-T3HZ6KY4.js → localSources-BXHBKGF4.js} +2 -2
- package/dist/mcp-network.d.ts +32 -35
- package/dist/metrics.d.ts +33 -0
- package/dist/sandbox/capabilities.d.ts +11 -0
- package/dist/sandbox/channel-a.d.ts +226 -0
- package/dist/sandbox/display-stack.d.ts +99 -0
- package/dist/sandbox/errors.d.ts +16 -0
- package/dist/sandbox/exec-banner.d.ts +19 -0
- package/dist/sandbox/index.d.ts +190 -6
- package/dist/sandbox/index.js +20 -4
- package/dist/sandbox/op-correlation.d.ts +24 -0
- package/dist/sandbox/provider-errors.d.ts +32 -0
- package/dist/sandbox/provider-operation-gate.d.ts +12 -0
- package/dist/sandbox/providers/blaxel.d.ts +2 -0
- package/dist/sandbox/providers/cloudflare.d.ts +2 -0
- package/dist/sandbox/providers/daytona.d.ts +2 -0
- package/dist/sandbox/providers/docker.d.ts +2 -0
- package/dist/sandbox/providers/e2b.d.ts +2 -0
- package/dist/sandbox/providers/index.d.ts +11 -0
- package/dist/sandbox/providers/local.d.ts +2 -0
- package/dist/sandbox/providers/modal.d.ts +132 -0
- package/dist/sandbox/providers/none.d.ts +2 -0
- package/dist/sandbox/providers/runloop.d.ts +2 -0
- package/dist/sandbox/providers/selfhosted.d.ts +2 -0
- package/dist/sandbox/providers/types.d.ts +30 -0
- package/dist/sandbox/providers/vercel.d.ts +2 -0
- package/dist/sandbox/recording.d.ts +80 -0
- package/dist/sandbox/routing/backend-resolver.d.ts +173 -0
- package/dist/sandbox/routing/routing-session.d.ts +401 -0
- package/dist/sandbox/run-credentials.d.ts +65 -0
- package/dist/sandbox/select.d.ts +120 -0
- package/dist/sandbox/selfhosted/capabilities.d.ts +91 -0
- package/dist/sandbox/selfhosted/control-rpc.d.ts +175 -0
- package/dist/sandbox/selfhosted/fault-rendering.d.ts +40 -0
- package/dist/sandbox/selfhosted/op-observer.d.ts +40 -0
- package/dist/sandbox/selfhosted/op-stream.d.ts +104 -0
- package/dist/sandbox/selfhosted/op-testing.d.ts +108 -0
- package/dist/sandbox/selfhosted/op-transport.d.ts +60 -0
- package/dist/sandbox/selfhosted/retry-policy.d.ts +106 -0
- package/dist/sandbox/selfhosted/session.d.ts +552 -0
- package/dist/sandbox/selfhosted/testing.d.ts +48 -0
- package/dist/sandbox/stream-port.d.ts +80 -0
- package/dist/sandbox/stream-token.d.ts +44 -0
- package/dist/sandbox/terminal-server.d.ts +67 -0
- package/dist/sandbox/toolspace-token.d.ts +23 -0
- package/dist/sandbox/turn-tool-cancellation.d.ts +72 -0
- package/dist/sandbox/workspace-archive.d.ts +39 -0
- package/dist/sandbox-computer.d.ts +227 -0
- package/dist/screenshot-error-card.d.ts +1 -0
- package/dist/skill-library.d.ts +10 -12
- package/dist/usage-telemetry.d.ts +45 -0
- package/dist/workspace-skills.d.ts +31 -0
- package/package.json +7 -7
- package/src/context-compaction.ts +600 -6
- package/src/history-sanitizer.ts +10 -92
- package/src/index.ts +301 -62
- package/src/sandbox/channel-a.ts +267 -81
- package/src/sandbox/index.ts +56 -94
- package/src/sandbox/provider-operation-gate.ts +110 -0
- package/src/sandbox/providers/modal.ts +433 -3
- package/src/sandbox/routing/routing-session.ts +20 -7
- package/src/sandbox/selfhosted/session.ts +7 -6
- package/src/sandbox/turn-tool-cancellation.ts +47 -7
- package/src/sandbox/workspace-archive.ts +176 -73
- package/src/sandbox-computer.ts +25 -75
- package/dist/chunk-GQIFSLAC.js.map +0 -1
- package/dist/index-BraazrAO.d.ts +0 -2931
- /package/dist/{localSources-T3HZ6KY4.js.map → localSources-BXHBKGF4.js.map} +0 -0
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
validateCredentialPair,
|
|
29
29
|
validateRemoteSandboxPathForManifest,
|
|
30
30
|
validateSandboxArchiveLimits
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-7E2ZSCZK.js";
|
|
32
32
|
import {
|
|
33
33
|
FileMode,
|
|
34
34
|
Manifest,
|
|
@@ -129,7 +129,7 @@ function assertDescriptorRegistryInvariants() {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
132
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/editor.mjs
|
|
133
133
|
var RemoteSandboxEditor = class {
|
|
134
134
|
io;
|
|
135
135
|
constructor(io) {
|
|
@@ -184,7 +184,7 @@ var RemoteSandboxEditor = class {
|
|
|
184
184
|
}
|
|
185
185
|
};
|
|
186
186
|
|
|
187
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
187
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/archive.mjs
|
|
188
188
|
var TAR_BLOCK_SIZE = 512;
|
|
189
189
|
var ZERO_BLOCK = new Uint8Array(TAR_BLOCK_SIZE);
|
|
190
190
|
function assertTarWorkspacePersistence(providerName, workspacePersistence) {
|
|
@@ -624,7 +624,7 @@ function tarError(member, reason) {
|
|
|
624
624
|
});
|
|
625
625
|
}
|
|
626
626
|
|
|
627
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
627
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/metadata.mjs
|
|
628
628
|
var MOUNT_MANIFEST_METADATA_SUPPORT = {
|
|
629
629
|
mounts: true
|
|
630
630
|
};
|
|
@@ -705,7 +705,7 @@ function joinSandboxPath(parent, child) {
|
|
|
705
705
|
return `${parent.replace(/\/+$/u, "")}/${normalizedChild}`;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
708
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/ports.mjs
|
|
709
709
|
function assertConfiguredExposedPort(args) {
|
|
710
710
|
const port = normalizeExposedPort(args.port);
|
|
711
711
|
if (args.allowOnDemand) {
|
|
@@ -768,7 +768,7 @@ function parseExposedPortEndpoint(value, args) {
|
|
|
768
768
|
};
|
|
769
769
|
}
|
|
770
770
|
|
|
771
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
771
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/pty.mjs
|
|
772
772
|
var PTY_YIELD_TIME_MS_MIN = 250;
|
|
773
773
|
var PTY_EMPTY_YIELD_TIME_MS_MIN = 5e3;
|
|
774
774
|
var PTY_YIELD_TIME_MS_MAX = 3e4;
|
|
@@ -1085,7 +1085,7 @@ function formatWebSocketEvent(event) {
|
|
|
1085
1085
|
return "unknown error";
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
1088
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
1088
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/session.mjs
|
|
1089
1089
|
async function closeRemoteSessionOnManifestError(providerName, session, manifestError) {
|
|
1090
1090
|
try {
|
|
1091
1091
|
await session.close();
|
|
@@ -1434,7 +1434,7 @@ function isNotFoundErrorMessage(message) {
|
|
|
1434
1434
|
return /\b(sandbox|sandbox instance|instance|devbox)\b.*\b(not found|missing|does not exist|no such)\b/iu.test(text) || /\b(not found|missing|does not exist|no such)\b.*\b(sandbox|sandbox instance|instance|devbox)\b/iu.test(text);
|
|
1435
1435
|
}
|
|
1436
1436
|
|
|
1437
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
1437
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/runAs.mjs
|
|
1438
1438
|
function sandboxUserShellCommand(command, user) {
|
|
1439
1439
|
if (!user) {
|
|
1440
1440
|
return command;
|
|
@@ -1566,7 +1566,7 @@ function randomId() {
|
|
|
1566
1566
|
return (globalThis.crypto?.randomUUID?.() ?? Math.random().toString(16).slice(2)).replace(/-/gu, "");
|
|
1567
1567
|
}
|
|
1568
1568
|
|
|
1569
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
1569
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/sessionBase.mjs
|
|
1570
1570
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1571
1571
|
var RemoteSandboxSessionBase = class {
|
|
1572
1572
|
state;
|
|
@@ -2004,7 +2004,7 @@ function joinRemoteCommandOutput(result) {
|
|
|
2004
2004
|
return [result.stdout ?? "", result.stderr ?? ""].filter((value) => value.trim().length > 0).join("\n");
|
|
2005
2005
|
}
|
|
2006
2006
|
|
|
2007
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
2007
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/sessionState.mjs
|
|
2008
2008
|
function serializeRemoteSandboxSessionState(state) {
|
|
2009
2009
|
return {
|
|
2010
2010
|
...state,
|
|
@@ -2034,7 +2034,7 @@ function deserializeRemotePersistedEnvironmentForRuntime(manifest, environment,
|
|
|
2034
2034
|
};
|
|
2035
2035
|
}
|
|
2036
2036
|
|
|
2037
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
2037
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/snapshots.mjs
|
|
2038
2038
|
var NATIVE_SNAPSHOT_PREFIXES = {
|
|
2039
2039
|
e2b: "E2B_SANDBOX_SNAPSHOT_V1\n",
|
|
2040
2040
|
modal_snapshot_directory: "MODAL_SANDBOX_DIR_SNAPSHOT_V1\n",
|
|
@@ -2076,10 +2076,10 @@ function decodeNativeSnapshotRef(data) {
|
|
|
2076
2076
|
return void 0;
|
|
2077
2077
|
}
|
|
2078
2078
|
|
|
2079
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
2079
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/mounts.mjs
|
|
2080
2080
|
import { createHash } from "crypto";
|
|
2081
2081
|
|
|
2082
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
2082
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/inContainerMounts.mjs
|
|
2083
2083
|
var DEFAULT_PACKAGE_MANAGERS = ["apt"];
|
|
2084
2084
|
var SAFE_PIDFILE_KILL_FUNCTION = String.raw`openai_agents_kill_pidfile() {
|
|
2085
2085
|
pidfile=$1
|
|
@@ -2699,7 +2699,7 @@ function normalizeBoxRemotePath(path) {
|
|
|
2699
2699
|
return path?.replace(/^\/+/gu, "") ?? "";
|
|
2700
2700
|
}
|
|
2701
2701
|
|
|
2702
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
2702
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/mounts.mjs
|
|
2703
2703
|
var GCSFUSE_VERSION = "3.4.4";
|
|
2704
2704
|
var GCSFUSE_AMD64_DEB_SHA256 = "406945ecc736e8cf0eee92a617fd4a038d138c9c31e48980b99862a5f1f55bb5";
|
|
2705
2705
|
var GCSFUSE_ARM64_DEB_SHA256 = "8587fe2ee274075d8ec5a363e32761bc523a72c531922a69dd35035a371fdf3a";
|
|
@@ -3157,7 +3157,7 @@ function safeId(value) {
|
|
|
3157
3157
|
return createHash("sha256").update(value).digest("hex");
|
|
3158
3158
|
}
|
|
3159
3159
|
|
|
3160
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
3160
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/sandbox.mjs
|
|
3161
3161
|
var BLAXEL_AUTOGENERATED_NAME_CREATE_ATTEMPTS = 5;
|
|
3162
3162
|
var BLAXEL_NON_RESUMABLE_SANDBOX_STATUSES = /* @__PURE__ */ new Set([
|
|
3163
3163
|
"DEACTIVATING",
|
|
@@ -4292,7 +4292,7 @@ var blaxelProvider = {
|
|
|
4292
4292
|
}
|
|
4293
4293
|
};
|
|
4294
4294
|
|
|
4295
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
4295
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/cloudflare/mounts.mjs
|
|
4296
4296
|
function buildCloudflareBucketMountConfig(mount) {
|
|
4297
4297
|
if (isS3Mount(mount)) {
|
|
4298
4298
|
const accessKeyId = readOptionalString(mount, "accessKeyId");
|
|
@@ -4428,7 +4428,7 @@ function validateCredentialPair4(args) {
|
|
|
4428
4428
|
});
|
|
4429
4429
|
}
|
|
4430
4430
|
|
|
4431
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
4431
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/cloudflare/sandbox.mjs
|
|
4432
4432
|
var CloudflareSandboxSession = class {
|
|
4433
4433
|
state;
|
|
4434
4434
|
apiKey;
|
|
@@ -4651,7 +4651,7 @@ var CloudflareSandboxSession = class {
|
|
|
4651
4651
|
async materializeEntry(args) {
|
|
4652
4652
|
assertSandboxEntryMetadataSupported("CloudflareSandboxClient", args.path, args.entry, MOUNT_MANIFEST_METADATA_SUPPORT);
|
|
4653
4653
|
if (entryContainsLocalSource(args.entry)) {
|
|
4654
|
-
const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-
|
|
4654
|
+
const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-BXHBKGF4.js");
|
|
4655
4655
|
await applyLocalSourceManifestEntryToState2(this.state, args.path, args.entry, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(args.runAs));
|
|
4656
4656
|
return;
|
|
4657
4657
|
}
|
|
@@ -4662,7 +4662,7 @@ var CloudflareSandboxSession = class {
|
|
|
4662
4662
|
assertSandboxManifestMetadataSupported("CloudflareSandboxClient", manifest, MOUNT_MANIFEST_METADATA_SUPPORT);
|
|
4663
4663
|
assertCloudflareManifestMountsSupported(manifest);
|
|
4664
4664
|
if (manifestContainsLocalSource(manifest)) {
|
|
4665
|
-
const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-
|
|
4665
|
+
const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-BXHBKGF4.js");
|
|
4666
4666
|
await applyLocalSourceManifestToState2(this.state, manifest, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(runAs));
|
|
4667
4667
|
return;
|
|
4668
4668
|
}
|
|
@@ -5581,12 +5581,12 @@ var cloudflareProvider = {
|
|
|
5581
5581
|
}
|
|
5582
5582
|
};
|
|
5583
5583
|
|
|
5584
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
5584
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/daytona/mounts.mjs
|
|
5585
5585
|
function isDaytonaCloudBucketMountEntry(entry) {
|
|
5586
5586
|
return isRcloneCloudBucketMountEntry(entry, "daytona_cloud_bucket");
|
|
5587
5587
|
}
|
|
5588
5588
|
|
|
5589
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
5589
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/daytona/sandbox.mjs
|
|
5590
5590
|
var DEFAULT_WORKSPACE_ROOT = "/home/daytona/workspace";
|
|
5591
5591
|
var DEFAULT_EXPOSED_PORT_URL_TTL_S = 60;
|
|
5592
5592
|
var DAYTONA_DELETE_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
@@ -10672,12 +10672,12 @@ var dockerProvider = {
|
|
|
10672
10672
|
}
|
|
10673
10673
|
};
|
|
10674
10674
|
|
|
10675
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
10675
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/e2b/mounts.mjs
|
|
10676
10676
|
function isE2BCloudBucketMountEntry(entry) {
|
|
10677
10677
|
return isRcloneCloudBucketMountEntry(entry, "e2b_cloud_bucket");
|
|
10678
10678
|
}
|
|
10679
10679
|
|
|
10680
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
10680
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/e2b/sandbox.mjs
|
|
10681
10681
|
var E2BSandboxSession = class extends RemoteSandboxSessionBase {
|
|
10682
10682
|
sandbox;
|
|
10683
10683
|
ptyProcesses = new PtyProcessRegistry();
|
|
@@ -11459,10 +11459,10 @@ var localProvider = {
|
|
|
11459
11459
|
}
|
|
11460
11460
|
};
|
|
11461
11461
|
|
|
11462
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
11462
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/modal/sandbox.mjs
|
|
11463
11463
|
import { posix as pathPosix } from "path";
|
|
11464
11464
|
|
|
11465
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
11465
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/modal/mounts.mjs
|
|
11466
11466
|
var ModalCloudBucketMountStrategy = class {
|
|
11467
11467
|
type = "modal_cloud_bucket";
|
|
11468
11468
|
secretName;
|
|
@@ -11646,7 +11646,7 @@ function isGCSMount2(entry) {
|
|
|
11646
11646
|
return entry.type === "gcs_mount";
|
|
11647
11647
|
}
|
|
11648
11648
|
|
|
11649
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
11649
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/modal/sandbox.mjs
|
|
11650
11650
|
var DEFAULT_MODAL_IMAGE_TAG = "debian:bookworm-slim";
|
|
11651
11651
|
var DEFAULT_EXEC_YIELD_TIME_MS2 = 1e4;
|
|
11652
11652
|
var DEFAULT_WRITE_STDIN_YIELD_TIME_MS2 = 250;
|
|
@@ -13068,7 +13068,11 @@ async function terminateModalSandboxAfterTimeout(sandbox) {
|
|
|
13068
13068
|
|
|
13069
13069
|
// src/sandbox/providers/modal.ts
|
|
13070
13070
|
import { effectiveModalIdleTimeoutSeconds } from "@opengeni/config";
|
|
13071
|
+
import {
|
|
13072
|
+
canonicalModalCheckpointProviderBinding
|
|
13073
|
+
} from "@opengeni/contracts";
|
|
13071
13074
|
var MODAL_ORPHAN_SWEEP_LIMIT = 50;
|
|
13075
|
+
var OPENGENI_MODAL_SDK_VERSION = "0.9.0";
|
|
13072
13076
|
var MODAL_UNATTRIBUTED_ORPHAN_GRACE_MS = 2 * 6e4;
|
|
13073
13077
|
function modalSandboxAttributionEnvironment(input) {
|
|
13074
13078
|
return {
|
|
@@ -13085,6 +13089,113 @@ function modalSandboxAttributionTags(input) {
|
|
|
13085
13089
|
opengeni_sandbox_group_id: input.sandboxGroupId
|
|
13086
13090
|
};
|
|
13087
13091
|
}
|
|
13092
|
+
var modalRetentionWrappedSessions = /* @__PURE__ */ new WeakSet();
|
|
13093
|
+
var modalFilesystemRetentionWrappedSandboxes = /* @__PURE__ */ new WeakSet();
|
|
13094
|
+
var modalDirectoryRetentionWrappedSandboxes = /* @__PURE__ */ new WeakSet();
|
|
13095
|
+
var MODAL_EXEC_STDIN_WRITE_PATH = "/modal.task_command_router.TaskCommandRouter/TaskExecStdinWrite";
|
|
13096
|
+
var MODAL_EXEC_ALREADY_COMPLETED_DETAILS = /^Exec has already completed; stdin is no longer accepting writes(?: \(Error code: [A-Z0-9]+\))?$/;
|
|
13097
|
+
function isModalExecAlreadyCompletedError(error) {
|
|
13098
|
+
if (!error || typeof error !== "object") return false;
|
|
13099
|
+
const record = error;
|
|
13100
|
+
return record.name === "ClientError" && record.path === MODAL_EXEC_STDIN_WRITE_PATH && record.code === 9 && typeof record.details === "string" && MODAL_EXEC_ALREADY_COMPLETED_DETAILS.test(record.details);
|
|
13101
|
+
}
|
|
13102
|
+
function assertPinnedModalSdk(session) {
|
|
13103
|
+
const actualVersion = session.modal?.version?.();
|
|
13104
|
+
if (actualVersion !== OPENGENI_MODAL_SDK_VERSION) {
|
|
13105
|
+
throw new Error(
|
|
13106
|
+
`OpenGeni Modal snapshot compatibility requires modal@${OPENGENI_MODAL_SDK_VERSION}; the active session reported ${actualVersion ?? "no version"}`
|
|
13107
|
+
);
|
|
13108
|
+
}
|
|
13109
|
+
}
|
|
13110
|
+
function installModalNativeSnapshotRetention(session) {
|
|
13111
|
+
const persistence = session.state?.workspacePersistence;
|
|
13112
|
+
if (persistence !== "snapshot_filesystem" && persistence !== "snapshot_directory") {
|
|
13113
|
+
return;
|
|
13114
|
+
}
|
|
13115
|
+
const sandbox = session.sandbox;
|
|
13116
|
+
if (!sandbox || typeof sandbox !== "object") {
|
|
13117
|
+
throw new Error(`Modal ${persistence} persistence has no active provider sandbox`);
|
|
13118
|
+
}
|
|
13119
|
+
if (persistence === "snapshot_filesystem") {
|
|
13120
|
+
if (modalFilesystemRetentionWrappedSandboxes.has(sandbox)) return;
|
|
13121
|
+
const snapshotFilesystem = sandbox.snapshotFilesystem;
|
|
13122
|
+
if (typeof snapshotFilesystem !== "function") {
|
|
13123
|
+
throw new Error("Modal snapshot_filesystem persistence is unavailable");
|
|
13124
|
+
}
|
|
13125
|
+
sandbox.snapshotFilesystem = async (legacyParams) => {
|
|
13126
|
+
if (legacyParams !== void 0 && typeof legacyParams !== "number") {
|
|
13127
|
+
throw new Error("Unexpected Modal snapshot_filesystem adapter call shape");
|
|
13128
|
+
}
|
|
13129
|
+
return await snapshotFilesystem.call(sandbox, {
|
|
13130
|
+
...legacyParams === void 0 ? {} : { timeoutMs: legacyParams },
|
|
13131
|
+
ttlMs: null
|
|
13132
|
+
});
|
|
13133
|
+
};
|
|
13134
|
+
modalFilesystemRetentionWrappedSandboxes.add(sandbox);
|
|
13135
|
+
return;
|
|
13136
|
+
}
|
|
13137
|
+
if (modalDirectoryRetentionWrappedSandboxes.has(sandbox)) return;
|
|
13138
|
+
const snapshotDirectory = sandbox.snapshotDirectory;
|
|
13139
|
+
if (typeof snapshotDirectory !== "function") {
|
|
13140
|
+
throw new Error("Modal snapshot_directory persistence is unavailable");
|
|
13141
|
+
}
|
|
13142
|
+
sandbox.snapshotDirectory = async (path, legacyParams) => {
|
|
13143
|
+
if (typeof path !== "string" || legacyParams !== void 0) {
|
|
13144
|
+
throw new Error("Unexpected Modal snapshot_directory adapter call shape");
|
|
13145
|
+
}
|
|
13146
|
+
return await snapshotDirectory.call(sandbox, path, {
|
|
13147
|
+
...session.state?.snapshotFilesystemTimeoutMs === void 0 ? {} : { timeoutMs: session.state.snapshotFilesystemTimeoutMs },
|
|
13148
|
+
ttlMs: null
|
|
13149
|
+
});
|
|
13150
|
+
};
|
|
13151
|
+
modalDirectoryRetentionWrappedSandboxes.add(sandbox);
|
|
13152
|
+
}
|
|
13153
|
+
function installModalExecCompletionRecovery(session) {
|
|
13154
|
+
const writeStdin = session.writeStdin;
|
|
13155
|
+
if (typeof writeStdin !== "function") return;
|
|
13156
|
+
session.writeStdin = async (args) => {
|
|
13157
|
+
try {
|
|
13158
|
+
return await writeStdin.call(session, args);
|
|
13159
|
+
} catch (error) {
|
|
13160
|
+
if (!isModalExecAlreadyCompletedError(error) || !Number.isSafeInteger(args.sessionId) || args.sessionId <= 0) {
|
|
13161
|
+
throw error;
|
|
13162
|
+
}
|
|
13163
|
+
try {
|
|
13164
|
+
return await writeStdin.call(session, { ...args, chars: "" });
|
|
13165
|
+
} catch {
|
|
13166
|
+
return `write_stdin failed: session not found: ${args.sessionId}`;
|
|
13167
|
+
}
|
|
13168
|
+
}
|
|
13169
|
+
};
|
|
13170
|
+
}
|
|
13171
|
+
function installOpenGeniModalSnapshotPolicy(session) {
|
|
13172
|
+
const mutable = session;
|
|
13173
|
+
if (modalRetentionWrappedSessions.has(session)) return session;
|
|
13174
|
+
if (typeof mutable.persistWorkspace !== "function") {
|
|
13175
|
+
throw new Error("Modal session does not expose workspace persistence");
|
|
13176
|
+
}
|
|
13177
|
+
assertPinnedModalSdk(mutable);
|
|
13178
|
+
installModalNativeSnapshotRetention(mutable);
|
|
13179
|
+
installModalExecCompletionRecovery(mutable);
|
|
13180
|
+
const persistWorkspace = mutable.persistWorkspace.bind(session);
|
|
13181
|
+
mutable.persistWorkspace = async () => {
|
|
13182
|
+
assertPinnedModalSdk(mutable);
|
|
13183
|
+
installModalNativeSnapshotRetention(mutable);
|
|
13184
|
+
return await persistWorkspace();
|
|
13185
|
+
};
|
|
13186
|
+
modalRetentionWrappedSessions.add(session);
|
|
13187
|
+
return session;
|
|
13188
|
+
}
|
|
13189
|
+
var OpenGeniModalSandboxClient = class extends ModalSandboxClient {
|
|
13190
|
+
async create(args, manifestOptions) {
|
|
13191
|
+
const session = await super.create(args, manifestOptions);
|
|
13192
|
+
return installOpenGeniModalSnapshotPolicy(session);
|
|
13193
|
+
}
|
|
13194
|
+
async resume(state) {
|
|
13195
|
+
const session = await super.resume(state);
|
|
13196
|
+
return installOpenGeniModalSnapshotPolicy(session);
|
|
13197
|
+
}
|
|
13198
|
+
};
|
|
13088
13199
|
var modalProvider = {
|
|
13089
13200
|
backend: "modal",
|
|
13090
13201
|
descriptor: CAPABILITY_DESCRIPTORS.modal,
|
|
@@ -13129,7 +13240,7 @@ var modalProvider = {
|
|
|
13129
13240
|
if (settings.modalEnvironment) {
|
|
13130
13241
|
options.environment = settings.modalEnvironment;
|
|
13131
13242
|
}
|
|
13132
|
-
return new
|
|
13243
|
+
return new OpenGeniModalSandboxClient(options);
|
|
13133
13244
|
}
|
|
13134
13245
|
};
|
|
13135
13246
|
var defaultModalLoader = () => import("modal");
|
|
@@ -13187,14 +13298,148 @@ function modalClientOptions(settings) {
|
|
|
13187
13298
|
return {
|
|
13188
13299
|
...settings.modalTokenId ? { tokenId: settings.modalTokenId } : {},
|
|
13189
13300
|
...settings.modalTokenSecret ? { tokenSecret: settings.modalTokenSecret } : {},
|
|
13190
|
-
...settings.modalEnvironment ? { environment: settings.modalEnvironment } : {}
|
|
13191
|
-
...settings.modalTimeoutSeconds ? { timeoutMs: settings.modalTimeoutSeconds * 1e3 } : {}
|
|
13301
|
+
...settings.modalEnvironment ? { environment: settings.modalEnvironment } : {}
|
|
13192
13302
|
};
|
|
13193
13303
|
}
|
|
13194
13304
|
async function createModalClient(settings) {
|
|
13195
13305
|
const modal = await import("modal");
|
|
13196
13306
|
return new modal.ModalClient(modalClientOptions(settings));
|
|
13197
13307
|
}
|
|
13308
|
+
function isModalNotFoundError(error) {
|
|
13309
|
+
const candidate = error;
|
|
13310
|
+
return candidate?.name === "NotFoundError" || candidate?.code === 5;
|
|
13311
|
+
}
|
|
13312
|
+
async function modalCheckpointProviderBindingForClient(settings, modal) {
|
|
13313
|
+
const identity = await modal.cpClient.workspaceNameLookup({});
|
|
13314
|
+
const workspaceName = identity.workspaceName || identity.username;
|
|
13315
|
+
if (!workspaceName) {
|
|
13316
|
+
throw new Error("Modal credential resolved no workspace identity");
|
|
13317
|
+
}
|
|
13318
|
+
const resolved = canonicalModalCheckpointProviderBinding({
|
|
13319
|
+
version: 1,
|
|
13320
|
+
serverUrl: modal.profile.serverUrl,
|
|
13321
|
+
workspaceName,
|
|
13322
|
+
// Resolve through the authenticated client, not the optional OpenGeni
|
|
13323
|
+
// override alone. When the override is absent Modal may select a profile
|
|
13324
|
+
// environment; persisting "" would fail to fence a later profile change.
|
|
13325
|
+
environment: modal.environmentName(settings.modalEnvironment)
|
|
13326
|
+
});
|
|
13327
|
+
if (!resolved) {
|
|
13328
|
+
throw new Error("Modal credential resolved an invalid checkpoint provider identity");
|
|
13329
|
+
}
|
|
13330
|
+
return resolved.binding;
|
|
13331
|
+
}
|
|
13332
|
+
var modalSessionCheckpointBindings = /* @__PURE__ */ new WeakMap();
|
|
13333
|
+
async function resolveModalCheckpointProviderBindingForSession(settings, session) {
|
|
13334
|
+
if (!session || typeof session !== "object") {
|
|
13335
|
+
throw new Error("Modal checkpoint session identity is unavailable");
|
|
13336
|
+
}
|
|
13337
|
+
const cached = modalSessionCheckpointBindings.get(session);
|
|
13338
|
+
if (cached) return await cached;
|
|
13339
|
+
const modal = session.modal;
|
|
13340
|
+
if (!modal || typeof modal.cpClient?.workspaceNameLookup !== "function" || typeof modal.profile?.serverUrl !== "string" || typeof modal.environmentName !== "function") {
|
|
13341
|
+
throw new Error("Pinned Modal session no longer exposes its authenticated checkpoint identity");
|
|
13342
|
+
}
|
|
13343
|
+
const pending = modalCheckpointProviderBindingForClient(settings, modal).then(
|
|
13344
|
+
(binding) => canonicalModalCheckpointProviderBinding(binding)
|
|
13345
|
+
);
|
|
13346
|
+
modalSessionCheckpointBindings.set(session, pending);
|
|
13347
|
+
try {
|
|
13348
|
+
return await pending;
|
|
13349
|
+
} catch (error) {
|
|
13350
|
+
modalSessionCheckpointBindings.delete(session);
|
|
13351
|
+
throw error;
|
|
13352
|
+
}
|
|
13353
|
+
}
|
|
13354
|
+
async function modalSessionMatchesCheckpointProviderBinding(settings, session, expectedBindingKey) {
|
|
13355
|
+
const identity = await resolveModalCheckpointProviderBindingForSession(settings, session);
|
|
13356
|
+
return identity.key === expectedBindingKey;
|
|
13357
|
+
}
|
|
13358
|
+
async function resolveModalCheckpointProviderBinding(settings, createClient = createModalClient) {
|
|
13359
|
+
const modal = await createClient(settings);
|
|
13360
|
+
try {
|
|
13361
|
+
const binding = await modalCheckpointProviderBindingForClient(settings, modal);
|
|
13362
|
+
return canonicalModalCheckpointProviderBinding(binding);
|
|
13363
|
+
} finally {
|
|
13364
|
+
modal.close();
|
|
13365
|
+
}
|
|
13366
|
+
}
|
|
13367
|
+
async function resolveModalCheckpointProviderBindingForLiveSandbox(settings, sandboxId, createClient = createModalClient) {
|
|
13368
|
+
if (!sandboxId) throw new Error("Modal live-sandbox identity requires a sandbox id");
|
|
13369
|
+
const modal = await createClient(settings);
|
|
13370
|
+
try {
|
|
13371
|
+
const binding = await modalCheckpointProviderBindingForClient(settings, modal);
|
|
13372
|
+
const sandbox = await modal.sandboxes.fromId(sandboxId);
|
|
13373
|
+
const exitCode = await sandbox.poll();
|
|
13374
|
+
if (exitCode !== null) {
|
|
13375
|
+
throw new Error(`Modal sandbox ${sandboxId} is no longer running`);
|
|
13376
|
+
}
|
|
13377
|
+
return canonicalModalCheckpointProviderBinding(binding);
|
|
13378
|
+
} finally {
|
|
13379
|
+
modal.close();
|
|
13380
|
+
}
|
|
13381
|
+
}
|
|
13382
|
+
async function inspectModalSandboxLifecycle(settings, sandboxId, expectedBindingKey, createClient = createModalClient) {
|
|
13383
|
+
if (!sandboxId) throw new Error("Modal lifecycle inspection requires a sandbox id");
|
|
13384
|
+
const modal = await createClient(settings);
|
|
13385
|
+
try {
|
|
13386
|
+
const binding = canonicalModalCheckpointProviderBinding(
|
|
13387
|
+
await modalCheckpointProviderBindingForClient(settings, modal)
|
|
13388
|
+
);
|
|
13389
|
+
if (expectedBindingKey && binding.key !== expectedBindingKey) {
|
|
13390
|
+
throw new Error(
|
|
13391
|
+
"Modal lifecycle inspection refused because the configured credential workspace changed"
|
|
13392
|
+
);
|
|
13393
|
+
}
|
|
13394
|
+
try {
|
|
13395
|
+
const sandbox = await modal.sandboxes.fromId(sandboxId);
|
|
13396
|
+
const exitCode = await sandbox.poll();
|
|
13397
|
+
return exitCode === null ? {
|
|
13398
|
+
status: "running",
|
|
13399
|
+
providerBindingKey: binding.key,
|
|
13400
|
+
providerBinding: binding.binding
|
|
13401
|
+
} : {
|
|
13402
|
+
status: "terminated",
|
|
13403
|
+
exitCode,
|
|
13404
|
+
providerBindingKey: binding.key,
|
|
13405
|
+
providerBinding: binding.binding
|
|
13406
|
+
};
|
|
13407
|
+
} catch (error) {
|
|
13408
|
+
if (isModalNotFoundError(error)) {
|
|
13409
|
+
return {
|
|
13410
|
+
status: "not_found",
|
|
13411
|
+
providerBindingKey: binding.key,
|
|
13412
|
+
providerBinding: binding.binding
|
|
13413
|
+
};
|
|
13414
|
+
}
|
|
13415
|
+
throw error;
|
|
13416
|
+
}
|
|
13417
|
+
} finally {
|
|
13418
|
+
modal.close();
|
|
13419
|
+
}
|
|
13420
|
+
}
|
|
13421
|
+
async function deleteModalCheckpointSnapshot(settings, expectedBindingKey, snapshotId, createClient = createModalClient) {
|
|
13422
|
+
if (!snapshotId) throw new Error("Modal checkpoint deletion requires a snapshot id");
|
|
13423
|
+
const modal = await createClient(settings);
|
|
13424
|
+
try {
|
|
13425
|
+
const binding = await modalCheckpointProviderBindingForClient(settings, modal);
|
|
13426
|
+
const identity = canonicalModalCheckpointProviderBinding(binding);
|
|
13427
|
+
if (expectedBindingKey !== identity.key) {
|
|
13428
|
+
throw new Error(
|
|
13429
|
+
"Modal checkpoint deletion refused because the configured credential workspace changed"
|
|
13430
|
+
);
|
|
13431
|
+
}
|
|
13432
|
+
try {
|
|
13433
|
+
await modal.images.delete(snapshotId);
|
|
13434
|
+
return "deleted";
|
|
13435
|
+
} catch (error) {
|
|
13436
|
+
if (isModalNotFoundError(error)) return "not_found";
|
|
13437
|
+
throw error;
|
|
13438
|
+
}
|
|
13439
|
+
} finally {
|
|
13440
|
+
modal.close();
|
|
13441
|
+
}
|
|
13442
|
+
}
|
|
13198
13443
|
async function tagModalSandbox(settings, sandboxId, attribution) {
|
|
13199
13444
|
if (!sandboxId) {
|
|
13200
13445
|
return false;
|
|
@@ -13369,15 +13614,15 @@ var noneProvider = {
|
|
|
13369
13614
|
}
|
|
13370
13615
|
};
|
|
13371
13616
|
|
|
13372
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
13617
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/runloop/sandbox.mjs
|
|
13373
13618
|
import { posix as pathPosix2 } from "path";
|
|
13374
13619
|
|
|
13375
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
13620
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/runloop/mounts.mjs
|
|
13376
13621
|
function isRunloopCloudBucketMountEntry(entry) {
|
|
13377
13622
|
return isRcloneCloudBucketMountEntry(entry, "runloop_cloud_bucket");
|
|
13378
13623
|
}
|
|
13379
13624
|
|
|
13380
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
13625
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/runloop/sandbox.mjs
|
|
13381
13626
|
var DEFAULT_RUNLOOP_WORKSPACE_ROOT = "/home/user";
|
|
13382
13627
|
var DEFAULT_RUNLOOP_ROOT_WORKSPACE_ROOT = "/root";
|
|
13383
13628
|
var UNKNOWN_RUNLOOP_EXIT_CODE = 1;
|
|
@@ -15960,10 +16205,11 @@ var SelfhostedSession = class {
|
|
|
15960
16205
|
}
|
|
15961
16206
|
}
|
|
15962
16207
|
}
|
|
15963
|
-
/** The clamped exec process deadline (ms): the exec-specific budget
|
|
15964
|
-
* else the control timeout.
|
|
15965
|
-
*
|
|
15966
|
-
|
|
16208
|
+
/** The effective clamped exec process deadline (ms): the exec-specific budget
|
|
16209
|
+
* when threaded, else the control timeout. Public so adapters that project a
|
|
16210
|
+
* structured command receipt can report the exact deadline the agent enforces
|
|
16211
|
+
* instead of repeating (and potentially drifting from) this normalization. */
|
|
16212
|
+
get effectiveExecDeadlineMs() {
|
|
15967
16213
|
return Math.max(
|
|
15968
16214
|
1,
|
|
15969
16215
|
Math.min(Math.trunc(this.execTimeoutMs ?? this.timeoutMs), SELFHOSTED_MAX_EXEC_TIMEOUT_MS)
|
|
@@ -15971,7 +16217,7 @@ var SelfhostedSession = class {
|
|
|
15971
16217
|
}
|
|
15972
16218
|
/** Channel-A `exec`: run a command on the machine and return its output. */
|
|
15973
16219
|
async exec(args) {
|
|
15974
|
-
const executionTimeoutMs = this.
|
|
16220
|
+
const executionTimeoutMs = this.effectiveExecDeadlineMs;
|
|
15975
16221
|
const execReq = {
|
|
15976
16222
|
// The agent does NOT shell-interpret unless `shell` — Channel-A passes a
|
|
15977
16223
|
// single shell command string, so run it through the platform shell.
|
|
@@ -16100,7 +16346,7 @@ var SelfhostedSession = class {
|
|
|
16100
16346
|
async execCommand(args) {
|
|
16101
16347
|
const result = await this.exec({ cmd: args.cmd, workdir: args.workdir, runAs: args.runAs });
|
|
16102
16348
|
if (result.timedOut) {
|
|
16103
|
-
const hint = execDeadlineHint(Math.round(this.
|
|
16349
|
+
const hint = execDeadlineHint(Math.round(this.effectiveExecDeadlineMs / 1e3));
|
|
16104
16350
|
return result.output ? `${result.output}
|
|
16105
16351
|
${hint}` : hint;
|
|
16106
16352
|
}
|
|
@@ -16616,7 +16862,7 @@ var selfhostedProvider = {
|
|
|
16616
16862
|
}
|
|
16617
16863
|
};
|
|
16618
16864
|
|
|
16619
|
-
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+
|
|
16865
|
+
// ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/vercel/sandbox.mjs
|
|
16620
16866
|
var DEFAULT_VERCEL_WORKSPACE_ROOT = "/vercel/sandbox";
|
|
16621
16867
|
var VercelSandboxSession = class _VercelSandboxSession extends RemoteSandboxSessionBase {
|
|
16622
16868
|
sandbox;
|
|
@@ -17612,7 +17858,99 @@ function isProviderSandboxTransientError(backendId, error) {
|
|
|
17612
17858
|
|
|
17613
17859
|
// src/sandbox/workspace-archive.ts
|
|
17614
17860
|
import { createHash as createHash4 } from "crypto";
|
|
17615
|
-
|
|
17861
|
+
import {
|
|
17862
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
17863
|
+
decodeNativeSnapshotRef as decodeNativeSnapshotRef2,
|
|
17864
|
+
parseWorkspaceArchiveDescriptor
|
|
17865
|
+
} from "@opengeni/contracts";
|
|
17866
|
+
|
|
17867
|
+
// src/sandbox/provider-operation-gate.ts
|
|
17868
|
+
var providerOperationGates = /* @__PURE__ */ new WeakMap();
|
|
17869
|
+
function sessionIdentity(session) {
|
|
17870
|
+
const identityType = typeof session;
|
|
17871
|
+
if (!["object", "function"].includes(identityType) || session === null) {
|
|
17872
|
+
throw new Error("Sandbox provider operation has no session identity");
|
|
17873
|
+
}
|
|
17874
|
+
return session;
|
|
17875
|
+
}
|
|
17876
|
+
function gateFor(session) {
|
|
17877
|
+
const existing = providerOperationGates.get(session);
|
|
17878
|
+
if (existing) return existing;
|
|
17879
|
+
const created = {
|
|
17880
|
+
activeOperations: 0,
|
|
17881
|
+
captureActive: false,
|
|
17882
|
+
operationWaiters: [],
|
|
17883
|
+
captureWaiters: []
|
|
17884
|
+
};
|
|
17885
|
+
providerOperationGates.set(session, created);
|
|
17886
|
+
return created;
|
|
17887
|
+
}
|
|
17888
|
+
async function enterOperation(gate) {
|
|
17889
|
+
if (!gate.captureActive && gate.captureWaiters.length === 0) {
|
|
17890
|
+
gate.activeOperations += 1;
|
|
17891
|
+
return;
|
|
17892
|
+
}
|
|
17893
|
+
await new Promise((resolve5) => gate.operationWaiters.push(resolve5));
|
|
17894
|
+
}
|
|
17895
|
+
function leaveOperation(gate) {
|
|
17896
|
+
gate.activeOperations -= 1;
|
|
17897
|
+
if (gate.activeOperations < 0) {
|
|
17898
|
+
throw new Error("Sandbox provider operation gate underflow");
|
|
17899
|
+
}
|
|
17900
|
+
if (gate.activeOperations === 0) {
|
|
17901
|
+
const nextCapture = gate.captureWaiters.shift();
|
|
17902
|
+
if (nextCapture) {
|
|
17903
|
+
gate.captureActive = true;
|
|
17904
|
+
nextCapture();
|
|
17905
|
+
}
|
|
17906
|
+
}
|
|
17907
|
+
}
|
|
17908
|
+
async function enterCapture(gate) {
|
|
17909
|
+
if (!gate.captureActive && gate.activeOperations === 0) {
|
|
17910
|
+
gate.captureActive = true;
|
|
17911
|
+
return;
|
|
17912
|
+
}
|
|
17913
|
+
await new Promise((resolve5) => gate.captureWaiters.push(resolve5));
|
|
17914
|
+
}
|
|
17915
|
+
function leaveCapture(gate) {
|
|
17916
|
+
if (!gate.captureActive) {
|
|
17917
|
+
throw new Error("Sandbox provider capture gate was not held");
|
|
17918
|
+
}
|
|
17919
|
+
const nextCapture = gate.captureWaiters.shift();
|
|
17920
|
+
if (nextCapture) {
|
|
17921
|
+
nextCapture();
|
|
17922
|
+
return;
|
|
17923
|
+
}
|
|
17924
|
+
gate.captureActive = false;
|
|
17925
|
+
const operations = gate.operationWaiters.splice(0);
|
|
17926
|
+
gate.activeOperations += operations.length;
|
|
17927
|
+
for (const operation of operations) operation();
|
|
17928
|
+
}
|
|
17929
|
+
async function withSandboxProviderOperation(session, operation) {
|
|
17930
|
+
const gate = gateFor(sessionIdentity(session));
|
|
17931
|
+
await enterOperation(gate);
|
|
17932
|
+
try {
|
|
17933
|
+
return await operation();
|
|
17934
|
+
} finally {
|
|
17935
|
+
leaveOperation(gate);
|
|
17936
|
+
}
|
|
17937
|
+
}
|
|
17938
|
+
async function withSandboxProviderCapture(session, capture) {
|
|
17939
|
+
const gate = gateFor(sessionIdentity(session));
|
|
17940
|
+
await enterCapture(gate);
|
|
17941
|
+
try {
|
|
17942
|
+
return await capture();
|
|
17943
|
+
} finally {
|
|
17944
|
+
leaveCapture(gate);
|
|
17945
|
+
}
|
|
17946
|
+
}
|
|
17947
|
+
|
|
17948
|
+
// src/sandbox/workspace-archive.ts
|
|
17949
|
+
import {
|
|
17950
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION as WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION2,
|
|
17951
|
+
decodeNativeSnapshotRef as decodeNativeSnapshotRef3,
|
|
17952
|
+
parseWorkspaceArchiveDescriptor as parseWorkspaceArchiveDescriptor2
|
|
17953
|
+
} from "@opengeni/contracts";
|
|
17616
17954
|
var WorkspaceArchiveIntegrityError = class extends Error {
|
|
17617
17955
|
constructor(code, message, options = {}) {
|
|
17618
17956
|
super(message);
|
|
@@ -17622,23 +17960,9 @@ var WorkspaceArchiveIntegrityError = class extends Error {
|
|
|
17622
17960
|
name = "WorkspaceArchiveIntegrityError";
|
|
17623
17961
|
retryable;
|
|
17624
17962
|
};
|
|
17625
|
-
var SHA256 = /^[a-f0-9]{64}$/;
|
|
17626
|
-
var REVISION = /^wa1:[0-9]{13}:[a-f0-9]{64}$/;
|
|
17627
17963
|
function sha256(bytes) {
|
|
17628
17964
|
return createHash4("sha256").update(bytes).digest("hex");
|
|
17629
17965
|
}
|
|
17630
|
-
function nonnegativeInteger(value) {
|
|
17631
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
17632
|
-
}
|
|
17633
|
-
function parseWorkspaceArchiveDescriptor(value) {
|
|
17634
|
-
if (!value || typeof value !== "object") return null;
|
|
17635
|
-
const candidate = value;
|
|
17636
|
-
const workspace = candidate.workspace;
|
|
17637
|
-
if (candidate.version !== WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION || typeof candidate.revision !== "string" || !REVISION.test(candidate.revision) || typeof candidate.archiveSha256 !== "string" || !SHA256.test(candidate.archiveSha256) || !nonnegativeInteger(candidate.archiveBytes) || candidate.archiveBytes === 0 || typeof candidate.capturedAt !== "string" || !Number.isFinite(Date.parse(candidate.capturedAt)) || !workspace || workspace.algorithm !== "sha256" || typeof workspace.sha256 !== "string" || !SHA256.test(workspace.sha256) || !nonnegativeInteger(workspace.entryCount) || !nonnegativeInteger(workspace.fileCount) || !nonnegativeInteger(workspace.totalFileBytes)) {
|
|
17638
|
-
return null;
|
|
17639
|
-
}
|
|
17640
|
-
return candidate;
|
|
17641
|
-
}
|
|
17642
17966
|
function decodeBase64Strict(value) {
|
|
17643
17967
|
if (value.length === 0 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(value)) {
|
|
17644
17968
|
return null;
|
|
@@ -17646,6 +17970,29 @@ function decodeBase64Strict(value) {
|
|
|
17646
17970
|
const bytes = Uint8Array.from(Buffer.from(value, "base64"));
|
|
17647
17971
|
return Buffer.from(bytes).toString("base64") === value ? bytes : null;
|
|
17648
17972
|
}
|
|
17973
|
+
function describeNativeSnapshotArchive(bytes, capturedAtMs = Date.now()) {
|
|
17974
|
+
const native = decodeNativeSnapshotRef2(bytes);
|
|
17975
|
+
if (!native) return null;
|
|
17976
|
+
const archiveSha256 = sha256(bytes);
|
|
17977
|
+
return {
|
|
17978
|
+
version: WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
17979
|
+
kind: "provider_snapshot",
|
|
17980
|
+
revision: `wa2:${String(capturedAtMs).padStart(13, "0")}:${archiveSha256}`,
|
|
17981
|
+
archiveSha256,
|
|
17982
|
+
archiveBytes: bytes.length,
|
|
17983
|
+
capturedAt: new Date(capturedAtMs).toISOString(),
|
|
17984
|
+
provider: native.provider,
|
|
17985
|
+
snapshotId: native.snapshotId,
|
|
17986
|
+
...native.workspacePersistence ? { workspacePersistence: native.workspacePersistence } : {}
|
|
17987
|
+
};
|
|
17988
|
+
}
|
|
17989
|
+
function describeLegacyNativeSnapshotArchive(base642, observedAtMs = Date.now()) {
|
|
17990
|
+
if (typeof base642 !== "string") return null;
|
|
17991
|
+
const bytes = decodeBase64Strict(base642);
|
|
17992
|
+
if (!bytes) return null;
|
|
17993
|
+
const descriptor = describeNativeSnapshotArchive(bytes, observedAtMs);
|
|
17994
|
+
return descriptor ? { archiveBase64: base642, descriptor } : null;
|
|
17995
|
+
}
|
|
17649
17996
|
function readVerifiedWorkspaceArchive(base642, metadata) {
|
|
17650
17997
|
if (base642 === void 0 || base642 === null || base642 === "") return null;
|
|
17651
17998
|
if (typeof base642 !== "string") {
|
|
@@ -17681,7 +18028,27 @@ function readVerifiedWorkspaceArchive(base642, metadata) {
|
|
|
17681
18028
|
`workspace archive revision ${descriptor.revision} failed SHA-256/size verification`
|
|
17682
18029
|
);
|
|
17683
18030
|
}
|
|
17684
|
-
|
|
18031
|
+
const nativeSnapshot = decodeNativeSnapshotRef2(bytes);
|
|
18032
|
+
if (descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION) {
|
|
18033
|
+
if (!nativeSnapshot || nativeSnapshot.provider !== descriptor.provider || nativeSnapshot.snapshotId !== descriptor.snapshotId || nativeSnapshot.workspacePersistence !== descriptor.workspacePersistence) {
|
|
18034
|
+
throw new WorkspaceArchiveIntegrityError(
|
|
18035
|
+
"native_snapshot_reference_invalid",
|
|
18036
|
+
`native snapshot receipt does not match descriptor revision ${descriptor.revision}`
|
|
18037
|
+
);
|
|
18038
|
+
}
|
|
18039
|
+
} else if (nativeSnapshot) {
|
|
18040
|
+
throw new WorkspaceArchiveIntegrityError(
|
|
18041
|
+
"native_snapshot_reference_invalid",
|
|
18042
|
+
`legacy native snapshot receipt ${descriptor.revision} was not durably upgraded to a v2 provider descriptor`
|
|
18043
|
+
);
|
|
18044
|
+
}
|
|
18045
|
+
return {
|
|
18046
|
+
bytes,
|
|
18047
|
+
base64: base642,
|
|
18048
|
+
descriptor,
|
|
18049
|
+
kind: descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION ? "provider_snapshot" : "tar",
|
|
18050
|
+
...descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION && nativeSnapshot ? { nativeSnapshot } : {}
|
|
18051
|
+
};
|
|
17685
18052
|
}
|
|
17686
18053
|
function stdoutFromExecResult(value) {
|
|
17687
18054
|
if (typeof value === "string") {
|
|
@@ -17692,15 +18059,33 @@ function stdoutFromExecResult(value) {
|
|
|
17692
18059
|
const output = value;
|
|
17693
18060
|
return typeof output.stdout === "string" ? output.stdout : typeof output.output === "string" ? output.output : "";
|
|
17694
18061
|
}
|
|
17695
|
-
|
|
17696
|
-
|
|
18062
|
+
function shellQuote3(value) {
|
|
18063
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
18064
|
+
}
|
|
18065
|
+
function workspaceFingerprintExcludes(session) {
|
|
18066
|
+
const paths = session.state?.manifest?.ephemeralPersistencePaths?.();
|
|
18067
|
+
if (!paths) return [];
|
|
18068
|
+
return [...paths].filter((path) => typeof path === "string" && path.length > 0).sort((left, right) => left.localeCompare(right));
|
|
18069
|
+
}
|
|
18070
|
+
function workspaceFingerprintCommand(excludedPaths) {
|
|
18071
|
+
const tarExcludes = excludedPaths.flatMap((path) => [
|
|
18072
|
+
shellQuote3(`--exclude=${path}`),
|
|
18073
|
+
shellQuote3(`--exclude=./${path}`)
|
|
18074
|
+
]);
|
|
18075
|
+
const findExcludes = excludedPaths.flatMap((path) => [
|
|
18076
|
+
`-path ${shellQuote3(`./${path}`)}`,
|
|
18077
|
+
`-path ${shellQuote3(`./${path}/*`)}`
|
|
18078
|
+
]);
|
|
18079
|
+
const findPrefix = findExcludes.length === 0 ? "" : `\\( ${findExcludes.join(" -o ")} \\) -prune -o `;
|
|
18080
|
+
const script = String.raw`set -eu
|
|
17697
18081
|
cd /workspace
|
|
17698
|
-
digest=$(LC_ALL=C tar --sort=name --mtime="@0" --owner=0 --group=0 --numeric-owner --format=gnu -cf - . | sha256sum | awk "{print \$1}")
|
|
17699
|
-
entries=$(find . -xdev -mindepth 1 -printf x | wc -c | tr -d " ")
|
|
17700
|
-
files=$(find . -xdev -type f -printf x | wc -c | tr -d " ")
|
|
17701
|
-
bytes=$(find . -xdev -type f -printf "%s\n" | awk "{s+=\$1} END {printf \"%.0f\", s+0}")
|
|
17702
|
-
printf "OPENGENI_WORKSPACE_FINGERPRINT_V1 %s %s %s %s\n" "$digest" "$entries" "$files" "$bytes"
|
|
17703
|
-
|
|
18082
|
+
digest=$(LC_ALL=C tar ${tarExcludes.join(" ")} --sort=name --mtime="@0" --owner=0 --group=0 --numeric-owner --hard-dereference --format=gnu -cf - . | sha256sum | awk "{print \$1}")
|
|
18083
|
+
entries=$(find . -xdev -mindepth 1 ${findPrefix}-printf x | wc -c | tr -d " ")
|
|
18084
|
+
files=$(find . -xdev ${findPrefix}-type f -printf x | wc -c | tr -d " ")
|
|
18085
|
+
bytes=$(find . -xdev ${findPrefix}-type f -printf "%s\n" | awk "{s+=\$1} END {printf \"%.0f\", s+0}")
|
|
18086
|
+
printf "OPENGENI_WORKSPACE_FINGERPRINT_V1 %s %s %s %s\n" "$digest" "$entries" "$files" "$bytes"`;
|
|
18087
|
+
return `bash -o pipefail -c ${shellQuote3(script)}`;
|
|
18088
|
+
}
|
|
17704
18089
|
async function fingerprintSandboxWorkspace(session) {
|
|
17705
18090
|
const target = session;
|
|
17706
18091
|
const run2 = target.exec ?? target.execCommand;
|
|
@@ -17711,7 +18096,7 @@ async function fingerprintSandboxWorkspace(session) {
|
|
|
17711
18096
|
);
|
|
17712
18097
|
}
|
|
17713
18098
|
const result = await run2.call(target, {
|
|
17714
|
-
cmd:
|
|
18099
|
+
cmd: workspaceFingerprintCommand(workspaceFingerprintExcludes(target)),
|
|
17715
18100
|
yieldTimeMs: 12e4,
|
|
17716
18101
|
maxOutputTokens: 1e3
|
|
17717
18102
|
});
|
|
@@ -17744,6 +18129,11 @@ function fingerprintsEqual(a, b) {
|
|
|
17744
18129
|
return a.sha256 === b.sha256 && a.entryCount === b.entryCount && a.fileCount === b.fileCount && a.totalFileBytes === b.totalFileBytes;
|
|
17745
18130
|
}
|
|
17746
18131
|
async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now()) {
|
|
18132
|
+
return await withSandboxProviderCapture(session, async () => {
|
|
18133
|
+
return await captureVerifiedWorkspaceArchiveExclusive(session, capturedAtMs);
|
|
18134
|
+
});
|
|
18135
|
+
}
|
|
18136
|
+
async function captureVerifiedWorkspaceArchiveExclusive(session, capturedAtMs) {
|
|
17747
18137
|
const target = session;
|
|
17748
18138
|
if (typeof target.persistWorkspace !== "function") {
|
|
17749
18139
|
throw new WorkspaceArchiveIntegrityError(
|
|
@@ -17751,7 +18141,10 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
|
|
|
17751
18141
|
"sandbox session does not support workspace persistence"
|
|
17752
18142
|
);
|
|
17753
18143
|
}
|
|
17754
|
-
const
|
|
18144
|
+
const configuredPersistence = target.state?.workspacePersistence;
|
|
18145
|
+
const configuredTarFallback = workspaceFingerprintExcludes(target).length > 0;
|
|
18146
|
+
const expectsNativeSnapshot = typeof configuredPersistence === "string" && configuredPersistence !== "tar" && !configuredTarFallback;
|
|
18147
|
+
const before = expectsNativeSnapshot ? null : await fingerprintSandboxWorkspace(target);
|
|
17755
18148
|
const bytes = await target.persistWorkspace();
|
|
17756
18149
|
if (!bytes || bytes.length === 0) {
|
|
17757
18150
|
throw new WorkspaceArchiveIntegrityError(
|
|
@@ -17760,8 +18153,25 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
|
|
|
17760
18153
|
{ retryable: true }
|
|
17761
18154
|
);
|
|
17762
18155
|
}
|
|
18156
|
+
const nativeSnapshot = decodeNativeSnapshotRef2(bytes);
|
|
18157
|
+
if (nativeSnapshot) {
|
|
18158
|
+
const descriptor2 = describeNativeSnapshotArchive(bytes, capturedAtMs);
|
|
18159
|
+
return {
|
|
18160
|
+
bytes,
|
|
18161
|
+
base64: Buffer.from(bytes).toString("base64"),
|
|
18162
|
+
descriptor: descriptor2,
|
|
18163
|
+
kind: "provider_snapshot",
|
|
18164
|
+
nativeSnapshot
|
|
18165
|
+
};
|
|
18166
|
+
}
|
|
18167
|
+
if (expectsNativeSnapshot) {
|
|
18168
|
+
throw new WorkspaceArchiveIntegrityError(
|
|
18169
|
+
"native_snapshot_fallback_unverified",
|
|
18170
|
+
`sandbox configured for ${String(configuredPersistence)} returned a tar archive instead of a native snapshot receipt`
|
|
18171
|
+
);
|
|
18172
|
+
}
|
|
17763
18173
|
const after = await fingerprintSandboxWorkspace(target);
|
|
17764
|
-
if (!fingerprintsEqual(before, after)) {
|
|
18174
|
+
if (!before || !fingerprintsEqual(before, after)) {
|
|
17765
18175
|
throw new WorkspaceArchiveIntegrityError(
|
|
17766
18176
|
"workspace_changed_during_capture",
|
|
17767
18177
|
"workspace changed while its durable archive was being captured",
|
|
@@ -17770,7 +18180,7 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
|
|
|
17770
18180
|
}
|
|
17771
18181
|
const archiveSha256 = sha256(bytes);
|
|
17772
18182
|
const descriptor = {
|
|
17773
|
-
version:
|
|
18183
|
+
version: 1,
|
|
17774
18184
|
revision: `wa1:${String(capturedAtMs).padStart(13, "0")}:${archiveSha256}`,
|
|
17775
18185
|
archiveSha256,
|
|
17776
18186
|
archiveBytes: bytes.length,
|
|
@@ -17780,10 +18190,14 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
|
|
|
17780
18190
|
return {
|
|
17781
18191
|
bytes,
|
|
17782
18192
|
base64: Buffer.from(bytes).toString("base64"),
|
|
17783
|
-
descriptor
|
|
18193
|
+
descriptor,
|
|
18194
|
+
kind: "tar"
|
|
17784
18195
|
};
|
|
17785
18196
|
}
|
|
17786
18197
|
async function verifyRestoredWorkspace(session, descriptor) {
|
|
18198
|
+
if (descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION) {
|
|
18199
|
+
return null;
|
|
18200
|
+
}
|
|
17787
18201
|
const actual = await fingerprintSandboxWorkspace(session);
|
|
17788
18202
|
if (!fingerprintsEqual(actual, descriptor.workspace)) {
|
|
17789
18203
|
throw new WorkspaceArchiveIntegrityError(
|
|
@@ -18146,7 +18560,7 @@ function buildDisplayStackScript(options = {}) {
|
|
|
18146
18560
|
const port = options.port ?? DESKTOP_STREAM_PORT4;
|
|
18147
18561
|
const env = `DESKTOP_W=${geometry.width} DESKTOP_H=${geometry.height} DESKTOP_DPI=${geometry.dpi} STREAM_PORT=${port}`;
|
|
18148
18562
|
const lockedLauncher = `ds_started=$1; fw=$2; ds_class=cold; ds_stage() { ds_now=$(date +%s%3N); echo "OPENGENI_DISPLAY_STAGE stage=$1 elapsed_ms=$((ds_now-ds_started)) classification=$ds_class"; }; fa=$(date +%s%3N); fd=$((fa-fw)); [ "$fd" -ge 50 ] && ds_class=contention; ds_stage outer_flock_acquired; ds_stage launcher_issued; env ${env} opengeni-desktop-up; urc=$?; ds_stage launcher_complete; exit "$urc"`;
|
|
18149
|
-
const bringUp = `if nc -z 127.0.0.1 ${port} >/dev/null 2>&1 && nc -z 127.0.0.1 5900 >/dev/null 2>&1; then ds_class=already_ready; ds_stage precheck_ready; echo "OPENGENI_DESKTOP_UP port=${port} geometry=${geometry.width}x${geometry.height} dpi=${geometry.dpi} (precheck)"; else ds_class=cold; ds_stage precheck_miss; mkdir -p /tmp/opengeni-desktop; ds_stage outer_flock_wait; fw=$(date +%s%3N); flock --close --conflict-exit-code 75 --wait 45 /tmp/opengeni-desktop/up.outer.lock bash -c ${
|
|
18563
|
+
const bringUp = `if nc -z 127.0.0.1 ${port} >/dev/null 2>&1 && nc -z 127.0.0.1 5900 >/dev/null 2>&1; then ds_class=already_ready; ds_stage precheck_ready; echo "OPENGENI_DESKTOP_UP port=${port} geometry=${geometry.width}x${geometry.height} dpi=${geometry.dpi} (precheck)"; else ds_class=cold; ds_stage precheck_miss; mkdir -p /tmp/opengeni-desktop; ds_stage outer_flock_wait; fw=$(date +%s%3N); flock --close --conflict-exit-code 75 --wait 45 /tmp/opengeni-desktop/up.outer.lock bash -c ${shellQuote4(lockedLauncher)} _ "$ds_started" "$fw"; frc=$?; if [ "$frc" -eq 75 ]; then ds_stage outer_flock_timeout; echo "OPENGENI_DESKTOP_LOCK_TIMEOUT"; exit 15; fi; if [ "$frc" -ne 0 ]; then exit "$frc"; fi; fi`;
|
|
18150
18564
|
const paintProbe = `ds_stage paint_probe_started; p=/tmp/opengeni-desktop/paint-probe.png; prev=0; for i in $(seq 1 ${PAINT_PROBE_ATTEMPTS}); do if DISPLAY=:0 scrot -o "$p" >/dev/null 2>&1; then sz=$(wc -c < "$p" 2>/dev/null || echo 0); else sz=0; fi; rm -f "$p"; if [ "$sz" -ge ${PAINT_MIN_BYTES} ] && [ "$prev" -ge ${PAINT_MIN_BYTES} ]; then d=$((sz-prev)); [ "$d" -lt 0 ] && d=$((0-d)); if [ "$d" -le ${PAINT_SETTLE_DELTA_BYTES} ]; then ds_stage paint_ready; break; fi; fi; prev=$sz; if [ "$i" = "${PAINT_PROBE_ATTEMPTS}" ]; then ds_stage paint_failed; echo "OPENGENI_DESKTOP_NOT_PAINTING scrot below ${PAINT_MIN_BYTES}B or unsettled after warmup (last=$sz)"; exit 14; fi; sleep ${PAINT_PROBE_INTERVAL_S}; done`;
|
|
18151
18565
|
const trace = `ds_started=$(date +%s%3N); ds_class=unknown; ds_stage() { ds_now=$(date +%s%3N); echo "OPENGENI_DISPLAY_STAGE stage=$1 elapsed_ms=$((ds_now-ds_started)) classification=$ds_class"; }; ds_stage script_entry`;
|
|
18152
18566
|
return `${trace}; mkdir -p /tmp/opengeni-desktop; { ${bringUp} ; } && { ${paintProbe} ; }`;
|
|
@@ -18173,7 +18587,7 @@ function execResultSessionId(result) {
|
|
|
18173
18587
|
const value = result.sessionId ?? result.session_id;
|
|
18174
18588
|
return typeof value === "number" ? value : null;
|
|
18175
18589
|
}
|
|
18176
|
-
function
|
|
18590
|
+
function shellQuote4(value) {
|
|
18177
18591
|
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
18178
18592
|
}
|
|
18179
18593
|
function boundedDisplayStackCommand(command, timeoutMs, markerPath, markerToken) {
|
|
@@ -18185,13 +18599,13 @@ function boundedDisplayStackCommand(command, timeoutMs, markerPath, markerToken)
|
|
|
18185
18599
|
const killAfterMs = Math.max(1, Math.floor(graceMs / 2));
|
|
18186
18600
|
const commandTimeoutSeconds = (commandTimeoutMs / 1e3).toFixed(3);
|
|
18187
18601
|
const killAfterSeconds = (killAfterMs / 1e3).toFixed(3);
|
|
18188
|
-
const managedCommand = `marker=${
|
|
18602
|
+
const managedCommand = `marker=${shellQuote4(markerPath)}; token=${shellQuote4(markerToken)}; cancel="$marker.cancelled"; if [ -e "$cancel" ]; then echo "OPENGENI_DISPLAY_CANCELLED"; exit 124; fi; pid=$$; pgid=$(ps -o pgid= -p "$pid" 2>/dev/null | tr -d ' '); start=$(awk '{print $22}' "/proc/$pid/stat" 2>/dev/null || true); printf '%s %s %s %s\\n' "$pid" "$pgid" "$start" "$token" >"$marker"; if [ -e "$cancel" ]; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CANCELLED"; exit 124; fi; bash -c ${shellQuote4(command)}; rc=$?; rm -f "$marker"; exit "$rc"`;
|
|
18189
18603
|
return (
|
|
18190
18604
|
// Do not use timeout --foreground here. The display command contains flock
|
|
18191
18605
|
// supervisors and launcher children; default process-group mode is required
|
|
18192
18606
|
// so a deadline cannot leave a waiter alive to acquire the lock and launch
|
|
18193
18607
|
// after the caller has already failed.
|
|
18194
|
-
`timeout --signal=TERM --kill-after=${killAfterSeconds}s ${commandTimeoutSeconds}s bash -c ${
|
|
18608
|
+
`timeout --signal=TERM --kill-after=${killAfterSeconds}s ${commandTimeoutSeconds}s bash -c ${shellQuote4(managedCommand)}; rc=$?; if [ "$rc" -eq 124 ]; then echo "OPENGENI_DISPLAY_TIMEOUT elapsed_ms=${commandTimeoutMs}"; fi; exit "$rc"`
|
|
18195
18609
|
);
|
|
18196
18610
|
}
|
|
18197
18611
|
var DisplayStackWallTimeoutError = class extends Error {
|
|
@@ -18426,10 +18840,10 @@ async function beforeDeadline(promise, deadline, now = monotonicNow) {
|
|
|
18426
18840
|
}
|
|
18427
18841
|
}
|
|
18428
18842
|
function displayStackCleanupCommand(markerPath, markerToken) {
|
|
18429
|
-
const marker =
|
|
18430
|
-
const token =
|
|
18843
|
+
const marker = shellQuote4(markerPath);
|
|
18844
|
+
const token = shellQuote4(markerToken);
|
|
18431
18845
|
const script = `marker=${marker}; token=${token}; cancel="$marker.cancelled"; : >"$cancel" || { echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75; }; if [ ! -r "$marker" ]; then echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; read -r pid pgid start actual <"$marker" || { echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75; }; [ "$actual" = "$token" ] || { echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75; }; case "$pid" in ''|*[!0-9]*) echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75;; esac; case "$pgid" in ''|*[!0-9]*) echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75;; esac; case "$start" in ''|*[!0-9]*) echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75;; esac; current=$(awk '{print $22}' "/proc/$pid/stat" 2>/dev/null || true); if [ -z "$current" ] || [ "$current" != "$start" ]; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; kill -TERM -- "-$pgid" 2>/dev/null || true; for i in $(seq 1 10); do if ! kill -0 -- "-$pgid" 2>/dev/null; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; sleep 0.05; done; kill -KILL -- "-$pgid" 2>/dev/null || true; for i in $(seq 1 20); do if ! kill -0 -- "-$pgid" 2>/dev/null; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; sleep 0.05; done; echo "OPENGENI_DISPLAY_CLEANUP status=alive"; exit 75`;
|
|
18432
|
-
return `timeout --signal=TERM --kill-after=0.2s 1.5s bash -c ${
|
|
18846
|
+
return `timeout --signal=TERM --kill-after=0.2s 1.5s bash -c ${shellQuote4(script)}`;
|
|
18433
18847
|
}
|
|
18434
18848
|
async function runProviderCommandToDeadline(session, command, deadline) {
|
|
18435
18849
|
const controller = new AbortController();
|
|
@@ -19173,7 +19587,7 @@ function runCredentialRoot(sessionId) {
|
|
|
19173
19587
|
function runCredentialPointerFile(sessionId) {
|
|
19174
19588
|
return `${runCredentialRoot(sessionId)}/current`;
|
|
19175
19589
|
}
|
|
19176
|
-
function
|
|
19590
|
+
function shellQuote5(value) {
|
|
19177
19591
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
19178
19592
|
}
|
|
19179
19593
|
function base64(value) {
|
|
@@ -19191,8 +19605,8 @@ function portableBase64DecodeCommand() {
|
|
|
19191
19605
|
].join("\n");
|
|
19192
19606
|
}
|
|
19193
19607
|
function pointerLockAcquireCommands(root) {
|
|
19194
|
-
const lockFile =
|
|
19195
|
-
const lockDirectory =
|
|
19608
|
+
const lockFile = shellQuote5(`${root}/.pointer.lock`);
|
|
19609
|
+
const lockDirectory = shellQuote5(`${root}/.pointer.lockdir`);
|
|
19196
19610
|
return [
|
|
19197
19611
|
`if command -v flock >/dev/null 2>&1; then`,
|
|
19198
19612
|
` exec 9>${lockFile}`,
|
|
@@ -19238,7 +19652,7 @@ ${cmd}
|
|
|
19238
19652
|
printf '\\n${COMMAND_OK_MARKER}\\n'`;
|
|
19239
19653
|
const args = {
|
|
19240
19654
|
cmd: `set +x
|
|
19241
|
-
env -u BASH_ENV bash --noprofile --norc -c ${
|
|
19655
|
+
env -u BASH_ENV bash --noprofile --norc -c ${shellQuote5(marked)}`,
|
|
19242
19656
|
yieldTimeMs: 12e4,
|
|
19243
19657
|
maxOutputTokens: 4e3
|
|
19244
19658
|
};
|
|
@@ -19248,19 +19662,19 @@ env -u BASH_ENV bash --noprofile --norc -c ${shellQuote4(marked)}`,
|
|
|
19248
19662
|
}
|
|
19249
19663
|
}
|
|
19250
19664
|
async function writeCredentialFile(session, path, content, commandRunner) {
|
|
19251
|
-
await runCredentialCommand(session, `: > ${
|
|
19665
|
+
await runCredentialCommand(session, `: > ${shellQuote5(path)}`, commandRunner);
|
|
19252
19666
|
const encoded = base64(content);
|
|
19253
19667
|
for (let offset = 0; offset < encoded.length; offset += WRITE_CHUNK_BYTES) {
|
|
19254
19668
|
const chunk = encoded.slice(offset, offset + WRITE_CHUNK_BYTES);
|
|
19255
19669
|
await runCredentialCommand(
|
|
19256
19670
|
session,
|
|
19257
|
-
`printf %s ${
|
|
19671
|
+
`printf %s ${shellQuote5(chunk)} | ${portableBase64DecodeCommand()} >> ${shellQuote5(path)}`,
|
|
19258
19672
|
commandRunner
|
|
19259
19673
|
);
|
|
19260
19674
|
}
|
|
19261
19675
|
await runCredentialCommand(
|
|
19262
19676
|
session,
|
|
19263
|
-
`[ "$(wc -c < ${
|
|
19677
|
+
`[ "$(wc -c < ${shellQuote5(path)} | tr -d '[:space:]')" = ${shellQuote5(String(byteLength(content)))} ]`,
|
|
19264
19678
|
commandRunner
|
|
19265
19679
|
);
|
|
19266
19680
|
}
|
|
@@ -19285,19 +19699,19 @@ async function materializeRunCredentials(session, material, options) {
|
|
|
19285
19699
|
session,
|
|
19286
19700
|
[
|
|
19287
19701
|
"umask 077",
|
|
19288
|
-
`mkdir -p -- ${
|
|
19289
|
-
`chmod 0700 -- ${
|
|
19290
|
-
`rm -rf -- ${
|
|
19291
|
-
`mkdir -p -- ${
|
|
19702
|
+
`mkdir -p -- ${shellQuote5(`${root}/versions`)}`,
|
|
19703
|
+
`chmod 0700 -- ${shellQuote5(root)} ${shellQuote5(`${root}/versions`)}`,
|
|
19704
|
+
`rm -rf -- ${shellQuote5(stage)}`,
|
|
19705
|
+
`mkdir -p -- ${shellQuote5(`${stage}/files`)}`
|
|
19292
19706
|
].join("\n"),
|
|
19293
19707
|
options.commandRunner
|
|
19294
19708
|
);
|
|
19295
19709
|
const environmentLines = [
|
|
19296
19710
|
...Object.entries(material.environment).map(
|
|
19297
|
-
([name, value]) => `export ${name}=${
|
|
19711
|
+
([name, value]) => `export ${name}=${shellQuote5(value)}`
|
|
19298
19712
|
),
|
|
19299
19713
|
...Object.entries(material.fileEnvironment).map(
|
|
19300
|
-
([name, path]) => `export ${name}=${
|
|
19714
|
+
([name, path]) => `export ${name}=${shellQuote5(`${version}/files/${path}`)}`
|
|
19301
19715
|
)
|
|
19302
19716
|
];
|
|
19303
19717
|
await writeCredentialFile(
|
|
@@ -19309,17 +19723,17 @@ async function materializeRunCredentials(session, material, options) {
|
|
|
19309
19723
|
);
|
|
19310
19724
|
await runCredentialCommand(
|
|
19311
19725
|
session,
|
|
19312
|
-
`chmod 0600 -- ${
|
|
19726
|
+
`chmod 0600 -- ${shellQuote5(`${stage}/env`)}`,
|
|
19313
19727
|
options.commandRunner
|
|
19314
19728
|
);
|
|
19315
19729
|
for (const file of material.files) {
|
|
19316
19730
|
const target = `${stage}/files/${file.path}`;
|
|
19317
19731
|
const parent = target.slice(0, target.lastIndexOf("/"));
|
|
19318
|
-
await runCredentialCommand(session, `mkdir -p -- ${
|
|
19732
|
+
await runCredentialCommand(session, `mkdir -p -- ${shellQuote5(parent)}`, options.commandRunner);
|
|
19319
19733
|
await writeCredentialFile(session, target, file.content, options.commandRunner);
|
|
19320
19734
|
await runCredentialCommand(
|
|
19321
19735
|
session,
|
|
19322
|
-
`chmod ${
|
|
19736
|
+
`chmod ${shellQuote5(file.mode ?? "0600")} -- ${shellQuote5(target)}`,
|
|
19323
19737
|
options.commandRunner
|
|
19324
19738
|
);
|
|
19325
19739
|
}
|
|
@@ -19327,19 +19741,19 @@ async function materializeRunCredentials(session, material, options) {
|
|
|
19327
19741
|
session,
|
|
19328
19742
|
[
|
|
19329
19743
|
...pointerLockAcquireCommands(root),
|
|
19330
|
-
`previous=$(cat -- ${
|
|
19331
|
-
`mv -- ${
|
|
19332
|
-
`printf '%s\\n' ${
|
|
19333
|
-
`mv -f -- ${
|
|
19744
|
+
`previous=$(cat -- ${shellQuote5(`${root}/current`)} 2>/dev/null || :)`,
|
|
19745
|
+
`mv -- ${shellQuote5(stage)} ${shellQuote5(version)}`,
|
|
19746
|
+
`printf '%s\\n' ${shellQuote5(versionName)} > ${shellQuote5(`${root}/.next`)}`,
|
|
19747
|
+
`mv -f -- ${shellQuote5(`${root}/.next`)} ${shellQuote5(`${root}/current`)}`,
|
|
19334
19748
|
...options.prunePreviousGenerations ? [
|
|
19335
|
-
`find ${
|
|
19749
|
+
`find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote5(versionName)} -exec rm -rf -- {} +`
|
|
19336
19750
|
] : options.pruneOtherAttempts ? [
|
|
19337
|
-
`find ${
|
|
19751
|
+
`find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote5(`${attemptId}-${options.executionGeneration}-*`)} -exec rm -rf -- {} +`
|
|
19338
19752
|
] : options.pruneSupersededGenerations ? [
|
|
19339
|
-
`for candidate in ${
|
|
19753
|
+
`for candidate in ${shellQuote5(`${root}/versions`)}/${prefix}*; do`,
|
|
19340
19754
|
` [ -e "$candidate" ] || continue`,
|
|
19341
19755
|
` name=\${candidate##*/}`,
|
|
19342
|
-
` [ "$name" = ${
|
|
19756
|
+
` [ "$name" = ${shellQuote5(versionName)} ] || [ "$name" = "$previous" ] || rm -rf -- "$candidate"`,
|
|
19343
19757
|
"done"
|
|
19344
19758
|
] : [],
|
|
19345
19759
|
...pointerLockReleaseCommands()
|
|
@@ -19352,10 +19766,10 @@ async function clearRunCredentials(session, sessionId, commandRunner) {
|
|
|
19352
19766
|
await runCredentialCommand(
|
|
19353
19767
|
session,
|
|
19354
19768
|
[
|
|
19355
|
-
`if [ -d ${
|
|
19769
|
+
`if [ -d ${shellQuote5(root)} ]; then`,
|
|
19356
19770
|
...pointerLockAcquireCommands(root).map((line) => ` ${line}`),
|
|
19357
|
-
` rm -f -- ${
|
|
19358
|
-
` rm -rf -- ${
|
|
19771
|
+
` rm -f -- ${shellQuote5(`${root}/current`)} ${shellQuote5(`${root}/.next`)}`,
|
|
19772
|
+
` rm -rf -- ${shellQuote5(`${root}/versions`)}`,
|
|
19359
19773
|
...pointerLockReleaseCommands().map((line) => ` ${line}`),
|
|
19360
19774
|
"fi"
|
|
19361
19775
|
].join("\n"),
|
|
@@ -19372,15 +19786,15 @@ async function clearRunCredentialsForAttempt(session, options, commandRunner) {
|
|
|
19372
19786
|
await runCredentialCommand(
|
|
19373
19787
|
session,
|
|
19374
19788
|
[
|
|
19375
|
-
`if [ -d ${
|
|
19789
|
+
`if [ -d ${shellQuote5(root)} ]; then`,
|
|
19376
19790
|
...pointerLockAcquireCommands(root).map((line) => ` ${line}`),
|
|
19377
|
-
` if [ -r ${
|
|
19378
|
-
` current=$(cat -- ${
|
|
19379
|
-
` case "$current" in ${
|
|
19791
|
+
` if [ -r ${shellQuote5(`${root}/current`)} ]; then`,
|
|
19792
|
+
` current=$(cat -- ${shellQuote5(`${root}/current`)} 2>/dev/null || :)`,
|
|
19793
|
+
` case "$current" in ${shellQuote5(prefix)}*) rm -f -- ${shellQuote5(`${root}/current`)} ;; esac`,
|
|
19380
19794
|
" fi",
|
|
19381
|
-
` if [ -d ${
|
|
19382
|
-
` find ${
|
|
19383
|
-
` find ${
|
|
19795
|
+
` if [ -d ${shellQuote5(`${root}/versions`)} ]; then`,
|
|
19796
|
+
` find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote5(`${prefix}*`)} -exec rm -rf -- {} +`,
|
|
19797
|
+
` find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote5(`.stage-${prefix}*`)} -exec rm -rf -- {} +`,
|
|
19384
19798
|
" fi",
|
|
19385
19799
|
...pointerLockReleaseCommands().map((line) => ` ${line}`),
|
|
19386
19800
|
"fi"
|
|
@@ -19392,12 +19806,12 @@ function withRunCredentialEnvironment(cmd, sessionId) {
|
|
|
19392
19806
|
const root = runCredentialRoot(sessionId);
|
|
19393
19807
|
const pointerFile = runCredentialPointerFile(sessionId);
|
|
19394
19808
|
return [
|
|
19395
|
-
`if [ -r ${
|
|
19396
|
-
` _opengeni_credential_version=$(cat -- ${
|
|
19809
|
+
`if [ -r ${shellQuote5(pointerFile)} ]; then`,
|
|
19810
|
+
` _opengeni_credential_version=$(cat -- ${shellQuote5(pointerFile)} 2>/dev/null || :)`,
|
|
19397
19811
|
' case "$_opengeni_credential_version" in',
|
|
19398
19812
|
" ''|*[!A-Za-z0-9_-]*) ;;",
|
|
19399
19813
|
" *)",
|
|
19400
|
-
` _opengeni_credential_env=${
|
|
19814
|
+
` _opengeni_credential_env=${shellQuote5(`${root}/versions`)}/"$_opengeni_credential_version/env"`,
|
|
19401
19815
|
' if [ -r "$_opengeni_credential_env" ]; then',
|
|
19402
19816
|
" set -a",
|
|
19403
19817
|
' . "$_opengeni_credential_env"',
|
|
@@ -19475,7 +19889,7 @@ var ToolspaceTokenPathError = class extends Error {
|
|
|
19475
19889
|
this.name = "ToolspaceTokenPathError";
|
|
19476
19890
|
}
|
|
19477
19891
|
};
|
|
19478
|
-
function
|
|
19892
|
+
function shellQuote6(value) {
|
|
19479
19893
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
19480
19894
|
}
|
|
19481
19895
|
function assertToolspaceSessionId(sessionId) {
|
|
@@ -19500,7 +19914,7 @@ function assertToolspaceFilePath(value, label) {
|
|
|
19500
19914
|
}
|
|
19501
19915
|
function shellToolspacePath(value) {
|
|
19502
19916
|
const validated = assertToolspaceFilePath(value, "Toolspace token file");
|
|
19503
|
-
return isHomeRelativeToolspacePath(validated) ? `"${validated}"` :
|
|
19917
|
+
return isHomeRelativeToolspacePath(validated) ? `"${validated}"` : shellQuote6(validated);
|
|
19504
19918
|
}
|
|
19505
19919
|
function toolspaceTokenFileForSession(manifestTokenFile, sessionId) {
|
|
19506
19920
|
const normalizedManifestFile = assertToolspaceFilePath(
|
|
@@ -20171,7 +20585,10 @@ var RoutingSandboxSession = class {
|
|
|
20171
20585
|
if (!write) throw new RoutingUnsupportedError(op, record.backend.kind);
|
|
20172
20586
|
let result;
|
|
20173
20587
|
try {
|
|
20174
|
-
result = await
|
|
20588
|
+
result = await withSandboxProviderOperation(
|
|
20589
|
+
record.backend.session,
|
|
20590
|
+
() => write.call(record.backend.session, args)
|
|
20591
|
+
);
|
|
20175
20592
|
} catch (error) {
|
|
20176
20593
|
if (this.deps.afterProcessMutation) {
|
|
20177
20594
|
const pending = {
|
|
@@ -20232,7 +20649,10 @@ var RoutingSandboxSession = class {
|
|
|
20232
20649
|
await this.ensureParentPromotion(record);
|
|
20233
20650
|
const write = record.backend.session.writeStdin;
|
|
20234
20651
|
if (!write) throw new RoutingUnsupportedError("writeStdin", record.backend.kind);
|
|
20235
|
-
const result = await
|
|
20652
|
+
const result = await withSandboxProviderOperation(
|
|
20653
|
+
record.backend.session,
|
|
20654
|
+
() => write.call(record.backend.session, args)
|
|
20655
|
+
);
|
|
20236
20656
|
const proof = retainedProcessTerminalProof(result, providerSessionId);
|
|
20237
20657
|
if (proof) await this.settleRetainedProcess(record, proof, result);
|
|
20238
20658
|
return result;
|
|
@@ -20256,7 +20676,7 @@ var RoutingSandboxSession = class {
|
|
|
20256
20676
|
const admission = mutatesWorkspace ? await this.deps.beforeMutation?.({ op, backend }) : void 0;
|
|
20257
20677
|
let result;
|
|
20258
20678
|
try {
|
|
20259
|
-
result = await fn(backend.session);
|
|
20679
|
+
result = await withSandboxProviderOperation(backend.session, () => fn(backend.session));
|
|
20260
20680
|
} catch (error) {
|
|
20261
20681
|
if (mutatesWorkspace && this.deps.afterMutation) {
|
|
20262
20682
|
try {
|
|
@@ -20476,11 +20896,21 @@ var RoutingSandboxSession = class {
|
|
|
20476
20896
|
return terminal.result;
|
|
20477
20897
|
}
|
|
20478
20898
|
await this.ensureParentPromotion(record);
|
|
20479
|
-
|
|
20480
|
-
|
|
20899
|
+
const execCommand = record.backend.session.execCommand;
|
|
20900
|
+
if (execCommand) {
|
|
20901
|
+
return await withSandboxProviderOperation(
|
|
20902
|
+
record.backend.session,
|
|
20903
|
+
() => execCommand.call(record.backend.session, args)
|
|
20904
|
+
);
|
|
20481
20905
|
}
|
|
20482
|
-
|
|
20483
|
-
|
|
20906
|
+
const exec = record.backend.session.exec;
|
|
20907
|
+
if (exec) {
|
|
20908
|
+
return formatExecResult(
|
|
20909
|
+
await withSandboxProviderOperation(
|
|
20910
|
+
record.backend.session,
|
|
20911
|
+
() => exec.call(record.backend.session, args)
|
|
20912
|
+
)
|
|
20913
|
+
);
|
|
20484
20914
|
}
|
|
20485
20915
|
throw new RoutingUnsupportedError("execCommand", record.backend.kind);
|
|
20486
20916
|
}
|
|
@@ -20739,15 +21169,52 @@ function singleQuote(value) {
|
|
|
20739
21169
|
function shellMarkerPath(token) {
|
|
20740
21170
|
return `${SHELL_MARKER_DIR}/${token}`;
|
|
20741
21171
|
}
|
|
21172
|
+
function processInspectionCommandLines() {
|
|
21173
|
+
return [
|
|
21174
|
+
"__opengeni_process_group_id() {",
|
|
21175
|
+
' __opengeni_lookup_pid="$1"',
|
|
21176
|
+
' __opengeni_lookup_pgid=""',
|
|
21177
|
+
" if command -v ps >/dev/null 2>&1; then",
|
|
21178
|
+
` __opengeni_lookup_pgid="$(command ps -o pgid= -p "$__opengeni_lookup_pid" 2>/dev/null | command tr -d '[:space:]')"`,
|
|
21179
|
+
" fi",
|
|
21180
|
+
' case "$__opengeni_lookup_pgid" in',
|
|
21181
|
+
' ""|*[!0-9]*) ;;',
|
|
21182
|
+
` *) command printf '%s\\n' "$__opengeni_lookup_pgid"; return 0 ;;`,
|
|
21183
|
+
" esac",
|
|
21184
|
+
' [ -r "/proc/$__opengeni_lookup_pid/stat" ] || return 1',
|
|
21185
|
+
' IFS= read -r __opengeni_lookup_stat < "/proc/$__opengeni_lookup_pid/stat" || return 1',
|
|
21186
|
+
' __opengeni_lookup_tail="${__opengeni_lookup_stat##*) }"',
|
|
21187
|
+
' [ "$__opengeni_lookup_tail" != "$__opengeni_lookup_stat" ] || return 1',
|
|
21188
|
+
" set -- $__opengeni_lookup_tail",
|
|
21189
|
+
' [ "$#" -ge 3 ] || return 1',
|
|
21190
|
+
' case "$3" in ""|*[!0-9]*) return 1 ;; esac',
|
|
21191
|
+
` command printf '%s\\n' "$3"`,
|
|
21192
|
+
"}",
|
|
21193
|
+
"__opengeni_process_args() {",
|
|
21194
|
+
' __opengeni_lookup_pid="$1"',
|
|
21195
|
+
' __opengeni_lookup_args=""',
|
|
21196
|
+
" if command -v ps >/dev/null 2>&1; then",
|
|
21197
|
+
' __opengeni_lookup_args="$(command ps -ww -o args= -p "$__opengeni_lookup_pid" 2>/dev/null)"',
|
|
21198
|
+
" fi",
|
|
21199
|
+
' if [ -n "$__opengeni_lookup_args" ]; then',
|
|
21200
|
+
` command printf '%s\\n' "$__opengeni_lookup_args"`,
|
|
21201
|
+
" return 0",
|
|
21202
|
+
" fi",
|
|
21203
|
+
' [ -r "/proc/$__opengeni_lookup_pid/cmdline" ] || return 1',
|
|
21204
|
+
` command tr '\\000' ' ' < "/proc/$__opengeni_lookup_pid/cmdline"`,
|
|
21205
|
+
"}"
|
|
21206
|
+
];
|
|
21207
|
+
}
|
|
20742
21208
|
function cancellableGroupLeaderCommand(command, markerPath) {
|
|
20743
21209
|
const marker = singleQuote(markerPath);
|
|
20744
21210
|
const markerDir = singleQuote(SHELL_MARKER_DIR);
|
|
20745
21211
|
return [
|
|
21212
|
+
...processInspectionCommandLines(),
|
|
20746
21213
|
`__opengeni_marker=${marker}`,
|
|
20747
21214
|
"umask 077",
|
|
20748
21215
|
`command mkdir -p ${markerDir} || exit 125`,
|
|
20749
21216
|
'__opengeni_pid="$$"',
|
|
20750
|
-
|
|
21217
|
+
'__opengeni_pgid="$(__opengeni_process_group_id "$__opengeni_pid")"',
|
|
20751
21218
|
'case "$__opengeni_pid:$__opengeni_pgid" in *[!0-9:]*|*:|:*) exit 125 ;; esac',
|
|
20752
21219
|
'[ "$__opengeni_pid" -gt 1 ] && [ "$__opengeni_pgid" -gt 1 ] || exit 125',
|
|
20753
21220
|
// Never signal a provider/container-wide process group. A cancellable PTY
|
|
@@ -20765,8 +21232,9 @@ function cancellableGroupLeaderCommand(command, markerPath) {
|
|
|
20765
21232
|
function cancellableShellCommand(command, markerPath) {
|
|
20766
21233
|
const groupLeaderCommand = cancellableGroupLeaderCommand(command, markerPath);
|
|
20767
21234
|
return [
|
|
21235
|
+
...processInspectionCommandLines(),
|
|
20768
21236
|
'__opengeni_outer_pid="$$"',
|
|
20769
|
-
|
|
21237
|
+
'__opengeni_outer_pgid="$(__opengeni_process_group_id "$__opengeni_outer_pid")"',
|
|
20770
21238
|
'case "$__opengeni_outer_pid:$__opengeni_outer_pgid" in *[!0-9:]*|*:|:*) exit 125 ;; esac',
|
|
20771
21239
|
'if [ "$__opengeni_outer_pid" != "$__opengeni_outer_pgid" ]; then',
|
|
20772
21240
|
' __opengeni_setsid="$(command -v setsid 2>/dev/null)"',
|
|
@@ -20811,15 +21279,16 @@ function identityGuardScript(state, body, missingIdentityExitCode) {
|
|
|
20811
21279
|
if (!identity || !state.token) return `exit ${missingIdentityExitCode}`;
|
|
20812
21280
|
const token = singleQuote(state.token);
|
|
20813
21281
|
return [
|
|
21282
|
+
...processInspectionCommandLines(),
|
|
20814
21283
|
`__opengeni_pid=${identity.pid}`,
|
|
20815
21284
|
`__opengeni_pgid=${identity.processGroupId}`,
|
|
20816
21285
|
`__opengeni_token=${token}`,
|
|
20817
|
-
// The randomized token lands late in the wrapped command line. Procps
|
|
20818
|
-
//
|
|
20819
|
-
//
|
|
20820
|
-
|
|
21286
|
+
// The randomized token lands late in the wrapped command line. Procps needs
|
|
21287
|
+
// `-ww` to avoid terminal-width truncation; minimal Linux images may omit ps,
|
|
21288
|
+
// so the same exact command line is read from /proc instead.
|
|
21289
|
+
`__opengeni_args="$(__opengeni_process_args "$__opengeni_pid")" || exit ${missingIdentityExitCode}`,
|
|
20821
21290
|
'case "$__opengeni_args" in *"$__opengeni_token"*) ;; *) exit 0 ;; esac',
|
|
20822
|
-
`__opengeni_live_pgid="$(
|
|
21291
|
+
`__opengeni_live_pgid="$(__opengeni_process_group_id "$__opengeni_pid")" || exit ${missingIdentityExitCode}`,
|
|
20823
21292
|
'[ "$__opengeni_live_pgid" = "$__opengeni_pgid" ] || exit 0',
|
|
20824
21293
|
body
|
|
20825
21294
|
].join("\n");
|
|
@@ -21492,6 +21961,42 @@ var FS_LIST_TRUNCATED_MARKER = "__OPENGENI_FS_LIST_TRUNCATED__";
|
|
|
21492
21961
|
var FS_LIST_MAX_OUTPUT_BYTES = 768 * 1024;
|
|
21493
21962
|
var GIT_COMMAND_CHUNK_BYTES = 512 * 1024;
|
|
21494
21963
|
var GIT_METADATA_MAX_BYTES = 2 * 1024 * 1024;
|
|
21964
|
+
var GIT_MEASURE_FRAME = "__OPENGENI_GIT_MEASURE_V1__";
|
|
21965
|
+
var GIT_CHUNK_FRAME = "__OPENGENI_GIT_CHUNK_V1__";
|
|
21966
|
+
var GIT_CHUNK_FRAME_END = "__OPENGENI_GIT_CHUNK_END_V1__";
|
|
21967
|
+
var PORTABLE_SHA256_FILE_FUNCTION = [
|
|
21968
|
+
"opengeni_sha256_file() {",
|
|
21969
|
+
` if command -v sha256sum >/dev/null 2>&1 && digest=$(sha256sum -- "$1" 2>/dev/null); then printf "%s\\n" "$digest" | awk '{print $1}'; return; fi`,
|
|
21970
|
+
` if command -v shasum >/dev/null 2>&1 && digest=$(shasum -a 256 "$1" 2>/dev/null); then printf "%s\\n" "$digest" | awk '{print $1}'; return; fi`,
|
|
21971
|
+
` if command -v openssl >/dev/null 2>&1 && digest=$(openssl dgst -sha256 "$1" 2>/dev/null); then printf "%s\\n" "$digest" | sed 's/^.*= //'; return; fi`,
|
|
21972
|
+
" return 127",
|
|
21973
|
+
"}"
|
|
21974
|
+
].join("\n");
|
|
21975
|
+
var PORTABLE_DESCRIPTOR_FUNCTIONS = [
|
|
21976
|
+
"opengeni_set_fd_path() {",
|
|
21977
|
+
' fd="$1"',
|
|
21978
|
+
" opengeni_fd_path=",
|
|
21979
|
+
' if opengeni_fd_path=$(readlink -f -- "/proc/$$/fd/$fd" 2>/dev/null); then [ -n "$opengeni_fd_path" ]; return; fi',
|
|
21980
|
+
" lsof_bin=",
|
|
21981
|
+
" if [ -x /usr/sbin/lsof ]; then lsof_bin=/usr/sbin/lsof; elif command -v lsof >/dev/null 2>&1; then lsof_bin=$(command -v lsof); else return 127; fi",
|
|
21982
|
+
` while IFS= read -r -d '' field; do case "$field" in n*) opengeni_fd_path=\${field#n} ;; esac; done < <("$lsof_bin" -a -p "$$" -d "$fd" -Fn0 2>/dev/null)`,
|
|
21983
|
+
' [ -n "$opengeni_fd_path" ]',
|
|
21984
|
+
"}",
|
|
21985
|
+
"opengeni_fd_identity() {",
|
|
21986
|
+
' fd="$1"',
|
|
21987
|
+
' if identity=$(stat -Lc "%d:%i" -- "/proc/$$/fd/$fd" 2>/dev/null); then printf "%s" "$identity"; return; fi',
|
|
21988
|
+
' stat -f "%d:%i" "/dev/fd/$fd" 2>/dev/null',
|
|
21989
|
+
"}",
|
|
21990
|
+
"opengeni_path_identity() {",
|
|
21991
|
+
' if identity=$(stat -c "%d:%i" -- "$1" 2>/dev/null); then printf "%s" "$identity"; return; fi',
|
|
21992
|
+
' stat -f "%d:%i" "$1" 2>/dev/null',
|
|
21993
|
+
"}",
|
|
21994
|
+
"opengeni_fd_size() {",
|
|
21995
|
+
' fd="$1"',
|
|
21996
|
+
' if size=$(stat -Lc "%s" -- "/proc/$$/fd/$fd" 2>/dev/null); then printf "%s" "$size"; return; fi',
|
|
21997
|
+
' stat -f "%z" "/dev/fd/$fd" 2>/dev/null',
|
|
21998
|
+
"}"
|
|
21999
|
+
].join("\n");
|
|
21495
22000
|
var US = String.fromCharCode(31);
|
|
21496
22001
|
var RS = String.fromCharCode(30);
|
|
21497
22002
|
var SELFHOSTED_VIRTUAL_ROOT2 = "/workspace";
|
|
@@ -21581,11 +22086,11 @@ var SandboxChannelAService = class {
|
|
|
21581
22086
|
const depthArg = Math.max(1, req.depth);
|
|
21582
22087
|
const maxCommandEntries = req.maxEntries + 1;
|
|
21583
22088
|
const gnuPrint = `-printf '%y\\t%s\\t%T@\\t%m\\t%p\\0'`;
|
|
21584
|
-
const gnuSelector = pruneNames.length ? `\\( -type d \\( ${pruneNames.map((name) => `-name ${
|
|
22089
|
+
const gnuSelector = pruneNames.length ? `\\( -type d \\( ${pruneNames.map((name) => `-name ${shellQuote7(name)}`).join(" -o ")} \\) ${gnuPrint} -prune \\) -o ${gnuPrint}` : gnuPrint;
|
|
21585
22090
|
const gnuVisibleSelector = req.includeHidden ? gnuSelector : `\\( -path '*/.*' -prune \\) -o \\( ${gnuSelector} \\)`;
|
|
21586
22091
|
const gnuFind = `find ${findRoot} -mindepth 1 -maxdepth ${depthArg} \\( ${gnuVisibleSelector} \\) 2>/dev/null`;
|
|
21587
22092
|
const portableHiddenGuard = req.includeHidden ? "" : `if [[ "$base" == .* ]]; then continue; fi;`;
|
|
21588
|
-
const portablePruneCase = pruneNames.length ? `case "$base" in ${pruneNames.map(
|
|
22093
|
+
const portablePruneCase = pruneNames.length ? `case "$base" in ${pruneNames.map(shellQuote7).join("|")}) pruned=1 ;; *) pruned=0 ;; esac;` : "pruned=0;";
|
|
21589
22094
|
const portableWalk = [
|
|
21590
22095
|
"shopt -s nullglob dotglob; count=0; stop=0;",
|
|
21591
22096
|
'walk() { local dir="$1" level="$2" p base t size mtime mode pruned;',
|
|
@@ -21614,12 +22119,12 @@ var SandboxChannelAService = class {
|
|
|
21614
22119
|
`if [ "$records" -ge ${req.maxEntries} ] || [ $((bytes + record_bytes + 1)) -gt ${FS_LIST_MAX_OUTPUT_BYTES} ]; then truncated=1; break; fi;`,
|
|
21615
22120
|
`printf '%s\\0' "$record"; bytes=$((bytes + record_bytes + 1)); records=$((records + 1));`,
|
|
21616
22121
|
"done;",
|
|
21617
|
-
`if [ "$truncated" -eq 1 ]; then printf '%s\\0' ${
|
|
22122
|
+
`if [ "$truncated" -eq 1 ]; then printf '%s\\0' ${shellQuote7(FS_LIST_TRUNCATED_MARKER)}; fi`
|
|
21618
22123
|
].join(" ");
|
|
21619
22124
|
const findCommand = [
|
|
21620
22125
|
`{ ${rawFindCommand}; } | { ${boundedOutput}; };`,
|
|
21621
22126
|
"producer_status=${PIPESTATUS[0]};",
|
|
21622
|
-
`if [ "$producer_status" -ne 0 ] && [ "$producer_status" -ne 141 ]; then printf '%s\\0' ${
|
|
22127
|
+
`if [ "$producer_status" -ne 0 ] && [ "$producer_status" -ne 141 ]; then printf '%s\\0' ${shellQuote7(FS_LIST_TRUNCATED_MARKER)}; fi`
|
|
21623
22128
|
].join(" ");
|
|
21624
22129
|
const { stdout, exitCode } = await this.runInConfinedDirectory(root, {
|
|
21625
22130
|
cmd: internalBashCommand(findCommand),
|
|
@@ -21712,11 +22217,11 @@ var SandboxChannelAService = class {
|
|
|
21712
22217
|
async assertConfinedExistingDirectory(path) {
|
|
21713
22218
|
const root = this.workspaceRoot || ".";
|
|
21714
22219
|
const abs = this.joinRoot(path);
|
|
21715
|
-
const rejectLink = path ? `test ! -L ${
|
|
22220
|
+
const rejectLink = path ? `test ! -L ${shellQuote7(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
|
|
21716
22221
|
const script = [
|
|
21717
|
-
`root=$(realpath -e -- ${
|
|
22222
|
+
`root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21718
22223
|
rejectLink,
|
|
21719
|
-
`target=$(realpath -e -- ${
|
|
22224
|
+
`target=$(realpath -e -- ${shellQuote7(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21720
22225
|
`case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
|
|
21721
22226
|
`test -d "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21722
22227
|
`printf '__OPENGENI_FS_CONFINED_OK__'`
|
|
@@ -21727,13 +22232,13 @@ var SandboxChannelAService = class {
|
|
|
21727
22232
|
async assertConfinedMutationParent(path, options) {
|
|
21728
22233
|
const root = this.workspaceRoot || ".";
|
|
21729
22234
|
const abs = this.joinRoot(path);
|
|
21730
|
-
const rejectLink = options.rejectFinalSymlink ? `test ! -L ${
|
|
22235
|
+
const rejectLink = options.rejectFinalSymlink ? `test ! -L ${shellQuote7(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
|
|
21731
22236
|
const locateParent = options.allowMissingParents ? 'probe="$parent"; while [ ! -e "$probe" ] && [ ! -L "$probe" ]; do next=$(dirname -- "$probe"); [ "$next" != "$probe" ] || break; probe="$next"; done' : 'probe="$parent"';
|
|
21732
22237
|
const requireParent = options.allowMissingParents ? ":" : 'test -d "$parent" || { printf "__OPENGENI_FS_NOT_FOUND__"; exit 66; }';
|
|
21733
22238
|
const script = [
|
|
21734
|
-
`root=$(realpath -e -- ${
|
|
22239
|
+
`root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21735
22240
|
rejectLink,
|
|
21736
|
-
`parent=$(dirname -- ${
|
|
22241
|
+
`parent=$(dirname -- ${shellQuote7(abs)})`,
|
|
21737
22242
|
locateParent,
|
|
21738
22243
|
`target=$(realpath -e -- "$probe") || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21739
22244
|
`case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
|
|
@@ -21770,8 +22275,8 @@ var SandboxChannelAService = class {
|
|
|
21770
22275
|
const root = this.workspaceRoot || ".";
|
|
21771
22276
|
const abs = this.joinRoot(path);
|
|
21772
22277
|
const script = [
|
|
21773
|
-
`root=$(realpath -e -- ${
|
|
21774
|
-
`exec 3<${
|
|
22278
|
+
`root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
22279
|
+
`exec 3<${shellQuote7(abs)} || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21775
22280
|
`target=$(readlink -f -- "/proc/$$/fd/3") || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
21776
22281
|
`case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
|
|
21777
22282
|
`test -f "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
@@ -21840,7 +22345,7 @@ var SandboxChannelAService = class {
|
|
|
21840
22345
|
});
|
|
21841
22346
|
if (!req.overwrite) {
|
|
21842
22347
|
const { exitCode: exitCode2 } = await this.run({
|
|
21843
|
-
cmd: `test -e ${
|
|
22348
|
+
cmd: `test -e ${shellQuote7(abs)} || test -L ${shellQuote7(abs)}`
|
|
21844
22349
|
});
|
|
21845
22350
|
if (exitCode2 === 0) {
|
|
21846
22351
|
throw new ChannelAConflictError(`path exists and overwrite is false: ${path}`);
|
|
@@ -21848,7 +22353,7 @@ var SandboxChannelAService = class {
|
|
|
21848
22353
|
}
|
|
21849
22354
|
if (req.createParents) {
|
|
21850
22355
|
const dir = dirnameAbs(abs);
|
|
21851
|
-
if (dir) await this.run({ cmd: `mkdir -p ${
|
|
22356
|
+
if (dir) await this.run({ cmd: `mkdir -p ${shellQuote7(dir)}` });
|
|
21852
22357
|
await this.assertConfinedMutationParent(path, {
|
|
21853
22358
|
allowMissingParents: false,
|
|
21854
22359
|
rejectFinalSymlink: true
|
|
@@ -21856,7 +22361,7 @@ var SandboxChannelAService = class {
|
|
|
21856
22361
|
}
|
|
21857
22362
|
const b64 = bytes.toString("base64");
|
|
21858
22363
|
const { exitCode, stderr } = await this.run({
|
|
21859
|
-
cmd: `printf %s ${
|
|
22364
|
+
cmd: `printf %s ${shellQuote7(b64)} | base64 -d > ${shellQuote7(abs)}`
|
|
21860
22365
|
});
|
|
21861
22366
|
if (exitCode !== null && exitCode !== 0) {
|
|
21862
22367
|
if (req.encoding !== "base64" && this.session.createEditor) {
|
|
@@ -21897,7 +22402,7 @@ var SandboxChannelAService = class {
|
|
|
21897
22402
|
rejectFinalSymlink: false
|
|
21898
22403
|
});
|
|
21899
22404
|
const flag = req.recursive ? "-rf" : "-f";
|
|
21900
|
-
const { exitCode, stderr } = await this.run({ cmd: `rm ${flag} ${
|
|
22405
|
+
const { exitCode, stderr } = await this.run({ cmd: `rm ${flag} ${shellQuote7(abs)}` });
|
|
21901
22406
|
if (exitCode !== null && exitCode !== 0) {
|
|
21902
22407
|
throw new ChannelAValidationError(
|
|
21903
22408
|
`failed to delete ${path}: ${stderr || `exit ${exitCode}`}`
|
|
@@ -21922,7 +22427,7 @@ var SandboxChannelAService = class {
|
|
|
21922
22427
|
});
|
|
21923
22428
|
if (!req.overwrite) {
|
|
21924
22429
|
const { exitCode: exitCode2 } = await this.run({
|
|
21925
|
-
cmd: `test -e ${
|
|
22430
|
+
cmd: `test -e ${shellQuote7(newAbs)} || test -L ${shellQuote7(newAbs)}`
|
|
21926
22431
|
});
|
|
21927
22432
|
if (exitCode2 === 0) {
|
|
21928
22433
|
throw new ChannelAConflictError(`destination exists and overwrite is false: ${newPath}`);
|
|
@@ -21930,7 +22435,7 @@ var SandboxChannelAService = class {
|
|
|
21930
22435
|
}
|
|
21931
22436
|
if (req.createParents) {
|
|
21932
22437
|
const dir = dirnameAbs(newAbs);
|
|
21933
|
-
if (dir) await this.run({ cmd: `mkdir -p ${
|
|
22438
|
+
if (dir) await this.run({ cmd: `mkdir -p ${shellQuote7(dir)}` });
|
|
21934
22439
|
await this.assertConfinedMutationParent(newPath, {
|
|
21935
22440
|
allowMissingParents: false,
|
|
21936
22441
|
rejectFinalSymlink: true
|
|
@@ -21938,7 +22443,7 @@ var SandboxChannelAService = class {
|
|
|
21938
22443
|
}
|
|
21939
22444
|
const flag = req.overwrite ? "-f " : "";
|
|
21940
22445
|
const { exitCode, stderr } = await this.run({
|
|
21941
|
-
cmd: `mv ${flag}${
|
|
22446
|
+
cmd: `mv ${flag}${shellQuote7(abs)} ${shellQuote7(newAbs)}`
|
|
21942
22447
|
});
|
|
21943
22448
|
if (exitCode !== null && exitCode !== 0) {
|
|
21944
22449
|
throw new ChannelAValidationError(
|
|
@@ -21963,7 +22468,7 @@ var SandboxChannelAService = class {
|
|
|
21963
22468
|
rejectFinalSymlink: true
|
|
21964
22469
|
});
|
|
21965
22470
|
const flag = req.recursive ? "-p " : "";
|
|
21966
|
-
const { exitCode, stderr } = await this.run({ cmd: `mkdir ${flag}${
|
|
22471
|
+
const { exitCode, stderr } = await this.run({ cmd: `mkdir ${flag}${shellQuote7(abs)}` });
|
|
21967
22472
|
if (exitCode !== null && exitCode !== 0) {
|
|
21968
22473
|
throw new ChannelAValidationError(`failed to mkdir ${path}: ${stderr || `exit ${exitCode}`}`);
|
|
21969
22474
|
}
|
|
@@ -21978,44 +22483,60 @@ var SandboxChannelAService = class {
|
|
|
21978
22483
|
async measureConfinedCommandBytes(repo, command) {
|
|
21979
22484
|
const measured = await this.runInConfinedDirectory(repo, {
|
|
21980
22485
|
cmd: [
|
|
21981
|
-
|
|
21982
|
-
|
|
21983
|
-
"
|
|
21984
|
-
|
|
22486
|
+
PORTABLE_SHA256_FILE_FUNCTION,
|
|
22487
|
+
"tmp=$(mktemp) || exit 70",
|
|
22488
|
+
`trap 'rm -f "$tmp"' EXIT`,
|
|
22489
|
+
`/bin/bash --noprofile --norc -c ${shellQuote7(command)} >"$tmp" 2>/dev/null`,
|
|
22490
|
+
"producer_status=$?",
|
|
22491
|
+
`bytes=$(wc -c <"$tmp" | tr -d ' \\n')`,
|
|
22492
|
+
`sha256=$(opengeni_sha256_file "$tmp") || exit 71`,
|
|
22493
|
+
`printf '${GIT_MEASURE_FRAME}\\t%s\\t%s\\t%s' "$producer_status" "$bytes" "$sha256"`
|
|
21985
22494
|
].join("; "),
|
|
21986
22495
|
maxOutputTokens: 1024
|
|
21987
22496
|
});
|
|
21988
|
-
const match = measured.stdout.match(
|
|
21989
|
-
|
|
22497
|
+
const match = measured.stdout.match(
|
|
22498
|
+
new RegExp(`^${GIT_MEASURE_FRAME}\\t(\\d+)\\t(\\d+)\\t([0-9a-f]{64})$`)
|
|
22499
|
+
);
|
|
22500
|
+
if (!match || measured.exitCode !== null && measured.exitCode !== 0 || Number(match[1]) !== 0) {
|
|
21990
22501
|
throw new ChannelAUnavailableError(
|
|
21991
22502
|
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
21992
22503
|
);
|
|
21993
22504
|
}
|
|
21994
|
-
const size = Number(match[
|
|
22505
|
+
const size = Number(match[2]);
|
|
21995
22506
|
if (!Number.isSafeInteger(size) || size < 0) {
|
|
21996
22507
|
throw new ChannelAUnavailableError(
|
|
21997
22508
|
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
21998
22509
|
);
|
|
21999
22510
|
}
|
|
22000
|
-
return size;
|
|
22511
|
+
return { sizeBytes: size, sha256: match[3] };
|
|
22001
22512
|
}
|
|
22002
22513
|
/** Read an exact prefix of a command's output in chunks that remain below
|
|
22003
22514
|
* every supported execCommand retained-output ceiling. The producer is
|
|
22004
22515
|
* intentionally rerun per chunk; turn-end capture calls this only after the
|
|
22005
22516
|
* durable mutation authority has quiesced the workspace. */
|
|
22006
|
-
async readConfinedCommandPrefix(repo, command,
|
|
22007
|
-
if (
|
|
22517
|
+
async readConfinedCommandPrefix(repo, command, measurement, prefixByteLength = measurement.sizeBytes) {
|
|
22518
|
+
if (!Number.isSafeInteger(prefixByteLength) || prefixByteLength < 0 || prefixByteLength > measurement.sizeBytes) {
|
|
22519
|
+
throw new ChannelAUnavailableError(
|
|
22520
|
+
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22521
|
+
);
|
|
22522
|
+
}
|
|
22523
|
+
if (prefixByteLength === 0) return Buffer.alloc(0);
|
|
22008
22524
|
const chunks = [];
|
|
22009
|
-
for (let offset = 0; offset <
|
|
22010
|
-
const expected = Math.min(GIT_COMMAND_CHUNK_BYTES,
|
|
22525
|
+
for (let offset = 0; offset < prefixByteLength; offset += GIT_COMMAND_CHUNK_BYTES) {
|
|
22526
|
+
const expected = Math.min(GIT_COMMAND_CHUNK_BYTES, prefixByteLength - offset);
|
|
22011
22527
|
const chunk = await this.runInConfinedDirectory(repo, {
|
|
22012
22528
|
cmd: [
|
|
22013
|
-
|
|
22014
|
-
|
|
22015
|
-
`
|
|
22016
|
-
"
|
|
22017
|
-
|
|
22018
|
-
|
|
22529
|
+
PORTABLE_SHA256_FILE_FUNCTION,
|
|
22530
|
+
"tmp=$(mktemp) || exit 70",
|
|
22531
|
+
`trap 'rm -f "$tmp"' EXIT`,
|
|
22532
|
+
`/bin/bash --noprofile --norc -c ${shellQuote7(command)} >"$tmp" 2>/dev/null`,
|
|
22533
|
+
"producer_status=$?",
|
|
22534
|
+
`bytes=$(wc -c <"$tmp" | tr -d ' \\n')`,
|
|
22535
|
+
`sha256=$(opengeni_sha256_file "$tmp") || exit 71`,
|
|
22536
|
+
`printf '${GIT_CHUNK_FRAME}\\t%s\\t%s\\t%s\\t%s\\t%s\\n' "$producer_status" "$bytes" "$sha256" ${offset} ${expected}`,
|
|
22537
|
+
`if [ "$producer_status" -eq 0 ]; then tail -c +${offset + 1} "$tmp" | head -c ${expected} | base64 | tr -d '\\n'; fi`,
|
|
22538
|
+
`printf '\\n${GIT_CHUNK_FRAME_END}'`
|
|
22539
|
+
].join("; "),
|
|
22019
22540
|
maxOutputTokens: Math.ceil(GIT_COMMAND_CHUNK_BYTES * 4 / 3) + 1024
|
|
22020
22541
|
});
|
|
22021
22542
|
if (chunk.exitCode !== null && chunk.exitCode !== 0) {
|
|
@@ -22023,7 +22544,21 @@ var SandboxChannelAService = class {
|
|
|
22023
22544
|
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22024
22545
|
);
|
|
22025
22546
|
}
|
|
22026
|
-
const
|
|
22547
|
+
const headerEnd = chunk.stdout.indexOf("\n");
|
|
22548
|
+
const trailer = `
|
|
22549
|
+
${GIT_CHUNK_FRAME_END}`;
|
|
22550
|
+
if (headerEnd < 0 || !chunk.stdout.endsWith(trailer)) {
|
|
22551
|
+
throw new ChannelAUnavailableError(
|
|
22552
|
+
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22553
|
+
);
|
|
22554
|
+
}
|
|
22555
|
+
const header = chunk.stdout.slice(0, headerEnd).split(" ");
|
|
22556
|
+
if (header.length !== 6 || header[0] !== GIT_CHUNK_FRAME || header[1] !== "0" || header[2] !== String(measurement.sizeBytes) || header[3] !== measurement.sha256 || header[4] !== String(offset) || header[5] !== String(expected)) {
|
|
22557
|
+
throw new ChannelAUnavailableError(
|
|
22558
|
+
"Workspace Git data changed during capture. Retry the operation."
|
|
22559
|
+
);
|
|
22560
|
+
}
|
|
22561
|
+
const encoded = chunk.stdout.slice(headerEnd + 1, -trailer.length);
|
|
22027
22562
|
const bytes = Buffer.from(encoded, "base64");
|
|
22028
22563
|
if (bytes.byteLength !== expected || bytes.toString("base64") !== encoded) {
|
|
22029
22564
|
throw new ChannelAUnavailableError(
|
|
@@ -22032,35 +22567,61 @@ var SandboxChannelAService = class {
|
|
|
22032
22567
|
}
|
|
22033
22568
|
chunks.push(bytes);
|
|
22034
22569
|
}
|
|
22035
|
-
return Buffer.concat(chunks,
|
|
22570
|
+
return Buffer.concat(chunks, prefixByteLength);
|
|
22036
22571
|
}
|
|
22037
22572
|
async readConfinedCommandBytes(repo, command, maxBytes) {
|
|
22038
|
-
const
|
|
22039
|
-
if (sizeBytes > maxBytes) {
|
|
22040
|
-
return { bytes: Buffer.alloc(0), sizeBytes, truncated: true };
|
|
22573
|
+
const measurement = await this.measureConfinedCommandBytes(repo, command);
|
|
22574
|
+
if (measurement.sizeBytes > maxBytes) {
|
|
22575
|
+
return { bytes: Buffer.alloc(0), sizeBytes: measurement.sizeBytes, truncated: true };
|
|
22041
22576
|
}
|
|
22042
22577
|
return {
|
|
22043
|
-
bytes: await this.readConfinedCommandPrefix(repo, command,
|
|
22044
|
-
sizeBytes,
|
|
22578
|
+
bytes: await this.readConfinedCommandPrefix(repo, command, measurement),
|
|
22579
|
+
sizeBytes: measurement.sizeBytes,
|
|
22045
22580
|
truncated: false
|
|
22046
22581
|
};
|
|
22047
22582
|
}
|
|
22583
|
+
/** Bind an untracked regular-file descriptor to its repository root and its
|
|
22584
|
+
* lstat identity before producing bytes. The final producer reads fd 3 rather
|
|
22585
|
+
* than reopening the path, so a check→read symlink swap cannot disclose a
|
|
22586
|
+
* target outside the repository (or substitute another in-repository inode). */
|
|
22587
|
+
confinedUntrackedRegularFileCommand(target, body) {
|
|
22588
|
+
const fileArg = target.startsWith("./") ? target : `./${target}`;
|
|
22589
|
+
return [
|
|
22590
|
+
PORTABLE_DESCRIPTOR_FUNCTIONS,
|
|
22591
|
+
`file=${shellQuote7(fileArg)}`,
|
|
22592
|
+
'exec 3<"$file" || exit 66',
|
|
22593
|
+
'exec 4<"$file" || exit 66',
|
|
22594
|
+
"root=$(pwd -P) || exit 66",
|
|
22595
|
+
"opengeni_set_fd_path 3 || exit 66",
|
|
22596
|
+
'opened3="$opengeni_fd_path"',
|
|
22597
|
+
"opengeni_set_fd_path 4 || exit 66",
|
|
22598
|
+
'opened4="$opengeni_fd_path"',
|
|
22599
|
+
'case "$opened3" in "$root"|"$root"/*) ;; *) exit 67 ;; esac',
|
|
22600
|
+
'case "$opened4" in "$root"|"$root"/*) ;; *) exit 67 ;; esac',
|
|
22601
|
+
'test ! -L "$file" && test -f "$file" || exit 66',
|
|
22602
|
+
"opened3_identity=$(opengeni_fd_identity 3) || exit 66",
|
|
22603
|
+
"opened4_identity=$(opengeni_fd_identity 4) || exit 66",
|
|
22604
|
+
'path_identity=$(opengeni_path_identity "$file") || exit 66',
|
|
22605
|
+
'test "$opened3_identity" = "$opened4_identity" || exit 66',
|
|
22606
|
+
'test "$opened3_identity" = "$path_identity" || exit 66',
|
|
22607
|
+
body
|
|
22608
|
+
].join("; ");
|
|
22609
|
+
}
|
|
22048
22610
|
/** Read a regular untracked file without routing its body through one large
|
|
22049
22611
|
* execCommand response. Native provider reads are binary-safe; providers
|
|
22050
22612
|
* without that surface use the same bounded chunk protocol as Git patches. */
|
|
22051
|
-
async readUntrackedRegularFile(repo, target,
|
|
22052
|
-
if (byteLength2 === 0) return Buffer.alloc(0);
|
|
22613
|
+
async readUntrackedRegularFile(repo, target, prefixByteLength, sizeBytes) {
|
|
22053
22614
|
const path = repo ? `${repo}/${target}` : target;
|
|
22054
22615
|
assertSafeRelPath(path);
|
|
22055
22616
|
if (this.session.readFile) {
|
|
22056
22617
|
try {
|
|
22057
22618
|
const raw = await this.session.readFile({
|
|
22058
22619
|
path: this.joinRoot(path),
|
|
22059
|
-
maxBytes:
|
|
22620
|
+
maxBytes: prefixByteLength,
|
|
22060
22621
|
...this.runAs ? { runAs: this.runAs } : {}
|
|
22061
22622
|
});
|
|
22062
22623
|
const bytes = typeof raw === "string" ? Buffer.from(raw, "utf8") : Buffer.from(raw);
|
|
22063
|
-
if (bytes.byteLength !==
|
|
22624
|
+
if (bytes.byteLength !== prefixByteLength) {
|
|
22064
22625
|
throw new ChannelAUnavailableError(
|
|
22065
22626
|
"Workspace Git data changed during capture. Retry the operation."
|
|
22066
22627
|
);
|
|
@@ -22081,12 +22642,14 @@ var SandboxChannelAService = class {
|
|
|
22081
22642
|
}
|
|
22082
22643
|
}
|
|
22083
22644
|
}
|
|
22084
|
-
const
|
|
22085
|
-
|
|
22086
|
-
|
|
22087
|
-
|
|
22088
|
-
|
|
22089
|
-
|
|
22645
|
+
const command = this.confinedUntrackedRegularFileCommand(target, "cat <&3");
|
|
22646
|
+
const measurement = await this.measureConfinedCommandBytes(repo, command);
|
|
22647
|
+
if (measurement.sizeBytes !== sizeBytes) {
|
|
22648
|
+
throw new ChannelAUnavailableError(
|
|
22649
|
+
"Workspace Git data changed during capture. Retry the operation."
|
|
22650
|
+
);
|
|
22651
|
+
}
|
|
22652
|
+
return await this.readConfinedCommandPrefix(repo, command, measurement, prefixByteLength);
|
|
22090
22653
|
}
|
|
22091
22654
|
async gitStatus(req) {
|
|
22092
22655
|
const repo = assertSafeRelPathOrRoot(req.path);
|
|
@@ -22115,24 +22678,24 @@ var SandboxChannelAService = class {
|
|
|
22115
22678
|
"Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
|
|
22116
22679
|
);
|
|
22117
22680
|
}
|
|
22118
|
-
return { ...parsePorcelainV2(status.bytes
|
|
22681
|
+
return { ...parsePorcelainV2(decodeGitMetadataUtf8(status.bytes)), revision: this.revision };
|
|
22119
22682
|
}
|
|
22120
22683
|
async gitDiff(req) {
|
|
22121
22684
|
const repo = assertSafeRelPathOrRoot(req.path);
|
|
22122
22685
|
const ctx = req.contextLines;
|
|
22123
22686
|
let range = "";
|
|
22124
|
-
if (req.fromRef && req.toRef) range = `${
|
|
22687
|
+
if (req.fromRef && req.toRef) range = `${shellQuote7(req.fromRef)} ${shellQuote7(req.toRef)}`;
|
|
22125
22688
|
else if (req.fromRef) {
|
|
22126
22689
|
if (req.fromRef === "HEAD") {
|
|
22127
22690
|
const head = await this.runInConfinedDirectory(repo, {
|
|
22128
22691
|
cmd: "if git rev-parse --verify --quiet HEAD >/dev/null; then printf 'present'; else printf 'unborn'; fi"
|
|
22129
22692
|
});
|
|
22130
|
-
range = head.stdout.trim() === "present" ?
|
|
22693
|
+
range = head.stdout.trim() === "present" ? shellQuote7(req.fromRef) : "--cached";
|
|
22131
22694
|
} else {
|
|
22132
|
-
range =
|
|
22695
|
+
range = shellQuote7(req.fromRef);
|
|
22133
22696
|
}
|
|
22134
22697
|
} else if (req.staged) range = "--cached";
|
|
22135
|
-
const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(
|
|
22698
|
+
const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote7).join(" ")}` : "";
|
|
22136
22699
|
const numstat = await this.readConfinedCommandBytes(
|
|
22137
22700
|
repo,
|
|
22138
22701
|
`git -c core.quotePath=false diff --no-color -z --numstat ${range}${pathspec}`.trim(),
|
|
@@ -22143,7 +22706,7 @@ var SandboxChannelAService = class {
|
|
|
22143
22706
|
"Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
|
|
22144
22707
|
);
|
|
22145
22708
|
}
|
|
22146
|
-
const stats = parseNumstatZ(numstat.bytes
|
|
22709
|
+
const stats = parseNumstatZ(decodeGitMetadataUtf8(numstat.bytes));
|
|
22147
22710
|
const files = [];
|
|
22148
22711
|
for (const stat4 of stats) {
|
|
22149
22712
|
const target = stat4.newPath;
|
|
@@ -22164,7 +22727,7 @@ var SandboxChannelAService = class {
|
|
|
22164
22727
|
}
|
|
22165
22728
|
const patch = await this.readConfinedCommandBytes(
|
|
22166
22729
|
repo,
|
|
22167
|
-
`git -c core.quotePath=false diff --no-color -U${ctx} ${range} -- ${
|
|
22730
|
+
`git -c core.quotePath=false diff --no-color -U${ctx} ${range} -- ${shellQuote7(target)}`.trim(),
|
|
22168
22731
|
req.maxBytesPerFile
|
|
22169
22732
|
);
|
|
22170
22733
|
const parsed = patch.truncated ? { hunks: [], status: "modified" } : parseUnifiedPatch(patch.bytes.toString("utf8"));
|
|
@@ -22191,48 +22754,75 @@ var SandboxChannelAService = class {
|
|
|
22191
22754
|
"Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
|
|
22192
22755
|
);
|
|
22193
22756
|
}
|
|
22194
|
-
for (const target of untracked.bytes
|
|
22757
|
+
for (const target of decodeGitMetadataUtf8(untracked.bytes).split(NUL).filter(Boolean)) {
|
|
22195
22758
|
const fileArg = target.startsWith("./") ? target : `./${target}`;
|
|
22196
|
-
const
|
|
22197
|
-
|
|
22198
|
-
|
|
22199
|
-
|
|
22200
|
-
|
|
22201
|
-
|
|
22202
|
-
'if [ "$size" -gt 0 ]; then last_byte=$(tail -c 1 "$file" | od -An -tu1 | tr -d " \\n"); if [ "$last_byte" != "10" ]; then line_count=$((line_count + 1)); fi; fi',
|
|
22203
|
-
'printf "F\\t%s\\t%s" "$size" "$line_count"'
|
|
22204
|
-
].join("; ")
|
|
22205
|
-
});
|
|
22206
|
-
if (read.exitCode !== null && read.exitCode !== 0) {
|
|
22759
|
+
const kind = await this.readConfinedCommandBytes(
|
|
22760
|
+
repo,
|
|
22761
|
+
`file=${shellQuote7(fileArg)}; if [ -L "$file" ]; then printf L; elif [ -f "$file" ]; then printf F; else exit 66; fi`,
|
|
22762
|
+
1
|
|
22763
|
+
);
|
|
22764
|
+
if (kind.truncated || kind.bytes[0] !== 76 && kind.bytes[0] !== 70) {
|
|
22207
22765
|
throw new ChannelAUnavailableError(
|
|
22208
22766
|
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22209
22767
|
);
|
|
22210
22768
|
}
|
|
22211
|
-
const [kind, first, second] = read.stdout.split(" ");
|
|
22212
22769
|
let sampled = Buffer.alloc(0);
|
|
22213
22770
|
let sizeBytes;
|
|
22214
22771
|
let lineCount;
|
|
22215
|
-
if (kind ===
|
|
22216
|
-
const
|
|
22217
|
-
|
|
22218
|
-
|
|
22772
|
+
if (kind.bytes[0] === 76) {
|
|
22773
|
+
const link = await this.readConfinedCommandBytes(
|
|
22774
|
+
repo,
|
|
22775
|
+
`file=${shellQuote7(fileArg)}; test -L "$file" || exit 66; readlink -n "$file" || exit 66; printf '\\0'`,
|
|
22776
|
+
GIT_METADATA_MAX_BYTES
|
|
22777
|
+
);
|
|
22778
|
+
if (link.truncated) {
|
|
22779
|
+
throw new ChannelAUnavailableError(
|
|
22780
|
+
"Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
|
|
22781
|
+
);
|
|
22782
|
+
}
|
|
22783
|
+
sampled = link.bytes;
|
|
22784
|
+
if (sampled.at(-1) !== 0) {
|
|
22785
|
+
throw new ChannelAUnavailableError(
|
|
22786
|
+
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22787
|
+
);
|
|
22788
|
+
}
|
|
22219
22789
|
sampled = sampled.subarray(0, -1);
|
|
22220
22790
|
sizeBytes = sampled.length;
|
|
22221
22791
|
lineCount = addedLines(sampled).length;
|
|
22222
22792
|
} else {
|
|
22223
|
-
|
|
22224
|
-
|
|
22225
|
-
|
|
22226
|
-
|
|
22227
|
-
|
|
22793
|
+
const metadata = await this.readConfinedCommandBytes(
|
|
22794
|
+
repo,
|
|
22795
|
+
this.confinedUntrackedRegularFileCommand(
|
|
22796
|
+
target,
|
|
22797
|
+
[
|
|
22798
|
+
"size=$(opengeni_fd_size 3) || exit 66",
|
|
22799
|
+
"line_count=$(wc -l <&3) || exit 66",
|
|
22800
|
+
'if [ "$size" -gt 0 ]; then last_byte=$(tail -c 1 <&4 | od -An -tu1 | tr -d " \\n") || exit 66; if [ "$last_byte" != "10" ]; then line_count=$((line_count + 1)); fi; fi',
|
|
22801
|
+
'printf "%s\\t%s" "$size" "$line_count"'
|
|
22802
|
+
].join("; ")
|
|
22803
|
+
),
|
|
22804
|
+
128
|
|
22805
|
+
);
|
|
22806
|
+
if (metadata.truncated) {
|
|
22807
|
+
throw new ChannelAUnavailableError(
|
|
22808
|
+
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22809
|
+
);
|
|
22810
|
+
}
|
|
22811
|
+
const frame = metadata.bytes.toString("ascii").match(/^(0|[1-9]\d*)\t(0|[1-9]\d*)$/);
|
|
22812
|
+
const parsedSize = safeInt(frame?.[1]);
|
|
22813
|
+
const parsedLineCount = safeInt(frame?.[2]);
|
|
22814
|
+
if (parsedSize === null || parsedLineCount === null) {
|
|
22815
|
+
throw new ChannelAUnavailableError(
|
|
22816
|
+
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
22817
|
+
);
|
|
22228
22818
|
}
|
|
22229
22819
|
sizeBytes = parsedSize;
|
|
22230
22820
|
lineCount = parsedLineCount;
|
|
22231
22821
|
const truncated2 = sizeBytes > req.maxBytesPerFile;
|
|
22232
22822
|
const sampleSize = Math.min(sizeBytes, 8192);
|
|
22233
|
-
sampled = await this.readUntrackedRegularFile(repo, target, sampleSize);
|
|
22823
|
+
sampled = await this.readUntrackedRegularFile(repo, target, sampleSize, sizeBytes);
|
|
22234
22824
|
if (!sniffBinary(sampled) && !truncated2 && sampleSize < sizeBytes) {
|
|
22235
|
-
sampled = await this.readUntrackedRegularFile(repo, target, sizeBytes);
|
|
22825
|
+
sampled = await this.readUntrackedRegularFile(repo, target, sizeBytes, sizeBytes);
|
|
22236
22826
|
}
|
|
22237
22827
|
}
|
|
22238
22828
|
const truncated = sizeBytes > req.maxBytesPerFile || sampled.length > req.maxBytesPerFile;
|
|
@@ -22266,9 +22856,9 @@ var SandboxChannelAService = class {
|
|
|
22266
22856
|
async gitLog(req) {
|
|
22267
22857
|
const repo = assertSafeRelPathOrRoot(req.path);
|
|
22268
22858
|
const fmt = `%H${US}%h${US}%P${US}%an${US}%ae${US}%at${US}%cn${US}%ce${US}%ct${US}%s${US}%b${RS}`;
|
|
22269
|
-
const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(
|
|
22859
|
+
const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote7).join(" ")}` : "";
|
|
22270
22860
|
const { stdout, exitCode } = await this.runInConfinedDirectory(repo, {
|
|
22271
|
-
cmd: `git log --format=${
|
|
22861
|
+
cmd: `git log --format=${shellQuote7(fmt)} -n${req.maxCount + 1} --skip=${req.skip} ${shellQuote7(req.ref)}${pathspec}`
|
|
22272
22862
|
});
|
|
22273
22863
|
if (exitCode !== null && exitCode !== 0) {
|
|
22274
22864
|
return { commits: [], hasMore: false };
|
|
@@ -22295,7 +22885,7 @@ var SandboxChannelAService = class {
|
|
|
22295
22885
|
const repo = assertSafeRelPathOrRoot(req.path);
|
|
22296
22886
|
if (req.filePath) {
|
|
22297
22887
|
const { stdout, exitCode } = await this.runInConfinedDirectory(repo, {
|
|
22298
|
-
cmd: `git cat-file blob ${
|
|
22888
|
+
cmd: `git cat-file blob ${shellQuote7(`${req.ref}:${req.filePath}`)} 2>/dev/null | base64`
|
|
22299
22889
|
});
|
|
22300
22890
|
if (exitCode !== null && exitCode !== 0 && stdout.trim() === "") {
|
|
22301
22891
|
throw new ChannelANotFoundError(`blob not found: ${req.ref}:${req.filePath}`);
|
|
@@ -22568,19 +23158,28 @@ var SandboxChannelAService = class {
|
|
|
22568
23158
|
const safe = assertSafeRelPathOrRoot(rel);
|
|
22569
23159
|
const root = this.workspaceRoot || ".";
|
|
22570
23160
|
const abs = this.joinRoot(safe);
|
|
22571
|
-
const rejectLink = safe ? `test ! -L ${
|
|
22572
|
-
const script = [
|
|
22573
|
-
`root=$(realpath -e -- ${shellQuote6(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
22574
|
-
rejectLink,
|
|
22575
|
-
`target=$(realpath -e -- ${shellQuote6(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
22576
|
-
`case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
|
|
22577
|
-
`test -d "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
22578
|
-
`cd -P -- "$target"`,
|
|
22579
|
-
`printf '__OPENGENI_FS_CONFINED_OK__\\n'`,
|
|
22580
|
-
args.cmd
|
|
22581
|
-
].join("; ");
|
|
22582
|
-
const successPrefix = "__OPENGENI_FS_CONFINED_OK__\n";
|
|
23161
|
+
const rejectLink = safe ? `test ! -L ${shellQuote7(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
|
|
22583
23162
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
23163
|
+
const frameId = crypto.randomUUID().replaceAll("-", "");
|
|
23164
|
+
const successPrefix = `__OPENGENI_FS_CONFINED_${frameId}_OK__
|
|
23165
|
+
`;
|
|
23166
|
+
const successSuffixPrefix = `__OPENGENI_FS_CONFINED_${frameId}_END__:`;
|
|
23167
|
+
const successSuffixTerminator = "__";
|
|
23168
|
+
const script = [
|
|
23169
|
+
`root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
23170
|
+
rejectLink,
|
|
23171
|
+
`target=$(realpath -e -- ${shellQuote7(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
23172
|
+
`case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
|
|
23173
|
+
`test -d "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
|
|
23174
|
+
`cd -P -- "$target"`,
|
|
23175
|
+
`printf ${shellQuote7(successPrefix)}`,
|
|
23176
|
+
// Keep an operation-level `exit` inside the subshell so the trusted end
|
|
23177
|
+
// frame is emitted for every completed command.
|
|
23178
|
+
`( ${args.cmd} )`,
|
|
23179
|
+
`operation_status=$?`,
|
|
23180
|
+
`printf ${shellQuote7(`${successSuffixPrefix}%s${successSuffixTerminator}`)} "$operation_status"`,
|
|
23181
|
+
`exit "$operation_status"`
|
|
23182
|
+
].join("; ");
|
|
22584
23183
|
let result;
|
|
22585
23184
|
try {
|
|
22586
23185
|
result = await this.run({
|
|
@@ -22602,7 +23201,24 @@ var SandboxChannelAService = class {
|
|
|
22602
23201
|
}
|
|
22603
23202
|
const successIndex = result.stdout.indexOf(successPrefix);
|
|
22604
23203
|
if (successIndex >= 0) {
|
|
22605
|
-
|
|
23204
|
+
const payloadStart = successIndex + successPrefix.length;
|
|
23205
|
+
const suffixIndex = result.stdout.lastIndexOf(successSuffixPrefix);
|
|
23206
|
+
if (suffixIndex >= payloadStart) {
|
|
23207
|
+
const suffixEnd = result.stdout.indexOf(
|
|
23208
|
+
successSuffixTerminator,
|
|
23209
|
+
suffixIndex + successSuffixPrefix.length
|
|
23210
|
+
);
|
|
23211
|
+
const statusText = suffixEnd < 0 ? null : result.stdout.slice(suffixIndex + successSuffixPrefix.length, suffixEnd);
|
|
23212
|
+
if (statusText && /^(?:0|[1-9][0-9]{0,2})$/.test(statusText)) {
|
|
23213
|
+
const operationStatus = Number(statusText);
|
|
23214
|
+
if (operationStatus > 255) continue;
|
|
23215
|
+
return {
|
|
23216
|
+
...result,
|
|
23217
|
+
stdout: result.stdout.slice(payloadStart, suffixIndex),
|
|
23218
|
+
exitCode: operationStatus
|
|
23219
|
+
};
|
|
23220
|
+
}
|
|
23221
|
+
}
|
|
22606
23222
|
}
|
|
22607
23223
|
if (result.stdout.includes("__OPENGENI_FS_ESCAPE__") || result.exitCode === 67) {
|
|
22608
23224
|
throw new ChannelAValidationError(`path resolves outside workspace: ${safe || "."}`);
|
|
@@ -22687,6 +23303,15 @@ function sniffBinary(bytes) {
|
|
|
22687
23303
|
for (let i = 0; i < n; i++) if (bytes[i] === 0) return true;
|
|
22688
23304
|
return false;
|
|
22689
23305
|
}
|
|
23306
|
+
function decodeGitMetadataUtf8(bytes) {
|
|
23307
|
+
const decoded = bytes.toString("utf8");
|
|
23308
|
+
if (!Buffer.from(decoded, "utf8").equals(bytes)) {
|
|
23309
|
+
throw new ChannelAUnavailableError(
|
|
23310
|
+
"Workspace Git paths are not valid UTF-8 and cannot be captured authoritatively."
|
|
23311
|
+
);
|
|
23312
|
+
}
|
|
23313
|
+
return decoded;
|
|
23314
|
+
}
|
|
22690
23315
|
function addedLines(bytes) {
|
|
22691
23316
|
if (bytes.length === 0) return [];
|
|
22692
23317
|
const lines = bytes.toString("utf8").split("\n");
|
|
@@ -22715,11 +23340,11 @@ function assertSafeRelPath(p) {
|
|
|
22715
23340
|
if (norm === "") throw new ChannelAValidationError("path is required");
|
|
22716
23341
|
return norm;
|
|
22717
23342
|
}
|
|
22718
|
-
function
|
|
23343
|
+
function shellQuote7(s) {
|
|
22719
23344
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
22720
23345
|
}
|
|
22721
23346
|
function internalBashCommand(script) {
|
|
22722
|
-
return `env -u BASH_ENV bash --noprofile --norc -c ${
|
|
23347
|
+
return `env -u BASH_ENV bash --noprofile --norc -c ${shellQuote7(script)}`;
|
|
22723
23348
|
}
|
|
22724
23349
|
function assertSafePruneDirectoryName(name) {
|
|
22725
23350
|
if (name.length > 255 || !/^[A-Za-z0-9._@+-]+$/.test(name) || name === "." || name === "..") {
|
|
@@ -23424,7 +24049,9 @@ function withDockerNetwork(client, network) {
|
|
|
23424
24049
|
...client.resume ? {
|
|
23425
24050
|
resume: async (state) => await wrapSession(await client.resume(state))
|
|
23426
24051
|
} : {},
|
|
23427
|
-
...client.delete ? {
|
|
24052
|
+
...client.delete ? {
|
|
24053
|
+
delete: async (state) => await client.delete(state)
|
|
24054
|
+
} : {},
|
|
23428
24055
|
...client.serializeSessionState ? {
|
|
23429
24056
|
serializeSessionState: async (state, options) => await client.serializeSessionState(state, options)
|
|
23430
24057
|
} : {},
|
|
@@ -23494,55 +24121,9 @@ function readWorkspaceArchiveFromEnvelopeSessionState(sessionState) {
|
|
|
23494
24121
|
return void 0;
|
|
23495
24122
|
}
|
|
23496
24123
|
}
|
|
23497
|
-
var MODAL_SNAPSHOT_REF_PREFIXES = [
|
|
23498
|
-
"MODAL_SANDBOX_FS_SNAPSHOT_V1\n",
|
|
23499
|
-
"MODAL_SANDBOX_DIR_SNAPSHOT_V1\n"
|
|
23500
|
-
];
|
|
23501
24124
|
function decodeModalSnapshotId(archive) {
|
|
23502
|
-
|
|
23503
|
-
|
|
23504
|
-
text = new TextDecoder().decode(archive);
|
|
23505
|
-
} catch {
|
|
23506
|
-
return void 0;
|
|
23507
|
-
}
|
|
23508
|
-
for (const prefix of MODAL_SNAPSHOT_REF_PREFIXES) {
|
|
23509
|
-
if (!text.startsWith(prefix)) {
|
|
23510
|
-
continue;
|
|
23511
|
-
}
|
|
23512
|
-
try {
|
|
23513
|
-
const payload = JSON.parse(text.slice(prefix.length));
|
|
23514
|
-
return typeof payload.snapshot_id === "string" && payload.snapshot_id.length > 0 ? payload.snapshot_id : void 0;
|
|
23515
|
-
} catch {
|
|
23516
|
-
return void 0;
|
|
23517
|
-
}
|
|
23518
|
-
}
|
|
23519
|
-
return void 0;
|
|
23520
|
-
}
|
|
23521
|
-
async function deletePriorPersistedSnapshot(session, priorArchiveBase64) {
|
|
23522
|
-
if (!priorArchiveBase64) {
|
|
23523
|
-
return void 0;
|
|
23524
|
-
}
|
|
23525
|
-
let bytes;
|
|
23526
|
-
try {
|
|
23527
|
-
bytes = Uint8Array.from(Buffer.from(priorArchiveBase64, "base64"));
|
|
23528
|
-
} catch {
|
|
23529
|
-
return void 0;
|
|
23530
|
-
}
|
|
23531
|
-
const snapshotId = decodeModalSnapshotId(bytes);
|
|
23532
|
-
if (!snapshotId) {
|
|
23533
|
-
return void 0;
|
|
23534
|
-
}
|
|
23535
|
-
const modal = session.modal;
|
|
23536
|
-
const del = modal?.images?.delete;
|
|
23537
|
-
if (typeof del !== "function") {
|
|
23538
|
-
return void 0;
|
|
23539
|
-
}
|
|
23540
|
-
try {
|
|
23541
|
-
await del.call(modal.images, snapshotId);
|
|
23542
|
-
return snapshotId;
|
|
23543
|
-
} catch {
|
|
23544
|
-
return void 0;
|
|
23545
|
-
}
|
|
24125
|
+
const ref = decodeNativeSnapshotRef3(archive);
|
|
24126
|
+
return ref?.provider === "modal_snapshot_filesystem" || ref?.provider === "modal_snapshot_directory" ? ref.snapshotId : void 0;
|
|
23546
24127
|
}
|
|
23547
24128
|
async function deserializeSandboxSessionStateEnvelope(client, envelope) {
|
|
23548
24129
|
if (!envelope || typeof envelope !== "object") {
|
|
@@ -23656,7 +24237,11 @@ async function establishSandboxSessionFromEnvelope(settings, envelope, opts) {
|
|
|
23656
24237
|
const envelopeBackend = typeof envelope?.backendId === "string" ? envelope.backendId : void 0;
|
|
23657
24238
|
const backend = opts.backendOverride ?? envelopeBackend ?? settings.sandboxBackend;
|
|
23658
24239
|
const environment = opts.environment ?? collectSandboxEnvironment(settings);
|
|
23659
|
-
const client =
|
|
24240
|
+
const client = (opts.clientFactory ?? createSandboxClientForBackend)(
|
|
24241
|
+
backend,
|
|
24242
|
+
settings,
|
|
24243
|
+
environment
|
|
24244
|
+
);
|
|
23660
24245
|
if (!client) {
|
|
23661
24246
|
throw new SandboxConfigError(
|
|
23662
24247
|
backend,
|
|
@@ -23749,20 +24334,22 @@ async function establishSandboxSessionFromEnvelope(settings, envelope, opts) {
|
|
|
23749
24334
|
throw error;
|
|
23750
24335
|
}
|
|
23751
24336
|
}
|
|
23752
|
-
|
|
23753
|
-
|
|
23754
|
-
|
|
23755
|
-
|
|
23756
|
-
|
|
23757
|
-
|
|
23758
|
-
|
|
23759
|
-
|
|
23760
|
-
|
|
23761
|
-
|
|
24337
|
+
if (workspaceArchive.kind === "tar") {
|
|
24338
|
+
try {
|
|
24339
|
+
await verifyRestoredWorkspace(restored, workspaceArchive.descriptor);
|
|
24340
|
+
} catch (error) {
|
|
24341
|
+
await terminateCreatedSandbox(client, restored, restored.state);
|
|
24342
|
+
if (error instanceof WorkspaceArchiveIntegrityError) throw error;
|
|
24343
|
+
throw new WorkspaceArchiveIntegrityError(
|
|
24344
|
+
"workspace_fingerprint_unavailable",
|
|
24345
|
+
`failed to verify selected workspace archive revision ${workspaceArchive.descriptor.revision}`,
|
|
24346
|
+
{ retryable: true }
|
|
24347
|
+
);
|
|
24348
|
+
}
|
|
23762
24349
|
}
|
|
23763
24350
|
hydrationApplied = true;
|
|
23764
24351
|
console.info(
|
|
23765
|
-
`[sandbox] cold-restore verified
|
|
24352
|
+
`[sandbox] cold-restore applied ${workspaceArchive.kind === "provider_snapshot" ? "native snapshot receipt" : "verified tar archive"} revision ${workspaceArchive.descriptor.revision}`
|
|
23766
24353
|
);
|
|
23767
24354
|
}
|
|
23768
24355
|
restoredState = restored.state;
|
|
@@ -23945,6 +24532,12 @@ export {
|
|
|
23945
24532
|
modalSandboxAttributionEnvironment,
|
|
23946
24533
|
modalSandboxAttributionTags,
|
|
23947
24534
|
ensureModalRegistryImage,
|
|
24535
|
+
resolveModalCheckpointProviderBindingForSession,
|
|
24536
|
+
modalSessionMatchesCheckpointProviderBinding,
|
|
24537
|
+
resolveModalCheckpointProviderBinding,
|
|
24538
|
+
resolveModalCheckpointProviderBindingForLiveSandbox,
|
|
24539
|
+
inspectModalSandboxLifecycle,
|
|
24540
|
+
deleteModalCheckpointSnapshot,
|
|
23948
24541
|
tagModalSandbox,
|
|
23949
24542
|
terminateModalSandboxById,
|
|
23950
24543
|
sweepModalOrphanSandboxes,
|
|
@@ -24003,13 +24596,16 @@ export {
|
|
|
24003
24596
|
isProviderSandboxNotFoundError2 as isProviderSandboxNotFoundError,
|
|
24004
24597
|
isProviderSandboxGoneDuringRoutedOperation,
|
|
24005
24598
|
isProviderSandboxTransientError,
|
|
24006
|
-
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
24007
24599
|
WorkspaceArchiveIntegrityError,
|
|
24008
|
-
|
|
24600
|
+
describeNativeSnapshotArchive,
|
|
24601
|
+
describeLegacyNativeSnapshotArchive,
|
|
24009
24602
|
readVerifiedWorkspaceArchive,
|
|
24010
24603
|
fingerprintSandboxWorkspace,
|
|
24011
24604
|
captureVerifiedWorkspaceArchive,
|
|
24012
24605
|
verifyRestoredWorkspace,
|
|
24606
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION2 as WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
24607
|
+
decodeNativeSnapshotRef3 as decodeNativeSnapshotRef,
|
|
24608
|
+
parseWorkspaceArchiveDescriptor2 as parseWorkspaceArchiveDescriptor,
|
|
24013
24609
|
selectBackend,
|
|
24014
24610
|
backendSupportsOs,
|
|
24015
24611
|
desktopCapableBackend,
|
|
@@ -24099,7 +24695,6 @@ export {
|
|
|
24099
24695
|
restoredSandboxSessionStateFromEntry,
|
|
24100
24696
|
readWorkspaceArchiveFromEnvelopeSessionState,
|
|
24101
24697
|
decodeModalSnapshotId,
|
|
24102
|
-
deletePriorPersistedSnapshot,
|
|
24103
24698
|
deserializeSandboxSessionStateEnvelope,
|
|
24104
24699
|
SandboxExecReadinessError,
|
|
24105
24700
|
verifySandboxExecReadiness,
|
|
@@ -24112,4 +24707,4 @@ export {
|
|
|
24112
24707
|
collectSandboxEnvironment2 as collectSandboxEnvironment,
|
|
24113
24708
|
parseExposedPorts2 as parseExposedPorts
|
|
24114
24709
|
};
|
|
24115
|
-
//# sourceMappingURL=chunk-
|
|
24710
|
+
//# sourceMappingURL=chunk-GNEGANUF.js.map
|