@ai-ecoverse/slicc-kernel 1.59.1 → 1.60.1
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 +21 -2
- package/dist/index.js +12 -1
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +159 -24
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node.js +157 -27
- package/dist/node.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,10 +90,29 @@ The user database, `/etc/passwd` and `/etc/group` (see [Users](#users)):
|
|
|
90
90
|
| | |
|
|
91
91
|
| --- | --- |
|
|
92
92
|
| `mode` | the `users` option the kernel was created with |
|
|
93
|
-
| `add({ name, home?, groups?, umask?, homeGroup? })` | adds a user and resolves with `{ name, uid, gid, home, shell, groups, umask? }`. It's idempotent: an existing name resolves with its entry, keeps its ids
|
|
93
|
+
| `add({ name, home?, groups?, umask?, homeGroup?, homeMode? })` | adds a user and resolves with `{ name, uid, gid, home, shell, groups, umask? }`. It's idempotent: an existing name resolves with its entry, keeps its ids and home, joins the groups in `groups` it isn't in yet (it never leaves one), remembers `umask`, creates a missing pnpm home or `config.yaml` (an existing pnpm home keeps its mode with `users: 'off'`), and, with owners on, gives the home to the user again. The new user gets the lowest free id from 1000 up, a private group of the same id and name, membership of `users` and of each group in `groups` (such as `sudo`), `home` (default `/home/<name>`, created), its pnpm home `~/.local/share/pnpm` (`0700`, `0750` for a `scoop-` user) and `~/.config/pnpm/config.yaml` with `minimumReleaseAge: 1440` (pnpm skips releases less than a day old), each only if missing, which an `add` of an existing user also does, and `/bin/bash`. `umask` is the umask its processes start with; the kernel keeps it in memory, so pass it again after a reload. With owners on, every `add`, of a new or an existing user, also gives a home under `/home/<dir>` to the user and sets its pnpm home to `0700` (`0750` for a `scoop-` user) again (see [File owners](#file-owners)). `homeGroup` names the group the home belongs to instead of the user's own, without making the user a member (`groups` does that), and its mode is then `2750`. `homeMode` sets the home's mode instead (setgid included, so `0o2750` makes new files in it take the home's group); like the owner, it is set again by every `add` with owners on, on the home itself only. A name must match `[a-z_][a-z0-9_.-]*`; a group that doesn't exist, in `groups` or `homeGroup`, rejects with `ENOENT` |
|
|
94
94
|
| `remove(name, { keepHome }?)` | removes the user, its private group and its group memberships, and deletes its home unless `keepHome` is set. A home outside `/home/<dir>` is never deleted. Resolves `false` for an unknown name; system accounts (ids below 1000 or above 60000) reject with `EPERM` |
|
|
95
95
|
| `list()` | every user, as `add` returns them |
|
|
96
96
|
|
|
97
|
+
### `kernel.groups`
|
|
98
|
+
|
|
99
|
+
The groups of `/etc/group`, on the page and the Node entry (not on attached clients):
|
|
100
|
+
|
|
101
|
+
| | |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `list()` | every group as `{ name, gid, members }`, `members` being the users listed in it (a user's own group lists nobody) |
|
|
104
|
+
| `addMember(group, user)` | adds `user` to `group`'s members and resolves with the group; a member already in it changes nothing |
|
|
105
|
+
| `removeMember(group, user)` | removes `user` from `group`'s members, the same way |
|
|
106
|
+
|
|
107
|
+
An unknown group or user rejects with `ENOENT`, and a user's own (primary) group with `EINVAL`. Every user has an own group with its name and its uid as gid, which is how a cone shares with its scoops: the scoops join the cone's group. As on Linux, a change counts from the user's next process (and the next client connected for it): processes already running keep the groups they started with, and so does a client already connected. The embedder's recipe, which bios and slicc-agent share, run at every boot:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
await kernel.users.add({ name: 'cone', groups: ['sudo'], homeMode: 0o710, umask: 0o077 });
|
|
111
|
+
await kernel.users.add({ name: 'scoop-site', groups: ['cone'], homeGroup: 'cone', homeMode: 0o2750, umask: 0o027 });
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The cone's home lets its group in only to pass through (`0710`), and the cone opens what it shares with `chmod g+r`. A scoop's home belongs to the cone's group, so the cone reads it, and new files there take that group. Change `/etc/passwd` and `/etc/group` through `kernel.users` and `kernel.groups`, which keep the two consistent and serialize their writes.
|
|
115
|
+
|
|
97
116
|
### `kernel.setRoutes({ prefixes, exit }) → Promise<void>`
|
|
98
117
|
|
|
99
118
|
Replaces the [uplink](#uplink)'s route table: `prefixes` are addresses or CIDR prefixes (`100.64.0.0/10`, `fd7a:115c:a1e0::/48`), and `exit: true` routes every address, as an exit node does. A prefix that does not parse rejects the whole table and keeps the old one.
|
|
@@ -365,7 +384,7 @@ The proxy answers `200` with `Content-Type: application/vnd.slicc.raw-fetch`: a
|
|
|
365
384
|
|
|
366
385
|
## Filesystem
|
|
367
386
|
|
|
368
|
-
`/` is the OPFS root. Each process mounts the top-level directories that exist when it starts (plus `/usr` and `/bin`), so files in them are shared by all processes and visible through the OPFS API as soon as the process that wrote them has closed them; `run` resolves only after that. `createKernel` creates `/tmp` and `/home` in OPFS, so they are shared too. Files directly in `/`, and directories created there after a process started, are OPFS as well, the same for Emscripten and WASI programs; only `/dev` and `/proc` live in each process's memory. File contents are buffered per open file and written back on close, `fsync` and exit; metadata operations (`mkdir`, `rename`, `rm`, …) go straight to OPFS. The kernel worker is the only writer.
|
|
387
|
+
`/` is the OPFS root. Each process mounts the top-level directories that exist when it starts (plus `/usr` and `/bin`), so files in them are shared by all processes and visible through the OPFS API as soon as the process that wrote them has closed them; `run` resolves only after that. `createKernel` creates `/tmp` and `/home` in OPFS, so they are shared too. Files directly in `/`, and directories created there after a process started, are OPFS as well, the same for Emscripten and WASI programs; only `/dev` and `/proc` live in each process's memory. An OPFS or IndexedDB failure that has no POSIX counterpart is `EIO`; its message names the DOM error and the operation (`lookup`, `read`, `write`, `commit` or `sidecar`), and the kernel worker logs the first of each kind to its console. File contents are buffered per open file and written back on close, `fsync` and exit; metadata operations (`mkdir`, `rename`, `rm`, …) go straight to OPFS. The kernel worker is the only writer.
|
|
369
388
|
|
|
370
389
|
Directories are renamed with `FileSystemHandle.move()` where available, else by copy and delete.
|
|
371
390
|
|
package/dist/index.js
CHANGED
|
@@ -1824,6 +1824,17 @@ function cdpBridge(hook) {
|
|
|
1824
1824
|
function failed(message, code) {
|
|
1825
1825
|
return Object.assign(new Error(message), code === void 0 ? {} : { code });
|
|
1826
1826
|
}
|
|
1827
|
+
function kernelGroups(call) {
|
|
1828
|
+
const member = (op) => async (group, user) => await call({ op, group, user });
|
|
1829
|
+
return {
|
|
1830
|
+
list: async () => await call({ op: "groups-list" }),
|
|
1831
|
+
addMember: member("groups-add-member"),
|
|
1832
|
+
removeMember: member("groups-remove-member")
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
function accounts(call, mode) {
|
|
1836
|
+
return { users: kernelUsers(call, mode), groups: kernelGroups(call) };
|
|
1837
|
+
}
|
|
1827
1838
|
function kernelUsers(call, mode = "off") {
|
|
1828
1839
|
return {
|
|
1829
1840
|
mode,
|
|
@@ -1977,7 +1988,7 @@ async function createKernel(options = {}) {
|
|
|
1977
1988
|
},
|
|
1978
1989
|
openTerminal,
|
|
1979
1990
|
connect: async (connectOptions = {}) => await call({ op: "connect", ...connectOptions }),
|
|
1980
|
-
|
|
1991
|
+
...accounts(call, options.users),
|
|
1981
1992
|
setRoutes: async (routes) => void await call({ op: "routes", routes }),
|
|
1982
1993
|
dial,
|
|
1983
1994
|
loopbackFetch: (input, fetchOptions) => loopbackFetch(dial, input, fetchOptions),
|