@ai-ecoverse/slicc-kernel 1.86.0 → 1.87.0

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.
@@ -2580,6 +2580,10 @@ var KernelError = class extends Error {
2580
2580
  if (detail !== void 0) this.detail = detail;
2581
2581
  }
2582
2582
  };
2583
+ function openAccess(flags2) {
2584
+ const mode = flags2 & 3;
2585
+ return mode === 0 ? "read" : mode === 1 ? "write" : "both";
2586
+ }
2583
2587
  function pollFile(file) {
2584
2588
  return file.poll?.() ?? { readable: !!file.read, writable: !!file.write, hangup: false };
2585
2589
  }
@@ -13255,17 +13259,15 @@ var WasmProcess = class {
13255
13259
  const file = tty.file();
13256
13260
  return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
13257
13261
  }
13258
- openSealed() {
13262
+ openSealed(flags2) {
13259
13263
  const broker = this.options.sealed;
13260
13264
  if (!broker) throw new KernelError("ENOENT");
13261
- return this.fds.install(broker.open(), 3);
13265
+ return this.fds.install(broker.open(openAccess(flags2)), 3);
13262
13266
  }
13263
13267
  async openClipboard(flags2) {
13264
13268
  const broker = this.options.clipboard;
13265
13269
  if (!broker) throw new KernelError("ENOENT");
13266
- const mode = flags2 & WRITE_ACCESS;
13267
- const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
13268
- const file = broker.open(access2, await this.clipboardStamp());
13270
+ const file = broker.open(openAccess(flags2), await this.clipboardStamp());
13269
13271
  return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
13270
13272
  }
13271
13273
  async clipboardStamp() {
@@ -13424,7 +13426,7 @@ var WasmProcess = class {
13424
13426
  case "fd-tty-names":
13425
13427
  return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
13426
13428
  case "fd-open-sealed":
13427
- return { ok: true, kind: "json", json: this.openSealed() };
13429
+ return { ok: true, kind: "json", json: this.openSealed(req.flags) };
13428
13430
  case "fd-open-clipboard":
13429
13431
  return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
13430
13432
  case "fd-tty-owner":
@@ -15143,14 +15145,19 @@ var SealedChannel = class {
15143
15145
  offset = 0;
15144
15146
  inflight;
15145
15147
  broker;
15146
- constructor(broker) {
15148
+ access;
15149
+ constructor(broker, access2) {
15147
15150
  this.broker = broker;
15151
+ this.access = access2;
15148
15152
  }
15149
15153
  send(bytes, caller, gone) {
15154
+ if (this.access === "read") {
15155
+ bytes.fill(0);
15156
+ throw new KernelError("EBADF");
15157
+ }
15150
15158
  const length2 = bytes.length;
15151
15159
  const fields = parseSealed(bytes);
15152
- this.reply = void 0;
15153
- this.offset = 0;
15160
+ this.drop();
15154
15161
  this.inflight?.control.abort("replaced");
15155
15162
  const control = new AbortController();
15156
15163
  const withdraw = () => control.abort("withdrawn");
@@ -15186,15 +15193,18 @@ var SealedChannel = class {
15186
15193
  if (!signal.aborted) return reply;
15187
15194
  return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
15188
15195
  }
15196
+ drop() {
15197
+ this.reply?.fill(0);
15198
+ this.reply = void 0;
15199
+ this.offset = 0;
15200
+ }
15189
15201
  async read(max, signal) {
15202
+ if (this.access === "write") throw new KernelError("EBADF");
15190
15203
  for (; ; ) {
15191
15204
  if (this.reply) {
15192
15205
  const out = this.reply.slice(this.offset, this.offset + max);
15193
15206
  this.offset += out.length;
15194
- if (this.offset >= this.reply.length) {
15195
- this.reply = void 0;
15196
- this.offset = 0;
15197
- }
15207
+ if (this.offset >= this.reply.length) this.drop();
15198
15208
  return out;
15199
15209
  }
15200
15210
  const flight = this.inflight;
@@ -15227,7 +15237,7 @@ var SealedChannel = class {
15227
15237
  close() {
15228
15238
  this.inflight?.control.abort("withdrawn");
15229
15239
  this.inflight = void 0;
15230
- this.reply = void 0;
15240
+ this.drop();
15231
15241
  }
15232
15242
  };
15233
15243
  function swapOf(reply) {
@@ -15284,12 +15294,14 @@ var SealedBroker = class {
15284
15294
  control.abort("done");
15285
15295
  }
15286
15296
  }
15287
- open() {
15288
- const channel = new SealedChannel(this);
15297
+ open(access2 = "both") {
15298
+ const channel = new SealedChannel(this, access2);
15289
15299
  return new OpenFile({
15290
- read: (max, signal) => channel.read(max, signal),
15291
- write: async () => {
15292
- throw new KernelError("EINVAL");
15300
+ ...access2 === "write" ? {} : { read: (max, signal) => channel.read(max, signal) },
15301
+ ...access2 === "read" ? {} : {
15302
+ write: async () => {
15303
+ throw new KernelError("EINVAL");
15304
+ }
15293
15305
  },
15294
15306
  poll: () => channel.poll(),
15295
15307
  changed: (signal) => channel.changed(signal),
@@ -16908,7 +16920,10 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
16908
16920
  var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
16909
16921
  var SUDO_TIMEOUT_MS = 3e5;
16910
16922
  var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
16911
- var RULE = /^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?Cmnd(?:\s+(.*))?$/;
16923
+ var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
16924
+ var RULE = new RegExp(
16925
+ String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
16926
+ );
16912
16927
  var TERM = /^[A-Za-z0-9._+-]+$/;
16913
16928
  var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
16914
16929
  var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
@@ -16943,17 +16958,25 @@ function validWho(who) {
16943
16958
  if (who === "ALL") return true;
16944
16959
  return NAME3.test(who.startsWith("%") ? who.slice(1) : who);
16945
16960
  }
16961
+ function cwdOf(word) {
16962
+ const words2 = splitWords(word);
16963
+ const path = words2?.length === 1 ? words2[0] : "";
16964
+ return path.startsWith("/") ? normalizePath(path) : "";
16965
+ }
16946
16966
  function parseRule(line) {
16947
16967
  const text = line.trim();
16948
16968
  if (text === "" || text.startsWith("#")) return null;
16949
16969
  const m = RULE.exec(text);
16950
16970
  if (!m) return void 0;
16951
- const [, nopasswd, who = "", target = "root", rest2 = ""] = m;
16971
+ const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
16952
16972
  if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
16953
- if (rest2.trim() === "*") return { nopasswd: !!nopasswd, who, target, cmnd: "*" };
16973
+ const cwd = dir === void 0 ? void 0 : cwdOf(dir);
16974
+ if (cwd === "") return void 0;
16975
+ const rule = { nopasswd: !!nopasswd, who, target, ...cwd !== void 0 ? { cwd } : {} };
16976
+ if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
16954
16977
  const cmnd = splitWords(rest2);
16955
16978
  if (!cmnd?.[0]?.startsWith("/")) return void 0;
16956
- return { nopasswd: !!nopasswd, who, target, cmnd };
16979
+ return { ...rule, cmnd };
16957
16980
  }
16958
16981
  function flags(parsed2, arg, next2) {
16959
16982
  for (let j = 1; j < arg.length; j++) {
@@ -16992,7 +17015,8 @@ function parseArgs(args) {
16992
17015
  }
16993
17016
  function described(rule) {
16994
17017
  const cmnd = rule.cmnd === "*" ? "ALL" : rule.cmnd.map(quoteWord).join(" ");
16995
- return ` (${rule.target}) ${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
17018
+ const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
17019
+ return ` (${rule.target}) ${cwd}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
16996
17020
  }
16997
17021
  var Sudo = class {
16998
17022
  o;
@@ -17132,7 +17156,7 @@ var Sudo = class {
17132
17156
  if (untrusted) return untrusted;
17133
17157
  const argv = [path, ...args];
17134
17158
  const matching = rules.filter(
17135
- (rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
17159
+ (rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
17136
17160
  );
17137
17161
  const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
17138
17162
  if (root || matching.some((rule) => rule.nopasswd)) return grant();
@@ -17154,7 +17178,7 @@ var Sudo = class {
17154
17178
  }
17155
17179
  const changed = await this.untrusted(path, cwd, word);
17156
17180
  if (changed) return changed;
17157
- if (answer === "always" && !await this.remember(self, target, argv)) {
17181
+ if (answer === "always" && !await this.remember(self, target, cwd, argv)) {
17158
17182
  return failed2("EIO", "sudo: the rule could not be recorded");
17159
17183
  }
17160
17184
  return grant();
@@ -17219,7 +17243,7 @@ ${lines2}
17219
17243
  requester.removeEventListener("abort", withdraw);
17220
17244
  }
17221
17245
  }
17222
- async remember(self, target, argv) {
17246
+ async remember(self, target, cwd, argv) {
17223
17247
  const { fs } = this.o;
17224
17248
  const path = `${SUDOERS_D}/${self.name}`;
17225
17249
  if (!NAME3.test(self.name)) return false;
@@ -17229,7 +17253,8 @@ ${lines2}
17229
17253
  const st = await fs.lstat(path).catch(() => void 0);
17230
17254
  if (st && !await this.trusted(path)) return false;
17231
17255
  const old = st ? await fs.readFile(path) : "";
17232
- const line = `NOPASSWD ${self.name} (${target.name}) Cmnd ${argv.map(quoteWord).join(" ")}
17256
+ const words2 = argv.map(quoteWord).join(" ");
17257
+ const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
17233
17258
  `;
17234
17259
  const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
17235
17260
  ${line}`;