@ai-ecoverse/slicc-vault 1.4.0 → 1.5.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 CHANGED
@@ -177,7 +177,7 @@ iframe.contentWindow.postMessage({ type: 'slicc-vault', v: 1, op: 'hello', role:
177
177
  | `dismissBackupReminder` | — | `{ backupReminder }`; the reminder becomes `dismissed` for this namespace |
178
178
  | `policy` | `files` | the attested policy files, below (Policy) |
179
179
  | `forward` | `head`, `body?`, `owner`, `exit`, `rawTraits`, with a `MessagePort` transferred alongside | the injected head, below (Forward) |
180
- | `materializeConsume` | `ticket`, `stamp`, `path`, `argv`, `cwd`, `interpreters` | the values for the child's environment, below (Exec) |
180
+ | `materializeConsume` | `ticket`, `stamp`, `path`, `argv`, `cwd`, `interpreters`, `trusted` | the values for the child's environment, below (Exec) |
181
181
  | `import`, `export`, anything else | | `ENOTSUP` |
182
182
 
183
183
  `put` and `seal` need the vault unlocked. They answer `EACCES` with a message starting `vault is locked` otherwise.
@@ -223,11 +223,22 @@ bios relays each kernel request unchanged as the `sealed` op, with the kernel's
223
223
  - Each real name is audited as `materialize { name, exec, path, argv, argvSha256, cwd, pid, ppid, uid, tag, ticket, consumed: false }`. `argv` is joined with spaces, scrubbed, and cut to 200 characters; `argvSha256` is the SHA-256 of each argument followed by a NUL byte.
224
224
  - The reply never carries a value. The ticket is 32 hex characters and expires after 30 s.
225
225
 
226
- **`materializeConsume`** (a page op, from bios for the kernel at exec) takes `{ ticket, stamp, path, argv, cwd, interpreters }`, with `stamp` the exec'ing process and `interpreters` the absolute, symlink-resolved shebang/binfmt chain the kernel actually resolved for `path` (empty for a native binary), relayed unchanged. The vault burns the ticket, then requires that:
226
+ **`materializeConsume`** (a page op, from bios for the kernel at exec) takes `{ ticket, stamp, path, argv, cwd, interpreters, trusted }`, all from the kernel and relayed unchanged:
227
+ - `stamp` is the exec'ing process.
228
+ - `interpreters` is the absolute, symlink-resolved shebang/binfmt chain the kernel resolved for `path`, empty for a native binary. A plain `#!/usr/bin/env X` (or `env -S`) is reported as the resolved `X`; `env` with any other option or a `NAME=value` assignment is reported as `env` itself.
229
+ - `trusted` is true when `path` and every chain entry are root-owned regular files, not group- or other-writable, under root-owned, non-writable parents (the attestation rule).
230
+
231
+ The vault burns the ticket, then requires that:
227
232
  - it's unexpired and from this namespace, `stamp.ppid` is the pid that asked, and `path`, `argv` (element by element) and `cwd` are exactly the ones it was issued for;
228
- - `interpreters` is a list of absolute paths, and fnox's claim matches it: a claimed `interpreter` equals `interpreters[0]`, and no claim means `interpreters` is empty;
229
- - under each real name's `[exec]` mode, in the policy as stored now (reloaded at materialize and at consume), no program in `path` and `interpreters` is refused: for `true` none may be on the refusal list; for `{ argv }` a refused one must itself be the program of one of the grant's prefixes; `{ shell = true }` allows any;
230
- - each real name is still granted by the policy in force now (a removed grant, or an `{ argv }` grant that no longer lists the command, refuses), and no real record has expired meanwhile. Any mismatch is `EACCES: ticket refused: …`, and the ticket stays burned. It answers `{ values: { NAME: value }, placeholders: { NAME: placeholder } }` for the names that were real and still exist, and marks their audit entries `consumed`. The kernel swaps each env var whose value is exactly one of those placeholders, and compiles its own scrubber over these values for the child's output (S2).
233
+ - `interpreters` is a list of absolute paths and `trusted` a boolean; a claimed `interpreter` from fnox equals `interpreters[0]` (without a claim, the kernel's chain is taken as it is);
234
+ - each real name is still granted by the policy as stored now (reloaded at materialize and at consume): a removed grant, or an `{ argv }` grant that no longer lists the command, refuses;
235
+ - under that name's mode, the chain passes:
236
+ - `true`: no entry of `path` and `interpreters` is on the refusal list, so a `#!/usr/bin/env node` script needs an `{ argv }` rule;
237
+ - `{ argv }`: the listed program is `path`, and whatever chain the kernel resolved for it is allowed, so a rule for `npm publish` allows `/usr/bin/npm`'s `node`. But when the chain holds a refused program and `trusted` is false, it refuses ("the script or its interpreter can be changed by a non-root user"), and `env` and the other wrappers in the chain always refuse;
238
+ - `{ shell = true }`: any chain;
239
+ - no real record has expired meanwhile.
240
+
241
+ Any failure is `EACCES: ticket refused: …`, and the ticket stays burned. It answers `{ values: { NAME: value }, placeholders: { NAME: placeholder } }` for the names that were real and still exist, and marks their audit entries `consumed`. The kernel swaps each env var whose value is exactly one of those placeholders, and compiles its own scrubber over these values for the child's output (S2).
231
242
 
232
243
  ## Forward
233
244
 
@@ -371,6 +371,7 @@ export type Op = {
371
371
  argv: string[];
372
372
  cwd: string;
373
373
  interpreters: string[];
374
+ trusted: boolean;
374
375
  };
375
376
  export type AgentOp = {
376
377
  op: 'redact';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-vault",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "The separate-origin vault at vault.sliccy.ai: sealed secrets, OAuth tokens, and model and MCP credentials for SLICC seven, used only by its injector",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",