@jigging/jig 0.1.0-alpha.26 → 0.1.0-alpha.29

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.
@@ -20,6 +20,7 @@ var POLICY = Object.freeze(["--no-env-file", "--no-install", "--config=/dev/null
20
20
  var SANDBOX_BUN = "/jig-runtime/bun";
21
21
  var SANDBOX_LIBRARY_PATH = "/jig-runtime/lib";
22
22
  var MAX_CONTROL_BYTES = 64 * 1024;
23
+ var CORE_DUMP_POLL_MS = 250;
23
24
  var MODULE_DESTINATION = "/jig/linux-rootless-supervisor.ts";
24
25
  var DIGEST = /^sha256:[0-9a-f]{64}$/;
25
26
  var OWNER_TOKEN = /^[0-9a-f]{64}$/;
@@ -112,6 +113,9 @@ async function superviseConnected(control, startupDeadlineUnixMs) {
112
113
  let exitSignal = null;
113
114
  let evidence = emptyEvidence();
114
115
  let terminal;
116
+ let coreDumpTimer;
117
+ let coreDumpCheck;
118
+ let monitoringClosed = false;
115
119
  try {
116
120
  await mkdir(runCgroup, { mode: 493 });
117
121
  cgroupCreated = true;
@@ -162,6 +166,19 @@ async function superviseConnected(control, startupDeadlineUnixMs) {
162
166
  });
163
167
  childExit = childClose(launched);
164
168
  child = launched;
169
+ coreDumpTimer = setInterval(() => {
170
+ if (monitoringClosed || stopReason !== undefined || coreDumpCheck !== undefined)
171
+ return;
172
+ coreDumpCheck = privateHasCoreDumpingProcess(runCgroup, limits.pids).then((dumping) => {
173
+ if (dumping && !monitoringClosed && stopReason === undefined)
174
+ stop("core_dump");
175
+ }).catch(() => {
176
+ if (!monitoringClosed && stopReason === undefined)
177
+ stop("setup_failed");
178
+ }).finally(() => {
179
+ coreDumpCheck = undefined;
180
+ });
181
+ }, CORE_DUMP_POLL_MS);
165
182
  launched.stdio[4].on("error", () => stop("setup_failed"));
166
183
  const ready = await readReady(launched);
167
184
  if (configuration.output) {
@@ -187,12 +204,16 @@ async function superviseConnected(control, startupDeadlineUnixMs) {
187
204
  process.stderr.write(`${errorText(error)}
188
205
  `);
189
206
  } finally {
207
+ monitoringClosed = true;
208
+ clearInterval(coreDumpTimer);
190
209
  clearTimeout(deadline);
191
210
  await outputDirectory?.close();
192
211
  let cleanupError;
193
212
  try {
194
213
  child?.kill("SIGKILL");
195
214
  await killRun();
215
+ if (coreDumpCheck !== undefined)
216
+ await withinTimeout(coreDumpCheck, limits.cleanupTimeoutMs, "core-dump check did not settle");
196
217
  if (childExit !== undefined) {
197
218
  await withinTimeout(childExit.catch(() => {
198
219
  return;
@@ -225,6 +246,36 @@ async function superviseConnected(control, startupDeadlineUnixMs) {
225
246
  control.end();
226
247
  }
227
248
  }
249
+ async function privateHasCoreDumpingProcess(runCgroup, maxProcesses, readText = (path) => readFile(path, "utf8")) {
250
+ const processes = (await readText(`${runCgroup}/cgroup.procs`)).trim();
251
+ const pids = processes === "" ? [] : processes.split(`
252
+ `);
253
+ if (!positiveInteger(maxProcesses) || pids.length > maxProcesses || pids.some((pid) => !/^[1-9][0-9]*$/.test(pid) || !Number.isSafeInteger(Number(pid))))
254
+ throw new Error("invalid owned process observation");
255
+ const membership = `0::${runCgroup.slice("/sys/fs/cgroup".length)}`;
256
+ for (const pid of pids) {
257
+ try {
258
+ const status = await readText(`/proc/${pid}/status`);
259
+ if (status.length > MAX_CONTROL_BYTES)
260
+ throw new Error("oversized owned process status");
261
+ if (!/^CoreDumping:/m.test(status))
262
+ continue;
263
+ const dumping = /^CoreDumping:[ \t]+([01])$/m.exec(status);
264
+ if (dumping === null)
265
+ throw new Error("kernel core-dump observation is unavailable");
266
+ if (dumping[1] !== "1")
267
+ continue;
268
+ if ((await readText(`/proc/${pid}/cgroup`)).split(`
269
+ `).includes(membership))
270
+ return true;
271
+ } catch (error) {
272
+ const code = error.code;
273
+ if (code !== "ENOENT" && code !== "ESRCH")
274
+ throw error;
275
+ }
276
+ }
277
+ return false;
278
+ }
228
279
  async function enterMain(arguments_) {
229
280
  requireFixedBunPosture("entry trampoline");
230
281
  if (arguments_.length < 7)
@@ -792,3 +843,6 @@ if (import.meta.main) {
792
843
  process.exitCode = 70;
793
844
  });
794
845
  }
846
+ export {
847
+ privateHasCoreDumpingProcess
848
+ };
@@ -1375,7 +1375,9 @@ function requirePrivateMacosGuardianStorage(storage, files, cwd) {
1375
1375
  if (storage === null || typeof storage !== "object" || Object.keys(storage).sort().join() !== "bytes,collect,mountPath" || typeof storage.mountPath !== "string" || !storage.mountPath.startsWith("/") || storage.mountPath === "/" || posix3.normalize(storage.mountPath) !== storage.mountPath || !Number.isSafeInteger(storage.bytes) || storage.bytes < 16 * 1024 * 1024 || storage.bytes > 512 * 1024 * 1024 || storage.bytes % (1024 * 1024) !== 0 || ![null, "output", "work"].includes(storage.collect))
1376
1376
  throw new TypeError("invalid macOS guardian storage");
1377
1377
  const roots = ["work", "tmp", "output"].map((name) => join5(storage.mountPath, name));
1378
- if (files.writableTrees.some((path) => !roots.includes(path)) || !roots.some((root) => cwd === root || cwd.startsWith(`${root}/`)))
1378
+ const inputs = join5(storage.mountPath, "inputs");
1379
+ const readOnlyInputCwd = files.writableTrees.length === 0 && storage.collect === null && files.readOnlyTrees.includes(inputs) && (cwd === inputs || cwd.startsWith(`${inputs}/`));
1380
+ if (files.writableTrees.some((path) => !roots.includes(path)) || !roots.some((root) => cwd === root || cwd.startsWith(`${root}/`)) && !readOnlyInputCwd)
1379
1381
  throw new TypeError("macOS writable projection is outside bounded storage");
1380
1382
  }
1381
1383
  async function preparePrivateMacosGuardianStorage(owner, token, storage, signal) {
@@ -20228,6 +20228,7 @@ async function captureAttempt(root, backing, selection) {
20228
20228
  const directories = new Set([identityKey(root.information)]);
20229
20229
  let totalBytes = 0;
20230
20230
  let directoryCount = 0;
20231
+ const copyBuffer = new Uint8Array(COPY_CHUNK_BYTES);
20231
20232
  async function walk(directory, logicalDirectory) {
20232
20233
  directoryCount += 1;
20233
20234
  if (directoryCount > MAX_DIRECTORIES) {
@@ -20253,7 +20254,7 @@ async function captureAttempt(root, backing, selection) {
20253
20254
  invalid("PACKAGE_LIMIT", "selected dependency source exceeds its capture budget", logicalPath);
20254
20255
  await rejectKnownOversizeFile(entry.handle, entry.information, logicalPath);
20255
20256
  const offset = totalBytes;
20256
- const size = await copyToBacking(entry.handle, backing, offset, totalBytes, logicalPath, selection?.maximumBytes);
20257
+ const size = await copyToBacking(entry.handle, backing, offset, totalBytes, logicalPath, copyBuffer, selection?.maximumBytes);
20257
20258
  totalBytes += size;
20258
20259
  if (selection !== undefined && totalBytes > selection.maximumBytes)
20259
20260
  invalid("PACKAGE_LIMIT", "selected dependency source exceeds its capture budget", logicalPath);
@@ -20277,10 +20278,9 @@ async function captureAttempt(root, backing, selection) {
20277
20278
  }
20278
20279
  return { records, fingerprints };
20279
20280
  }
20280
- async function copyToBacking(source, backing, backingOffset, priorTotal, logicalPath, maximumBytes = MAX_TOTAL_BYTES2) {
20281
+ async function copyToBacking(source, backing, backingOffset, priorTotal, logicalPath, buffer, maximumBytes = MAX_TOTAL_BYTES2) {
20281
20282
  let sourceOffset = 0;
20282
20283
  while (true) {
20283
- const buffer = new Uint8Array(COPY_CHUNK_BYTES);
20284
20284
  let bytesRead;
20285
20285
  try {
20286
20286
  ({ bytesRead } = await source.read(buffer, 0, buffer.byteLength, sourceOffset));
@@ -188,6 +188,33 @@ function ordinaryRecord(value) {
188
188
  return value;
189
189
  }
190
190
 
191
+ // src/internal/bun-native-inputs.ts
192
+ async function privateBunNativeInputs(input) {
193
+ const manifests = [
194
+ "package.json",
195
+ ...input.members?.map((path) => `${path}/package.json`) ?? []
196
+ ];
197
+ const paths = new Set(manifests);
198
+ if (input.paths.includes("bun.lock"))
199
+ paths.add("bun.lock");
200
+ let patches = {};
201
+ for (const path of manifests) {
202
+ const bytes = await input.read(path);
203
+ if (bytes.byteLength > 1024 * 1024)
204
+ throw new TypeError("oversized native manifest");
205
+ const manifest = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
206
+ requirePrivateBunResolutionManifest(manifest, input.members === undefined ? undefined : path === "package.json" ? "root" : "member");
207
+ if (path === "package.json")
208
+ patches = requirePrivateBunPatches(manifest.patchedDependencies);
209
+ }
210
+ for (const path of Object.values(patches)) {
211
+ if ((await input.read(path)).byteLength > 1024 * 1024)
212
+ throw new TypeError("oversized captured patch");
213
+ paths.add(path);
214
+ }
215
+ return Object.freeze({ paths, patches });
216
+ }
217
+
191
218
  // src/package/normalization-data-15.1.ts
192
219
  var CANONICAL_CLASS_15_1 = new Map([
193
220
  [768, 230],
@@ -5014,29 +5041,21 @@ try {
5014
5041
  if (!(await iterator.next()).done) {
5015
5042
  throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "preparation source has trailing data");
5016
5043
  }
5017
- const inputPaths = new Set([
5018
- "package.json",
5019
- "bun.lock",
5020
- ...workspace?.members.map((path) => `${path}/package.json`) ?? []
5021
- ]);
5044
+ let inputPaths;
5022
5045
  let patches = {};
5023
5046
  try {
5024
- for (const path of [
5025
- "package.json",
5026
- ...workspace?.members.map((path2) => `${path2}/package.json`) ?? []
5027
- ]) {
5028
- const file = source.files.find((file2) => file2.path === path);
5029
- const manifest = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64(file.content, path)));
5030
- requirePrivateBunResolutionManifest(manifest, workspace === undefined ? undefined : path === "package.json" ? "root" : "member");
5031
- if (path === "package.json")
5032
- patches = requirePrivateBunPatches(manifest.patchedDependencies);
5033
- }
5034
- for (const path of Object.values(patches)) {
5035
- const file = source.files.find((file2) => file2.path === path);
5036
- if (file === undefined || decodeBase64(file.content, path).byteLength > 1024 * 1024)
5037
- throw new TypeError("missing or oversized captured patch");
5038
- inputPaths.add(path);
5039
- }
5047
+ const native = await privateBunNativeInputs({
5048
+ paths: source.files.map(({ path }) => path),
5049
+ ...workspace === undefined ? {} : { members: workspace.members },
5050
+ read(path) {
5051
+ const file = source.files.find((file2) => file2.path === path);
5052
+ if (file === undefined)
5053
+ throw new TypeError("missing native input");
5054
+ return decodeBase64(file.content, path);
5055
+ }
5056
+ });
5057
+ inputPaths = native.paths;
5058
+ patches = native.patches;
5040
5059
  } catch {
5041
5060
  throw new WorkerFailure("PACKAGE_BUN_SOURCE_UNSUPPORTED", "native manifests or declared patch inputs are unsupported or incomplete");
5042
5061
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jigging/jig",
3
- "version": "0.1.0-alpha.26",
3
+ "version": "0.1.0-alpha.29",
4
4
  "description": "A local, secure host for admitted FLOW packages",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {