@ai-ecoverse/slicc-kernel 1.178.1 → 1.178.3
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 +8 -7
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +255 -113
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +272 -130
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/children.d.ts +5 -0
- package/dist/types/launcher.d.ts +3 -0
- package/dist/types/node.d.ts +1 -1
- package/dist/types/sudo-timestamp.d.ts +4 -2
- package/dist/types/sudo.d.ts +12 -1
- package/dist/types/sudoers.d.ts +3 -1
- package/package.json +3 -3
package/dist/node.js
CHANGED
|
@@ -3709,7 +3709,7 @@ function satisfies(version, range2) {
|
|
|
3709
3709
|
}
|
|
3710
3710
|
|
|
3711
3711
|
// src/version.ts
|
|
3712
|
-
var KERNEL_VERSION = true ? "1.178.
|
|
3712
|
+
var KERNEL_VERSION = true ? "1.178.3" : "0.0.0-dev";
|
|
3713
3713
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3714
3714
|
function procVersion() {
|
|
3715
3715
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -5004,9 +5004,9 @@ var UnlinkedKeeper = class {
|
|
|
5004
5004
|
if (kept.whole) return kept.undoing(async () => void 0);
|
|
5005
5005
|
await kept.undoing(
|
|
5006
5006
|
() => replace(target, async (gated, sealed) => {
|
|
5007
|
-
const
|
|
5008
|
-
if (
|
|
5009
|
-
else await keeper.settle(
|
|
5007
|
+
const pinned2 = await keeper.pin(target, gated, sealed);
|
|
5008
|
+
if (pinned2.moved.has(target)) pinned2.commit();
|
|
5009
|
+
else await keeper.settle(pinned2, () => fs.rm(path, options));
|
|
5010
5010
|
})
|
|
5011
5011
|
);
|
|
5012
5012
|
},
|
|
@@ -5019,8 +5019,8 @@ var UnlinkedKeeper = class {
|
|
|
5019
5019
|
() => keeper.marks.around(
|
|
5020
5020
|
[source],
|
|
5021
5021
|
() => replace(target, async (gated, sealed) => {
|
|
5022
|
-
const
|
|
5023
|
-
await keeper.settle(
|
|
5022
|
+
const pinned2 = await keeper.pin(target, gated, sealed);
|
|
5023
|
+
await keeper.settle(pinned2, () => fs.rename(from, to));
|
|
5024
5024
|
})
|
|
5025
5025
|
)
|
|
5026
5026
|
);
|
|
@@ -5055,14 +5055,14 @@ var UnlinkedKeeper = class {
|
|
|
5055
5055
|
}
|
|
5056
5056
|
return false;
|
|
5057
5057
|
}
|
|
5058
|
-
async settle(
|
|
5058
|
+
async settle(pinned2, op) {
|
|
5059
5059
|
try {
|
|
5060
5060
|
await op();
|
|
5061
5061
|
} catch (err) {
|
|
5062
|
-
await
|
|
5062
|
+
await pinned2.rollback();
|
|
5063
5063
|
throw err;
|
|
5064
5064
|
}
|
|
5065
|
-
|
|
5065
|
+
pinned2.commit();
|
|
5066
5066
|
}
|
|
5067
5067
|
heldWithin(target) {
|
|
5068
5068
|
const held = /* @__PURE__ */ new Map();
|
|
@@ -8294,6 +8294,13 @@ var SpawnError = class extends Error {
|
|
|
8294
8294
|
this.code = code;
|
|
8295
8295
|
}
|
|
8296
8296
|
};
|
|
8297
|
+
var ChangedError = class extends SpawnError {
|
|
8298
|
+
notice;
|
|
8299
|
+
constructor(notice) {
|
|
8300
|
+
super("EPERM");
|
|
8301
|
+
this.notice = notice;
|
|
8302
|
+
}
|
|
8303
|
+
};
|
|
8297
8304
|
function interrupted(signal) {
|
|
8298
8305
|
const { promise, reject } = Promise.withResolvers();
|
|
8299
8306
|
const fail3 = () => reject(new KernelError("EINTR"));
|
|
@@ -12766,11 +12773,11 @@ function systemFile(name2, listing, now, memory) {
|
|
|
12766
12773
|
listing.processes.reduce((sum2, p) => sum2 + p.memory, 0)
|
|
12767
12774
|
);
|
|
12768
12775
|
}
|
|
12769
|
-
const
|
|
12776
|
+
const live2 = listing.processes.filter((p) => p.state !== "Z");
|
|
12770
12777
|
if (name2 === "loadavg") {
|
|
12771
12778
|
const last = Math.max(0, ...listing.processes.map((p) => p.pid));
|
|
12772
12779
|
const [one, five, fifteen] = (listing.load ?? [0, 0, 0]).map((n) => n.toFixed(2));
|
|
12773
|
-
return `${one} ${five} ${fifteen} 1/${
|
|
12780
|
+
return `${one} ${five} ${fifteen} 1/${live2.length} ${last}
|
|
12774
12781
|
`;
|
|
12775
12782
|
}
|
|
12776
12783
|
const sum = (key) => listing.cpu?.[key] ?? listing.processes.reduce((n, p) => n + (p[key] ?? 0), 0);
|
|
@@ -15259,30 +15266,49 @@ function timestampKey(owner, type) {
|
|
|
15259
15266
|
}
|
|
15260
15267
|
return parent ? JSON.stringify(["ppid", parent.pid, parent.started]) : void 0;
|
|
15261
15268
|
}
|
|
15269
|
+
function boundKey(bound3) {
|
|
15270
|
+
return JSON.stringify(
|
|
15271
|
+
Object.keys(bound3).sort().map((path) => [path, bound3[path]])
|
|
15272
|
+
);
|
|
15273
|
+
}
|
|
15274
|
+
function writable2(bound3) {
|
|
15275
|
+
return bound3 !== void 0 && Object.keys(bound3).length > 0;
|
|
15276
|
+
}
|
|
15277
|
+
function live(stamp, policy, now) {
|
|
15278
|
+
return stamp.at <= now && (policy.minutes < 0 || now - stamp.at < policy.minutes * MINUTE_MS2);
|
|
15279
|
+
}
|
|
15262
15280
|
var Timestamps = class {
|
|
15263
15281
|
users = /* @__PURE__ */ new Map();
|
|
15264
15282
|
now;
|
|
15265
15283
|
constructor(now) {
|
|
15266
15284
|
this.now = now;
|
|
15267
15285
|
}
|
|
15268
|
-
current(owner, policy) {
|
|
15286
|
+
current(owner, policy, bound3) {
|
|
15269
15287
|
if (policy.minutes === 0) return false;
|
|
15270
15288
|
const key = timestampKey(owner, policy.type);
|
|
15271
|
-
const
|
|
15272
|
-
if (
|
|
15289
|
+
const stamp = key === void 0 ? void 0 : this.users.get(owner.uid)?.get(key);
|
|
15290
|
+
if (stamp === void 0) return false;
|
|
15273
15291
|
const now = this.now();
|
|
15274
|
-
|
|
15292
|
+
if (!live(stamp, policy, now)) {
|
|
15293
|
+
this.drop(owner.uid, key);
|
|
15294
|
+
return false;
|
|
15295
|
+
}
|
|
15296
|
+
if (!writable2(bound3)) return true;
|
|
15297
|
+
return stamp.covered.has(boundKey(bound3));
|
|
15275
15298
|
}
|
|
15276
|
-
stamp(owner, policy) {
|
|
15299
|
+
stamp(owner, policy, bound3) {
|
|
15277
15300
|
const key = policy.minutes === 0 ? void 0 : timestampKey(owner, policy.type);
|
|
15278
15301
|
if (key === void 0) return false;
|
|
15279
15302
|
const now = this.now();
|
|
15280
15303
|
const records = this.users.get(owner.uid) ?? /* @__PURE__ */ new Map();
|
|
15281
15304
|
this.users.set(owner.uid, records);
|
|
15305
|
+
const prior = records.get(key);
|
|
15306
|
+
const covered = prior !== void 0 && live(prior, policy, now) ? prior.covered : /* @__PURE__ */ new Set();
|
|
15307
|
+
if (writable2(bound3)) covered.add(boundKey(bound3));
|
|
15282
15308
|
records.delete(key);
|
|
15283
|
-
records.set(key, now);
|
|
15284
|
-
for (const [old,
|
|
15285
|
-
const stale = policy.minutes > 0 && (
|
|
15309
|
+
records.set(key, { at: now, covered });
|
|
15310
|
+
for (const [old, stamp] of records) {
|
|
15311
|
+
const stale = policy.minutes > 0 && !live(stamp, policy, now);
|
|
15286
15312
|
if (stale || records.size > TIMESTAMPS_MAX) records.delete(old);
|
|
15287
15313
|
}
|
|
15288
15314
|
return true;
|
|
@@ -15296,6 +15322,11 @@ var Timestamps = class {
|
|
|
15296
15322
|
remove(uid) {
|
|
15297
15323
|
this.users.delete(uid);
|
|
15298
15324
|
}
|
|
15325
|
+
drop(uid, key) {
|
|
15326
|
+
const records = this.users.get(uid);
|
|
15327
|
+
records?.delete(key);
|
|
15328
|
+
if (records?.size === 0) this.users.delete(uid);
|
|
15329
|
+
}
|
|
15299
15330
|
};
|
|
15300
15331
|
|
|
15301
15332
|
// src/sudoers.ts
|
|
@@ -15304,8 +15335,10 @@ var SUDOERS_D = "/etc/sudoers.d";
|
|
|
15304
15335
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
15305
15336
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
15306
15337
|
var KERNEL_FORM = new RegExp(
|
|
15307
|
-
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?Cmnd(?:\s+(.*))?$`
|
|
15338
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?((?:Sha256\s+${WORD}\s+)*)Cmnd(?:\s+(.*))?$`
|
|
15308
15339
|
);
|
|
15340
|
+
var SHA256_CLAUSE = new RegExp(String.raw`Sha256\s+(${WORD})`, "g");
|
|
15341
|
+
var HEX = /^[0-9a-f]{64}$/;
|
|
15309
15342
|
var SUDOERS_FORM = /^(\S+)\s+([^\s=]+)\s*=\s*(.*)$/;
|
|
15310
15343
|
var RUNAS = /^\(([^()]*)\)\s*/;
|
|
15311
15344
|
var TAG = /^([A-Z_]+)\s*:\s*/;
|
|
@@ -15314,7 +15347,7 @@ var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
|
15314
15347
|
var CONTROL2 = /[\p{Cc}\u2028\u2029]/u;
|
|
15315
15348
|
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
15316
15349
|
var SHOWN_MAX = 60;
|
|
15317
|
-
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
15350
|
+
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] [Sha256 <file>=<sha256>\u2026] Cmnd <command\u2026|*>";
|
|
15318
15351
|
var SUDOERS_SYNTAX = "<user|%group|ALL> ALL=[(<target>[,<target>\u2026])] [NOPASSWD:] <command\u2026|ALL>";
|
|
15319
15352
|
var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
15320
15353
|
var TIMESTAMP_TIMEOUT = 5;
|
|
@@ -15481,6 +15514,23 @@ function commandOf2(text, after) {
|
|
|
15481
15514
|
if (only && /\s""$/.test(text)) return { path, args: [] };
|
|
15482
15515
|
return args.length === 0 ? { path } : { path, args };
|
|
15483
15516
|
}
|
|
15517
|
+
function sha256Of(clauses) {
|
|
15518
|
+
const files = {};
|
|
15519
|
+
for (const [, word = ""] of clauses.matchAll(SHA256_CLAUSE)) {
|
|
15520
|
+
const [text = ""] = splitWords(word) ?? [];
|
|
15521
|
+
const at = text.lastIndexOf("=");
|
|
15522
|
+
const path = text.slice(0, at);
|
|
15523
|
+
const hex4 = text.slice(at + 1).toLowerCase();
|
|
15524
|
+
if (!path.startsWith("/") || !HEX.test(hex4)) {
|
|
15525
|
+
return `Sha256 expects <absolute file>=<sha256 in hex>, not ${shown(word)}`;
|
|
15526
|
+
}
|
|
15527
|
+
files[normalizePath(path)] = hex4;
|
|
15528
|
+
}
|
|
15529
|
+
return files;
|
|
15530
|
+
}
|
|
15531
|
+
function sha256Text(files) {
|
|
15532
|
+
return Object.entries(files).map(([path, hex4]) => `Sha256 ${quoteWord(`${path}=${hex4}`)} `).join("");
|
|
15533
|
+
}
|
|
15484
15534
|
function targetError(list) {
|
|
15485
15535
|
if (list.includes(",")) {
|
|
15486
15536
|
return `(${list}) names one user in this form: write one line per user, or use '${SUDOERS_SYNTAX}'`;
|
|
@@ -15488,19 +15538,22 @@ function targetError(list) {
|
|
|
15488
15538
|
return `expected one user name or ALL in (\u2026), not ${shown(`(${list})`)}`;
|
|
15489
15539
|
}
|
|
15490
15540
|
function kernelRules(m) {
|
|
15491
|
-
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
15541
|
+
const [, nopasswd, who = "", target = "root", dir, stdin, sums = "", rest2 = ""] = m;
|
|
15492
15542
|
const bad = whoError(who);
|
|
15493
15543
|
if (bad !== void 0) return bad;
|
|
15494
15544
|
if (target !== "ALL" && !NAME3.test(target)) return targetError(target);
|
|
15495
15545
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
15496
15546
|
if (cwd === "") return `Cwd expects one absolute directory, not ${shown(dir)}`;
|
|
15497
15547
|
if (stdin !== void 0 && stdin !== "none") return `Stdin takes none, not ${shown(stdin)}`;
|
|
15548
|
+
const sha2564 = sha256Of(sums);
|
|
15549
|
+
if (typeof sha2564 === "string") return sha2564;
|
|
15498
15550
|
const rule = {
|
|
15499
15551
|
nopasswd: !!nopasswd,
|
|
15500
15552
|
who,
|
|
15501
15553
|
target,
|
|
15502
15554
|
...cwd !== void 0 ? { cwd } : {},
|
|
15503
|
-
...stdin === "none" ? { stdin: "none" } : {}
|
|
15555
|
+
...stdin === "none" ? { stdin: "none" } : {},
|
|
15556
|
+
...sums === "" ? {} : { sha256: sha2564 }
|
|
15504
15557
|
};
|
|
15505
15558
|
const text = rest2.trim();
|
|
15506
15559
|
if (text === "*") return [{ ...rule, cmnd: "*" }];
|
|
@@ -16130,12 +16183,26 @@ var RAN_ONCE = "sudo: ran once; this command line can't be recorded as always";
|
|
|
16130
16183
|
var ROOT_ONLY_MAX = 64;
|
|
16131
16184
|
var OPERANDS_MAX = 256;
|
|
16132
16185
|
var PATH_MAX = 4096;
|
|
16186
|
+
function userWritable(bound3) {
|
|
16187
|
+
const files = Object.entries(bound3).map(([path, hex4]) => ({ path, sha256: hex4 }));
|
|
16188
|
+
return files.length > 0 ? { userWritable: files } : {};
|
|
16189
|
+
}
|
|
16133
16190
|
function stdinMatches(rule, stdin) {
|
|
16134
16191
|
return rule.stdin === void 0 || stdin === "tty" || stdin === "none";
|
|
16135
16192
|
}
|
|
16136
16193
|
function recordable(cwd, argv) {
|
|
16137
16194
|
return !hasControl(cwd) && !argv.some(hasControl);
|
|
16138
16195
|
}
|
|
16196
|
+
function changedText(file) {
|
|
16197
|
+
return `sudo: ${file} changed since it was approved`;
|
|
16198
|
+
}
|
|
16199
|
+
function changedFile(approved, now) {
|
|
16200
|
+
const files = /* @__PURE__ */ new Set([...Object.keys(approved), ...Object.keys(now)]);
|
|
16201
|
+
return [...files].find((file) => approved[file] !== now[file]);
|
|
16202
|
+
}
|
|
16203
|
+
function pinned(rule, bound3) {
|
|
16204
|
+
return rule.sha256 === void 0 || changedFile(rule.sha256, bound3) === void 0;
|
|
16205
|
+
}
|
|
16139
16206
|
var VISUDO_FILES_MAX = 64;
|
|
16140
16207
|
var VISUDO_TEXT_MAX = 1024 * 1024;
|
|
16141
16208
|
function visudoCall(req) {
|
|
@@ -16266,11 +16333,13 @@ function usable(parsed2) {
|
|
|
16266
16333
|
function policyOf(settings) {
|
|
16267
16334
|
return { type: settings.timestampType, minutes: settings.timestampTimeout };
|
|
16268
16335
|
}
|
|
16269
|
-
function described(rule) {
|
|
16336
|
+
function described(rule, writable3) {
|
|
16270
16337
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
16271
16338
|
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
16272
16339
|
const stdin = rule.stdin === void 0 ? "" : "STDIN=none ";
|
|
16273
|
-
|
|
16340
|
+
const sums = Object.entries(rule.sha256 ?? {}).map(([path, hex4]) => `SHA256=${quoteWord(path)}:${hex4} `).join("");
|
|
16341
|
+
const flag = writable3 ? " # user-writable command" : "";
|
|
16342
|
+
return ` (${rule.target}) ${cwd}${stdin}${sums}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}${flag}`;
|
|
16274
16343
|
}
|
|
16275
16344
|
var Sudo = class {
|
|
16276
16345
|
o;
|
|
@@ -16461,15 +16530,31 @@ var Sudo = class {
|
|
|
16461
16530
|
if (walked.denied !== void 0 || walked.missing) return false;
|
|
16462
16531
|
return (await this.o.fs.stat(cwd).catch(() => void 0))?.isDirectory === true;
|
|
16463
16532
|
}
|
|
16464
|
-
async
|
|
16465
|
-
const
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16533
|
+
async real(file) {
|
|
16534
|
+
const { fs } = this.o;
|
|
16535
|
+
return await fs.realpath?.(file, true).catch(() => file) ?? file;
|
|
16536
|
+
}
|
|
16537
|
+
async digests(files) {
|
|
16538
|
+
const { fs } = this.o;
|
|
16539
|
+
const found = {};
|
|
16540
|
+
for (const file of new Set(files)) {
|
|
16541
|
+
if (await this.trusted(file)) continue;
|
|
16542
|
+
const real = await this.real(file);
|
|
16543
|
+
found[real] = await fs.readFileBuffer(real).then(sha2562, () => "");
|
|
16471
16544
|
}
|
|
16472
|
-
return
|
|
16545
|
+
return found;
|
|
16546
|
+
}
|
|
16547
|
+
async bound(path, cwd) {
|
|
16548
|
+
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
16549
|
+
const bound3 = files && await this.digests([path, ...files]);
|
|
16550
|
+
return bound3 && !Object.values(bound3).includes("") ? bound3 : void 0;
|
|
16551
|
+
}
|
|
16552
|
+
async writable(rule) {
|
|
16553
|
+
if (rule.cmnd === "*") return false;
|
|
16554
|
+
const { path } = rule.cmnd;
|
|
16555
|
+
const bound3 = await this.bound(path, "/");
|
|
16556
|
+
if (bound3) return Object.keys(bound3).length > 0;
|
|
16557
|
+
return !await this.trusted(await this.existing(path));
|
|
16473
16558
|
}
|
|
16474
16559
|
async locate(word, cwd) {
|
|
16475
16560
|
const { fs } = this.o;
|
|
@@ -16514,7 +16599,7 @@ var Sudo = class {
|
|
|
16514
16599
|
const root = cred.euid === 0;
|
|
16515
16600
|
const rules = root ? [] : policy.rules;
|
|
16516
16601
|
const mine = rules.filter((rule) => applies(rule.who));
|
|
16517
|
-
if (parsed2.list) return this.listed(self, root, mine, settings.matching);
|
|
16602
|
+
if (parsed2.list) return await this.listed(self, root, mine, settings.matching);
|
|
16518
16603
|
const session = { caller, self, target, owner, policy: policyOf(settings), parsed: parsed2, signal };
|
|
16519
16604
|
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
16520
16605
|
return this.command(session, root, mine, call);
|
|
@@ -16531,14 +16616,13 @@ var Sudo = class {
|
|
|
16531
16616
|
);
|
|
16532
16617
|
}
|
|
16533
16618
|
const path = await this.locate(word, cwd);
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
if (untrusted2) return untrusted2;
|
|
16619
|
+
const bound3 = path && await this.bound(path, cwd);
|
|
16620
|
+
if (!path || !bound3) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
16537
16621
|
const argv = [path, ...args];
|
|
16538
16622
|
const matching = mine.filter(
|
|
16539
|
-
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv)
|
|
16623
|
+
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv) && pinned(rule, bound3)
|
|
16540
16624
|
);
|
|
16541
|
-
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
16625
|
+
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term, bound3);
|
|
16542
16626
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
16543
16627
|
const quoted = argv.map(quoteWord).join(" ");
|
|
16544
16628
|
if (matching.length === 0) {
|
|
@@ -16547,22 +16631,23 @@ var Sudo = class {
|
|
|
16547
16631
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
16548
16632
|
);
|
|
16549
16633
|
}
|
|
16550
|
-
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy)) {
|
|
16551
|
-
this.timestamps.stamp(s.owner, s.policy);
|
|
16634
|
+
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy, bound3)) {
|
|
16635
|
+
this.timestamps.stamp(s.owner, s.policy, bound3);
|
|
16552
16636
|
this.logged(s, cwd, argv);
|
|
16553
16637
|
return grant();
|
|
16554
16638
|
}
|
|
16555
16639
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
16556
16640
|
return this.pendingFor(cred.ruid, async () => {
|
|
16557
|
-
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd });
|
|
16641
|
+
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd, bound: bound3 });
|
|
16558
16642
|
if ("error" in answer2) return answer2;
|
|
16559
16643
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
16560
16644
|
return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
16561
16645
|
}
|
|
16562
|
-
const
|
|
16563
|
-
if (
|
|
16564
|
-
const
|
|
16565
|
-
|
|
16646
|
+
const now = await this.bound(path, cwd);
|
|
16647
|
+
if (!now) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
16648
|
+
const shown2 = recordable(cwd, [...parsed2.command, ...Object.keys(bound3)]);
|
|
16649
|
+
const result = answer2.answer === "once" ? grant() : await this.always(self, target, { cwd, argv, bound: bound3 }, now, shown2, grant);
|
|
16650
|
+
if (!("error" in result)) this.stamped(s, answer2, bound3);
|
|
16566
16651
|
return result;
|
|
16567
16652
|
});
|
|
16568
16653
|
}
|
|
@@ -16580,7 +16665,7 @@ var Sudo = class {
|
|
|
16580
16665
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
16581
16666
|
const cwd = await this.canonical(dir) ?? normalizePath(dir);
|
|
16582
16667
|
return this.pendingFor(s.caller.cred.ruid, async () => {
|
|
16583
|
-
const answer2 = await this.ask(s, { argv: [], path: "", cwd, validate: true });
|
|
16668
|
+
const answer2 = await this.ask(s, { argv: [], path: "", cwd, bound: {}, validate: true });
|
|
16584
16669
|
if ("error" in answer2) return answer2;
|
|
16585
16670
|
if (!answer2.person) await s.caller.report?.(NOT_STAMPED);
|
|
16586
16671
|
this.stamped(s, answer2);
|
|
@@ -16596,8 +16681,8 @@ var Sudo = class {
|
|
|
16596
16681
|
this.pending.delete(uid);
|
|
16597
16682
|
}
|
|
16598
16683
|
}
|
|
16599
|
-
stamped(s, answer2) {
|
|
16600
|
-
if (answer2.person && !s.parsed.reset) this.timestamps.stamp(s.owner, s.policy);
|
|
16684
|
+
stamped(s, answer2, bound3 = {}) {
|
|
16685
|
+
if (answer2.person && !s.parsed.reset) this.timestamps.stamp(s.owner, s.policy, bound3);
|
|
16601
16686
|
}
|
|
16602
16687
|
logged(s, cwd, argv) {
|
|
16603
16688
|
const { caller, self, target, owner, policy } = s;
|
|
@@ -16608,14 +16693,17 @@ var Sudo = class {
|
|
|
16608
16693
|
`sudo: ${self.name} : TTY=${tty} ; PWD=${quoteWord(cwd)} ; USER=${target.name} ; TIMESTAMP=${type} ; COMMAND=${command}`
|
|
16609
16694
|
);
|
|
16610
16695
|
}
|
|
16611
|
-
async always(self, target,
|
|
16696
|
+
async always(self, target, line, now, shown2, grant) {
|
|
16697
|
+
const { cwd, argv, bound: bound3 } = line;
|
|
16612
16698
|
if (!shown2 || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
16613
|
-
|
|
16699
|
+
const changed = changedFile(bound3, now);
|
|
16700
|
+
if (changed !== void 0) return failed2("EPERM", changedText(changed));
|
|
16701
|
+
if (!await this.remember(self, target, line)) {
|
|
16614
16702
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
16615
16703
|
}
|
|
16616
16704
|
return grant();
|
|
16617
16705
|
}
|
|
16618
|
-
listed(self, root, rules, defaults2) {
|
|
16706
|
+
async listed(self, root, rules, defaults2) {
|
|
16619
16707
|
const host = this.o.hostname;
|
|
16620
16708
|
if (root) {
|
|
16621
16709
|
return {
|
|
@@ -16627,7 +16715,9 @@ var Sudo = class {
|
|
|
16627
16715
|
if (rules.length === 0) {
|
|
16628
16716
|
return failed2("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
16629
16717
|
}
|
|
16630
|
-
const
|
|
16718
|
+
const shown2 = [];
|
|
16719
|
+
for (const rule of rules) shown2.push(described(rule, await this.writable(rule)));
|
|
16720
|
+
const lines2 = shown2.join("\n");
|
|
16631
16721
|
const params = defaults2.flatMap((d) => d.params).join(", ");
|
|
16632
16722
|
const matching = params === "" ? "" : `Matching Defaults entries for ${self.name} on ${host}:
|
|
16633
16723
|
${params}
|
|
@@ -16660,9 +16750,10 @@ ${lines2}
|
|
|
16660
16750
|
...caller.tty ? { tty: caller.tty } : {},
|
|
16661
16751
|
createdAt,
|
|
16662
16752
|
expiresAt: createdAt + timeout,
|
|
16663
|
-
always: asked.validate ? false : recordable(cwd, [path, ...argv]),
|
|
16753
|
+
always: asked.validate ? false : recordable(cwd, [path, ...argv, ...Object.keys(asked.bound)]),
|
|
16664
16754
|
stdin: caller.stdin,
|
|
16665
16755
|
rootOnly: asked.validate ? {} : await this.rootOnly(cwd, argv.slice(1)),
|
|
16756
|
+
...userWritable(asked.bound),
|
|
16666
16757
|
...asked.validate ? { validate: true } : {},
|
|
16667
16758
|
timestamp: true
|
|
16668
16759
|
};
|
|
@@ -16682,7 +16773,7 @@ ${lines2}
|
|
|
16682
16773
|
requester.removeEventListener("abort", withdraw);
|
|
16683
16774
|
}
|
|
16684
16775
|
}
|
|
16685
|
-
async remember(self, target, cwd, argv) {
|
|
16776
|
+
async remember(self, target, { cwd, argv, bound: bound3 }) {
|
|
16686
16777
|
const { fs } = this.o;
|
|
16687
16778
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
16688
16779
|
if (!NAME3.test(self.name)) return false;
|
|
@@ -16693,7 +16784,7 @@ ${lines2}
|
|
|
16693
16784
|
if (st && !await this.trusted(path)) return false;
|
|
16694
16785
|
const old = st ? await fs.readFile(path) : "";
|
|
16695
16786
|
const words2 = recordedCommand(argv);
|
|
16696
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none Cmnd ${words2}
|
|
16787
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${words2}
|
|
16697
16788
|
`;
|
|
16698
16789
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
16699
16790
|
${line}`;
|
|
@@ -16704,7 +16795,7 @@ ${line}`;
|
|
|
16704
16795
|
return false;
|
|
16705
16796
|
}
|
|
16706
16797
|
}
|
|
16707
|
-
grant(self, target, cred, argv, file, cwd, term) {
|
|
16798
|
+
grant(self, target, cred, argv, file, cwd, term, files) {
|
|
16708
16799
|
const env = {
|
|
16709
16800
|
...this.o.env(),
|
|
16710
16801
|
...userEnv(target, this.o.pnpmHome),
|
|
@@ -16717,7 +16808,9 @@ ${line}`;
|
|
|
16717
16808
|
SUDO_GID: String(cred.rgid),
|
|
16718
16809
|
SUDO_COMMAND: [file, ...argv.slice(1)].join(" ")
|
|
16719
16810
|
};
|
|
16720
|
-
return {
|
|
16811
|
+
return {
|
|
16812
|
+
grant: { file, argv: [...argv], env, cwd, cred: credOf(target), caller: cred, files }
|
|
16813
|
+
};
|
|
16721
16814
|
}
|
|
16722
16815
|
};
|
|
16723
16816
|
|
|
@@ -22789,18 +22882,18 @@ var VfsNodes = class {
|
|
|
22789
22882
|
if (id2 !== void 0) this.know(node, id2);
|
|
22790
22883
|
return node;
|
|
22791
22884
|
}
|
|
22792
|
-
open(path, pin,
|
|
22885
|
+
open(path, pin, writable3 = false, id2, ino) {
|
|
22793
22886
|
const found = this.named(path, id2);
|
|
22794
22887
|
const same2 = !found || ino === void 0 || found.ino === void 0 || found.ino === ino;
|
|
22795
22888
|
if (found && !same2) this.orphan(found);
|
|
22796
22889
|
const node = (same2 ? found : void 0) ?? this.create(path, id2, new VfsNode(this.fs, path, void 0, false, false, pin));
|
|
22797
22890
|
node.ino ??= ino;
|
|
22798
22891
|
node.opens++;
|
|
22799
|
-
if (
|
|
22892
|
+
if (writable3) node.writers++;
|
|
22800
22893
|
if (node.opens === 1) this.opened?.(node);
|
|
22801
22894
|
return node;
|
|
22802
22895
|
}
|
|
22803
|
-
adopt(path, contents2, dirty,
|
|
22896
|
+
adopt(path, contents2, dirty, writable3 = false, id2) {
|
|
22804
22897
|
let node = this.named(path, id2);
|
|
22805
22898
|
if (!node) {
|
|
22806
22899
|
node = this.create(path, id2, new VfsNode(this.fs, path, contents2, false, dirty));
|
|
@@ -22808,7 +22901,7 @@ var VfsNodes = class {
|
|
|
22808
22901
|
node.replace(contents2);
|
|
22809
22902
|
}
|
|
22810
22903
|
node.opens++;
|
|
22811
|
-
if (
|
|
22904
|
+
if (writable3) node.writers++;
|
|
22812
22905
|
if (node.opens === 1) this.opened?.(node);
|
|
22813
22906
|
return node;
|
|
22814
22907
|
}
|
|
@@ -22821,11 +22914,11 @@ var VfsNodes = class {
|
|
|
22821
22914
|
if (node.writers > 0 && within7(path, prefix)) return true;
|
|
22822
22915
|
return false;
|
|
22823
22916
|
}
|
|
22824
|
-
closed(node,
|
|
22917
|
+
closed(node, writable3 = false) {
|
|
22825
22918
|
node.opens--;
|
|
22826
|
-
if (
|
|
22919
|
+
if (writable3) node.writers--;
|
|
22827
22920
|
if (node.opens > 0) {
|
|
22828
|
-
if (
|
|
22921
|
+
if (writable3 && node.writers === 0) this.onClosed?.(node.path);
|
|
22829
22922
|
return;
|
|
22830
22923
|
}
|
|
22831
22924
|
this.forget(node);
|
|
@@ -23144,8 +23237,8 @@ function keepingOpen(fs, nodes, changed = () => {
|
|
|
23144
23237
|
function vfsFile(fs, opts, nodes) {
|
|
23145
23238
|
const access2 = opts.flags & O_ACCMODE;
|
|
23146
23239
|
const readable2 = access2 !== O_WRONLY;
|
|
23147
|
-
const
|
|
23148
|
-
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true,
|
|
23240
|
+
const writable3 = access2 === O_WRONLY || access2 === O_RDWR;
|
|
23241
|
+
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true, writable3, opts.id) : nodes.open(opts.path, opts.pin, writable3, opts.id, opts.ino);
|
|
23149
23242
|
let openError;
|
|
23150
23243
|
const atOpen = (op) => {
|
|
23151
23244
|
void node.serial(op).catch((err) => {
|
|
@@ -23172,7 +23265,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
23172
23265
|
offset += out.length;
|
|
23173
23266
|
return out;
|
|
23174
23267
|
}) : void 0,
|
|
23175
|
-
write:
|
|
23268
|
+
write: writable3 ? (bytes) => serial(async () => {
|
|
23176
23269
|
if (opts.flags & O_APPEND) offset = await node.append(bytes);
|
|
23177
23270
|
else offset += await node.pwrite(bytes, offset);
|
|
23178
23271
|
return bytes.length;
|
|
@@ -23191,11 +23284,11 @@ function vfsFile(fs, opts, nodes) {
|
|
|
23191
23284
|
return node.pread(max, at);
|
|
23192
23285
|
}),
|
|
23193
23286
|
pwrite: (bytes, at) => serial(() => {
|
|
23194
|
-
if (!
|
|
23287
|
+
if (!writable3) throw new KernelError("EBADF");
|
|
23195
23288
|
return node.pwrite(bytes, at);
|
|
23196
23289
|
}),
|
|
23197
23290
|
resize: (size) => serial(() => {
|
|
23198
|
-
if (!
|
|
23291
|
+
if (!writable3) throw new KernelError("EBADF");
|
|
23199
23292
|
return node.truncate(size);
|
|
23200
23293
|
}),
|
|
23201
23294
|
stat: () => serial(async () => ({
|
|
@@ -23211,7 +23304,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
23211
23304
|
takeOpenError();
|
|
23212
23305
|
await node.flush();
|
|
23213
23306
|
} finally {
|
|
23214
|
-
nodes?.closed(node,
|
|
23307
|
+
nodes?.closed(node, writable3);
|
|
23215
23308
|
}
|
|
23216
23309
|
})
|
|
23217
23310
|
});
|
|
@@ -24887,14 +24980,20 @@ var WasmProcess = class {
|
|
|
24887
24980
|
if (!("grant" in answer2)) return answer2;
|
|
24888
24981
|
if (this.dying) throw new KernelError("EINTR");
|
|
24889
24982
|
if (answer2.notice !== void 0) await this.complainLine(answer2.notice);
|
|
24890
|
-
const { file, argv, env, cwd, cred, caller } = answer2.grant;
|
|
24983
|
+
const { file, argv, env, cwd, cred, caller, files } = answer2.grant;
|
|
24891
24984
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24985
|
+
try {
|
|
24986
|
+
return {
|
|
24987
|
+
pid: await this.children.spawn({ file, argv, env, cwd, pgid: 0 }, stdio, [], {
|
|
24988
|
+
cred,
|
|
24989
|
+
caller,
|
|
24990
|
+
files
|
|
24991
|
+
})
|
|
24992
|
+
};
|
|
24993
|
+
} catch (err) {
|
|
24994
|
+
if (err instanceof ChangedError) return { error: err.notice, errno: err.code };
|
|
24995
|
+
throw err;
|
|
24996
|
+
}
|
|
24898
24997
|
}
|
|
24899
24998
|
stdinKind() {
|
|
24900
24999
|
if (!this.fds.has(0)) return "none";
|
|
@@ -24934,8 +25033,8 @@ var WasmProcess = class {
|
|
|
24934
25033
|
};
|
|
24935
25034
|
withDl(state) {
|
|
24936
25035
|
if (this.dlLog.length === 0) return state;
|
|
24937
|
-
const { next: next3, handle, free, live } = this.closures;
|
|
24938
|
-
const dl = { log: [...this.dlLog], next: next3, handle, free: [...free], live: [...
|
|
25036
|
+
const { next: next3, handle, free, live: live2 } = this.closures;
|
|
25037
|
+
const dl = { log: [...this.dlLog], next: next3, handle, free: [...free], live: [...live2] };
|
|
24939
25038
|
return { ...state, dl };
|
|
24940
25039
|
}
|
|
24941
25040
|
seedDl(dl) {
|
|
@@ -26153,8 +26252,8 @@ var RemoteWatch = class {
|
|
|
26153
26252
|
const { held = [], pending = [] } = await this.locks.query();
|
|
26154
26253
|
if (![...held, ...pending].some((lock) => lock.name === name2)) {
|
|
26155
26254
|
this.mourned.delete(peer);
|
|
26156
|
-
const
|
|
26157
|
-
if (tries > 1 &&
|
|
26255
|
+
const live2 = this.peers.has(peer) || this.flushes.has(peer);
|
|
26256
|
+
if (tries > 1 && live2) {
|
|
26158
26257
|
setTimeout(() => void this.mourn(peer, tries - 1), MOURN_RETRY_MS);
|
|
26159
26258
|
} else this.flushedAt(peer);
|
|
26160
26259
|
return;
|
|
@@ -28362,11 +28461,11 @@ async function positioned(handle, op) {
|
|
|
28362
28461
|
}
|
|
28363
28462
|
return;
|
|
28364
28463
|
}
|
|
28365
|
-
const
|
|
28464
|
+
const writable3 = await handle.createWritable({ keepExistingData: true });
|
|
28366
28465
|
try {
|
|
28367
28466
|
await op({
|
|
28368
28467
|
write: async (at, bytes) => {
|
|
28369
|
-
await
|
|
28468
|
+
await writable3.write({
|
|
28370
28469
|
type: "write",
|
|
28371
28470
|
position: at,
|
|
28372
28471
|
data: bytes
|
|
@@ -28374,15 +28473,15 @@ async function positioned(handle, op) {
|
|
|
28374
28473
|
extent.wrote(at + bytes.length);
|
|
28375
28474
|
},
|
|
28376
28475
|
truncate: async (n) => {
|
|
28377
|
-
await
|
|
28476
|
+
await writable3.truncate(n);
|
|
28378
28477
|
extent.cut(n);
|
|
28379
28478
|
}
|
|
28380
28479
|
});
|
|
28381
28480
|
} catch (err) {
|
|
28382
|
-
await
|
|
28481
|
+
await writable3.abort();
|
|
28383
28482
|
throw err;
|
|
28384
28483
|
}
|
|
28385
|
-
await
|
|
28484
|
+
await writable3.close();
|
|
28386
28485
|
if (extent.big()) extent.check((await handle.getFile()).size);
|
|
28387
28486
|
}
|
|
28388
28487
|
function isHandle(child) {
|
|
@@ -29464,21 +29563,21 @@ var OpfsFs = class {
|
|
|
29464
29563
|
}
|
|
29465
29564
|
async writeSession(path, truncate) {
|
|
29466
29565
|
const [handle, , target] = await this.fileFor(path);
|
|
29467
|
-
const
|
|
29566
|
+
const writable3 = await this.retrying(
|
|
29468
29567
|
path,
|
|
29469
29568
|
() => this.io(handle.createWritable({ keepExistingData: !truncate })),
|
|
29470
29569
|
true
|
|
29471
29570
|
);
|
|
29472
29571
|
return {
|
|
29473
|
-
write: (at, bytes) =>
|
|
29572
|
+
write: (at, bytes) => writable3.write({ type: "write", position: at, data: bytes }).catch((err) => {
|
|
29474
29573
|
throw translate(err, path, "write", false);
|
|
29475
29574
|
}),
|
|
29476
|
-
truncate: (size) =>
|
|
29575
|
+
truncate: (size) => writable3.truncate(size).catch((err) => {
|
|
29477
29576
|
throw translate(err, path, "write", false);
|
|
29478
29577
|
}),
|
|
29479
29578
|
close: async () => {
|
|
29480
29579
|
this.wrote(handle);
|
|
29481
|
-
await
|
|
29580
|
+
await writable3.close().catch((err) => {
|
|
29482
29581
|
this.wrote(handle);
|
|
29483
29582
|
throw translate(err, path, "commit", false);
|
|
29484
29583
|
});
|
|
@@ -29530,19 +29629,19 @@ var OpfsFs = class {
|
|
|
29530
29629
|
const [file, existed, target] = await this.fileFor(path, owner?.existing !== true);
|
|
29531
29630
|
if (!existed) await this.stampNew(target, owner, false);
|
|
29532
29631
|
if (!existed && content.length === 0) return;
|
|
29533
|
-
let
|
|
29632
|
+
let writable3;
|
|
29534
29633
|
this.wrote(file);
|
|
29535
29634
|
try {
|
|
29536
|
-
|
|
29537
|
-
await
|
|
29538
|
-
await
|
|
29635
|
+
writable3 = await this.io(file.createWritable());
|
|
29636
|
+
await writable3.write(content);
|
|
29637
|
+
await writable3.close();
|
|
29539
29638
|
if (typeof content !== "string" && content.length >= CHECKED_BYTES) {
|
|
29540
29639
|
const extent = new Extent();
|
|
29541
29640
|
extent.cut(content.length);
|
|
29542
29641
|
extent.check((await file.getFile()).size);
|
|
29543
29642
|
}
|
|
29544
29643
|
} catch (err) {
|
|
29545
|
-
await
|
|
29644
|
+
await writable3?.abort().catch(() => void 0);
|
|
29546
29645
|
throw translate(err, path, "commit", false);
|
|
29547
29646
|
} finally {
|
|
29548
29647
|
this.wrote(file);
|
|
@@ -30267,7 +30366,7 @@ var OpfsFs = class {
|
|
|
30267
30366
|
created4 = true;
|
|
30268
30367
|
}
|
|
30269
30368
|
let target = destination;
|
|
30270
|
-
let
|
|
30369
|
+
let writable3;
|
|
30271
30370
|
let handle;
|
|
30272
30371
|
try {
|
|
30273
30372
|
const kept = created4 ? this.files.get(destination) : void 0;
|
|
@@ -30286,11 +30385,11 @@ var OpfsFs = class {
|
|
|
30286
30385
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", to);
|
|
30287
30386
|
}
|
|
30288
30387
|
this.wrote(handle);
|
|
30289
|
-
|
|
30290
|
-
await
|
|
30291
|
-
await
|
|
30388
|
+
writable3 = await handle.createWritable();
|
|
30389
|
+
await writable3.write(file);
|
|
30390
|
+
await writable3.close();
|
|
30292
30391
|
} catch (err) {
|
|
30293
|
-
await
|
|
30392
|
+
await writable3?.abort().catch(() => void 0);
|
|
30294
30393
|
if (created4) await this.rm(target, { file: true }).catch(() => void 0);
|
|
30295
30394
|
throw translate(err, to, "commit", false);
|
|
30296
30395
|
} finally {
|
|
@@ -30379,10 +30478,10 @@ var OpfsFs = class {
|
|
|
30379
30478
|
}
|
|
30380
30479
|
if (handle.kind === "file") {
|
|
30381
30480
|
const made2 = await this.io(dir.getFileHandle(name2, { create: true }));
|
|
30382
|
-
const
|
|
30481
|
+
const writable3 = await this.io(made2.createWritable());
|
|
30383
30482
|
const file = await this.io(handle.getFile());
|
|
30384
|
-
await
|
|
30385
|
-
await
|
|
30483
|
+
await writable3.write(file);
|
|
30484
|
+
await writable3.close();
|
|
30386
30485
|
copies?.set(rest2, { before: copies.get(rest2)?.before ?? file.lastModified, made: made2 });
|
|
30387
30486
|
return;
|
|
30388
30487
|
}
|
|
@@ -31094,7 +31193,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
31094
31193
|
if (remote.client.token === remote.token && !remote.client.gone) return remote;
|
|
31095
31194
|
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
31096
31195
|
};
|
|
31097
|
-
const
|
|
31196
|
+
const live2 = (fh) => {
|
|
31098
31197
|
const remote = handles.get(fh);
|
|
31099
31198
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
31100
31199
|
return fresh3(remote);
|
|
@@ -31113,7 +31212,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
31113
31212
|
}, againMs);
|
|
31114
31213
|
timer.unref?.();
|
|
31115
31214
|
});
|
|
31116
|
-
async function
|
|
31215
|
+
async function writable3(client, path, flags2) {
|
|
31117
31216
|
const { ifMatch: _, ...asked } = flags2;
|
|
31118
31217
|
const opening2 = () => client.call("open", { path: rel(path), ...asked });
|
|
31119
31218
|
try {
|
|
@@ -31144,7 +31243,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
31144
31243
|
async open(path, flags2) {
|
|
31145
31244
|
const client = current();
|
|
31146
31245
|
const token = client.token;
|
|
31147
|
-
const { opened: opened2, restore } = await
|
|
31246
|
+
const { opened: opened2, restore } = await writable3(client, path, flags2);
|
|
31148
31247
|
if (flags2.ifMatch !== void 0 && opened2.attr?.etag !== flags2.ifMatch) {
|
|
31149
31248
|
await client.call("release", { fh: opened2.fh }, true);
|
|
31150
31249
|
throw fsError2("ESTALE", `${path} changed on the host while it was being read`);
|
|
@@ -31159,7 +31258,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
31159
31258
|
return nextFh;
|
|
31160
31259
|
},
|
|
31161
31260
|
async read(fh, offset, size) {
|
|
31162
|
-
const remote =
|
|
31261
|
+
const remote = live2(fh);
|
|
31163
31262
|
return remote.client.read(
|
|
31164
31263
|
remote.fh,
|
|
31165
31264
|
offset,
|
|
@@ -31168,7 +31267,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
31168
31267
|
);
|
|
31169
31268
|
},
|
|
31170
31269
|
async write(fh, offset, bytes) {
|
|
31171
|
-
const remote =
|
|
31270
|
+
const remote = live2(fh);
|
|
31172
31271
|
const most = remote.client.maxIo;
|
|
31173
31272
|
for (let at = 0; at < bytes.length; at += most) {
|
|
31174
31273
|
await remote.client.write(remote.fh, offset + at, bytes.subarray(at, at + most));
|
|
@@ -32466,6 +32565,10 @@ function describe(req, tty) {
|
|
|
32466
32565
|
};
|
|
32467
32566
|
return { argv: [req.argv0, ...req.args], tty, started: Date.now(), ...exe };
|
|
32468
32567
|
}
|
|
32568
|
+
function refuseChanged(approved, now) {
|
|
32569
|
+
const changed = changedFile(approved, now);
|
|
32570
|
+
if (changed !== void 0) throw new ChangedError(changedText(changed));
|
|
32571
|
+
}
|
|
32469
32572
|
function linksOf2(req) {
|
|
32470
32573
|
return req.links === void 0 ? {} : { links: req.links };
|
|
32471
32574
|
}
|
|
@@ -33599,6 +33702,27 @@ var Launcher = class {
|
|
|
33599
33702
|
}
|
|
33600
33703
|
return true;
|
|
33601
33704
|
}
|
|
33705
|
+
async unchanged(planned, file, cwd, grant) {
|
|
33706
|
+
const approved = grant?.files;
|
|
33707
|
+
if (!approved) return {};
|
|
33708
|
+
const files = await this.backingOf(planned, file, cwd, "");
|
|
33709
|
+
refuseChanged(approved, await this.sudoer.digests([file, ...files]));
|
|
33710
|
+
return { pinned: approved };
|
|
33711
|
+
}
|
|
33712
|
+
async pinOf(path, caller) {
|
|
33713
|
+
const { pinned: pinned2 } = caller;
|
|
33714
|
+
if (!pinned2) return {};
|
|
33715
|
+
const real = await this.sudoer.real(path);
|
|
33716
|
+
const hex4 = pinned2[real];
|
|
33717
|
+
if (hex4 !== void 0) return { [real]: hex4 };
|
|
33718
|
+
if (await this.sudoer.trusted(real)) return {};
|
|
33719
|
+
throw new ChangedError(changedText(real));
|
|
33720
|
+
}
|
|
33721
|
+
async pinnedBytes(pin, bytes) {
|
|
33722
|
+
const [real = ""] = Object.keys(pin);
|
|
33723
|
+
refuseChanged(pin, { [real]: await sha2562(bytes) });
|
|
33724
|
+
return bytes;
|
|
33725
|
+
}
|
|
33602
33726
|
async grantedCwd(caller, cwd) {
|
|
33603
33727
|
const real = await physicalPathAsync(this.base, cwd).catch(() => void 0);
|
|
33604
33728
|
return real === cwd && await this.sudoer.reachable(caller, cwd);
|
|
@@ -33687,13 +33811,19 @@ var Launcher = class {
|
|
|
33687
33811
|
return found;
|
|
33688
33812
|
}
|
|
33689
33813
|
async module(path, caller, asked) {
|
|
33690
|
-
const
|
|
33814
|
+
const pin = await this.pinOf(path, caller);
|
|
33815
|
+
const sum = Object.values(pin)[0];
|
|
33816
|
+
const key = sum === void 0 ? await this.cacheKey(path, asked) : `${path}:sha256:${sum}`;
|
|
33691
33817
|
return this.cached(this.compiled, key, async () => {
|
|
33692
|
-
const { bytes, key:
|
|
33818
|
+
const { bytes: read, key: readKey } = await this.keyed(path, caller, asked);
|
|
33819
|
+
const bytes = sum === void 0 ? read : await this.pinnedBytes(pin, read);
|
|
33693
33820
|
const memory = importedMemory(bytes);
|
|
33694
33821
|
const foreign = foreignImports(bytes);
|
|
33695
33822
|
const compiled = await WebAssembly.compile(bytes);
|
|
33696
|
-
return {
|
|
33823
|
+
return {
|
|
33824
|
+
value: { module: compiled, ...memory ? { memory } : {}, foreign },
|
|
33825
|
+
key: sum === void 0 ? readKey : key
|
|
33826
|
+
};
|
|
33697
33827
|
});
|
|
33698
33828
|
}
|
|
33699
33829
|
async checkedSources(planned, caller) {
|
|
@@ -33718,6 +33848,11 @@ var Launcher = class {
|
|
|
33718
33848
|
}
|
|
33719
33849
|
}
|
|
33720
33850
|
async text(path, caller, asked) {
|
|
33851
|
+
const pin = await this.pinOf(path, caller);
|
|
33852
|
+
if (Object.keys(pin).length > 0) {
|
|
33853
|
+
const { bytes } = await this.keyed(path, caller, asked);
|
|
33854
|
+
return new TextDecoder().decode(await this.pinnedBytes(pin, bytes));
|
|
33855
|
+
}
|
|
33721
33856
|
if (!this.integrity) return this.base.readFile(path);
|
|
33722
33857
|
const key = await this.cacheKey(path, asked);
|
|
33723
33858
|
return this.cached(this.texts, key, async () => {
|
|
@@ -33906,7 +34041,12 @@ var Launcher = class {
|
|
|
33906
34041
|
const own = env.HOSTNAME;
|
|
33907
34042
|
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
33908
34043
|
const planned = chosen2(asked, env);
|
|
33909
|
-
const caller = {
|
|
34044
|
+
const caller = {
|
|
34045
|
+
pid: req.ppid ?? 0,
|
|
34046
|
+
uid: req.cred.euid,
|
|
34047
|
+
tag: req.tags?.[0],
|
|
34048
|
+
pinned: req.pinned
|
|
34049
|
+
};
|
|
33910
34050
|
if (this.integrity) await this.checkedSources(planned, caller);
|
|
33911
34051
|
const [program, exeId] = await this.loaded(planned.target, env, caller);
|
|
33912
34052
|
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
@@ -34421,6 +34561,7 @@ var Launcher = class {
|
|
|
34421
34561
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
34422
34562
|
const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
|
|
34423
34563
|
const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
|
|
34564
|
+
const pin = await this.unchanged(planned, file, req.cwd, grant);
|
|
34424
34565
|
const { recheck, ...redeemed } = await this.redeemed(
|
|
34425
34566
|
{ ...req, file },
|
|
34426
34567
|
{ ppid, cred, scope, booked },
|
|
@@ -34432,6 +34573,7 @@ var Launcher = class {
|
|
|
34432
34573
|
const replan = () => this.planOrSearch({ ...req, file }, { ppid, cred, scope });
|
|
34433
34574
|
const again = { ...planned, replan, recheck };
|
|
34434
34575
|
const handle = await this.launch(again, {
|
|
34576
|
+
...pin,
|
|
34435
34577
|
...deciding ? { decided: deciding.promise } : {},
|
|
34436
34578
|
cwd: req.cwd,
|
|
34437
34579
|
cwdFrom: inheritedCwd(req.chdir, this.cwdSlots.get(ppid)),
|
|
@@ -37132,7 +37274,7 @@ function dialStream(port, onClose) {
|
|
|
37132
37274
|
else finish(errorWithCode(data.error));
|
|
37133
37275
|
});
|
|
37134
37276
|
port.start?.();
|
|
37135
|
-
const
|
|
37277
|
+
const writable3 = new WritableStream({
|
|
37136
37278
|
write(chunk2) {
|
|
37137
37279
|
if (closed) throw errorWithCode("EPIPE: the connection is closed");
|
|
37138
37280
|
const copy = fresh(chunk2);
|
|
@@ -37151,7 +37293,7 @@ function dialStream(port, onClose) {
|
|
|
37151
37293
|
shut();
|
|
37152
37294
|
finish(error);
|
|
37153
37295
|
};
|
|
37154
|
-
return { readable: readable2, writable:
|
|
37296
|
+
return { readable: readable2, writable: writable3, close, fail: fail3 };
|
|
37155
37297
|
}
|
|
37156
37298
|
|
|
37157
37299
|
// src/client/loopback-fetch.ts
|
|
@@ -37577,10 +37719,10 @@ function endedOf(done4, signal) {
|
|
|
37577
37719
|
async function runOn(channel, argv, opts) {
|
|
37578
37720
|
const { onStdout, onStderr, ...rest2 } = opts;
|
|
37579
37721
|
const chunks2 = { 1: [], 2: [] };
|
|
37580
|
-
const
|
|
37722
|
+
const live2 = { 1: new TextDecoder(), 2: new TextDecoder() };
|
|
37581
37723
|
const tee = (fd, on) => (bytes) => {
|
|
37582
37724
|
chunks2[fd].push(bytes);
|
|
37583
|
-
on?.(
|
|
37725
|
+
on?.(live2[fd].decode(bytes, { stream: true }));
|
|
37584
37726
|
};
|
|
37585
37727
|
const child = await spawnOn(channel, argv, {
|
|
37586
37728
|
...rest2,
|
|
@@ -37795,7 +37937,7 @@ var TERMINATED = "the kernel is terminated";
|
|
|
37795
37937
|
var EXIT_GRACE_MS = 50;
|
|
37796
37938
|
var WARM_IDLE_MS = 3e4;
|
|
37797
37939
|
var MAX_WARM_WORKERS = 64;
|
|
37798
|
-
function warmPool(make,
|
|
37940
|
+
function warmPool(make, live2, idleMs = WARM_IDLE_MS, size = 1) {
|
|
37799
37941
|
const spares = [];
|
|
37800
37942
|
let idle2;
|
|
37801
37943
|
let closed = false;
|
|
@@ -37805,7 +37947,7 @@ function warmPool(make, live, idleMs = WARM_IDLE_MS, size = 1) {
|
|
|
37805
37947
|
spares.splice(at, 1);
|
|
37806
37948
|
if (spares.length > 0) return;
|
|
37807
37949
|
clearTimeout(idle2);
|
|
37808
|
-
|
|
37950
|
+
live2.delete(kill);
|
|
37809
37951
|
};
|
|
37810
37952
|
const kill = () => {
|
|
37811
37953
|
for (const worker of [...spares]) {
|
|
@@ -37826,7 +37968,7 @@ function warmPool(make, live, idleMs = WARM_IDLE_MS, size = 1) {
|
|
|
37826
37968
|
worker.once("error", () => drop(worker));
|
|
37827
37969
|
worker.once("exit", () => drop(worker));
|
|
37828
37970
|
spares.push(worker);
|
|
37829
|
-
|
|
37971
|
+
live2.add(kill);
|
|
37830
37972
|
}
|
|
37831
37973
|
clearTimeout(idle2);
|
|
37832
37974
|
idle2 = setTimeout(kill, idleMs);
|
|
@@ -37899,12 +38041,12 @@ function sourceModule(source) {
|
|
|
37899
38041
|
return { url, source, revoke: () => {
|
|
37900
38042
|
} };
|
|
37901
38043
|
}
|
|
37902
|
-
function warmPoolOf(options, file, workerData,
|
|
38044
|
+
function warmPoolOf(options, file, workerData, live2) {
|
|
37903
38045
|
const size = sparesOf(options);
|
|
37904
38046
|
if (size === 0) return void 0;
|
|
37905
|
-
return warmPool(() => processWorker(file, workerData, true),
|
|
38047
|
+
return warmPool(() => processWorker(file, workerData, true), live2, WARM_IDLE_MS, size);
|
|
37906
38048
|
}
|
|
37907
|
-
function nodeWorker(file,
|
|
38049
|
+
function nodeWorker(file, live2, closed, workerData, take, internals = false) {
|
|
37908
38050
|
const errors = /* @__PURE__ */ new Set();
|
|
37909
38051
|
const messages = /* @__PURE__ */ new Map();
|
|
37910
38052
|
const fail3 = (message3) => {
|
|
@@ -37921,9 +38063,9 @@ function nodeWorker(file, live, closed, workerData, take, internals = false) {
|
|
|
37921
38063
|
void worker.terminate();
|
|
37922
38064
|
fail3(TERMINATED);
|
|
37923
38065
|
};
|
|
37924
|
-
|
|
38066
|
+
live2.add(kill);
|
|
37925
38067
|
worker.once("exit", (code) => {
|
|
37926
|
-
|
|
38068
|
+
live2.delete(kill);
|
|
37927
38069
|
setTimeout(() => {
|
|
37928
38070
|
if (!ending) fail3(`the process worker exited with ${code}`);
|
|
37929
38071
|
}, EXIT_GRACE_MS);
|
|
@@ -38080,23 +38222,23 @@ async function createNodeKernel(options = {}) {
|
|
|
38080
38222
|
const root = options.root ?? memoryRoot();
|
|
38081
38223
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
38082
38224
|
await fs.reconcile();
|
|
38083
|
-
const
|
|
38225
|
+
const live2 = /* @__PURE__ */ new Set();
|
|
38084
38226
|
const pending = /* @__PURE__ */ new Set();
|
|
38085
38227
|
const clients = /* @__PURE__ */ new Set();
|
|
38086
38228
|
let terminated = false;
|
|
38087
38229
|
const file = options.worker ?? new URL("./node-process-worker.cjs", import.meta.url);
|
|
38088
38230
|
const cache = cacheDirOf(options.compileCache);
|
|
38089
38231
|
const workerData = cacheData(cache);
|
|
38090
|
-
const warm = warmPoolOf(options, file, workerData,
|
|
38232
|
+
const warm = warmPoolOf(options, file, workerData, live2);
|
|
38091
38233
|
const transport = options.network?.transport;
|
|
38092
38234
|
const launcher = new Launcher({
|
|
38093
38235
|
fs,
|
|
38094
38236
|
moduleUrl: sourceModule,
|
|
38095
38237
|
unlinkOwner: pidOwner(process),
|
|
38096
|
-
createWorker: () => nodeWorker(file,
|
|
38238
|
+
createWorker: () => nodeWorker(file, live2, terminated, workerData, warm ? () => warm.take() : void 0, true),
|
|
38097
38239
|
createDriverWorker: () => nodeWorker(
|
|
38098
38240
|
options.driverWorker ?? new URL("./node-driver-worker.js", import.meta.url),
|
|
38099
|
-
|
|
38241
|
+
live2,
|
|
38100
38242
|
terminated
|
|
38101
38243
|
),
|
|
38102
38244
|
...options.modules ? { modules: options.modules } : {},
|
|
@@ -38227,7 +38369,7 @@ async function createNodeKernel(options = {}) {
|
|
|
38227
38369
|
warm?.close();
|
|
38228
38370
|
for (const client of [...clients]) client.detach();
|
|
38229
38371
|
for (const reject of [...pending]) reject(new Error(TERMINATED));
|
|
38230
|
-
for (const kill of [...
|
|
38372
|
+
for (const kill of [...live2]) kill();
|
|
38231
38373
|
launcher.cdp.close();
|
|
38232
38374
|
launcher.endFills();
|
|
38233
38375
|
launcher.unmountAll();
|