@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.
package/dist/node.js CHANGED
@@ -753,6 +753,10 @@ var KernelError = class extends Error {
753
753
  if (detail !== void 0) this.detail = detail;
754
754
  }
755
755
  };
756
+ function openAccess(flags2) {
757
+ const mode = flags2 & 3;
758
+ return mode === 0 ? "read" : mode === 1 ? "write" : "both";
759
+ }
756
760
  function pollFile(file) {
757
761
  return file.poll?.() ?? { readable: !!file.read, writable: !!file.write, hangup: false };
758
762
  }
@@ -12897,17 +12901,15 @@ var WasmProcess = class {
12897
12901
  const file = tty.file();
12898
12902
  return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
12899
12903
  }
12900
- openSealed() {
12904
+ openSealed(flags2) {
12901
12905
  const broker = this.options.sealed;
12902
12906
  if (!broker) throw new KernelError("ENOENT");
12903
- return this.fds.install(broker.open(), 3);
12907
+ return this.fds.install(broker.open(openAccess(flags2)), 3);
12904
12908
  }
12905
12909
  async openClipboard(flags2) {
12906
12910
  const broker = this.options.clipboard;
12907
12911
  if (!broker) throw new KernelError("ENOENT");
12908
- const mode = flags2 & WRITE_ACCESS;
12909
- const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
12910
- const file = broker.open(access2, await this.clipboardStamp());
12912
+ const file = broker.open(openAccess(flags2), await this.clipboardStamp());
12911
12913
  return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
12912
12914
  }
12913
12915
  async clipboardStamp() {
@@ -13066,7 +13068,7 @@ var WasmProcess = class {
13066
13068
  case "fd-tty-names":
13067
13069
  return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
13068
13070
  case "fd-open-sealed":
13069
- return { ok: true, kind: "json", json: this.openSealed() };
13071
+ return { ok: true, kind: "json", json: this.openSealed(req.flags) };
13070
13072
  case "fd-open-clipboard":
13071
13073
  return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
13072
13074
  case "fd-tty-owner":
@@ -14785,14 +14787,19 @@ var SealedChannel = class {
14785
14787
  offset = 0;
14786
14788
  inflight;
14787
14789
  broker;
14788
- constructor(broker) {
14790
+ access;
14791
+ constructor(broker, access2) {
14789
14792
  this.broker = broker;
14793
+ this.access = access2;
14790
14794
  }
14791
14795
  send(bytes, caller, gone) {
14796
+ if (this.access === "read") {
14797
+ bytes.fill(0);
14798
+ throw new KernelError("EBADF");
14799
+ }
14792
14800
  const length2 = bytes.length;
14793
14801
  const fields = parseSealed(bytes);
14794
- this.reply = void 0;
14795
- this.offset = 0;
14802
+ this.drop();
14796
14803
  this.inflight?.control.abort("replaced");
14797
14804
  const control = new AbortController();
14798
14805
  const withdraw = () => control.abort("withdrawn");
@@ -14828,15 +14835,18 @@ var SealedChannel = class {
14828
14835
  if (!signal.aborted) return reply;
14829
14836
  return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
14830
14837
  }
14838
+ drop() {
14839
+ this.reply?.fill(0);
14840
+ this.reply = void 0;
14841
+ this.offset = 0;
14842
+ }
14831
14843
  async read(max, signal) {
14844
+ if (this.access === "write") throw new KernelError("EBADF");
14832
14845
  for (; ; ) {
14833
14846
  if (this.reply) {
14834
14847
  const out = this.reply.slice(this.offset, this.offset + max);
14835
14848
  this.offset += out.length;
14836
- if (this.offset >= this.reply.length) {
14837
- this.reply = void 0;
14838
- this.offset = 0;
14839
- }
14849
+ if (this.offset >= this.reply.length) this.drop();
14840
14850
  return out;
14841
14851
  }
14842
14852
  const flight = this.inflight;
@@ -14869,7 +14879,7 @@ var SealedChannel = class {
14869
14879
  close() {
14870
14880
  this.inflight?.control.abort("withdrawn");
14871
14881
  this.inflight = void 0;
14872
- this.reply = void 0;
14882
+ this.drop();
14873
14883
  }
14874
14884
  };
14875
14885
  function swapOf(reply) {
@@ -14926,12 +14936,14 @@ var SealedBroker = class {
14926
14936
  control.abort("done");
14927
14937
  }
14928
14938
  }
14929
- open() {
14930
- const channel = new SealedChannel(this);
14939
+ open(access2 = "both") {
14940
+ const channel = new SealedChannel(this, access2);
14931
14941
  return new OpenFile({
14932
- read: (max, signal) => channel.read(max, signal),
14933
- write: async () => {
14934
- throw new KernelError("EINVAL");
14942
+ ...access2 === "write" ? {} : { read: (max, signal) => channel.read(max, signal) },
14943
+ ...access2 === "read" ? {} : {
14944
+ write: async () => {
14945
+ throw new KernelError("EINVAL");
14946
+ }
14935
14947
  },
14936
14948
  poll: () => channel.poll(),
14937
14949
  changed: (signal) => channel.changed(signal),
@@ -16653,7 +16665,10 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
16653
16665
  var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
16654
16666
  var SUDO_TIMEOUT_MS = 3e5;
16655
16667
  var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
16656
- var RULE = /^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?Cmnd(?:\s+(.*))?$/;
16668
+ var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
16669
+ var RULE = new RegExp(
16670
+ String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
16671
+ );
16657
16672
  var TERM = /^[A-Za-z0-9._+-]+$/;
16658
16673
  var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
16659
16674
  var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
@@ -16688,17 +16703,25 @@ function validWho(who) {
16688
16703
  if (who === "ALL") return true;
16689
16704
  return NAME3.test(who.startsWith("%") ? who.slice(1) : who);
16690
16705
  }
16706
+ function cwdOf(word) {
16707
+ const words2 = splitWords(word);
16708
+ const path = words2?.length === 1 ? words2[0] : "";
16709
+ return path.startsWith("/") ? normalizePath(path) : "";
16710
+ }
16691
16711
  function parseRule(line) {
16692
16712
  const text = line.trim();
16693
16713
  if (text === "" || text.startsWith("#")) return null;
16694
16714
  const m = RULE.exec(text);
16695
16715
  if (!m) return void 0;
16696
- const [, nopasswd, who = "", target = "root", rest2 = ""] = m;
16716
+ const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
16697
16717
  if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
16698
- if (rest2.trim() === "*") return { nopasswd: !!nopasswd, who, target, cmnd: "*" };
16718
+ const cwd = dir === void 0 ? void 0 : cwdOf(dir);
16719
+ if (cwd === "") return void 0;
16720
+ const rule = { nopasswd: !!nopasswd, who, target, ...cwd !== void 0 ? { cwd } : {} };
16721
+ if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
16699
16722
  const cmnd = splitWords(rest2);
16700
16723
  if (!cmnd?.[0]?.startsWith("/")) return void 0;
16701
- return { nopasswd: !!nopasswd, who, target, cmnd };
16724
+ return { ...rule, cmnd };
16702
16725
  }
16703
16726
  function flags(parsed2, arg, next2) {
16704
16727
  for (let j = 1; j < arg.length; j++) {
@@ -16737,7 +16760,8 @@ function parseArgs(args) {
16737
16760
  }
16738
16761
  function described(rule) {
16739
16762
  const cmnd = rule.cmnd === "*" ? "ALL" : rule.cmnd.map(quoteWord).join(" ");
16740
- return ` (${rule.target}) ${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
16763
+ const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
16764
+ return ` (${rule.target}) ${cwd}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
16741
16765
  }
16742
16766
  var Sudo = class {
16743
16767
  o;
@@ -16877,7 +16901,7 @@ var Sudo = class {
16877
16901
  if (untrusted) return untrusted;
16878
16902
  const argv = [path, ...args];
16879
16903
  const matching = rules.filter(
16880
- (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]))
16904
+ (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]))
16881
16905
  );
16882
16906
  const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
16883
16907
  if (root || matching.some((rule) => rule.nopasswd)) return grant();
@@ -16899,7 +16923,7 @@ var Sudo = class {
16899
16923
  }
16900
16924
  const changed = await this.untrusted(path, cwd, word);
16901
16925
  if (changed) return changed;
16902
- if (answer === "always" && !await this.remember(self, target, argv)) {
16926
+ if (answer === "always" && !await this.remember(self, target, cwd, argv)) {
16903
16927
  return failed2("EIO", "sudo: the rule could not be recorded");
16904
16928
  }
16905
16929
  return grant();
@@ -16964,7 +16988,7 @@ ${lines2}
16964
16988
  requester.removeEventListener("abort", withdraw);
16965
16989
  }
16966
16990
  }
16967
- async remember(self, target, argv) {
16991
+ async remember(self, target, cwd, argv) {
16968
16992
  const { fs } = this.o;
16969
16993
  const path = `${SUDOERS_D}/${self.name}`;
16970
16994
  if (!NAME3.test(self.name)) return false;
@@ -16974,7 +16998,8 @@ ${lines2}
16974
16998
  const st = await fs.lstat(path).catch(() => void 0);
16975
16999
  if (st && !await this.trusted(path)) return false;
16976
17000
  const old = st ? await fs.readFile(path) : "";
16977
- const line = `NOPASSWD ${self.name} (${target.name}) Cmnd ${argv.map(quoteWord).join(" ")}
17001
+ const words2 = argv.map(quoteWord).join(" ");
17002
+ const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
16978
17003
  `;
16979
17004
  const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
16980
17005
  ${line}`;