@jigging/jig 0.1.0-alpha.27 → 0.1.0-alpha.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -182,7 +182,7 @@ function readRecord(directory, name) {
182
182
  const parent = privateDirectory(directory);
183
183
  let fd;
184
184
  try {
185
- fd = openSync(join(directory, name), constants.O_RDONLY | O_NOFOLLOW_ANY | O_CLOEXEC);
185
+ fd = openSync(join(directory, name), constants.O_RDONLY | constants.O_NONBLOCK | O_NOFOLLOW_ANY | O_CLOEXEC);
186
186
  const before = fstatSync(fd, { bigint: true });
187
187
  if (!before.isFile() || before.uid !== BigInt(process.getuid?.() ?? -1) || (before.mode & 0o177n) !== 0n || before.nlink !== 1n || before.size < 1n || before.size > 1024n)
188
188
  throw new Error("macOS ownership journal is unsafe");
@@ -434,13 +434,11 @@ function acquirePrivateMacosCoalition() {
434
434
  observedMembers++;
435
435
  }
436
436
  const after = usage(owner.coalition);
437
- if (after.cpuNanoseconds < before.cpuNanoseconds)
438
- throw new Error("macOS CPU accounting moved backwards");
439
437
  return Object.freeze({
440
438
  ...after,
441
439
  footprintBytes,
442
440
  observedMembers,
443
- complete: complete && before.active === after.active && after.active === BigInt(observedMembers + 1),
441
+ complete: complete && after.cpuNanoseconds >= before.cpuNanoseconds && before.active === after.active && after.active === BigInt(observedMembers + 1),
444
442
  sampleMilliseconds: performance.now() - start
445
443
  });
446
444
  },
@@ -694,6 +692,10 @@ function privateMacosUnlinkAt(parent, name, directory = false) {
694
692
  const { ptr, symbols } = calls2(), path = nameBytes(name);
695
693
  checked(symbols.unlinkat(parent, ptr(path), directory ? 128 : 0));
696
694
  }
695
+ function privateMacosRenameAt(source, from, target, to, exclusive = false) {
696
+ const { ptr, symbols } = calls2(), old = nameBytes(from), next = nameBytes(to);
697
+ checked(symbols.renameatx_np(source, ptr(old), target, ptr(next), exclusive ? 4 : 0));
698
+ }
697
699
 
698
700
  // src/internal/macos-descriptor-handoff.ts
699
701
  var MAX_DESCRIPTORS = 64;
@@ -1018,6 +1020,41 @@ async function sendPrivateMacosDescriptors(path, peer, descriptors, timeoutMs, s
1018
1020
  }
1019
1021
  }
1020
1022
 
1023
+ // src/internal/macos-guardian-diagnostics.ts
1024
+ import { AsyncLocalStorage } from "async_hooks";
1025
+ var causes = new Map([
1026
+ ["macOS control channel ended", "CONTROL_EOF"],
1027
+ ["macOS control channel socket failed", "CONTROL_SOCKET"],
1028
+ ["macOS control channel capacity exceeded", "CONTROL_CAPACITY"],
1029
+ ["macOS control channel malformed", "CONTROL_MALFORMED"],
1030
+ ["macOS control channel truncated", "CONTROL_TRUNCATED"],
1031
+ ["macOS control deadline expired", "CONTROL_DEADLINE"],
1032
+ ["macOS control delivery unavailable", "CONTROL_DELIVERY"],
1033
+ ["invalid macOS guardian response", "INVALID_RESPONSE"],
1034
+ ["macOS collector has no successful fenced owner", "INVALID_COLLECTOR"],
1035
+ ["macOS collector descriptor count changed", "DESCRIPTOR_COUNT"],
1036
+ ["macOS guardian job removal is unconfirmed", "JOB_REMOVAL_UNCONFIRMED"],
1037
+ ["macOS guardian operation deadline expired", "OPERATION_DEADLINE"],
1038
+ ["macOS volume create failed", "VOLUME_CREATE"],
1039
+ ["macOS volume attach failed", "VOLUME_ATTACH"],
1040
+ ["macOS volume info failed", "VOLUME_INFO"],
1041
+ ["macOS volume detach failed", "VOLUME_DETACH"],
1042
+ ["macOS volume plist conversion failed", "VOLUME_PLIST"],
1043
+ ["macOS image attachment does not match its allocation", "VOLUME_IMAGE"],
1044
+ ["macOS volume device does not match its allocation", "VOLUME_DEVICE"]
1045
+ ]);
1046
+ function closedCause(error) {
1047
+ try {
1048
+ return error instanceof Error ? causes.get(error.message) ?? "OTHER" : "OTHER";
1049
+ } catch {
1050
+ return "OTHER";
1051
+ }
1052
+ }
1053
+ function privateMacosGuardianFailure(step, error) {
1054
+ return Object.freeze({ step, cause: closedCause(error) });
1055
+ }
1056
+ var observers = new AsyncLocalStorage;
1057
+
1021
1058
  // src/internal/macos-guardian-storage.ts
1022
1059
  import { constants as constants5 } from "fs";
1023
1060
  import { lstat, open as open4 } from "fs/promises";
@@ -1036,6 +1073,7 @@ var MIB = 1024 * 1024;
1036
1073
  var IMAGE = "volume.dmg";
1037
1074
  var INTENT = "volume.json";
1038
1075
  var IMAGE_RECORD = "volume-image.json";
1076
+ var IMAGE_PENDING = "volume-image.pending";
1039
1077
  var RETIRE_RECORD = "storage.release.json";
1040
1078
  function identity(stat) {
1041
1079
  return { device: String(stat.dev), inode: String(stat.ino) };
@@ -1179,7 +1217,7 @@ async function attached(controlPath, allocation, signal) {
1179
1217
  if (candidates.length !== 1 || item["owner-uid"] !== process.getuid() || item.blocksize !== 512 || item.blockcount !== allocation.bytes / 512 || item["image-encrypted"] !== false || !Array.isArray(entities) || entities.length !== 1)
1180
1218
  throw new Error("macOS image attachment does not match its allocation");
1181
1219
  const entity = entities[0];
1182
- if (entity === null || typeof entity !== "object" || typeof entity["dev-entry"] !== "string" || !/^\/dev\/disk[1-9][0-9]{0,5}$/.test(entity["dev-entry"]) || entity["mount-point"] !== undefined && entity["mount-point"] !== allocation.mount.path)
1220
+ if (entity === null || typeof entity !== "object" || typeof entity["dev-entry"] !== "string" || !/^\/dev\/disk[1-9][0-9]{0,5}$/.test(entity["dev-entry"]))
1183
1221
  throw new Error("macOS volume device does not match its allocation");
1184
1222
  return entity["dev-entry"];
1185
1223
  }
@@ -1243,7 +1281,9 @@ async function attachPrivateMacosVolume(controlPath, token, signal) {
1243
1281
  if (stat2.size !== BigInt(bytes))
1244
1282
  throw new Error("macOS volume capacity changed");
1245
1283
  recordedImage = { ...identity(stat2), allocationMac };
1246
- await writeRecord(parent, IMAGE_RECORD, token, recordedImage);
1284
+ await writeRecord(parent, IMAGE_PENDING, token, recordedImage, IMAGE_RECORD);
1285
+ privateMacosRenameAt(parent.fd, IMAGE_PENDING, parent.fd, IMAGE_RECORD, true);
1286
+ await parent.sync();
1247
1287
  } finally {
1248
1288
  await image.close();
1249
1289
  }
@@ -1795,18 +1835,19 @@ async function preparePrivateMacosScope(input) {
1795
1835
  stop("process_limit");
1796
1836
  break;
1797
1837
  }
1798
- if (!sample.complete) {
1838
+ const cpuRegressed = sample.cpuNanoseconds < previousCpu;
1839
+ if (!sample.complete || cpuRegressed) {
1799
1840
  incompleteSamples++;
1800
1841
  incompleteSince ??= now;
1842
+ if (now - incompleteSince > 500) {
1843
+ stop("accounting_failed");
1844
+ break;
1845
+ }
1801
1846
  } else
1802
1847
  incompleteSince = undefined;
1803
- if (incompleteSince !== undefined && now - incompleteSince > 500) {
1804
- stop("accounting_failed");
1805
- break;
1806
- }
1807
- if (sample.cpuNanoseconds < previousCpu) {
1808
- stop("accounting_failed");
1809
- break;
1848
+ if (cpuRegressed) {
1849
+ await new Promise((resolve) => setTimeout(resolve, 20));
1850
+ continue;
1810
1851
  }
1811
1852
  credit += BigInt(Math.max(0, Math.floor((now - previousTime) * 1e6))) * BigInt(limits.cpuQuotaMicros) / BigInt(limits.cpuPeriodMicros) - (sample.cpuNanoseconds - previousCpu);
1812
1853
  if (credit > burst)
@@ -1984,6 +2025,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
1984
2025
  releaseCollection = resolve;
1985
2026
  });
1986
2027
  let stopped;
2028
+ let preparationDeadlineExpired = false;
1987
2029
  let resolveAdmission = () => {};
1988
2030
  let rejectAdmission = () => {};
1989
2031
  const admission = new Promise((resolve, reject) => {
@@ -1995,8 +2037,11 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
1995
2037
  });
1996
2038
  let phase = "starting";
1997
2039
  const currentPhase = () => phase;
1998
- const stop = (reason) => {
1999
- stopped ??= reason;
2040
+ const stop = (reason, deadlineExpired = false) => {
2041
+ if (stopped === undefined) {
2042
+ stopped = reason;
2043
+ preparationDeadlineExpired = deadlineExpired;
2044
+ }
2000
2045
  cancellation.abort();
2001
2046
  releaseCollection();
2002
2047
  rejectAdmission(new Error("macOS guardian admission stopped"));
@@ -2007,6 +2052,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2007
2052
  stop("coordinator_lost");
2008
2053
  });
2009
2054
  let timer;
2055
+ let failureStep = "configuration";
2010
2056
  try {
2011
2057
  configuration = startMessage(await privateMacosBefore(channel.receive(), 1e4));
2012
2058
  if (stopped !== undefined)
@@ -2023,7 +2069,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2023
2069
  phase = "prepared";
2024
2070
  channel.send({ type: "prepared", identity: owner.identity });
2025
2071
  const operationDeadline = configuration.type === "start" ? configuration.limits.deadlineUnixMs : configuration.deadlineUnixMs;
2026
- timer = setTimeout(() => stop("cancelled"), Math.max(0, Math.min(1e4, operationDeadline - Date.now())));
2072
+ timer = setTimeout(() => stop("cancelled", Date.now() >= operationDeadline), Math.max(0, Math.min(1e4, operationDeadline - Date.now())));
2027
2073
  const commands = (async () => {
2028
2074
  for (;; ) {
2029
2075
  const next = object(await channel.receive(), "type");
@@ -2033,7 +2079,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2033
2079
  releaseCollection();
2034
2080
  else if (next.type === "admit" && phase === "prepared" && stopped === undefined) {
2035
2081
  clearTimeout(timer);
2036
- timer = setTimeout(() => stop("cancelled"), Math.max(0, operationDeadline - Date.now()));
2082
+ timer = setTimeout(() => stop("cancelled", true), Math.max(0, operationDeadline - Date.now()));
2037
2083
  phase = "preparing";
2038
2084
  resolveAdmission();
2039
2085
  } else if (next.type === "continue" && currentPhase() === "ready" && stopped === undefined) {
@@ -2044,10 +2090,12 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2044
2090
  }
2045
2091
  })();
2046
2092
  commands.catch(() => stop("coordinator_lost"));
2093
+ failureStep = "admission";
2047
2094
  await admission;
2048
2095
  if (stopped !== undefined)
2049
2096
  throw new Error("macOS guardian stopped before preparation");
2050
2097
  if (configuration.type === "recover-storage") {
2098
+ failureStep = "storage-recovery";
2051
2099
  await recoverPrivateMacosGuardianStorage(configuration.targetDirectory, configuration.targetToken, cancellation.signal);
2052
2100
  const fencedBy = performance.now() + 5000;
2053
2101
  while (!owner.empty()) {
@@ -2061,20 +2109,23 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2061
2109
  stdin.destroy();
2062
2110
  stdout.end();
2063
2111
  stderr.end();
2064
- channel.send({ type: "terminal", result: null, outputLost: false });
2112
+ channel.send({ type: "terminal", result: null, outputLost: false, failure: null });
2065
2113
  await privateMacosBefore(new Promise((resolve) => control.end(resolve)), 1000);
2066
2114
  return;
2067
2115
  }
2068
2116
  if (inputReceiver !== undefined) {
2117
+ failureStep = "input-transfer";
2069
2118
  inputBundle = await inputReceiver.receive({ pid: coordinatorPid, version: coordinatorVersion }, 5000, cancellation.signal);
2070
2119
  await inputReceiver.close();
2071
2120
  }
2072
2121
  if (configuration.storage !== undefined) {
2122
+ failureStep = "storage";
2073
2123
  const storage = await preparePrivateMacosGuardianStorage(configuration.ownerDirectory, configuration.ownerToken, configuration.storage, cancellation.signal);
2074
2124
  collector = storage.collector;
2075
2125
  storageRoot = storage.directory;
2076
2126
  }
2077
2127
  if ((configuration.inputDirectories?.length ?? 0) > 0) {
2128
+ failureStep = "input-projection";
2078
2129
  await projectPrivateMacosInputs(storageRoot, configuration.inputs, configuration.inputDirectories, inputBundle, cancellation.signal);
2079
2130
  inputBundle?.close();
2080
2131
  inputBundle = undefined;
@@ -2082,6 +2133,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2082
2133
  await storageRoot?.close();
2083
2134
  storageRoot = undefined;
2084
2135
  cancellation.signal.throwIfAborted();
2136
+ failureStep = "scope-preparation";
2085
2137
  execution = await preparePrivateMacosScope({
2086
2138
  ...configuration,
2087
2139
  owner,
@@ -2132,6 +2184,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2132
2184
  stdin.pipe(execution.stdin);
2133
2185
  phase = "ready";
2134
2186
  channel.send({ type: "ready", pid: execution.pid, version: execution.version });
2187
+ failureStep = "execution";
2135
2188
  const result = await execution.completion;
2136
2189
  stdin.destroy();
2137
2190
  for (const destination of [stdout, stderr]) {
@@ -2151,6 +2204,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2151
2204
  execution.stdout.destroy();
2152
2205
  execution.stderr.destroy();
2153
2206
  if (configuration.storage !== undefined) {
2207
+ failureStep = "collection";
2154
2208
  phase = "collecting";
2155
2209
  const collect = collector !== undefined && stopped === undefined && !outputLost && result.reason === "payload_exit" && result.exitCode === 0;
2156
2210
  channel.send({ type: "fenced", result, outputLost, collect });
@@ -2160,14 +2214,16 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2160
2214
  }
2161
2215
  await collector?.close();
2162
2216
  collector = undefined;
2217
+ failureStep = "storage-recovery";
2163
2218
  await recoverPrivateMacosGuardianStorage(configuration.ownerDirectory, configuration.ownerToken, AbortSignal.timeout(30000));
2164
2219
  if (stopped !== undefined)
2165
2220
  outputLost = true;
2166
2221
  }
2167
2222
  phase = "terminal";
2168
- channel.send({ type: "terminal", result, outputLost });
2223
+ channel.send({ type: "terminal", result, outputLost, failure: null });
2169
2224
  await privateMacosBefore(new Promise((resolve) => control.end(resolve)), 1000);
2170
2225
  } catch (error) {
2226
+ const failure = privateMacosGuardianFailure(failureStep, configuration?.type === "start" && execution === undefined && preparationDeadlineExpired ? new Error("macOS guardian operation deadline expired", { cause: error }) : error);
2171
2227
  cancellation.abort();
2172
2228
  execution?.stop("coordinator_lost");
2173
2229
  let result;
@@ -2190,7 +2246,7 @@ async function supervise(path2, coordinatorPid, coordinatorVersion) {
2190
2246
  await recoverPrivateMacosGuardianStorage(configuration.ownerDirectory, configuration.ownerToken, AbortSignal.timeout(30000));
2191
2247
  phase = "terminal";
2192
2248
  try {
2193
- channel.send({ type: "terminal", result: result ?? null, outputLost: true });
2249
+ channel.send({ type: "terminal", result: result ?? null, outputLost: true, failure });
2194
2250
  await privateMacosBefore(new Promise((resolve) => control.end(resolve)), 1000);
2195
2251
  } catch {}
2196
2252
  if (stopped === undefined)
@@ -88,12 +88,20 @@ function requirePrivateBunPatches(value) {
88
88
  }
89
89
  return Object.freeze({ ...patches });
90
90
  }
91
+
92
+ class PrivateBunLockVersionError extends TypeError {
93
+ constructor() {
94
+ super("bun.lock uses a format unsupported by the pinned Bun runtime");
95
+ }
96
+ }
91
97
  function requirePrivateBunLockPolicy(value, members, version = 1) {
92
98
  const lock = ordinaryRecord(value);
93
99
  const workspaces = ordinaryRecord(lock?.workspaces);
94
100
  const rootWorkspace = ordinaryRecord(workspaces?.[""]);
95
101
  const packages = ordinaryRecord(lock?.packages);
96
- if (version !== 1 && version !== 2 || lock?.lockfileVersion !== version || workspaces === undefined || rootWorkspace === undefined || packages === undefined || (members === undefined ? Object.keys(workspaces).length !== 1 : Object.keys(workspaces).some((path) => path !== "" && !members.has(path))) || members === undefined && lock.patchedDependencies !== undefined) {
102
+ if (lock !== undefined && lock.lockfileVersion !== 1 && lock.lockfileVersion !== version)
103
+ throw new PrivateBunLockVersionError;
104
+ if (version !== 1 && version !== 2 || lock === undefined || workspaces === undefined || rootWorkspace === undefined || packages === undefined || (members === undefined ? Object.keys(workspaces).length !== 1 : Object.keys(workspaces).some((path) => path !== "" && !members.has(path))) || members === undefined && lock.patchedDependencies !== undefined) {
97
105
  throw new TypeError("unsupported Bun lock source");
98
106
  }
99
107
  requirePrivateBunPatches(lock.patchedDependencies);
@@ -5128,10 +5136,12 @@ async function requireSupportedLock(resolved, patches) {
5128
5136
  }
5129
5137
  try {
5130
5138
  requirePrivateBunLockPolicy(value, workspace === undefined ? undefined : new Set(workspace.members), process.platform === "darwin" && process.versions.bun === "1.4.2" ? 2 : 1);
5131
- } catch {
5139
+ } catch (error) {
5132
5140
  if (resolved) {
5133
5141
  throw new WorkerFailure("PACKAGE_BUN_RESOLVED_SOURCE_UNSUPPORTED", "resolved dependencies are unsupported; resolution requests may already have occurred");
5134
5142
  }
5143
+ if (error instanceof PrivateBunLockVersionError)
5144
+ throw new WorkerFailure("PACKAGE_BUN_LOCK_VERSION_UNSUPPORTED", error.message);
5135
5145
  unsupportedSource();
5136
5146
  }
5137
5147
  if (workspace !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jigging/jig",
3
- "version": "0.1.0-alpha.27",
3
+ "version": "0.1.0-alpha.33",
4
4
  "description": "A local, secure host for admitted FLOW packages",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {