shadok-ai 0.17.26 → 0.17.27

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.
Files changed (39) hide show
  1. package/README.md +18 -2
  2. package/context/agents-skill/SKILL.md +5 -2
  3. package/context/agents-skill/pilotctl.mjs +7 -12
  4. package/context/files-skill/SKILL.md +2 -3
  5. package/context/ledger-skill/ledger.mjs +1 -4
  6. package/context/pilot-prompt.md +3 -1
  7. package/context/reload-skill/SKILL.md +5 -2
  8. package/context/reload-skill/reload.mjs +2 -4
  9. package/context/scheduler-skill/SKILL.md +5 -2
  10. package/context/scheduler-skill/scripts/schedule.mjs +3 -5
  11. package/context/scheduler-skill/test/schedule.test.mjs +3 -1
  12. package/context/secrets-skill/SKILL.md +5 -2
  13. package/context/secrets-skill/scripts/secret.mjs +3 -6
  14. package/context/secrets-skill/test/secret.test.mjs +3 -1
  15. package/dist/accounts.d.ts +13 -0
  16. package/dist/accounts.js +37 -0
  17. package/dist/accounts.js.map +1 -1
  18. package/dist/agent-principal.d.ts +107 -0
  19. package/dist/agent-principal.js +105 -0
  20. package/dist/agent-principal.js.map +1 -0
  21. package/dist/groups.d.ts +25 -6
  22. package/dist/groups.js +38 -11
  23. package/dist/groups.js.map +1 -1
  24. package/dist/osusers.d.ts +2 -2
  25. package/dist/osusers.js +2 -2
  26. package/dist/secret-audit.d.ts +1 -1
  27. package/dist/secret-audit.js +1 -1
  28. package/dist/secret-audit.js.map +1 -1
  29. package/dist/secrets.d.ts +1 -2
  30. package/dist/secrets.js +4 -7
  31. package/dist/secrets.js.map +1 -1
  32. package/dist/server.d.ts +14 -0
  33. package/dist/server.js +170 -62
  34. package/dist/server.js.map +1 -1
  35. package/dist/session.js +8 -2
  36. package/dist/session.js.map +1 -1
  37. package/dist/tmux.js +8 -2
  38. package/dist/tmux.js.map +1 -1
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -639,8 +639,8 @@ know before opening it up:
639
639
  add, and flags it to every admin. There is no mail yet: this panel is the
640
640
  channel, so keep an eye on its badge.
641
641
  - While it is on, the instance password (`admin`) **cannot sign in to the
642
- browser** — it lives in every agent's environment and no one could reset it;
643
- use a named account. Agents, Telegram and peers keep working (they never use
642
+ browser** — no one could reset it (and agents started before it was removed
643
+ from their environment still hold it); use a named account. Agents, Telegram and peers keep working (they never use
644
644
  the login), but account and two-factor management is reserved to a signed-in
645
645
  person: an agent's key can no longer create or reset accounts.
646
646
  - Passkeys need a **secure context**: `https://` (see "Behind TLS") or
@@ -653,6 +653,22 @@ know before opening it up:
653
653
  session issued before it was switched on (they stop working). What it does
654
654
  not: anything already running as the machine's user — same soft isolation as
655
655
  profiles.
656
+ - **An agent is not the admin.** An agent authenticates to its own cockpit with
657
+ `SHADOK_SESSION_KEY`, and that key makes it **that agent**: a member of its own
658
+ channel's group, never an admin. It can drive its siblings (in multi-tenant:
659
+ the agents of its own group plus public ones), schedule prompts on its
660
+ channel, store a secret it obtained, record in the ledger, send you files,
661
+ reload itself — and is refused (`403`) on account, peer, Telegram, backend and
662
+ the other admin routes, and on every **browser-only** route (guardrails, shell
663
+ mode, uploads…), which now require a signed-in person's session rather than
664
+ an `Origin` header. Agents are no longer handed the admin's cookie
665
+ (`SHADOK_AUTH`) nor the instance password (`SHADOK_GUI_PASSWORD`). An agent
666
+ that a restricted peer spawned stays in that peer's box.
667
+ **Upgrading:** the first start of this version signs out whoever is signed in
668
+ with the instance password (once). Agents spawned before it still hold the
669
+ password in their environment — **change the password** (`--password` /
670
+ `SHADOK_GUI_PASSWORD`) and **reload those agents** (version menu → *Restart all
671
+ agents*) to take it away from them.
656
672
  - Once people are named, **a prompt carries its sender**: the agent sees who
657
673
  asked, and the other browsers show the name above the message instead of
658
674
  "pilot (elsewhere)". The server takes that name from the session, never from
@@ -229,8 +229,11 @@ curl -sS -H "x-shadok-session-key: $SHADOK_SESSION_KEY" \
229
229
  "http://127.0.0.1:$SHADOK_PORT/channels"
230
230
  ```
231
231
 
232
- `$SHADOK_AUTH` (a cookie) is still accepted, but it was frozen into your
233
- environment at spawn and expires after a week, so never rely on it alone. A
232
+ That key is your ONLY credential, and it does not expire. You are no longer
233
+ handed a cookie or the cockpit password, and a call made with the key is made
234
+ as YOU — an agent of your own group, never an admin: account, backend and
235
+ other cockpit-admin routes answer `403`, and so do the person-only (browser)
236
+ ones. That is by design; ask the human when you need one of those. A
234
237
  `401` means that header is missing — or that you were started before this
235
238
  existed, in which case nothing you hold can authenticate any more and only a
236
239
  human can fix it: ask them for *Reload agent* on your ⋯ menu.
@@ -69,17 +69,12 @@ export function resolvePeer(peersOut, alias) {
69
69
  if (!p || typeof p.url !== "string" || typeof p.token !== "string" || !p.url || !p.token) return null;
70
70
  return { url: p.url.replace(/\/+$/, ""), token: p.token };
71
71
  }
72
- // When a GUI password is set, the server injects SHADOK_AUTH=sk_auth=<token>
73
- // into every agent's env; loopback HTTP + WS calls must present it as the cookie
74
- // or the password gate 401s them — exactly what secret.py / schedule.py and the
75
- // Telegram bridge already do. Empty when no password is set → no change.
76
- // The session key is the DURABLE half and is sent whenever it is set.
77
- // SHADOK_AUTH is a dated cookie frozen into this process's environment at
78
- // spawn, so it expires after a week and nothing can refresh it — an agent
79
- // older than that got 401 on every call here. The key is derived from the
80
- // session id, verifies for as long as the agent runs, and grants exactly what
81
- // the cookie did. Both are sent: the cookie still works, and an older server
82
- // that does not know the header simply ignores it.
72
+ // An agent authenticates with its own session key (SHADOK_SESSION_KEY) — its
73
+ // ONLY credential: the server no longer hands agents a cookie or the cockpit
74
+ // password. The key is derived from the session id, verifies for as long as the
75
+ // agent runs, and makes the caller THIS AGENT (its own group's agents, never an
76
+ // admin). A human running pilotctl by hand has no key; on a password-protected
77
+ // cockpit they can export SHADOK_AUTH (their own `sk_auth=…` cookie) instead.
83
78
  export const authHeaders = () =>
84
79
  PEER
85
80
  ? // Targeting a remote peer: the ONLY credential it accepts is the peer token.
@@ -100,7 +95,7 @@ export const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
100
95
  // `ws` already has them, so it is returned untouched.
101
96
  //
102
97
  // Both accept the non-standard `{ headers }` option, which is what carries the
103
- // SHADOK_AUTH cookie past the password gate — verified against a real upgrade
98
+ // auth headers past the password gate — verified against a real upgrade
104
99
  // handler on the built-in, not assumed.
105
100
  function makeWS(url, opts) {
106
101
  if (!WS)
@@ -57,9 +57,8 @@ curl -sS -X POST -H "content-type: application/json" \
57
57
  "http://127.0.0.1:$SHADOK_PORT/files"
58
58
  ```
59
59
 
60
- `$SHADOK_AUTH` (a cookie) is still accepted elsewhere, but it was frozen into
61
- this process's environment at spawn and expires after a week, so never rely on
62
- it alone. A `401` or `403` means that header is missing — or that you were
60
+ That key is your only credential and it does not expire (no cookie, no
61
+ cockpit password is handed to an agent). A `401` or `403` means that header is missing — or that you were
63
62
  started before this existed, in which case nothing you hold can authenticate
64
63
  any more and only a human can fix it: ask them for *Reload agent* on your ⋯
65
64
  menu.
@@ -30,7 +30,6 @@ import { upsertEntry, searchEntries, ageDays, resolveId, normEntity, rowKind, KI
30
30
 
31
31
  const PORT = (process.env.SHADOK_PORT || "").trim();
32
32
  const KEY = (process.env.SHADOK_SESSION_KEY || "").trim();
33
- const AUTH = (process.env.SHADOK_AUTH || "").trim();
34
33
  // On-server: a port AND a session key. The key is what proves WHICH agent calls,
35
34
  // and it is what the server scopes the authoring group by — without it there is
36
35
  // no identity, so we fall back to the local file.
@@ -79,9 +78,7 @@ async function api(method, p, body, { soft404 = false } = {}) {
79
78
  method,
80
79
  headers: {
81
80
  "content-type": "application/json",
82
- ...(AUTH ? { Cookie: AUTH } : {}),
83
- // The durable credential: the cookie in the env expires after a week,
84
- // the session key does not (invariant 33).
81
+ // The agent's only credential; it does not expire (invariant 33).
85
82
  ...(KEY ? { "x-shadok-session-key": KEY } : {}),
86
83
  },
87
84
  body: body === undefined ? undefined : JSON.stringify(body),
@@ -81,7 +81,9 @@ Claude Code sessions in parallel. A human pilots you from a browser chat
81
81
  - The cockpit exposes a local API at `http://127.0.0.1:$SHADOK_PORT`. If you
82
82
  call it yourself, authenticate with `-H "x-shadok-session-key:
83
83
  $SHADOK_SESSION_KEY"` — a `401` means that header is missing. (The shadok
84
- skills already do this for you.)
84
+ skills already do this for you.) That key is your only credential and it
85
+ makes you an agent of your own group, not an admin: admin-only and
86
+ person-only routes answer `403` by design.
85
87
 
86
88
  ## Language — two different rules, don't mix them up
87
89
  - **Anything you write into a repo is in English**: code comments, identifiers,
@@ -32,8 +32,11 @@ curl -sS -H "x-shadok-session-key: $SHADOK_SESSION_KEY" \
32
32
  "http://127.0.0.1:$SHADOK_PORT/channels"
33
33
  ```
34
34
 
35
- `$SHADOK_AUTH` (a cookie) is still accepted, but it was frozen into your
36
- environment at spawn and expires after a week, so never rely on it alone. A
35
+ That key is your ONLY credential, and it does not expire. You are no longer
36
+ handed a cookie or the cockpit password, and a call made with the key is made
37
+ as YOU — an agent of your own group, never an admin: account, backend and
38
+ other cockpit-admin routes answer `403`, and so do the person-only (browser)
39
+ ones. That is by design; ask the human when you need one of those. A
37
40
  `401` means that header is missing — or that you were started before this
38
41
  existed, in which case nothing you hold can authenticate any more and only a
39
42
  human can fix it: ask them for *Reload agent* on your ⋯ menu.
@@ -6,7 +6,6 @@ import http from "node:http";
6
6
 
7
7
  const key = process.env.SHADOK_SESSION_KEY;
8
8
  const port = process.env.SHADOK_PORT || "3789";
9
- const cookie = process.env.SHADOK_AUTH; // "sk_auth=…" when a GUI password is set
10
9
 
11
10
  if (!key) {
12
11
  console.error("SHADOK_SESSION_KEY is not set — not running under the shadok-ai cockpit?");
@@ -23,9 +22,8 @@ const req = http.request(
23
22
  headers: {
24
23
  "content-type": "application/json",
25
24
  "content-length": Buffer.byteLength(body),
26
- ...(cookie ? { cookie } : {}),
27
- // The key authenticates too, and unlike the cookie it cannot age out —
28
- // which matters most here: an expired cookie left the agent unable to
25
+ // The agent's only credential, and it cannot age out — which matters
26
+ // most here: an expired cookie once left an agent unable to
29
27
  // reach the one endpoint that would have repaired it.
30
28
  "x-shadok-session-key": key,
31
29
  },
@@ -137,8 +137,11 @@ curl -sS -H "x-shadok-session-key: $SHADOK_SESSION_KEY" \
137
137
  "http://127.0.0.1:$SHADOK_PORT/channels"
138
138
  ```
139
139
 
140
- `$SHADOK_AUTH` (a cookie) is still accepted, but it was frozen into your
141
- environment at spawn and expires after a week, so never rely on it alone. A
140
+ That key is your ONLY credential, and it does not expire. You are no longer
141
+ handed a cookie or the cockpit password, and a call made with the key is made
142
+ as YOU — an agent of your own group, never an admin: account, backend and
143
+ other cockpit-admin routes answer `403`, and so do the person-only (browser)
144
+ ones. That is by design; ask the human when you need one of those. A
142
145
  `401` means that header is missing — or that you were started before this
143
146
  existed, in which case nothing you hold can authenticate any more and only a
144
147
  human can fix it: ask them for *Reload agent* on your ⋯ menu.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // schedule — manage the CURRENT shadok-ai channel's scheduled prompts (crons)
3
3
  // through the local server API. Reads SHADOK_SESSION_ID / SHADOK_PORT /
4
- // SHADOK_AUTH from the env (injected by shadok-ai into every agent).
4
+ // SHADOK_SESSION_KEY from the env (injected by shadok-ai into every agent).
5
5
  //
6
6
  // Node, not Python: shadok-ai IS a Node program, so the runtime is guaranteed
7
7
  // present wherever a skill runs. The Dockerfile's python3 is there to build
@@ -25,7 +25,7 @@ function env() {
25
25
  const port = process.env.SHADOK_PORT;
26
26
  const sid = process.env.SHADOK_SESSION_ID;
27
27
  if (!port || !sid) die("Not inside a shadok-ai channel (SHADOK_PORT / SHADOK_SESSION_ID unset).");
28
- return { base: `http://127.0.0.1:${port}`, sid, auth: process.env.SHADOK_AUTH ?? "" , key: process.env.SHADOK_SESSION_KEY ?? "" };
28
+ return { base: `http://127.0.0.1:${port}`, sid, key: process.env.SHADOK_SESSION_KEY ?? "" };
29
29
  }
30
30
 
31
31
  async function api(ctx, method, path, body) {
@@ -35,9 +35,7 @@ async function api(ctx, method, path, body) {
35
35
  method,
36
36
  headers: {
37
37
  "content-type": "application/json",
38
- ...(ctx.auth ? { Cookie: ctx.auth } : {}),
39
- // Durable half — see the note in pilotctl.mjs: the cookie is frozen
40
- // into this process's env at spawn and expires after a week.
38
+ // The agent's ONLY credential (no cookie is handed to agents any more).
41
39
  ...(ctx.key ? { "x-shadok-session-key": ctx.key } : {}),
42
40
  },
43
41
  body: body === undefined ? undefined : JSON.stringify(body),
@@ -86,7 +86,9 @@ test("add posts the channel's own sessionId, the guard and the timezone", async
86
86
  check: "sh guard.sh",
87
87
  tz: "Europe/Paris",
88
88
  });
89
- assert.equal(srv.seen[0].cookie, "sk_auth=tok");
89
+ // No cookie any more, even if one sits in the env: the session key is an
90
+ // agent's only credential.
91
+ assert.equal(srv.seen[0].cookie, undefined);
90
92
  assert.match(res.out, /scheduled \[abcdef01\] daily 09:00 \(Europe\/Paris\) \+guard/);
91
93
  });
92
94
 
@@ -81,8 +81,11 @@ curl -sS -H "x-shadok-session-key: $SHADOK_SESSION_KEY" \
81
81
  "http://127.0.0.1:$SHADOK_PORT/channels"
82
82
  ```
83
83
 
84
- `$SHADOK_AUTH` (a cookie) is still accepted, but it was frozen into your
85
- environment at spawn and expires after a week, so never rely on it alone. A
84
+ That key is your ONLY credential, and it does not expire. You are no longer
85
+ handed a cookie or the cockpit password, and a call made with the key is made
86
+ as YOU — an agent of your own group, never an admin: account, backend and
87
+ other cockpit-admin routes answer `403`, and so do the person-only (browser)
88
+ ones. That is by design; ask the human when you need one of those. A
86
89
  `401` means that header is missing — or that you were started before this
87
90
  existed, in which case nothing you hold can authenticate any more and only a
88
91
  human can fix it: ask them for *Reload agent* on your ⋯ menu.
@@ -7,7 +7,7 @@
7
7
  // leaks. There is deliberately no way to read a value back out — `list` prints
8
8
  // names only, and there is no `get`.
9
9
  //
10
- // Reads SHADOK_PORT / SHADOK_AUTH from the env (injected into every agent).
10
+ // Reads SHADOK_PORT / SHADOK_SESSION_KEY from the env (injected into every agent).
11
11
  //
12
12
  // Node, not Python: shadok-ai IS a Node program, so the runtime is guaranteed
13
13
  // present wherever a skill runs — the image's python3 exists to build native
@@ -29,7 +29,7 @@ class UsageError extends Error {}
29
29
  function env() {
30
30
  const port = process.env.SHADOK_PORT;
31
31
  if (!port) die("Not inside a shadok-ai agent (SHADOK_PORT unset).");
32
- return { base: `http://127.0.0.1:${port}`, auth: process.env.SHADOK_AUTH ?? "" , key: process.env.SHADOK_SESSION_KEY ?? "" };
32
+ return { base: `http://127.0.0.1:${port}`, key: process.env.SHADOK_SESSION_KEY ?? "" };
33
33
  }
34
34
 
35
35
  async function api(ctx, method, path, body) {
@@ -39,9 +39,7 @@ async function api(ctx, method, path, body) {
39
39
  method,
40
40
  headers: {
41
41
  "content-type": "application/json",
42
- ...(ctx.auth ? { Cookie: ctx.auth } : {}),
43
- // Durable half — see the note in pilotctl.mjs: the cookie is frozen
44
- // into this process's env at spawn and expires after a week.
42
+ // The agent's ONLY credential (no cookie is handed to agents any more).
45
43
  ...(ctx.key ? { "x-shadok-session-key": ctx.key } : {}),
46
44
  },
47
45
  body: body === undefined ? undefined : JSON.stringify(body),
@@ -102,7 +100,6 @@ async function apiSoft(ctx, method, path, body) {
102
100
  method,
103
101
  headers: {
104
102
  "content-type": "application/json",
105
- ...(ctx.auth ? { Cookie: ctx.auth } : {}),
106
103
  ...(ctx.key ? { "x-shadok-session-key": ctx.key } : {}),
107
104
  },
108
105
  body: body === undefined ? undefined : JSON.stringify(body),
@@ -27,7 +27,9 @@ test("set reads the value from stdin and sends it in the body", async () => {
27
27
  await srv.close();
28
28
  assert.equal(res.code, 0, res.err);
29
29
  assert.deepEqual(srv.seen.body, { name: "A", value: "s3cr3t" });
30
- assert.equal(srv.seen.cookie, "sk_auth=tok");
30
+ // No cookie any more, even if one sits in the env: the session key is an
31
+ // agent's only credential.
32
+ assert.equal(srv.seen.cookie, undefined);
31
33
  // The value must never be echoed back — the reply lands in the transcript.
32
34
  assert.doesNotMatch(res.out, /s3cr3t/);
33
35
  // And the user has to be told the secret is inert until attached.
@@ -79,6 +79,19 @@ export declare function userWriteVerdict(o: {
79
79
  * cookie for any user. Untidy becomes impersonation the moment accounts exist.
80
80
  */
81
81
  export declare function sessionSecret(): Buffer;
82
+ /**
83
+ * Bootstrap-admin cookies issued BEFORE this instant are dead.
84
+ *
85
+ * Until agents stopped being handed one, every agent carried `SHADOK_AUTH` — a
86
+ * bootstrap-admin cookie valid for a week, from the network too. Those cookies
87
+ * are indistinguishable from a person's bootstrap login, so the only way to
88
+ * retire them is by date: the first boot of a server that no longer issues them
89
+ * records "now", once, and from then on an older bootstrap cookie is refused.
90
+ * Cost: whoever is signed in with the instance password signs in again, once.
91
+ * Named accounts are untouched (their cookies were never given to agents).
92
+ * Best-effort: a write that fails returns 0, i.e. today's behaviour.
93
+ */
94
+ export declare function bootstrapSessionsAfter(now: number): number;
82
95
  /** `<user base64url>.<issuedAt>.<mfa>.<hmac>` — the name is encoded so a dot in
83
96
  * it cannot shift the fields. The ROLE is deliberately absent: it is re-read
84
97
  * from the account file at use time, so a demotion takes effect immediately
package/dist/accounts.js CHANGED
@@ -59,6 +59,12 @@ export function userWriteVerdict(o) {
59
59
  if (o.action === "create") {
60
60
  if (name === BOOTSTRAP_ADMIN)
61
61
  return { ok: false, error: `"${BOOTSTRAP_ADMIN}" is reserved for the instance password` };
62
+ // `agent:<sessionId>` is how an AGENT is named as a principal
63
+ // (src/agent-principal.ts). Authorization never trusts the name — it reads
64
+ // the principal's own `agent` field — but a person wearing an agent's name
65
+ // would be one more thing for a reader of the logs to get wrong.
66
+ if (name.startsWith("agent:"))
67
+ return { ok: false, error: `"agent:" names are reserved for agents` };
62
68
  return o.exists ? { ok: false, error: `${name} already exists` } : { ok: true };
63
69
  }
64
70
  return o.exists ? { ok: true } : { ok: false, error: `no such account: ${name}` };
@@ -87,6 +93,37 @@ export function sessionSecret() {
87
93
  fs.chmodSync(f, 0o600);
88
94
  return secret;
89
95
  }
96
+ /**
97
+ * Bootstrap-admin cookies issued BEFORE this instant are dead.
98
+ *
99
+ * Until agents stopped being handed one, every agent carried `SHADOK_AUTH` — a
100
+ * bootstrap-admin cookie valid for a week, from the network too. Those cookies
101
+ * are indistinguishable from a person's bootstrap login, so the only way to
102
+ * retire them is by date: the first boot of a server that no longer issues them
103
+ * records "now", once, and from then on an older bootstrap cookie is refused.
104
+ * Cost: whoever is signed in with the instance password signs in again, once.
105
+ * Named accounts are untouched (their cookies were never given to agents).
106
+ * Best-effort: a write that fails returns 0, i.e. today's behaviour.
107
+ */
108
+ export function bootstrapSessionsAfter(now) {
109
+ const f = path.join(os.homedir(), ".shadok-ai", "users", instanceKey() + ".bootstrap-after");
110
+ try {
111
+ const n = Number(fs.readFileSync(f, "utf8").trim());
112
+ if (Number.isFinite(n) && n > 0)
113
+ return n;
114
+ }
115
+ catch {
116
+ /* first boot of this version: record it below */
117
+ }
118
+ try {
119
+ fs.mkdirSync(path.dirname(f), { recursive: true });
120
+ fs.writeFileSync(f, String(now), { mode: 0o600 });
121
+ return now;
122
+ }
123
+ catch {
124
+ return 0;
125
+ }
126
+ }
90
127
  /** `<user base64url>.<issuedAt>.<mfa>.<hmac>` — the name is encoded so a dot in
91
128
  * it cannot shift the fields. The ROLE is deliberately absent: it is re-read
92
129
  * from the account file at use time, so a demotion takes effect immediately
@@ -1 +1 @@
1
- {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The AGENT as a principal of its own — not the bootstrap admin.
3
+ *
4
+ * Every agent carries `SHADOK_SESSION_KEY` (`src/accounts.ts`), and the server
5
+ * used to resolve a valid key to `{name: BOOTSTRAP_ADMIN, role: "admin"}`. That
6
+ * made every agent — including a multi-tenant agent running as an unprivileged
7
+ * OS user precisely so it could NOT reach other groups — a full admin of the
8
+ * API: mint an admin invitation, rewrite the model backend, restart every
9
+ * agent, see and drive every group's agents. The OS-user wall was moot.
10
+ *
11
+ * A key now resolves to THE AGENT: its session id, the group its channel was
12
+ * born into, its profile, the person it was created for, and the restricted
13
+ * peer it was spawned by, if any. As an account it is a `member` (never an
14
+ * admin), named `agent:<sessionId>` so it can never collide with a person's
15
+ * name, and its group membership is exactly its channel's group — nothing a
16
+ * frame or a body says. Pure, so the rules are tested without a server.
17
+ */
18
+ import type { Role } from "./accounts.js";
19
+ /** Who an agent is, as far as authorization goes. */
20
+ export interface AgentPrincipal {
21
+ sessionId: string;
22
+ /** The group its channel was born into; null = the commons. */
23
+ group: string | null;
24
+ profile: string | null;
25
+ /** The person this agent ultimately works for (`Channel.createdBy`). */
26
+ createdBy: string | null;
27
+ /**
28
+ * The RESTRICTED peer whose box this agent lives in, when a restricted peer
29
+ * spawned it (directly or through an ancestor that carried the tag). Such an
30
+ * agent inherits the box: it sees and drives only that peer's agents. null
31
+ * for an agent no restricted peer owns.
32
+ */
33
+ peer: string | null;
34
+ }
35
+ /** The account-shaped view of an agent: a member, never an admin. */
36
+ export interface AgentAccount {
37
+ name: string;
38
+ role: Role;
39
+ agent: AgentPrincipal;
40
+ }
41
+ /** Prefix of an agent's account name. Reserved: `userWriteVerdict` refuses a
42
+ * person account named with it. Nothing authorizes on the NAME anyway — an
43
+ * agent is recognised by the `agent` field, which only the key resolution sets. */
44
+ export declare const AGENT_ACCOUNT_PREFIX = "agent:";
45
+ export declare function agentAccountName(sessionId: string): string;
46
+ /**
47
+ * Resolve the principal behind a VERIFIED session id (the caller has already
48
+ * checked the key's MAC and that it came from this machine). The channel
49
+ * registry is the authority (invariant 1): the group, profile and creator are
50
+ * read from the row, never from the request.
51
+ *
52
+ * `peerScope` answers the scope of a peer by name, or null when that peer is no
53
+ * longer listed. A `createdByPeer` tag on the channel puts the agent in that
54
+ * peer's box when the peer is restricted — AND when it has been revoked: an
55
+ * unknown peer can no longer be proven to be a member, and the box is the
56
+ * fail-closed direction.
57
+ */
58
+ export declare function resolveAgentPrincipal(sessionId: string, channels: readonly {
59
+ sessionId: string;
60
+ group?: string | null;
61
+ profile?: string | null;
62
+ createdBy?: string | null;
63
+ createdByPeer?: string;
64
+ }[], peerScope: (name: string) => "member" | "restricted" | null, liveProfile?: string | null): AgentPrincipal;
65
+ export declare function agentAccount(p: AgentPrincipal): AgentAccount;
66
+ /**
67
+ * Credentials that must NEVER reach an agent's environment.
68
+ *
69
+ * `SHADOK_AUTH` was the bootstrap admin's cookie, injected into every agent and
70
+ * valid from the network for a week. `SHADOK_GUI_PASSWORD` is the instance
71
+ * password, which IS the bootstrap admin: the supervisor hands it to the server
72
+ * through the env, and every child the server spawned inherited it — node-pty
73
+ * copies `process.env`, a tmux pane inherits the tmux SERVER's global
74
+ * environment (captured whenever that server first started, possibly by an
75
+ * older shadok), and `setpriv` keeps the env across the uid drop. Either one
76
+ * let an agent `POST /login` or present a cookie as the admin, from anywhere.
77
+ *
78
+ * The agent's own credential is `SHADOK_SESSION_KEY`, which proves "I am this
79
+ * agent" and nothing more.
80
+ */
81
+ export declare const AGENT_CREDENTIAL_VARS: readonly string[];
82
+ export declare function isAgentCredentialVar(name: string): boolean;
83
+ /** A copy of `env` without the credential variables. */
84
+ export declare function withoutAgentCredentials<T extends Record<string, string | undefined>>(env: T): T;
85
+ /**
86
+ * Is this request a PERSON in a browser on our own origin — the only caller the
87
+ * "browser-only" routes (guardrails, accounts, shell mode, uploads…) accept?
88
+ *
89
+ * `Origin` alone proved nothing: any process can send `Origin: http://<host>`,
90
+ * so an agent's `curl -H Origin:…` passed every one of those gates. Now:
91
+ * - a request carrying an agent's session key or a peer token is a MACHINE,
92
+ * whatever else it carries — a browser never sends either header;
93
+ * - with a password set, it must also carry a PERSON's session cookie;
94
+ * - and the same-origin `Origin` check stays, as the CSRF layer it always was.
95
+ * With no password there is no cookie to ask for (local single-user default),
96
+ * so the Origin check and the machine-header refusal are what remain.
97
+ */
98
+ export declare function isBrowserPerson(o: {
99
+ hasAgentKey: boolean;
100
+ hasPeerToken: boolean;
101
+ passwordSet: boolean;
102
+ personCookie: boolean;
103
+ sameOrigin: boolean;
104
+ }): boolean;
105
+ /** Was a header sent at all (any non-empty value)? Presence is what makes a
106
+ * request a machine's — a browser never sets these, valid or not. */
107
+ export declare function headerPresent(v: unknown): boolean;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The AGENT as a principal of its own — not the bootstrap admin.
3
+ *
4
+ * Every agent carries `SHADOK_SESSION_KEY` (`src/accounts.ts`), and the server
5
+ * used to resolve a valid key to `{name: BOOTSTRAP_ADMIN, role: "admin"}`. That
6
+ * made every agent — including a multi-tenant agent running as an unprivileged
7
+ * OS user precisely so it could NOT reach other groups — a full admin of the
8
+ * API: mint an admin invitation, rewrite the model backend, restart every
9
+ * agent, see and drive every group's agents. The OS-user wall was moot.
10
+ *
11
+ * A key now resolves to THE AGENT: its session id, the group its channel was
12
+ * born into, its profile, the person it was created for, and the restricted
13
+ * peer it was spawned by, if any. As an account it is a `member` (never an
14
+ * admin), named `agent:<sessionId>` so it can never collide with a person's
15
+ * name, and its group membership is exactly its channel's group — nothing a
16
+ * frame or a body says. Pure, so the rules are tested without a server.
17
+ */
18
+ /** Prefix of an agent's account name. Reserved: `userWriteVerdict` refuses a
19
+ * person account named with it. Nothing authorizes on the NAME anyway — an
20
+ * agent is recognised by the `agent` field, which only the key resolution sets. */
21
+ export const AGENT_ACCOUNT_PREFIX = "agent:";
22
+ export function agentAccountName(sessionId) {
23
+ return `${AGENT_ACCOUNT_PREFIX}${sessionId}`;
24
+ }
25
+ /**
26
+ * Resolve the principal behind a VERIFIED session id (the caller has already
27
+ * checked the key's MAC and that it came from this machine). The channel
28
+ * registry is the authority (invariant 1): the group, profile and creator are
29
+ * read from the row, never from the request.
30
+ *
31
+ * `peerScope` answers the scope of a peer by name, or null when that peer is no
32
+ * longer listed. A `createdByPeer` tag on the channel puts the agent in that
33
+ * peer's box when the peer is restricted — AND when it has been revoked: an
34
+ * unknown peer can no longer be proven to be a member, and the box is the
35
+ * fail-closed direction.
36
+ */
37
+ export function resolveAgentPrincipal(sessionId, channels, peerScope, liveProfile) {
38
+ const ch = channels.find((c) => c.sessionId === sessionId);
39
+ const tag = ch?.createdByPeer;
40
+ const peer = tag && peerScope(tag) !== "member" ? tag : null;
41
+ return {
42
+ sessionId,
43
+ group: ch?.group ?? null,
44
+ profile: liveProfile ?? ch?.profile ?? null,
45
+ createdBy: ch?.createdBy ?? null,
46
+ peer,
47
+ };
48
+ }
49
+ export function agentAccount(p) {
50
+ return { name: agentAccountName(p.sessionId), role: "member", agent: p };
51
+ }
52
+ /**
53
+ * Credentials that must NEVER reach an agent's environment.
54
+ *
55
+ * `SHADOK_AUTH` was the bootstrap admin's cookie, injected into every agent and
56
+ * valid from the network for a week. `SHADOK_GUI_PASSWORD` is the instance
57
+ * password, which IS the bootstrap admin: the supervisor hands it to the server
58
+ * through the env, and every child the server spawned inherited it — node-pty
59
+ * copies `process.env`, a tmux pane inherits the tmux SERVER's global
60
+ * environment (captured whenever that server first started, possibly by an
61
+ * older shadok), and `setpriv` keeps the env across the uid drop. Either one
62
+ * let an agent `POST /login` or present a cookie as the admin, from anywhere.
63
+ *
64
+ * The agent's own credential is `SHADOK_SESSION_KEY`, which proves "I am this
65
+ * agent" and nothing more.
66
+ */
67
+ export const AGENT_CREDENTIAL_VARS = ["SHADOK_AUTH", "SHADOK_GUI_PASSWORD"];
68
+ export function isAgentCredentialVar(name) {
69
+ return AGENT_CREDENTIAL_VARS.includes(name);
70
+ }
71
+ /** A copy of `env` without the credential variables. */
72
+ export function withoutAgentCredentials(env) {
73
+ const out = { ...env };
74
+ for (const k of AGENT_CREDENTIAL_VARS)
75
+ delete out[k];
76
+ return out;
77
+ }
78
+ /**
79
+ * Is this request a PERSON in a browser on our own origin — the only caller the
80
+ * "browser-only" routes (guardrails, accounts, shell mode, uploads…) accept?
81
+ *
82
+ * `Origin` alone proved nothing: any process can send `Origin: http://<host>`,
83
+ * so an agent's `curl -H Origin:…` passed every one of those gates. Now:
84
+ * - a request carrying an agent's session key or a peer token is a MACHINE,
85
+ * whatever else it carries — a browser never sends either header;
86
+ * - with a password set, it must also carry a PERSON's session cookie;
87
+ * - and the same-origin `Origin` check stays, as the CSRF layer it always was.
88
+ * With no password there is no cookie to ask for (local single-user default),
89
+ * so the Origin check and the machine-header refusal are what remain.
90
+ */
91
+ export function isBrowserPerson(o) {
92
+ if (o.hasAgentKey || o.hasPeerToken)
93
+ return false;
94
+ if (o.passwordSet && !o.personCookie)
95
+ return false;
96
+ return o.sameOrigin;
97
+ }
98
+ /** Was a header sent at all (any non-empty value)? Presence is what makes a
99
+ * request a machine's — a browser never sets these, valid or not. */
100
+ export function headerPresent(v) {
101
+ if (Array.isArray(v))
102
+ return v.some((x) => typeof x === "string" && x.length > 0);
103
+ return typeof v === "string" && v.length > 0;
104
+ }
105
+ //# sourceMappingURL=agent-principal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-principal.js","sourceRoot":"","sources":["../src/agent-principal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA4BH;;oFAEoF;AACpF,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAE7C,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,GAAG,oBAAoB,GAAG,SAAS,EAAE,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,QAMG,EACH,SAA2D,EAC3D,WAA2B;IAE3B,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,EAAE,EAAE,aAAa,CAAC;IAC9B,MAAM,IAAI,GAAG,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,OAAO;QACL,SAAS;QACT,KAAK,EAAE,EAAE,EAAE,KAAK,IAAI,IAAI;QACxB,OAAO,EAAE,WAAW,IAAI,EAAE,EAAE,OAAO,IAAI,IAAI;QAC3C,SAAS,EAAE,EAAE,EAAE,SAAS,IAAI,IAAI;QAChC,IAAI;KACL,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAiB;IAC5C,OAAO,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAsB,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC;AAE/F,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,uBAAuB,CAA+C,GAAM;IAC1F,MAAM,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;IACvB,KAAK,MAAM,CAAC,IAAI,qBAAqB;QAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,CAM/B;IACC,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAClD,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IACnD,OAAO,CAAC,CAAC,UAAU,CAAC;AACtB,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClF,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/C,CAAC"}