@ai-ecoverse/slicc-kernel 1.180.0 → 1.182.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/README.md +32 -6
- package/dist/driver-worker.js +15 -1
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +26 -1
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +373 -96
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-driver-worker.js +15 -1
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +389 -95
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/cdp/types.d.ts +2 -0
- package/dist/types/client/attach.d.ts +12 -0
- package/dist/types/client/protocol.d.ts +9 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/kernel/children.d.ts +2 -1
- package/dist/types/kernel/socket.d.ts +2 -0
- package/dist/types/launcher.d.ts +22 -0
- package/dist/types/node.d.ts +5 -3
- package/dist/types/serve.d.ts +11 -1
- package/dist/types/sudo.d.ts +15 -1
- package/package.json +2 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -652,8 +652,8 @@ function dirsChannel(metadata) {
|
|
|
652
652
|
function noticeOf(data) {
|
|
653
653
|
if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === "string"), trees: [] };
|
|
654
654
|
const notice = data ?? {};
|
|
655
|
-
const
|
|
656
|
-
return { paths:
|
|
655
|
+
const strings2 = (list) => Array.isArray(list) ? list.filter((p) => typeof p === "string") : [];
|
|
656
|
+
return { paths: strings2(notice.paths), trees: strings2(notice.trees), outside: true };
|
|
657
657
|
}
|
|
658
658
|
|
|
659
659
|
// src/fs/types.ts
|
|
@@ -4825,10 +4825,10 @@ var CdpFacade = class {
|
|
|
4825
4825
|
);
|
|
4826
4826
|
return;
|
|
4827
4827
|
}
|
|
4828
|
-
await this.write(conn, json(await this.list(runtime)));
|
|
4828
|
+
await this.write(conn, json(await this.list(runtime, conn.peerStamp)));
|
|
4829
4829
|
}
|
|
4830
|
-
async list(runtime) {
|
|
4831
|
-
const conn = await this.host(runtime);
|
|
4830
|
+
async list(runtime, stamp) {
|
|
4831
|
+
const conn = await this.host(runtime, stamp);
|
|
4832
4832
|
try {
|
|
4833
4833
|
const reply = await new Promise(
|
|
4834
4834
|
(resolve2, reject) => {
|
|
@@ -4863,12 +4863,15 @@ var CdpFacade = class {
|
|
|
4863
4863
|
conn.close();
|
|
4864
4864
|
}
|
|
4865
4865
|
}
|
|
4866
|
-
host(runtime) {
|
|
4867
|
-
return this.options.hosts.connect(
|
|
4866
|
+
host(runtime, stamp) {
|
|
4867
|
+
return this.options.hosts.connect({
|
|
4868
|
+
...runtime ? { runtime } : {},
|
|
4869
|
+
...stamp ? { stamp } : {}
|
|
4870
|
+
});
|
|
4868
4871
|
}
|
|
4869
4872
|
async upgrade(conn, incoming, req, runtime) {
|
|
4870
4873
|
const accept2 = await acceptKey(req.headers);
|
|
4871
|
-
const host = await this.host(runtime);
|
|
4874
|
+
const host = await this.host(runtime, conn.peerStamp);
|
|
4872
4875
|
const limits = {
|
|
4873
4876
|
max: this.options.maxMessage ?? MAX_MESSAGE,
|
|
4874
4877
|
closeWaitMs: this.options.closeWaitMs ?? CLOSE_WAIT_MS
|
|
@@ -4948,6 +4951,7 @@ function enableCdp(net, hosts) {
|
|
|
4948
4951
|
let facade;
|
|
4949
4952
|
net.kernelOnly(CDP_PORT, true);
|
|
4950
4953
|
net.reserve(CDP_PORT);
|
|
4954
|
+
net.stampPeers(CDP_PORT);
|
|
4951
4955
|
net.activate({ family: "inet", host: "127.0.0.1", port: CDP_PORT }, () => {
|
|
4952
4956
|
const started = new CdpFacade({ net, hosts });
|
|
4953
4957
|
facade = started;
|
|
@@ -4990,7 +4994,7 @@ var CdpHosts = class {
|
|
|
4990
4994
|
if (!entry) throw new HttpError(503, NO_CDP_HOST);
|
|
4991
4995
|
let conn;
|
|
4992
4996
|
try {
|
|
4993
|
-
conn = await entry.hook(request3
|
|
4997
|
+
conn = await entry.hook(hookRequest(request3));
|
|
4994
4998
|
} catch (e) {
|
|
4995
4999
|
throw new HttpError(502, `CDP host: ${e instanceof Error ? e.message : String(e)}`);
|
|
4996
5000
|
}
|
|
@@ -5010,6 +5014,12 @@ var CdpHosts = class {
|
|
|
5010
5014
|
for (const entry of [this.embedder, ...this.clients]) if (entry) closeAll(entry);
|
|
5011
5015
|
}
|
|
5012
5016
|
};
|
|
5017
|
+
function hookRequest({ runtime, stamp }) {
|
|
5018
|
+
return {
|
|
5019
|
+
...runtime ? { runtime } : {},
|
|
5020
|
+
...stamp ? { stamp: structuredClone(stamp) } : {}
|
|
5021
|
+
};
|
|
5022
|
+
}
|
|
5013
5023
|
function closeAll(entry) {
|
|
5014
5024
|
for (const conn of [...entry.open]) {
|
|
5015
5025
|
conn.close();
|
|
@@ -7158,6 +7168,7 @@ var LoopbackNet = class {
|
|
|
7158
7168
|
reserved = /* @__PURE__ */ new Set();
|
|
7159
7169
|
facades = /* @__PURE__ */ new Map();
|
|
7160
7170
|
proxyStamped;
|
|
7171
|
+
stamped = /* @__PURE__ */ new Set();
|
|
7161
7172
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
7162
7173
|
route;
|
|
7163
7174
|
origins;
|
|
@@ -7232,6 +7243,9 @@ var LoopbackNet = class {
|
|
|
7232
7243
|
this.kernelOnly(port, true);
|
|
7233
7244
|
this.facades.set(port, name2);
|
|
7234
7245
|
}
|
|
7246
|
+
stampPeers(port) {
|
|
7247
|
+
this.stamped.add(port);
|
|
7248
|
+
}
|
|
7235
7249
|
stampProxy(port) {
|
|
7236
7250
|
this.proxyStamped = port;
|
|
7237
7251
|
}
|
|
@@ -7240,7 +7254,7 @@ var LoopbackNet = class {
|
|
|
7240
7254
|
}
|
|
7241
7255
|
stampsPeers(addr) {
|
|
7242
7256
|
if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return false;
|
|
7243
|
-
return this.facades.has(addr.port) || this.proxyStamped === addr.port;
|
|
7257
|
+
return this.facades.has(addr.port) || this.stamped.has(addr.port) || this.proxyStamped === addr.port;
|
|
7244
7258
|
}
|
|
7245
7259
|
activate(addr, start2) {
|
|
7246
7260
|
this.activators.set(keyOf(addr), start2);
|
|
@@ -8206,7 +8220,7 @@ var UserDb = class {
|
|
|
8206
8220
|
};
|
|
8207
8221
|
|
|
8208
8222
|
// src/client/protocol.ts
|
|
8209
|
-
var PROTOCOL = [1,
|
|
8223
|
+
var PROTOCOL = [1, 17];
|
|
8210
8224
|
var FS_METHODS = [
|
|
8211
8225
|
"readFile",
|
|
8212
8226
|
"writeFile",
|
|
@@ -8362,9 +8376,9 @@ async function accountOf(l, user) {
|
|
|
8362
8376
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
8363
8377
|
return found;
|
|
8364
8378
|
}
|
|
8365
|
-
async function runAs(l, self,
|
|
8366
|
-
if (
|
|
8367
|
-
const target = await accountOf(l,
|
|
8379
|
+
async function runAs(l, self, requested2) {
|
|
8380
|
+
if (requested2 === void 0) return self;
|
|
8381
|
+
const target = await accountOf(l, requested2);
|
|
8368
8382
|
if (self.uid !== 0 && target.uid !== self.uid) {
|
|
8369
8383
|
throw fsError("EPERM", `${self.name} may not run as ${target.name}`);
|
|
8370
8384
|
}
|
|
@@ -8373,21 +8387,9 @@ async function runAs(l, self, requested) {
|
|
|
8373
8387
|
function clientCred(self) {
|
|
8374
8388
|
return self ? credOf(self) : copyCred(ROOT);
|
|
8375
8389
|
}
|
|
8376
|
-
var MAX_SPAWN_TAGS = 8;
|
|
8377
|
-
function spawnTags(value2) {
|
|
8378
|
-
if (!Array.isArray(value2)) {
|
|
8379
|
-
tagOption(value2);
|
|
8380
|
-
return value2 === void 0 ? [] : [value2];
|
|
8381
|
-
}
|
|
8382
|
-
if (value2.length > MAX_SPAWN_TAGS) {
|
|
8383
|
-
throw new TypeError(`a spawn adds at most ${MAX_SPAWN_TAGS} tags`);
|
|
8384
|
-
}
|
|
8385
|
-
for (const each of value2) tagOption(each ?? 0);
|
|
8386
|
-
return value2;
|
|
8387
|
-
}
|
|
8388
8390
|
async function runTagged(l, self, options, tag, session = -1) {
|
|
8389
8391
|
let tags = withTag(void 0, tag);
|
|
8390
|
-
for (const added of
|
|
8392
|
+
for (const added of tagList(options.tag)) tags = withTag(tags, added);
|
|
8391
8393
|
return {
|
|
8392
8394
|
user: await runAs(l, self, options.user),
|
|
8393
8395
|
tag,
|
|
@@ -8572,6 +8574,20 @@ function requestBinding(send2, port) {
|
|
|
8572
8574
|
close: () => unbind?.()
|
|
8573
8575
|
};
|
|
8574
8576
|
}
|
|
8577
|
+
async function sudoRunAs(l, self, host, req, reply) {
|
|
8578
|
+
if (self.uid !== 0) throw sudoFailure("EPERM", "sudo: only a root client may run a sudo request");
|
|
8579
|
+
const { stdout, stderr, tag } = req.options;
|
|
8580
|
+
const running = await l.sudoRun(req.replay, {
|
|
8581
|
+
stdout,
|
|
8582
|
+
stderr,
|
|
8583
|
+
tag,
|
|
8584
|
+
base: host.tag,
|
|
8585
|
+
session: host.session
|
|
8586
|
+
});
|
|
8587
|
+
reply(req.id, { started: running.pid });
|
|
8588
|
+
const { status, signal } = await running.ended;
|
|
8589
|
+
return { result: status, ...signalField(signal) };
|
|
8590
|
+
}
|
|
8575
8591
|
function answered(pending, req, reply, detach) {
|
|
8576
8592
|
pending.then(
|
|
8577
8593
|
({ result, signal, transfer }) => {
|
|
@@ -8721,6 +8737,8 @@ function serveClient(port, host) {
|
|
|
8721
8737
|
case "trace":
|
|
8722
8738
|
case "untrace":
|
|
8723
8739
|
return traces.answer(l, self, req);
|
|
8740
|
+
case "sudo-run":
|
|
8741
|
+
return sudoRunAs(l, self, host, req, reply);
|
|
8724
8742
|
case "detach":
|
|
8725
8743
|
return { result: true };
|
|
8726
8744
|
default:
|
|
@@ -8904,7 +8922,7 @@ function satisfies(version, range2) {
|
|
|
8904
8922
|
}
|
|
8905
8923
|
|
|
8906
8924
|
// src/version.ts
|
|
8907
|
-
var KERNEL_VERSION = true ? "1.
|
|
8925
|
+
var KERNEL_VERSION = true ? "1.182.0" : "0.0.0-dev";
|
|
8908
8926
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8909
8927
|
function procVersion() {
|
|
8910
8928
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9769,27 +9787,27 @@ function hashId(text) {
|
|
|
9769
9787
|
return hex4(a) + hex4(b);
|
|
9770
9788
|
}
|
|
9771
9789
|
function split2(text, count2) {
|
|
9772
|
-
const
|
|
9790
|
+
const words3 = [];
|
|
9773
9791
|
let rest2 = text;
|
|
9774
9792
|
for (let i = 0; i < count2; i++) {
|
|
9775
9793
|
const match = /^(\S+)\s+/.exec(rest2);
|
|
9776
9794
|
if (!match) return void 0;
|
|
9777
|
-
|
|
9795
|
+
words3.push(match[1]);
|
|
9778
9796
|
rest2 = rest2.slice(match[0].length);
|
|
9779
9797
|
}
|
|
9780
|
-
return [
|
|
9798
|
+
return [words3, rest2.trim()];
|
|
9781
9799
|
}
|
|
9782
9800
|
function jobOf(content, pending, ctx, env) {
|
|
9783
9801
|
const fields = content.startsWith("@") ? 1 : 5;
|
|
9784
9802
|
const parts2 = split2(content, fields + (ctx.system ? 1 : 0));
|
|
9785
9803
|
if (!parts2 || parts2[1] === "") throw new Error("no command");
|
|
9786
|
-
const [
|
|
9787
|
-
const schedule =
|
|
9804
|
+
const [words3, command] = parts2;
|
|
9805
|
+
const schedule = words3.slice(0, fields).join(" ");
|
|
9788
9806
|
const when = parseWhen(schedule);
|
|
9789
9807
|
const zone = env.CRON_TZ;
|
|
9790
9808
|
if (zone && !when.reboot && canonicalZone(zone) === void 0)
|
|
9791
9809
|
throw new Error(`CRON_TZ: unknown time zone "${zone}"`);
|
|
9792
|
-
const user = ctx.system ?
|
|
9810
|
+
const user = ctx.system ? words3[fields] : void 0;
|
|
9793
9811
|
if (user !== void 0 && !USER_NAME.test(user)) throw new Error(`bad user name ${user}`);
|
|
9794
9812
|
if (pending !== void 0 && !JOB_NAME.test(pending))
|
|
9795
9813
|
throw new Error(`bad job name "${pending}"`);
|
|
@@ -12770,9 +12788,11 @@ var SpawnError = class extends Error {
|
|
|
12770
12788
|
};
|
|
12771
12789
|
var ChangedError = class extends SpawnError {
|
|
12772
12790
|
notice;
|
|
12773
|
-
|
|
12791
|
+
file;
|
|
12792
|
+
constructor(notice, file) {
|
|
12774
12793
|
super("EPERM");
|
|
12775
12794
|
this.notice = notice;
|
|
12795
|
+
this.file = file;
|
|
12776
12796
|
}
|
|
12777
12797
|
};
|
|
12778
12798
|
function interrupted(signal) {
|
|
@@ -19818,21 +19838,21 @@ function unescaped(double) {
|
|
|
19818
19838
|
}
|
|
19819
19839
|
function splitWords(text) {
|
|
19820
19840
|
const piece = /'([^']*)'|"((?:[^"\\]|\\[\s\S])*)"|\\([\s\S])|([^\s'"\\]+)|(\s+)/y;
|
|
19821
|
-
const
|
|
19841
|
+
const words3 = [];
|
|
19822
19842
|
let word;
|
|
19823
19843
|
while (piece.lastIndex < text.length) {
|
|
19824
19844
|
const m = piece.exec(text);
|
|
19825
19845
|
if (!m) return void 0;
|
|
19826
19846
|
const [, single, double, escaped, plain3, space] = m;
|
|
19827
19847
|
if (space !== void 0) {
|
|
19828
|
-
if (word !== void 0)
|
|
19848
|
+
if (word !== void 0) words3.push(word);
|
|
19829
19849
|
word = void 0;
|
|
19830
19850
|
continue;
|
|
19831
19851
|
}
|
|
19832
19852
|
word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain3));
|
|
19833
19853
|
}
|
|
19834
|
-
if (word !== void 0)
|
|
19835
|
-
return
|
|
19854
|
+
if (word !== void 0) words3.push(word);
|
|
19855
|
+
return words3;
|
|
19836
19856
|
}
|
|
19837
19857
|
function quoteWord(word) {
|
|
19838
19858
|
const text = hasControl(word) ? withoutControl(word) : word;
|
|
@@ -19853,14 +19873,14 @@ function addPlain(word, plain3) {
|
|
|
19853
19873
|
}
|
|
19854
19874
|
function splitPatterns(text) {
|
|
19855
19875
|
const piece = /'([^']*)'|"((?:[^"\\]|\\[\s\S])*)"|\\([\s\S])|([^\s'"\\]+)|(\s+)/y;
|
|
19856
|
-
const
|
|
19876
|
+
const words3 = [];
|
|
19857
19877
|
let word;
|
|
19858
19878
|
while (piece.lastIndex < text.length) {
|
|
19859
19879
|
const m = piece.exec(text);
|
|
19860
19880
|
if (!m) return void 0;
|
|
19861
19881
|
const [, single, double, escaped, plain3, space] = m;
|
|
19862
19882
|
if (space !== void 0) {
|
|
19863
|
-
if (word !== void 0)
|
|
19883
|
+
if (word !== void 0) words3.push(word);
|
|
19864
19884
|
word = void 0;
|
|
19865
19885
|
continue;
|
|
19866
19886
|
}
|
|
@@ -19868,8 +19888,8 @@ function splitPatterns(text) {
|
|
|
19868
19888
|
if (plain3 !== void 0) addPlain(word, plain3);
|
|
19869
19889
|
else addPart(word, single ?? (double !== void 0 ? unescaped(double) : escaped));
|
|
19870
19890
|
}
|
|
19871
|
-
if (word !== void 0)
|
|
19872
|
-
return
|
|
19891
|
+
if (word !== void 0) words3.push(word);
|
|
19892
|
+
return words3;
|
|
19873
19893
|
}
|
|
19874
19894
|
var literal = (pattern) => pattern.map((p) => p ?? "*").join("");
|
|
19875
19895
|
var isAny = (pattern) => pattern?.length === 1 && pattern[0] === null;
|
|
@@ -19942,14 +19962,14 @@ function whoError(who) {
|
|
|
19942
19962
|
return `expected a user name, %group or ALL first, not ${shown(who)}`;
|
|
19943
19963
|
}
|
|
19944
19964
|
function cwdOf(word) {
|
|
19945
|
-
const
|
|
19946
|
-
const path =
|
|
19965
|
+
const words3 = splitWords(word);
|
|
19966
|
+
const path = words3?.length === 1 ? words3[0] : "";
|
|
19947
19967
|
return path.startsWith("/") ? normalizePath(path) : "";
|
|
19948
19968
|
}
|
|
19949
19969
|
function commandOf2(text, after) {
|
|
19950
|
-
const
|
|
19951
|
-
if (
|
|
19952
|
-
const [first, ...args] =
|
|
19970
|
+
const words3 = splitPatterns(text);
|
|
19971
|
+
if (words3 === void 0) return "a quote in the command is not closed, or it ends in a \\";
|
|
19972
|
+
const [first, ...args] = words3;
|
|
19953
19973
|
const path = first ? literal(first) : "";
|
|
19954
19974
|
if (path === "") return `expected a command after ${after}`;
|
|
19955
19975
|
if (!path.startsWith("/")) return `expected an absolute command path, not ${shown(path)}`;
|
|
@@ -20262,6 +20282,9 @@ function recordable(cwd, argv) {
|
|
|
20262
20282
|
function changedText(file) {
|
|
20263
20283
|
return `sudo: ${file} changed since it was approved`;
|
|
20264
20284
|
}
|
|
20285
|
+
function requestedText(file) {
|
|
20286
|
+
return `sudo: ${file} changed since it was requested`;
|
|
20287
|
+
}
|
|
20265
20288
|
function changedFile(approved, now) {
|
|
20266
20289
|
const files = /* @__PURE__ */ new Set([...Object.keys(approved), ...Object.keys(now)]);
|
|
20267
20290
|
return [...files].find((file) => approved[file] !== now[file]);
|
|
@@ -20269,6 +20292,67 @@ function changedFile(approved, now) {
|
|
|
20269
20292
|
function pinned(rule, bound3) {
|
|
20270
20293
|
return rule.sha256 === void 0 || changedFile(rule.sha256, bound3) === void 0;
|
|
20271
20294
|
}
|
|
20295
|
+
var REPLAY_ID = /^[!-~]{1,256}$/;
|
|
20296
|
+
var REPLAY_TAGS_MAX = 64;
|
|
20297
|
+
var REPLAY_ARGV_MAX = 4096;
|
|
20298
|
+
var REPLAY_BYTES_MAX = 1024 * 1024;
|
|
20299
|
+
var NOT_A_REQUEST = "sudo: that isn't a sudo request this kernel can run";
|
|
20300
|
+
function strings(value2, max) {
|
|
20301
|
+
return Array.isArray(value2) && value2.length <= max && value2.every((s) => typeof s === "string");
|
|
20302
|
+
}
|
|
20303
|
+
function words(value2) {
|
|
20304
|
+
if (!strings(value2, REPLAY_ARGV_MAX) || value2.length === 0) return false;
|
|
20305
|
+
const bytes = value2.reduce((n, s) => n + s.length + 1, 0);
|
|
20306
|
+
return bytes <= REPLAY_BYTES_MAX && !value2.some((s) => s.includes("\0"));
|
|
20307
|
+
}
|
|
20308
|
+
function filesOf(value2) {
|
|
20309
|
+
if (value2 === void 0) return {};
|
|
20310
|
+
if (!Array.isArray(value2) || value2.length > OPERANDS_MAX) return void 0;
|
|
20311
|
+
const files = {};
|
|
20312
|
+
for (const file of value2) {
|
|
20313
|
+
const { path, sha256: hex4 } = file ?? {};
|
|
20314
|
+
if (typeof path !== "string" || typeof hex4 !== "string") return void 0;
|
|
20315
|
+
files[path] = hex4;
|
|
20316
|
+
}
|
|
20317
|
+
return files;
|
|
20318
|
+
}
|
|
20319
|
+
function flagsOf(value2) {
|
|
20320
|
+
if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) return void 0;
|
|
20321
|
+
const entries = Object.entries(value2);
|
|
20322
|
+
if (entries.length > ROOT_ONLY_MAX || entries.some(([, v]) => typeof v !== "boolean")) {
|
|
20323
|
+
return void 0;
|
|
20324
|
+
}
|
|
20325
|
+
return Object.fromEntries(entries);
|
|
20326
|
+
}
|
|
20327
|
+
function replayOf(value2) {
|
|
20328
|
+
if (typeof value2 !== "object" || value2 === null) return failed2("EINVAL", NOT_A_REQUEST);
|
|
20329
|
+
const r = value2;
|
|
20330
|
+
if (r.validate === true) return failed2("EINVAL", "sudo: a sudo -v request runs no command");
|
|
20331
|
+
if (r.stdin === "pipe" || r.stdin === "file") {
|
|
20332
|
+
return failed2("EINVAL", `sudo: the request read a ${r.stdin}, and that input is gone`);
|
|
20333
|
+
}
|
|
20334
|
+
const { id: id2, user, uid, target, argv, path, cwd, stdin, tag, tags } = r;
|
|
20335
|
+
const rootOnly2 = flagsOf(r.rootOnly);
|
|
20336
|
+
const bound3 = filesOf(r.userWritable);
|
|
20337
|
+
const named = (s) => typeof s === "string" && s !== "";
|
|
20338
|
+
const absolute2 = (s) => typeof s === "string" && s.startsWith("/") && s.length <= PATH_MAX && !s.includes("\0");
|
|
20339
|
+
const valid = typeof id2 === "string" && REPLAY_ID.test(id2) && named(user) && named(target) && Number.isInteger(uid) && uid >= 0 && words(argv) && absolute2(path) && absolute2(cwd) && (stdin === "tty" || stdin === "none") && (tag === void 0 || typeof tag === "string") && (tags === void 0 || strings(tags, REPLAY_TAGS_MAX)) && rootOnly2 !== void 0 && bound3 !== void 0;
|
|
20340
|
+
if (!valid) return failed2("EINVAL", NOT_A_REQUEST);
|
|
20341
|
+
const all = tags ?? (tag === void 0 ? [] : [tag]);
|
|
20342
|
+
return {
|
|
20343
|
+
id: id2,
|
|
20344
|
+
user,
|
|
20345
|
+
uid,
|
|
20346
|
+
target,
|
|
20347
|
+
argv,
|
|
20348
|
+
path,
|
|
20349
|
+
cwd,
|
|
20350
|
+
stdin,
|
|
20351
|
+
rootOnly: rootOnly2,
|
|
20352
|
+
bound: bound3,
|
|
20353
|
+
tags: [...new Set(all)]
|
|
20354
|
+
};
|
|
20355
|
+
}
|
|
20272
20356
|
var VISUDO_FILES_MAX = 64;
|
|
20273
20357
|
var VISUDO_TEXT_MAX = 1024 * 1024;
|
|
20274
20358
|
function visudoCall(req) {
|
|
@@ -20670,6 +20754,61 @@ var Sudo = class {
|
|
|
20670
20754
|
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
20671
20755
|
return this.command(session, root, mine, call);
|
|
20672
20756
|
}
|
|
20757
|
+
async replay(value2) {
|
|
20758
|
+
const r = replayOf(value2);
|
|
20759
|
+
if ("error" in r) return r;
|
|
20760
|
+
if (this.o.mode !== "enforce") {
|
|
20761
|
+
return failed2("EINVAL", `sudo: users are '${this.o.mode}', so no request needed approval`);
|
|
20762
|
+
}
|
|
20763
|
+
const self = await this.o.users.lookup(r.user);
|
|
20764
|
+
if (!self) return failed2("ENOENT", `sudo: unknown user ${r.user}`);
|
|
20765
|
+
if (self.uid !== r.uid) return failed2("EPERM", `sudo: ${self.name} is no longer uid ${r.uid}`);
|
|
20766
|
+
const target = await this.lookup(r.target);
|
|
20767
|
+
if (!target) return failed2("ENOENT", `sudo: unknown user ${r.target}`);
|
|
20768
|
+
const cred = credOf(self);
|
|
20769
|
+
const [word = "", ...args] = r.argv;
|
|
20770
|
+
const argv = [r.path, ...args];
|
|
20771
|
+
if (!await this.mayAsk(self, target, r, argv)) {
|
|
20772
|
+
const quoted = argv.map(quoteWord).join(" ");
|
|
20773
|
+
return failed2(
|
|
20774
|
+
"EACCES",
|
|
20775
|
+
`sudo: ${self.name} may no longer ask to run ${quoted} as ${target.name}`
|
|
20776
|
+
);
|
|
20777
|
+
}
|
|
20778
|
+
if (await this.canonical(r.cwd) !== r.cwd) {
|
|
20779
|
+
return failed2("EACCES", `sudo: ${r.cwd} changed since it was requested`);
|
|
20780
|
+
}
|
|
20781
|
+
if (!await this.reachable(cred, r.cwd)) {
|
|
20782
|
+
return failed2(
|
|
20783
|
+
"EACCES",
|
|
20784
|
+
`sudo: cannot run in ${r.cwd}: it isn't a directory ${self.name} can enter`
|
|
20785
|
+
);
|
|
20786
|
+
}
|
|
20787
|
+
const path = await this.locate(word, r.cwd);
|
|
20788
|
+
if (!path) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
20789
|
+
if (path !== r.path) return failed2("EPERM", `sudo: ${word} now runs ${path}, not ${r.path}`);
|
|
20790
|
+
const bound3 = await this.bound(path, r.cwd);
|
|
20791
|
+
if (!bound3) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
20792
|
+
const changed = changedFile(r.bound, bound3);
|
|
20793
|
+
if (changed !== void 0) return failed2("EPERM", requestedText(changed));
|
|
20794
|
+
const now = await this.rootOnly(r.cwd, args);
|
|
20795
|
+
const flipped = Object.keys(r.rootOnly).find((at) => r.rootOnly[at] && now[at] !== true);
|
|
20796
|
+
if (flipped !== void 0) return failed2("EPERM", `sudo: ${flipped} is no longer root-only`);
|
|
20797
|
+
const { grant } = this.grant(self, target, cred, r.argv, path, r.cwd, void 0, bound3);
|
|
20798
|
+
(this.o.warn ?? console.warn)(
|
|
20799
|
+
`sudo: ${self.name} : TTY=unknown ; PWD=${quoteWord(r.cwd)} ; USER=${target.name} ; REPLAY=${r.id} ; COMMAND=${argv.map(quoteWord).join(" ")}`
|
|
20800
|
+
);
|
|
20801
|
+
return { grant, caller: self, target, tags: r.tags };
|
|
20802
|
+
}
|
|
20803
|
+
async mayAsk(self, target, r, argv) {
|
|
20804
|
+
if (self.uid === 0) return true;
|
|
20805
|
+
const cred = credOf(self);
|
|
20806
|
+
const { rules } = await this.policyRules({ cred, pid: 0, stdin: r.stdin });
|
|
20807
|
+
const applies = await this.applies(self, cred);
|
|
20808
|
+
return rules.some(
|
|
20809
|
+
(rule) => applies(rule.who) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === r.cwd) && stdinMatches(rule, r.stdin) && commandMatches(rule.cmnd, argv) && pinned(rule, r.bound)
|
|
20810
|
+
);
|
|
20811
|
+
}
|
|
20673
20812
|
async command(s, root, mine, call) {
|
|
20674
20813
|
const { caller, self, target, parsed: parsed2 } = s;
|
|
20675
20814
|
const { cred } = caller;
|
|
@@ -20849,8 +20988,8 @@ ${lines2}
|
|
|
20849
20988
|
const st = await fs.lstat(path).catch(() => void 0);
|
|
20850
20989
|
if (st && !await this.trusted(path)) return false;
|
|
20851
20990
|
const old = st ? await fs.readFile(path) : "";
|
|
20852
|
-
const
|
|
20853
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${
|
|
20991
|
+
const words3 = recordedCommand(argv);
|
|
20992
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${words3}
|
|
20854
20993
|
`;
|
|
20855
20994
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
20856
20995
|
${line}`;
|
|
@@ -22155,8 +22294,8 @@ function ipv6(host) {
|
|
|
22155
22294
|
const head = groups(halves[0]);
|
|
22156
22295
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
22157
22296
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
22158
|
-
const
|
|
22159
|
-
const missing6 = 8 -
|
|
22297
|
+
const words3 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
22298
|
+
const missing6 = 8 - words3.length - tail2.length;
|
|
22160
22299
|
if (halves.length === 2 ? missing6 < 1 : missing6 !== 0) return void 0;
|
|
22161
22300
|
const all = [
|
|
22162
22301
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
@@ -25797,7 +25936,7 @@ function selectFlag(req) {
|
|
|
25797
25936
|
throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
|
|
25798
25937
|
return TLS_SERVER_SELECT;
|
|
25799
25938
|
}
|
|
25800
|
-
function
|
|
25939
|
+
function flagsOf2(req) {
|
|
25801
25940
|
return certFlags(req) | selectFlag(req) | (req.keylog ? TLS_KEYLOG : 0);
|
|
25802
25941
|
}
|
|
25803
25942
|
async function engineOf(proc, { select, keylog }) {
|
|
@@ -25848,7 +25987,7 @@ async function serverOf(proc, req) {
|
|
|
25848
25987
|
let mine;
|
|
25849
25988
|
try {
|
|
25850
25989
|
mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
|
|
25851
|
-
const flags2 =
|
|
25990
|
+
const flags2 = flagsOf2(req);
|
|
25852
25991
|
const store = mine ?? (flags2 & CERT_FLAGS ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
|
|
25853
25992
|
return {
|
|
25854
25993
|
engine,
|
|
@@ -27737,7 +27876,7 @@ var WRITE_ACCESS = 3;
|
|
|
27737
27876
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
27738
27877
|
var STUCK_ESCAPES = /* @__PURE__ */ new Set([SIG.INT, SIG.TERM, SIG.QUIT, SIG.HUP]);
|
|
27739
27878
|
var DEFAULT_UMASK2 = 18;
|
|
27740
|
-
function
|
|
27879
|
+
function words2(value2) {
|
|
27741
27880
|
if (!Array.isArray(value2) || !value2.every((w) => typeof w === "string")) {
|
|
27742
27881
|
throw new KernelError("EINVAL");
|
|
27743
27882
|
}
|
|
@@ -29190,7 +29329,7 @@ var WasmProcess = class {
|
|
|
29190
29329
|
if (!sudo) throw new KernelError("ENOSYS");
|
|
29191
29330
|
const call = {
|
|
29192
29331
|
op: "proc-sudo",
|
|
29193
|
-
args:
|
|
29332
|
+
args: words2(req.args),
|
|
29194
29333
|
cwd: typeof req.cwd === "string" && req.cwd.startsWith("/") ? req.cwd : "/",
|
|
29195
29334
|
...typeof req.term === "string" ? { term: req.term } : {}
|
|
29196
29335
|
};
|
|
@@ -33800,7 +33939,40 @@ function describe(req, tty) {
|
|
|
33800
33939
|
}
|
|
33801
33940
|
function refuseChanged(approved, now) {
|
|
33802
33941
|
const changed = changedFile(approved, now);
|
|
33803
|
-
if (changed !== void 0) throw new ChangedError(changedText(changed));
|
|
33942
|
+
if (changed !== void 0) throw new ChangedError(changedText(changed), changed);
|
|
33943
|
+
}
|
|
33944
|
+
var O_WRONLY2 = 1;
|
|
33945
|
+
var OUTPUT_MODE = 384;
|
|
33946
|
+
var ERRNO_TEXT = {
|
|
33947
|
+
EACCES: "Permission denied",
|
|
33948
|
+
EISDIR: "Is a directory",
|
|
33949
|
+
ENOENT: "No such file or directory",
|
|
33950
|
+
ENOTDIR: "Not a directory",
|
|
33951
|
+
EROFS: "Read-only file system"
|
|
33952
|
+
};
|
|
33953
|
+
function sudoFailure(errno3, message3) {
|
|
33954
|
+
return Object.assign(new Error(message3), { code: errno3 });
|
|
33955
|
+
}
|
|
33956
|
+
function sudoCause(err) {
|
|
33957
|
+
const code = codeOf8(err);
|
|
33958
|
+
if (typeof code !== "string") throw err;
|
|
33959
|
+
return code;
|
|
33960
|
+
}
|
|
33961
|
+
function requested(err) {
|
|
33962
|
+
if (err instanceof ChangedError) throw sudoFailure(err.code, requestedText(err.file));
|
|
33963
|
+
throw err;
|
|
33964
|
+
}
|
|
33965
|
+
var MAX_SPAWN_TAGS = 8;
|
|
33966
|
+
function tagList(value2) {
|
|
33967
|
+
if (!Array.isArray(value2)) {
|
|
33968
|
+
tagOption(value2);
|
|
33969
|
+
return value2 === void 0 ? [] : [value2];
|
|
33970
|
+
}
|
|
33971
|
+
if (value2.length > MAX_SPAWN_TAGS) {
|
|
33972
|
+
throw new TypeError(`a spawn adds at most ${MAX_SPAWN_TAGS} tags`);
|
|
33973
|
+
}
|
|
33974
|
+
for (const each of value2) tagOption(each ?? 0);
|
|
33975
|
+
return value2;
|
|
33804
33976
|
}
|
|
33805
33977
|
function linksOf2(req) {
|
|
33806
33978
|
return req.links === void 0 ? {} : { links: req.links };
|
|
@@ -33926,27 +34098,27 @@ function appendedRoots(given) {
|
|
|
33926
34098
|
}
|
|
33927
34099
|
return [...roots];
|
|
33928
34100
|
}
|
|
33929
|
-
function plainEnv(
|
|
33930
|
-
const next3 =
|
|
33931
|
-
if (baseName2(
|
|
34101
|
+
function plainEnv(words3) {
|
|
34102
|
+
const next3 = words3[1];
|
|
34103
|
+
if (baseName2(words3[0] ?? "") !== "env" || next3 === void 0) return false;
|
|
33932
34104
|
return next3 === "-S" || !next3.startsWith("-") && !next3.includes("=");
|
|
33933
34105
|
}
|
|
33934
|
-
function shebangCommand(
|
|
33935
|
-
if (!plainEnv(
|
|
33936
|
-
const arg2 =
|
|
33937
|
-
return { interp:
|
|
34106
|
+
function shebangCommand(words3) {
|
|
34107
|
+
if (!plainEnv(words3)) {
|
|
34108
|
+
const arg2 = words3.slice(1).join(" ");
|
|
34109
|
+
return { interp: words3[0], args: arg2 ? [arg2] : [] };
|
|
33938
34110
|
}
|
|
33939
|
-
const split3 =
|
|
33940
|
-
const [interp, ...rest2] =
|
|
34111
|
+
const split3 = words3[1] === "-S";
|
|
34112
|
+
const [interp, ...rest2] = words3.slice(split3 ? 2 : 1);
|
|
33941
34113
|
const arg = rest2.join(" ");
|
|
33942
34114
|
return { interp, args: split3 ? rest2 : arg ? [arg] : [] };
|
|
33943
34115
|
}
|
|
33944
34116
|
function interpreter(head) {
|
|
33945
|
-
const
|
|
33946
|
-
if (!
|
|
33947
|
-
if (baseName2(
|
|
33948
|
-
if (
|
|
33949
|
-
return baseName2(
|
|
34117
|
+
const words3 = shebang(head);
|
|
34118
|
+
if (!words3) return "node";
|
|
34119
|
+
if (baseName2(words3[0]) === "env") words3.shift();
|
|
34120
|
+
if (words3[0] === "-S") words3.shift();
|
|
34121
|
+
return baseName2(words3[0] ?? "");
|
|
33950
34122
|
}
|
|
33951
34123
|
function expandDefaults(defaults2, env) {
|
|
33952
34124
|
const out = {};
|
|
@@ -34721,9 +34893,9 @@ var Launcher = class {
|
|
|
34721
34893
|
const head = await this.head(script);
|
|
34722
34894
|
if (!head) return void 0;
|
|
34723
34895
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
34724
|
-
const
|
|
34725
|
-
if (!
|
|
34726
|
-
const { interp, args } = shebangCommand(
|
|
34896
|
+
const words3 = shebang(head) ?? (binfmt ? [binfmt] : void 0);
|
|
34897
|
+
if (!words3) return void 0;
|
|
34898
|
+
const { interp, args } = shebangCommand(words3);
|
|
34727
34899
|
const passed = [...args, command ? script : file, ...argv.slice(1)];
|
|
34728
34900
|
if (!interp) return void 0;
|
|
34729
34901
|
const found = await this.resolve(interp, interp, cwd, scope);
|
|
@@ -34954,7 +35126,7 @@ var Launcher = class {
|
|
|
34954
35126
|
const hex4 = pinned2[real];
|
|
34955
35127
|
if (hex4 !== void 0) return { [real]: hex4 };
|
|
34956
35128
|
if (await this.sudoer.trusted(real)) return {};
|
|
34957
|
-
throw new ChangedError(changedText(real));
|
|
35129
|
+
throw new ChangedError(changedText(real), real);
|
|
34958
35130
|
}
|
|
34959
35131
|
async pinnedBytes(pin, bytes) {
|
|
34960
35132
|
const [real = ""] = Object.keys(pin);
|
|
@@ -35233,6 +35405,10 @@ var Launcher = class {
|
|
|
35233
35405
|
}
|
|
35234
35406
|
async launch(asked, req) {
|
|
35235
35407
|
const cwd = await physicalPathAsync(this.base, req.cwd);
|
|
35408
|
+
if (req.exactCwd && cwd !== req.cwd) {
|
|
35409
|
+
await req.fds.closeAll();
|
|
35410
|
+
throw sudoFailure("EACCES", `sudo: ${req.cwd} changed since it was requested`);
|
|
35411
|
+
}
|
|
35236
35412
|
const seen = { ...req.env, HOSTNAME: this.hostname, cwd };
|
|
35237
35413
|
await this.pnpmReady();
|
|
35238
35414
|
let loaded;
|
|
@@ -36928,6 +37104,96 @@ var Launcher = class {
|
|
|
36928
37104
|
const signal = handle.termsig();
|
|
36929
37105
|
return { status, ...signal ? { signal } : {}, stdout: concat7(out), stderr: concat7(err) };
|
|
36930
37106
|
}
|
|
37107
|
+
async sudoRun(replay, options = {}) {
|
|
37108
|
+
const added = tagList(options.tag);
|
|
37109
|
+
const replayed = await this.sudoer.replay(replay);
|
|
37110
|
+
if ("error" in replayed) throw sudoFailure(replayed.errno, replayed.error);
|
|
37111
|
+
const { grant, caller, target } = replayed;
|
|
37112
|
+
let tags = withTag(void 0, options.base);
|
|
37113
|
+
for (const tag of [...replayed.tags, ...added]) tags = withTag(tags, tag);
|
|
37114
|
+
const tagged = { tags, tagBase: options.base === void 0 ? 0 : 1 };
|
|
37115
|
+
await this.swaps.settled();
|
|
37116
|
+
this.resetCatalogs();
|
|
37117
|
+
const req = { file: grant.file, argv: grant.argv, env: grant.env, cwd: grant.cwd };
|
|
37118
|
+
const ctx = { ppid: 0, cred: grant.cred, scope: "" };
|
|
37119
|
+
const planned = await this.planOne(req, ctx).catch((err2) => {
|
|
37120
|
+
const code = sudoCause(err2);
|
|
37121
|
+
const word = grant.argv[0] ?? grant.file;
|
|
37122
|
+
if (code === "ENOENT") throw sudoFailure(code, `sudo: ${word}: command not found`);
|
|
37123
|
+
throw sudoFailure(code, `sudo: ${grant.file}: ${ERRNO_TEXT[code] ?? code}`);
|
|
37124
|
+
});
|
|
37125
|
+
const pin = await this.unchanged(planned, grant.file, grant.cwd, grant).catch(requested);
|
|
37126
|
+
const fds = await this.sudoOutputs(options, caller, this.stackFor(tags, tagged.tagBase));
|
|
37127
|
+
const err = fds.get(2).file;
|
|
37128
|
+
const report = (message3) => void Promise.resolve(err.write?.(encoder10.encode(`${message3}
|
|
37129
|
+
`))).catch(() => void 0);
|
|
37130
|
+
const replan = () => this.planOne(req, ctx);
|
|
37131
|
+
if (!await this.grantedCwd(grant.caller, grant.cwd)) {
|
|
37132
|
+
await fds.closeAll();
|
|
37133
|
+
throw sudoFailure("EACCES", `sudo: ${grant.cwd} changed since it was requested`);
|
|
37134
|
+
}
|
|
37135
|
+
const handle = await this.launch(
|
|
37136
|
+
{ ...planned, replan },
|
|
37137
|
+
{
|
|
37138
|
+
...pin,
|
|
37139
|
+
env: grant.env,
|
|
37140
|
+
cwd: grant.cwd,
|
|
37141
|
+
fds,
|
|
37142
|
+
report,
|
|
37143
|
+
...this.identity(target, tagged, options.session),
|
|
37144
|
+
...caller.umask !== void 0 ? { umask: caller.umask } : {},
|
|
37145
|
+
links: grant.cred.euid,
|
|
37146
|
+
exactCwd: true
|
|
37147
|
+
}
|
|
37148
|
+
).catch(requested);
|
|
37149
|
+
const ended = handle.exited.then((status) => {
|
|
37150
|
+
const signal = handle.termsig();
|
|
37151
|
+
return { status, ...signal ? { signal } : {} };
|
|
37152
|
+
});
|
|
37153
|
+
return { pid: handle.pid, ended };
|
|
37154
|
+
}
|
|
37155
|
+
async sudoOutputs(options, caller, stack) {
|
|
37156
|
+
const fds = new FdTable();
|
|
37157
|
+
const opened2 = /* @__PURE__ */ new Map();
|
|
37158
|
+
fds.installAt(0, deviceFile("null"));
|
|
37159
|
+
try {
|
|
37160
|
+
fds.installAt(1, await this.sudoOutput(options.stdout, caller, stack, opened2));
|
|
37161
|
+
fds.installAt(2, await this.sudoOutput(options.stderr, caller, stack, opened2));
|
|
37162
|
+
} catch (err) {
|
|
37163
|
+
await fds.closeAll();
|
|
37164
|
+
throw err;
|
|
37165
|
+
}
|
|
37166
|
+
return fds;
|
|
37167
|
+
}
|
|
37168
|
+
async sudoOutput(path, caller, stack, opened2) {
|
|
37169
|
+
if (path === void 0) return deviceFile("null");
|
|
37170
|
+
if (typeof path !== "string" || !path.startsWith("/")) {
|
|
37171
|
+
throw sudoFailure("EINVAL", `sudo: ${String(path)} is not an absolute path`);
|
|
37172
|
+
}
|
|
37173
|
+
const cred = credOf(caller);
|
|
37174
|
+
const walked = await walk(this.fs, cred, normalizePath(path), true, caller.uid);
|
|
37175
|
+
const real = walked.path;
|
|
37176
|
+
const same3 = opened2.get(real);
|
|
37177
|
+
if (same3) return same3.retain();
|
|
37178
|
+
try {
|
|
37179
|
+
if (walked.denied !== void 0) throw fsError("EACCES", path);
|
|
37180
|
+
await writable({ ...this.execGuard(cred, 0), links: caller.uid }, "open", real);
|
|
37181
|
+
const owner = { uid: caller.uid, gid: caller.gid, mode: OUTPUT_MODE };
|
|
37182
|
+
await stack.noLinks.writeFile(real, new Uint8Array(0), owner);
|
|
37183
|
+
} catch (err) {
|
|
37184
|
+
const code = sudoCause(err);
|
|
37185
|
+
throw sudoFailure(code, `sudo: ${path}: ${ERRNO_TEXT[code] ?? code}`);
|
|
37186
|
+
}
|
|
37187
|
+
const file = vfsFile(stack.fs, { path: real, flags: O_WRONLY2, position: 0 }, stack.nodes);
|
|
37188
|
+
const again = await walk(this.fs, cred, real, true, caller.uid);
|
|
37189
|
+
const st = await stack.noLinks.lstat(real).catch(() => void 0);
|
|
37190
|
+
if (again.path !== real || again.denied !== void 0 || !st?.isFile) {
|
|
37191
|
+
await file.release();
|
|
37192
|
+
throw sudoFailure("EACCES", `sudo: ${path} changed while it was opened`);
|
|
37193
|
+
}
|
|
37194
|
+
opened2.set(real, file);
|
|
37195
|
+
return file;
|
|
37196
|
+
}
|
|
36931
37197
|
};
|
|
36932
37198
|
function cronLocks() {
|
|
36933
37199
|
return globalThis.navigator?.locks;
|
|
@@ -37393,11 +37659,38 @@ function policyAsker(port) {
|
|
|
37393
37659
|
}
|
|
37394
37660
|
};
|
|
37395
37661
|
}
|
|
37662
|
+
function processOps(ready2, reply) {
|
|
37663
|
+
const terminals = /* @__PURE__ */ new Map();
|
|
37664
|
+
async function terminal(req) {
|
|
37665
|
+
const onData = (bytes) => reply(req.id, { fd: 1, bytes });
|
|
37666
|
+
const session = await (await ready2()).openTerminal(req.argv, { ...req.options, onData });
|
|
37667
|
+
terminals.set(req.id, session);
|
|
37668
|
+
reply(req.id, { started: session.pid });
|
|
37669
|
+
try {
|
|
37670
|
+
const status = await session.exited;
|
|
37671
|
+
const signal = session.termsig();
|
|
37672
|
+
return signal ? { status, signal } : status;
|
|
37673
|
+
} finally {
|
|
37674
|
+
terminals.delete(req.id);
|
|
37675
|
+
}
|
|
37676
|
+
}
|
|
37677
|
+
async function sudoRun(req) {
|
|
37678
|
+
const running = await (await ready2()).sudoRun(req.replay, req.options);
|
|
37679
|
+
reply(req.id, { started: running.pid });
|
|
37680
|
+
return running.ended;
|
|
37681
|
+
}
|
|
37682
|
+
function onTerminal(req) {
|
|
37683
|
+
const session = terminals.get(req.terminal);
|
|
37684
|
+
if (!session) throw new Error(`no terminal ${req.terminal}`);
|
|
37685
|
+
act2(session, req);
|
|
37686
|
+
return true;
|
|
37687
|
+
}
|
|
37688
|
+
return { terminal, sudoRun, act: onTerminal };
|
|
37689
|
+
}
|
|
37396
37690
|
function serveKernel(port, deps) {
|
|
37397
37691
|
let launcher;
|
|
37398
37692
|
let remote;
|
|
37399
37693
|
let uplink;
|
|
37400
|
-
const terminals = /* @__PURE__ */ new Map();
|
|
37401
37694
|
const reply = (id2, body, transfer) => port.postMessage({ id: id2, ...body }, transfer);
|
|
37402
37695
|
const clients = /* @__PURE__ */ new Set();
|
|
37403
37696
|
const sealed = sealedAsker(port);
|
|
@@ -37426,19 +37719,7 @@ function serveKernel(port, deps) {
|
|
|
37426
37719
|
if (!launcher) throw new Error("the kernel is not initialized");
|
|
37427
37720
|
return launcher;
|
|
37428
37721
|
}
|
|
37429
|
-
|
|
37430
|
-
const onData = (bytes) => reply(req.id, { fd: 1, bytes });
|
|
37431
|
-
const session = await (await ready2()).openTerminal(req.argv, { ...req.options, onData });
|
|
37432
|
-
terminals.set(req.id, session);
|
|
37433
|
-
reply(req.id, { started: session.pid });
|
|
37434
|
-
try {
|
|
37435
|
-
const status = await session.exited;
|
|
37436
|
-
const signal = session.termsig();
|
|
37437
|
-
return signal ? { status, signal } : status;
|
|
37438
|
-
} finally {
|
|
37439
|
-
terminals.delete(req.id);
|
|
37440
|
-
}
|
|
37441
|
-
}
|
|
37722
|
+
const processes2 = processOps(ready2, reply);
|
|
37442
37723
|
async function init(req) {
|
|
37443
37724
|
launcher = rootOf(deps, req).then(async (root) => {
|
|
37444
37725
|
req = await rootNamed(deps, req, root);
|
|
@@ -37493,7 +37774,8 @@ function serveKernel(port, deps) {
|
|
|
37493
37774
|
if (req.op === "init") return init(req);
|
|
37494
37775
|
if (isAttestRequest(req)) return attestOp(await ready2(), req);
|
|
37495
37776
|
if (req.op === "sealed-placeholders") return (await ready2()).setPlaceholders(req.list);
|
|
37496
|
-
if (req.op === "open-terminal") return terminal(req);
|
|
37777
|
+
if (req.op === "open-terminal") return processes2.terminal(req);
|
|
37778
|
+
if (req.op === "sudo-run") return processes2.sudoRun(req);
|
|
37497
37779
|
if (req.op === "connect") return connect2(req.user, req.tag, req.requests);
|
|
37498
37780
|
if (isUsersRequest(req)) return usersOp(await ready2(), req);
|
|
37499
37781
|
if (req.op === "routes" || req.op === "transport-traits") {
|
|
@@ -37502,12 +37784,7 @@ function serveKernel(port, deps) {
|
|
|
37502
37784
|
if (req.op === "dial") return dial(await ready2(), req);
|
|
37503
37785
|
if (req.op === "mount" || req.op === "umount" || req.op === "mounts" || req.op === "insert")
|
|
37504
37786
|
return mountOp(req);
|
|
37505
|
-
if (req.op === "terminal")
|
|
37506
|
-
const session = terminals.get(req.terminal);
|
|
37507
|
-
if (!session) throw new Error(`no terminal ${req.terminal}`);
|
|
37508
|
-
act2(session, req);
|
|
37509
|
-
return true;
|
|
37510
|
-
}
|
|
37787
|
+
if (req.op === "terminal") return processes2.act(req);
|
|
37511
37788
|
return (await ready2()).run(req.argv, {
|
|
37512
37789
|
...req.options,
|
|
37513
37790
|
onStdout: (bytes) => reply(req.id, { fd: 1, bytes }),
|