@ai-ecoverse/slicc-kernel 1.77.0 → 1.77.1

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.
@@ -373,6 +373,9 @@ function writerTags(protection) {
373
373
  return new Set(writers);
374
374
  }
375
375
  function protectedPrefixes(paths) {
376
+ if (!Array.isArray(paths) || paths.some((p) => typeof p !== "string" || !p.startsWith("/"))) {
377
+ throw new TypeError("protect.paths must be a list of absolute paths");
378
+ }
376
379
  return [...new Set(paths.map((p) => normalizePath(p)))];
377
380
  }
378
381
  function within(path, prefix) {
@@ -476,6 +479,9 @@ var ProtectedFs = class {
476
479
  await check(path, true);
477
480
  return fs.utimes(path, atime, mtime);
478
481
  },
482
+ async mayChange(path, follow2) {
483
+ await check(path, follow2);
484
+ },
479
485
  async stat(path) {
480
486
  return marked(path, await fs.stat(path));
481
487
  },
@@ -1155,6 +1161,10 @@ var OpfsFs = class {
1155
1161
  };
1156
1162
  }
1157
1163
  async describe(found) {
1164
+ const stat = await this.described(found);
1165
+ return isProtected(this.guarded, found.path) ? { ...stat, readonly: true } : stat;
1166
+ }
1167
+ async described(found) {
1158
1168
  if (found.link) return this.owned(this.linkStat(found.link), found.path, found.link);
1159
1169
  const touched = this.timesOf(found.path);
1160
1170
  if (!this.owners) {
@@ -7318,6 +7328,83 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
7318
7328
  };
7319
7329
  }
7320
7330
 
7331
+ // src/fs/fresh-modules.ts
7332
+ var MAGIC = [0, 97, 115, 109];
7333
+ var MAX_FRESH = 65536;
7334
+ function isModule(bytes) {
7335
+ return MAGIC.every((b, i) => bytes[i] === b);
7336
+ }
7337
+ var FreshModules = class {
7338
+ fresh = /* @__PURE__ */ new Map();
7339
+ add(path, umask, pid) {
7340
+ const key = normalizePath(path);
7341
+ this.fresh.delete(key);
7342
+ const oldest = this.fresh.size >= MAX_FRESH ? this.fresh.keys().next().value : void 0;
7343
+ if (oldest !== void 0) this.fresh.delete(oldest);
7344
+ this.fresh.set(key, { umask: umask & 511, pid, added: 0 });
7345
+ }
7346
+ forget(pid) {
7347
+ for (const [path, fresh2] of this.fresh) if (fresh2.pid === pid) this.fresh.delete(path);
7348
+ }
7349
+ wrap(fs) {
7350
+ const decide = async (given, bytes) => {
7351
+ const path = normalizePath(given);
7352
+ const fresh2 = this.fresh.get(path);
7353
+ if (!fresh2 || typeof bytes === "string" || bytes.length < MAGIC.length) return;
7354
+ const want = isModule(bytes) ? 73 & ~fresh2.umask : 0;
7355
+ if (want === fresh2.added) return;
7356
+ const mode = (await fs.stat(path)).mode & 4095;
7357
+ await fs.chmod(path, mode & ~fresh2.added | want);
7358
+ fresh2.added = want;
7359
+ };
7360
+ const overrides = {
7361
+ writeFile: async (path, content, owner) => {
7362
+ await fs.writeFile(path, content, owner);
7363
+ await decide(path, content);
7364
+ },
7365
+ chmod: async (path, mode) => {
7366
+ const fresh2 = this.fresh.get(normalizePath(path));
7367
+ const creating = fresh2?.added === 0 && (mode & 4095) === (438 & ~fresh2.umask);
7368
+ if (!creating) this.fresh.delete(normalizePath(path));
7369
+ await fs.chmod(path, mode);
7370
+ },
7371
+ rm: async (path, options) => {
7372
+ this.fresh.delete(normalizePath(path));
7373
+ await fs.rm(path, options);
7374
+ },
7375
+ rename: async (from, to) => {
7376
+ await fs.rename(from, to);
7377
+ const fresh2 = this.fresh.get(normalizePath(from));
7378
+ this.fresh.delete(normalizePath(from));
7379
+ this.fresh.delete(normalizePath(to));
7380
+ if (fresh2) this.fresh.set(normalizePath(to), fresh2);
7381
+ }
7382
+ };
7383
+ const ranged2 = rangedOps(fs);
7384
+ if (ranged2) {
7385
+ overrides.pwrite = async (path, at, bytes, transfer) => {
7386
+ const head = at === 0 && this.fresh.has(normalizePath(path)) ? bytes.slice(0, 4) : void 0;
7387
+ await ranged2.pwrite(path, at, bytes, transfer);
7388
+ if (head) await decide(path, head);
7389
+ };
7390
+ }
7391
+ const bound = /* @__PURE__ */ new WeakMap();
7392
+ return new Proxy(fs, {
7393
+ get(target, key, receiver) {
7394
+ if (Object.hasOwn(overrides, key)) return overrides[key];
7395
+ const value = Reflect.get(target, key, receiver);
7396
+ if (typeof value !== "function") return value;
7397
+ let method = bound.get(value);
7398
+ if (method === void 0) {
7399
+ method = value.bind(target);
7400
+ bound.set(value, method);
7401
+ }
7402
+ return method;
7403
+ }
7404
+ });
7405
+ }
7406
+ };
7407
+
7321
7408
  // src/fs/physical-path.ts
7322
7409
  var MAX_HOPS = 40;
7323
7410
  function start(path) {
@@ -9194,6 +9281,7 @@ async function run(entry, path, req) {
9194
9281
  case "create":
9195
9282
  await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
9196
9283
  entry.created?.add(path);
9284
+ entry.fresh?.(path);
9197
9285
  return done;
9198
9286
  case "readlink":
9199
9287
  return json2(await fs.readlink(path));
@@ -9292,11 +9380,39 @@ async function accessOp(entry, path, req) {
9292
9380
  await need({ ...g, cred }, open ? "open" : "access", path, req.mode ?? 0, options);
9293
9381
  return done;
9294
9382
  }
9383
+ var CHANGING = /* @__PURE__ */ new Set([
9384
+ "mkdir",
9385
+ "create",
9386
+ "symlink",
9387
+ "unlink",
9388
+ "rmdir",
9389
+ "rm",
9390
+ "rename",
9391
+ "link",
9392
+ "utimes",
9393
+ "lutimes",
9394
+ "chmod",
9395
+ "chown",
9396
+ "lchown"
9397
+ ]);
9398
+ var CONTENT = /* @__PURE__ */ new Set(["write", "pwrite", "truncate"]);
9399
+ async function mayChange(entry, path, req) {
9400
+ const { mayChange: mayChange2 } = entry.fs;
9401
+ if (!mayChange2) return;
9402
+ const { op } = req;
9403
+ if (CONTENT.has(op) && req.handle === void 0) return mayChange2.call(entry.fs, path, true);
9404
+ if (!CHANGING.has(op)) return;
9405
+ await mayChange2.call(entry.fs, path, op === "utimes" || op === "chmod" || op === "chown");
9406
+ if (op === "rename" || op === "link") {
9407
+ await mayChange2.call(entry.fs, entry.fs.resolvePath(entry.cwd, req.arg2 ?? ""), false);
9408
+ }
9409
+ }
9295
9410
  async function guarded(entry, path, req) {
9296
9411
  const g = guardOf(entry);
9297
9412
  if (!g) return void 0;
9298
9413
  if (LOOKS.has(req.op) && await entry.holdsKept?.(path)) return void 0;
9299
9414
  try {
9415
+ await mayChange(entry, path, req);
9300
9416
  await guard(g, path, req, entry.cwd);
9301
9417
  return void 0;
9302
9418
  } catch (err) {
@@ -12613,6 +12729,7 @@ var WasmProcess = class {
12613
12729
  throw Object.assign(new Error(alias.refused), { code: alias.refused });
12614
12730
  if (alias !== void 0) return this.openProc(req, alias);
12615
12731
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
12732
+ if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
12616
12733
  await this.mayOpen(req);
12617
12734
  const fd = this.fds.install(heldFile(), 3);
12618
12735
  try {
@@ -13483,6 +13600,7 @@ function holdingToken(opts, holds, caller) {
13483
13600
  return mintSyncFsToken({
13484
13601
  ...opts.owners ? caller : {},
13485
13602
  ...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
13603
+ ...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
13486
13604
  fs: opts.fs,
13487
13605
  cwd: opts.cwd,
13488
13606
  ...opts.statfs ? { statfs: opts.statfs } : {},
@@ -16321,6 +16439,7 @@ var Launcher = class {
16321
16439
  described = /* @__PURE__ */ new Map();
16322
16440
  creds = /* @__PURE__ */ new Map();
16323
16441
  tags = /* @__PURE__ */ new Map();
16442
+ freshModules = new FreshModules();
16324
16443
  granted = /* @__PURE__ */ new Map();
16325
16444
  users;
16326
16445
  sudoer;
@@ -16391,7 +16510,8 @@ var Launcher = class {
16391
16510
  changed: this.watchers.changed.bind(this.watchers),
16392
16511
  owners: this.owners
16393
16512
  });
16394
- this.base = this.watchers.wrap(this.mounts.wrap(options.fs));
16513
+ const watched = this.watchers.wrap(this.mounts.wrap(options.fs));
16514
+ this.base = this.owners ? this.freshModules.wrap(watched) : watched;
16395
16515
  this.createWorker = options.createWorker;
16396
16516
  this.createDriverWorker = options.createDriverWorker;
16397
16517
  this.media = options.media ?? memoryMedia();
@@ -16794,6 +16914,7 @@ var Launcher = class {
16794
16914
  ...req.ignored ? { ignored: req.ignored } : {},
16795
16915
  ...req.umask !== void 0 ? { umask: req.umask } : {},
16796
16916
  cred: req.cred,
16917
+ ...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
16797
16918
  ...this.owners ? { owners: true } : {},
16798
16919
  sealed: this.sealed,
16799
16920
  clipboard: this.clipboard,
@@ -16856,6 +16977,7 @@ var Launcher = class {
16856
16977
  (state) => state === "stopped" ? this.stopped.add(pid) : this.stopped.delete(pid)
16857
16978
  );
16858
16979
  void handle.exited.then(() => {
16980
+ this.freshModules.forget(pid);
16859
16981
  const spent = handle.times?.();
16860
16982
  if (spent) this.spent.set(pid, spent);
16861
16983
  if (spent) addTimes(this.imageTimes, this.jobs.shown(pid), spent);
@@ -17522,8 +17644,9 @@ var Launcher = class {
17522
17644
  return this.writers;
17523
17645
  }
17524
17646
  writerStack() {
17647
+ const watched = this.watchers.wrap(this.mounts.wrap(this.unguardedRoot));
17525
17648
  const fs = withCommandDirs(
17526
- this.watchers.wrap(this.mounts.wrap(this.unguardedRoot)),
17649
+ this.owners ? this.freshModules.wrap(watched) : watched,
17527
17650
  async () => new Set((await this.commands()).keys()),
17528
17651
  (dir) => this.userCommandDir(dir),
17529
17652
  this.owners