@ai-ecoverse/slicc-kernel 1.145.0 → 1.146.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 +2 -2
- package/dist/kernel-worker.js +19 -1
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +34 -14
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +19 -1
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +34 -14
- package/dist/process-worker.js.map +2 -2
- package/dist/types/process/js/js-net.d.ts +7 -1
- package/dist/types/process/js/js-sync.d.ts +3 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -448,7 +448,7 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
448
448
|
- `wait(pid, { untraced })` resolves with `{ status }` once a child ends, or `{ status: 128 + signal, signal }` when a signal ended it, without blocking the program; with `untraced: true` it also resolves when the child stops, with `{ status: 128 + signal, signal, stopped: true }`, as `waitpid` with `WUNTRACED` (a child's `wait({ untraced })` is the same), and options that aren't an object are `EINVAL`; `kill(pid, signal)` signals any process, by number or as `'SIGTERM'` (the default);
|
|
449
449
|
- `sudo(args)`, what the [`sudo`](#sudo) command calls: `args` are its arguments after `sudo`, and it resolves with `{ pid }`, the command the kernel started as the program's child, to `wait` for; `{ run }`, an argv to run as the caller (with `users: 'off'`); `{ list }`, the text of `sudo -l`; or `{ error, errno }`, the message to print;
|
|
450
450
|
- `crontab({ action, user?, text? })`, what the [`crontab`](#cron) command calls: `action` is `'list'`, `'remove'` or `'install'` (with the table as `text`), on the caller's own table or, for an effective uid of 0, on `user`'s. It resolves with `{ text }` (the table for `list`, `''` otherwise) or `{ error }`, the message to print. A malformed call is `EINVAL`;
|
|
451
|
-
- `net`: `listen({ port, host, backlog })` and `connect({ host, port, signal })` (`host` defaults to `127.0.0.1`) on the kernel's loopback, the same sockets WASIX programs use, so a JS server is reached by other processes, by the page as `<port>.kernel.localhost` (`loopbackFetch`, `dial`) and by attached clients. A listener has its `port` (as bound, so port `0` picks a free one), `accept({ signal })`, `close()` and `for await` over its connections. A connection has `local` and `remote` addresses, `readable` and `writable` web streams (closing the writable shuts down the sending side, so the peer reads the end), and `close()`. The loopback is IPv4 (`127.0.0.1` by default, or `0.0.0.0`), so an IPv6 host such as `::1` fails with `EADDRNOTAVAIL` for both `listen` and `connect`, and binding and connecting fail as they would for a WASIX program (`EADDRINUSE`, `ECONNREFUSED`, `EADDRNOTAVAIL`). A blocked accept, read or write waits without holding anything in the kernel, so aborting it or closing the socket leaves nothing behind. A write to a connection the peer closed fails with `EPIPE` and no `SIGPIPE`;
|
|
451
|
+
- `net`: `listen({ port, host, backlog })` and `connect({ host, port, signal })` (`host` defaults to `127.0.0.1`) on the kernel's loopback, the same sockets WASIX programs use, so a JS server is reached by other processes, by the page as `<port>.kernel.localhost` (`loopbackFetch`, `dial`) and by attached clients. A listener has its `port` (as bound, so port `0` picks a free one), `accept({ signal })`, `close()` and `for await` over its connections. A connection has `local` and `remote` addresses, `readable` and `writable` web streams (closing the writable shuts down the sending side, so the peer reads the end), and `close()`. The loopback is IPv4 (`127.0.0.1` by default, or `0.0.0.0`), so an IPv6 host such as `::1` fails with `EADDRNOTAVAIL` for both `listen` and `connect`, and binding and connecting fail as they would for a WASIX program (`EADDRINUSE`, `ECONNREFUSED`, `EADDRNOTAVAIL`). `sync.net.listen` takes the same options and gives the same listener, bound and listening when it returns, so its `port` is known at once, as Node's `listen()` needs ([#1398](https://github.com/ai-ecoverse/slicc-kernel/issues/1398)); it needs the sync lane. A blocked accept, read or write waits without holding anything in the kernel, so aborting it or closing the socket leaves nothing behind. A write to a connection the peer closed fails with `EPIPE` and no `SIGPIPE`;
|
|
452
452
|
- `net.connect({ host, port, tls: { servername, alpn, rejectUnauthorized, ca, path, cert, key, passphrase, sni, checkHostname } })` takes one of two paths. By default it's **A1, TLS through the transport** ([#914](https://github.com/ai-ecoverse/slicc-kernel/issues/914)), described first below. For a destination the uplink routes it can also be **A2, a TLS handshake in the kernel** ([#922](https://github.com/ai-ecoverse/slicc-kernel/issues/922)), described after it. `conn.tls.path` (`'transport'` or `'kernel'`) and `conn.tls.substitutes` say which one was taken.
|
|
453
453
|
- **What it does:** there's no handshake in the kernel. The connection carries plain HTTP/1.1 (and WebSocket upgrades) to the realm proxy's HTTP path for the origin `https://<servername or host>[:port]`, exactly as a `CONNECT` through `127.0.0.1:3128` does after the kernel terminates its TLS. The transport (the page's `fetch` or WebSocket, or the uplink's) makes the real TLS connection and verifies it. So `https.request` over a socket, keep-alive agents, `agent-base` and `wss://` clients work with the transport's semantics. That includes sealed placeholders in headers, which reach the transport exactly as from `ctx.fetch`.
|
|
454
454
|
- **The `tls` property:** the connection's `tls` is `{ path: 'transport', substitutes: true, protocol: 'transport', alpnProtocol: 'http/1.1', authorized: true, servername }`. `authorized` means the transport verified the server. There's no peer certificate chain and no TLS version of the kernel's own, so don't read it as a real handshake's result.
|
|
@@ -616,7 +616,7 @@ The kernel answers DNS itself, so DNS clients (BIND's `dig`, `host` and `nslooku
|
|
|
616
616
|
### Node name
|
|
617
617
|
|
|
618
618
|
The kernel has one node name, `slicc` unless `createKernel({ hostname })` (or `createNodeKernel`) names another; it must be a valid host name, and not `localhost`, a `*.localhost` name, `host.slicc.internal`, `wasmer.sh` or an IPv4 address, or `createKernel` rejects. `no_proxy` lists it (and `emscripten`), so HTTP clients reach the kernel's own servers by it directly.
|
|
619
|
-
- **Where programs see it:** through `uname`, `gethostname` and `/etc/hostname`, never only from the environment ([#1272](https://github.com/ai-ecoverse/slicc-kernel/issues/1272)). `HOSTNAME` is in the kernel's base and login environments, so `kernel.run`, terminals and login shells have it, and a program keeps whatever `HOSTNAME` its caller passes (`env -i env` shows none). One exception: a WASI or WASIX program
|
|
619
|
+
- **Where programs see it:** through `uname`, `gethostname` and `/etc/hostname`, never only from the environment ([#1272](https://github.com/ai-ecoverse/slicc-kernel/issues/1272)). `HOSTNAME` is in the kernel's base and login environments, so `kernel.run`, terminals and login shells have it, and a program keeps whatever `HOSTNAME` its caller passes (`env -i env` shows none). One exception: a WASI or WASIX program built on wasix-sysroot before 2025.9.30-42 (its `slicc.libc` marker), or with no marker, gets `HOSTNAME` set to the node name, because that `gethostname` reads it from the environment, so its `os.environ` shows it after `env -i`. From -42 on, `gethostname` and `uname` read `/etc/hostname`, and such a program keeps the environment its caller gave it. Every program can read it from `/etc/hostname`: the node name and a newline, a `0644` root-owned file that a real `/etc/hostname` in the root replaces ([#1297](https://github.com/ai-ecoverse/slicc-kernel/issues/1297)). Emscripten programs also have the synthetic `/etc/hosts` and `/etc/passwd`, which only they have (WASI programs resolve names through the kernel instead), and `Module.sliccKernel.hostname`.
|
|
620
620
|
- **What `uname` says:** for an Emscripten program built with homescoop's `__syscall_uname` import (wasm-coreutils 9.12.0-7 on), the kernel answers `uname(2)`: sysname `Linux`, nodename the node name, release `6.0.0-slicc` (as `/proc/sys/kernel/osrelease`), version `#1 SMP PREEMPT_DYNAMIC` (as `/proc/version`), machine `wasm32` and domainname `(none)`, so `uname -a` and musl's `gethostname()` see them. `uname -o` is coreutils' compiled-in `Emscripten`. Older Emscripten builds still report their C library's `Emscripten 4.0.23` and `emscripten`, and WASIX programs `wasmer.sh`; the kernel has nothing to answer there.
|
|
621
621
|
- **Resolving it:** `/etc/hosts` maps the node name and both of those names to `127.0.1.1` (Debian's convention), and name resolution answers them, and `localhost.localdomain`, itself, as `127.0.1.1` and `::1`. So a program that looks up its own host name, as git does for every commit, never asks the [uplink](#uplink), and `127.0.1.1` is the kernel's loopback.
|
|
622
622
|
- **The trade-off:** a raw connection to the real `wasmer.sh` resolves to loopback too. HTTP(S) to it still goes through the realm proxy and the transport, which resolve names themselves; `wasmer.sh` is deliberately not in `no_proxy`.
|
package/dist/kernel-worker.js
CHANGED
|
@@ -7728,7 +7728,7 @@ function satisfies(version, range2) {
|
|
|
7728
7728
|
}
|
|
7729
7729
|
|
|
7730
7730
|
// src/version.ts
|
|
7731
|
-
var KERNEL_VERSION = true ? "1.
|
|
7731
|
+
var KERNEL_VERSION = true ? "1.146.0" : "0.0.0-dev";
|
|
7732
7732
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7733
7733
|
function procVersion() {
|
|
7734
7734
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -28178,6 +28178,14 @@ function foreignImports(bytes) {
|
|
|
28178
28178
|
}
|
|
28179
28179
|
return {};
|
|
28180
28180
|
}
|
|
28181
|
+
var LIBC_MARK = /^wasix-sysroot \d{4}\.\d+\.\d+-(\d+)/;
|
|
28182
|
+
function libcVersion(module) {
|
|
28183
|
+
for (const section of WebAssembly.Module.customSections(module, "slicc.libc")) {
|
|
28184
|
+
const found = LIBC_MARK.exec(new TextDecoder().decode(section));
|
|
28185
|
+
if (found) return Number(found[1]);
|
|
28186
|
+
}
|
|
28187
|
+
return void 0;
|
|
28188
|
+
}
|
|
28181
28189
|
|
|
28182
28190
|
// src/refused-command.ts
|
|
28183
28191
|
var REFUSED_PATH = "/usr/lib/slicc/refused";
|
|
@@ -28730,6 +28738,14 @@ function cronPath(path) {
|
|
|
28730
28738
|
(at) => path === at || path.startsWith(`${at}/`) || at.startsWith(path === "/" ? "/" : `${path}/`)
|
|
28731
28739
|
);
|
|
28732
28740
|
}
|
|
28741
|
+
var ETC_HOSTNAME_LIBC = 42;
|
|
28742
|
+
function readsEtcHostname(program) {
|
|
28743
|
+
return program.abi === "wasi" && (libcVersion(program.module) ?? 0) >= ETC_HOSTNAME_LIBC;
|
|
28744
|
+
}
|
|
28745
|
+
function setOrDrop(env, key, value2) {
|
|
28746
|
+
if (value2 === void 0) delete env[key];
|
|
28747
|
+
else env[key] = value2;
|
|
28748
|
+
}
|
|
28733
28749
|
function baseName2(path) {
|
|
28734
28750
|
return path.slice(path.lastIndexOf("/") + 1);
|
|
28735
28751
|
}
|
|
@@ -29892,6 +29908,7 @@ var Launcher = class {
|
|
|
29892
29908
|
const env = { ...expandDefaults(asked.target.env, seen), ...req.env };
|
|
29893
29909
|
for (const key of asked.target.unset ?? []) delete env[key];
|
|
29894
29910
|
delete env[TICKET_ENV];
|
|
29911
|
+
const own = env.HOSTNAME;
|
|
29895
29912
|
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
29896
29913
|
const planned = chosen(asked, env);
|
|
29897
29914
|
const { target, args } = planned;
|
|
@@ -29902,6 +29919,7 @@ var Launcher = class {
|
|
|
29902
29919
|
const caller = { pid: req.ppid ?? 0, uid: req.cred.euid, tag: req.tags?.[0] };
|
|
29903
29920
|
if (this.integrity) await this.checkedSources(planned, caller);
|
|
29904
29921
|
[program, exeId] = await Promise.all([this.program(target, env, caller), this.exeId(target)]);
|
|
29922
|
+
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
29905
29923
|
} catch (err) {
|
|
29906
29924
|
await req.fds.closeAll();
|
|
29907
29925
|
throw err;
|