@opengeni/runtime 0.13.11 → 0.13.12

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.
@@ -21427,6 +21427,8 @@ var REPOSITORY_DISCOVERY_STATUS_PREFIX = "__OPENGENI_REPOSITORY_DISCOVERY_STATUS
21427
21427
  var NUL = String.fromCharCode(0);
21428
21428
  var FS_LIST_TRUNCATED_MARKER = "__OPENGENI_FS_LIST_TRUNCATED__";
21429
21429
  var FS_LIST_MAX_OUTPUT_BYTES = 768 * 1024;
21430
+ var GIT_COMMAND_CHUNK_BYTES = 512 * 1024;
21431
+ var GIT_METADATA_MAX_BYTES = 2 * 1024 * 1024;
21430
21432
  var US = String.fromCharCode(31);
21431
21433
  var RS = String.fromCharCode(30);
21432
21434
  var SELFHOSTED_VIRTUAL_ROOT2 = "/workspace";
@@ -21467,8 +21469,9 @@ var SandboxChannelAService = class {
21467
21469
  // ════════════════════════════ exec primitive ══════════════════════════════
21468
21470
  // RAW exec — returns {stdout, stderr, exitCode}. Uses session.exec when present
21469
21471
  // (the local/docker sessions return raw output); falls back to execCommand +
21470
- // a banner strip (last resort; banner-truncation can mangle, so exec is always
21471
- // preferred). Throws ChannelAUnsupportedError when neither exists.
21472
+ // a banner strip. Callers that parse output must independently bound/frame it
21473
+ // because provider retained-output truncation drops command prefixes. Throws
21474
+ // ChannelAUnsupportedError when neither exists.
21472
21475
  async run(args) {
21473
21476
  const withRunAs = this.runAs ? { ...args, runAs: this.runAs } : args;
21474
21477
  if (this.session.exec) {
@@ -21907,6 +21910,121 @@ var SandboxChannelAService = class {
21907
21910
  return { path, revision: this.revision };
21908
21911
  }
21909
21912
  // ════════════════════════════ Git (A2, read-only) ═════════════════════════
21913
+ /** Measure one Git command without returning its potentially large or
21914
+ * NUL-bearing output through the provider's text transport. */
21915
+ async measureConfinedCommandBytes(repo, command) {
21916
+ const measured = await this.runInConfinedDirectory(repo, {
21917
+ cmd: [
21918
+ "set -o pipefail",
21919
+ `{ ${command}; } 2>/dev/null | { bytes=$(wc -c | tr -d ' \\n'); printf '%s' "$bytes"; }`,
21920
+ "producer_status=${PIPESTATUS[0]}",
21921
+ `printf '\\t%s\\n' "$producer_status"`
21922
+ ].join("; "),
21923
+ maxOutputTokens: 1024
21924
+ });
21925
+ const match = measured.stdout.match(/^(\d+)\t(\d+)\n?$/);
21926
+ if (!match || measured.exitCode !== null && measured.exitCode !== 0 || Number(match[2]) !== 0) {
21927
+ throw new ChannelAUnavailableError(
21928
+ "Workspace Git data is temporarily unavailable. Retry the operation."
21929
+ );
21930
+ }
21931
+ const size = Number(match[1]);
21932
+ if (!Number.isSafeInteger(size) || size < 0) {
21933
+ throw new ChannelAUnavailableError(
21934
+ "Workspace Git data is temporarily unavailable. Retry the operation."
21935
+ );
21936
+ }
21937
+ return size;
21938
+ }
21939
+ /** Read an exact prefix of a command's output in chunks that remain below
21940
+ * every supported execCommand retained-output ceiling. The producer is
21941
+ * intentionally rerun per chunk; turn-end capture calls this only after the
21942
+ * durable mutation authority has quiesced the workspace. */
21943
+ async readConfinedCommandPrefix(repo, command, byteLength2) {
21944
+ if (byteLength2 === 0) return Buffer.alloc(0);
21945
+ const chunks = [];
21946
+ for (let offset = 0; offset < byteLength2; offset += GIT_COMMAND_CHUNK_BYTES) {
21947
+ const expected = Math.min(GIT_COMMAND_CHUNK_BYTES, byteLength2 - offset);
21948
+ const chunk = await this.runInConfinedDirectory(repo, {
21949
+ cmd: [
21950
+ `{ ${command}; } 2>/dev/null`,
21951
+ `tail -c +${offset + 1}`,
21952
+ `head -c ${expected}`,
21953
+ "base64",
21954
+ `tr -d '\\n'`
21955
+ ].join(" | "),
21956
+ maxOutputTokens: Math.ceil(GIT_COMMAND_CHUNK_BYTES * 4 / 3) + 1024
21957
+ });
21958
+ if (chunk.exitCode !== null && chunk.exitCode !== 0) {
21959
+ throw new ChannelAUnavailableError(
21960
+ "Workspace Git data is temporarily unavailable. Retry the operation."
21961
+ );
21962
+ }
21963
+ const encoded = chunk.stdout.replace(/\s/g, "");
21964
+ const bytes = Buffer.from(encoded, "base64");
21965
+ if (bytes.byteLength !== expected || bytes.toString("base64") !== encoded) {
21966
+ throw new ChannelAUnavailableError(
21967
+ "Workspace Git data is temporarily unavailable. Retry the operation."
21968
+ );
21969
+ }
21970
+ chunks.push(bytes);
21971
+ }
21972
+ return Buffer.concat(chunks, byteLength2);
21973
+ }
21974
+ async readConfinedCommandBytes(repo, command, maxBytes) {
21975
+ const sizeBytes = await this.measureConfinedCommandBytes(repo, command);
21976
+ if (sizeBytes > maxBytes) {
21977
+ return { bytes: Buffer.alloc(0), sizeBytes, truncated: true };
21978
+ }
21979
+ return {
21980
+ bytes: await this.readConfinedCommandPrefix(repo, command, sizeBytes),
21981
+ sizeBytes,
21982
+ truncated: false
21983
+ };
21984
+ }
21985
+ /** Read a regular untracked file without routing its body through one large
21986
+ * execCommand response. Native provider reads are binary-safe; providers
21987
+ * without that surface use the same bounded chunk protocol as Git patches. */
21988
+ async readUntrackedRegularFile(repo, target, byteLength2) {
21989
+ if (byteLength2 === 0) return Buffer.alloc(0);
21990
+ const path = repo ? `${repo}/${target}` : target;
21991
+ assertSafeRelPath(path);
21992
+ if (this.session.readFile) {
21993
+ try {
21994
+ const raw = await this.session.readFile({
21995
+ path: this.joinRoot(path),
21996
+ maxBytes: byteLength2,
21997
+ ...this.runAs ? { runAs: this.runAs } : {}
21998
+ });
21999
+ const bytes = typeof raw === "string" ? Buffer.from(raw, "utf8") : Buffer.from(raw);
22000
+ if (bytes.byteLength !== byteLength2) {
22001
+ throw new ChannelAUnavailableError(
22002
+ "Workspace Git data changed during capture. Retry the operation."
22003
+ );
22004
+ }
22005
+ return bytes;
22006
+ } catch (error) {
22007
+ if (error instanceof ChannelAUnavailableError) throw error;
22008
+ if (isWorkspaceEscapeError(error)) {
22009
+ throw new ChannelAValidationError(`path resolves outside workspace: ${path}`);
22010
+ }
22011
+ if (isDefinitePathNotFoundError(error)) {
22012
+ throw new ChannelANotFoundError(`file not found: ${path}`);
22013
+ }
22014
+ if (!this.session.exec && !this.session.execCommand) {
22015
+ throw new ChannelAUnavailableError(
22016
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22017
+ );
22018
+ }
22019
+ }
22020
+ }
22021
+ const fileArg = target.startsWith("./") ? target : `./${target}`;
22022
+ return await this.readConfinedCommandPrefix(
22023
+ repo,
22024
+ `file=${shellQuote6(fileArg)}; test ! -L "$file" && test -f "$file" || exit 66; cat -- "$file"`,
22025
+ byteLength2
22026
+ );
22027
+ }
21910
22028
  async gitStatus(req) {
21911
22029
  const repo = assertSafeRelPathOrRoot(req.path);
21912
22030
  const inside = await this.runInConfinedDirectory(repo, {
@@ -21924,23 +22042,45 @@ var SandboxChannelAService = class {
21924
22042
  revision: this.revision
21925
22043
  };
21926
22044
  }
21927
- const { stdout } = await this.runInConfinedDirectory(repo, {
21928
- cmd: "git status --porcelain=v2 --branch -z"
21929
- });
21930
- return { ...parsePorcelainV2(stdout), revision: this.revision };
22045
+ const status = await this.readConfinedCommandBytes(
22046
+ repo,
22047
+ "git status --porcelain=v2 --branch -z",
22048
+ GIT_METADATA_MAX_BYTES
22049
+ );
22050
+ if (status.truncated) {
22051
+ throw new ChannelAUnavailableError(
22052
+ "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22053
+ );
22054
+ }
22055
+ return { ...parsePorcelainV2(status.bytes.toString("utf8")), revision: this.revision };
21931
22056
  }
21932
22057
  async gitDiff(req) {
21933
22058
  const repo = assertSafeRelPathOrRoot(req.path);
21934
22059
  const ctx = req.contextLines;
21935
22060
  let range = "";
21936
22061
  if (req.fromRef && req.toRef) range = `${shellQuote6(req.fromRef)} ${shellQuote6(req.toRef)}`;
21937
- else if (req.fromRef) range = `${shellQuote6(req.fromRef)}`;
21938
- else if (req.staged) range = "--cached";
22062
+ else if (req.fromRef) {
22063
+ if (req.fromRef === "HEAD") {
22064
+ const head = await this.runInConfinedDirectory(repo, {
22065
+ cmd: "if git rev-parse --verify --quiet HEAD >/dev/null; then printf 'present'; else printf 'unborn'; fi"
22066
+ });
22067
+ range = head.stdout.trim() === "present" ? shellQuote6(req.fromRef) : "--cached";
22068
+ } else {
22069
+ range = shellQuote6(req.fromRef);
22070
+ }
22071
+ } else if (req.staged) range = "--cached";
21939
22072
  const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote6).join(" ")}` : "";
21940
- const numstat = await this.runInConfinedDirectory(repo, {
21941
- cmd: `git -c core.quotePath=false diff --no-color -z --numstat ${range}${pathspec}`.trim()
21942
- });
21943
- const stats = parseNumstatZ(numstat.stdout);
22073
+ const numstat = await this.readConfinedCommandBytes(
22074
+ repo,
22075
+ `git -c core.quotePath=false diff --no-color -z --numstat ${range}${pathspec}`.trim(),
22076
+ GIT_METADATA_MAX_BYTES
22077
+ );
22078
+ if (numstat.truncated) {
22079
+ throw new ChannelAUnavailableError(
22080
+ "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22081
+ );
22082
+ }
22083
+ const stats = parseNumstatZ(numstat.bytes.toString("utf8"));
21944
22084
  const files = [];
21945
22085
  for (const stat4 of stats) {
21946
22086
  const target = stat4.newPath;
@@ -21959,11 +22099,12 @@ var SandboxChannelAService = class {
21959
22099
  });
21960
22100
  continue;
21961
22101
  }
21962
- const patch = await this.runInConfinedDirectory(repo, {
21963
- cmd: `git -c core.quotePath=false diff --no-color -U${ctx} ${range} -- ${shellQuote6(target)}`.trim()
21964
- });
21965
- const oversized = Buffer.byteLength(patch.stdout, "utf8") > req.maxBytesPerFile;
21966
- const parsed = oversized ? { hunks: [], status: "modified" } : parseUnifiedPatch(patch.stdout);
22102
+ const patch = await this.readConfinedCommandBytes(
22103
+ repo,
22104
+ `git -c core.quotePath=false diff --no-color -U${ctx} ${range} -- ${shellQuote6(target)}`.trim(),
22105
+ req.maxBytesPerFile
22106
+ );
22107
+ const parsed = patch.truncated ? { hunks: [], status: "modified" } : parseUnifiedPatch(patch.bytes.toString("utf8"));
21967
22108
  files.push({
21968
22109
  path: target,
21969
22110
  oldPath: stat4.oldPath,
@@ -21973,49 +22114,63 @@ var SandboxChannelAService = class {
21973
22114
  additions: stat4.additions,
21974
22115
  deletions: stat4.deletions,
21975
22116
  hunks: parsed.hunks,
21976
- truncated: oversized
22117
+ truncated: patch.truncated
21977
22118
  });
21978
22119
  }
21979
22120
  if (req.includeUntracked) {
21980
- const untracked = await this.runInConfinedDirectory(repo, {
21981
- cmd: `git -c core.quotePath=false ls-files --others --exclude-standard -z${pathspec}`
21982
- });
21983
- for (const target of untracked.stdout.split(NUL).filter(Boolean)) {
22121
+ const untracked = await this.readConfinedCommandBytes(
22122
+ repo,
22123
+ `git -c core.quotePath=false ls-files --others --exclude-standard -z${pathspec}`,
22124
+ GIT_METADATA_MAX_BYTES
22125
+ );
22126
+ if (untracked.truncated) {
22127
+ throw new ChannelAUnavailableError(
22128
+ "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22129
+ );
22130
+ }
22131
+ for (const target of untracked.bytes.toString("utf8").split(NUL).filter(Boolean)) {
21984
22132
  const fileArg = target.startsWith("./") ? target : `./${target}`;
21985
22133
  const read = await this.runInConfinedDirectory(repo, {
21986
22134
  cmd: [
21987
22135
  `file=${shellQuote6(fileArg)}`,
21988
- 'if [ -L "$file" ]; then printf "L\\n"; readlink -z -- "$file" | base64 | tr -d "\\n"; exit; fi',
22136
+ 'if [ -L "$file" ]; then printf "L\\t"; readlink -z -- "$file" | base64 | tr -d "\\n"; exit; fi',
21989
22137
  'size=$(wc -c < "$file") || exit 66',
21990
22138
  'line_count=$(wc -l < "$file") || exit 66',
21991
22139
  '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',
21992
- 'printf "F\\t%s\\t%s\\n" "$size" "$line_count"',
21993
- `head -c ${req.maxBytesPerFile + 1} "$file" | base64 | tr -d "\\n"`
22140
+ 'printf "F\\t%s\\t%s" "$size" "$line_count"'
21994
22141
  ].join("; ")
21995
22142
  });
21996
- if (read.exitCode !== null && read.exitCode !== 0) continue;
21997
- const lineBreak = read.stdout.indexOf("\n");
21998
- if (lineBreak < 0) continue;
21999
- const header = read.stdout.slice(0, lineBreak);
22000
- const encoded = read.stdout.slice(lineBreak + 1).replace(/\s/g, "");
22001
- let sampled = Buffer.from(encoded, "base64");
22143
+ if (read.exitCode !== null && read.exitCode !== 0) {
22144
+ throw new ChannelAUnavailableError(
22145
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22146
+ );
22147
+ }
22148
+ const [kind, first, second] = read.stdout.split(" ");
22149
+ let sampled = Buffer.alloc(0);
22002
22150
  let sizeBytes;
22003
22151
  let lineCount;
22004
- if (header === "L") {
22152
+ if (kind === "L") {
22153
+ const encoded = (first ?? "").replace(/\s/g, "");
22154
+ sampled = Buffer.from(encoded, "base64");
22005
22155
  if (sampled.at(-1) !== 0) continue;
22006
22156
  sampled = sampled.subarray(0, -1);
22007
22157
  sizeBytes = sampled.length;
22008
22158
  lineCount = addedLines(sampled).length;
22009
22159
  } else {
22010
- const [kind, sizeRaw, lineCountRaw] = header.split(" ");
22011
22160
  if (kind !== "F") continue;
22012
- const parsedSize = safeInt(sizeRaw);
22013
- const parsedLineCount = safeInt(lineCountRaw);
22161
+ const parsedSize = safeInt(first);
22162
+ const parsedLineCount = safeInt(second);
22014
22163
  if (parsedSize === null || parsedSize < 0 || parsedLineCount === null || parsedLineCount < 0) {
22015
22164
  continue;
22016
22165
  }
22017
22166
  sizeBytes = parsedSize;
22018
22167
  lineCount = parsedLineCount;
22168
+ const truncated2 = sizeBytes > req.maxBytesPerFile;
22169
+ const sampleSize = Math.min(sizeBytes, 8192);
22170
+ sampled = await this.readUntrackedRegularFile(repo, target, sampleSize);
22171
+ if (!sniffBinary(sampled) && !truncated2 && sampleSize < sizeBytes) {
22172
+ sampled = await this.readUntrackedRegularFile(repo, target, sizeBytes);
22173
+ }
22019
22174
  }
22020
22175
  const truncated = sizeBytes > req.maxBytesPerFile || sampled.length > req.maxBytesPerFile;
22021
22176
  const bytes = truncated ? sampled.subarray(0, req.maxBytesPerFile) : sampled;
@@ -23893,4 +24048,4 @@ export {
23893
24048
  collectSandboxEnvironment2 as collectSandboxEnvironment,
23894
24049
  parseExposedPorts2 as parseExposedPorts
23895
24050
  };
23896
- //# sourceMappingURL=chunk-RHB7ETON.js.map
24051
+ //# sourceMappingURL=chunk-FLRCDJRI.js.map