@cotal-ai/auth 0.0.0 → 0.11.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/LICENSE +202 -0
- package/dist/callout.d.ts +108 -0
- package/dist/callout.d.ts.map +1 -0
- package/dist/callout.js +219 -0
- package/dist/callout.js.map +1 -0
- package/dist/commands.d.ts +2 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +359 -0
- package/dist/commands.js.map +1 -0
- package/dist/derive.d.ts +15 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +72 -0
- package/dist/derive.js.map +1 -0
- package/dist/idp.d.ts +63 -0
- package/dist/idp.d.ts.map +1 -0
- package/dist/idp.js +125 -0
- package/dist/idp.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/issuer.d.ts +78 -0
- package/dist/issuer.d.ts.map +1 -0
- package/dist/issuer.js +137 -0
- package/dist/issuer.js.map +1 -0
- package/dist/ledger.d.ts +108 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +399 -0
- package/dist/ledger.js.map +1 -0
- package/dist/login.d.ts +69 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +338 -0
- package/dist/login.js.map +1 -0
- package/dist/permissions.d.ts +28 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +50 -0
- package/dist/permissions.js.map +1 -0
- package/dist/provider.d.ts +18 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +213 -0
- package/dist/provider.js.map +1 -0
- package/dist/service.d.ts +10 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +288 -0
- package/dist/service.js.map +1 -0
- package/dist/store.d.ts +82 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +208 -0
- package/dist/store.js.map +1 -0
- package/dist/token.d.ts +68 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +128 -0
- package/dist/token.js.map +1 -0
- package/package.json +35 -5
- package/README.md +0 -4
package/dist/ledger.js
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The local ACTOR LEDGER — the server-side authority over which (owner, actor) pairs may run agents
|
|
3
|
+
* in this space, and with what capability scope + channel ACL (plan gate 4: "define the local actor
|
|
4
|
+
* ledger + channel ACL resolver used by both the IdP bridge and callout permission supplier").
|
|
5
|
+
*
|
|
6
|
+
* This is THE single authorization source on the user-auth path — both trust boundaries read it:
|
|
7
|
+
* - the IdP bridge's `authorizeActor` (Plane 1, bearer MINT time): is this actor granted, and what
|
|
8
|
+
* `scope`/`parent` does its bearer carry;
|
|
9
|
+
* - the callout's `authorizeActor` + `AclResolver` (Plane 2, CONNECT time): is the actor STILL
|
|
10
|
+
* granted (a revoked row kills new connects even while an old bearer lives), has its granted scope
|
|
11
|
+
* been narrowed since the bearer was minted, and what channel read/post ACL + role gets minted.
|
|
12
|
+
*
|
|
13
|
+
* TWO DISJOINT ROW SPACES, split by construction (the gate-1 review convergence): `actors/` holds
|
|
14
|
+
* INTERACTIVE rows (written by `cotal actor grant`, exchanged via a human IdP proof) and
|
|
15
|
+
* `managed-actors/` holds MANAGED-AGENT rows (written only by the spawn path, carrying the hash of
|
|
16
|
+
* the per-agent secret, exchanged only via that secret). The IdP path reads only the interactive
|
|
17
|
+
* space and the agent path only the managed space, so no corruption, partial write, or misrepair
|
|
18
|
+
* can reclassify a managed child as human-exchangeable — the fail-open class is unrepresentable,
|
|
19
|
+
* not detected. Writers refuse a duplicate (owner, actor) across the two spaces; the CONNECT
|
|
20
|
+
* boundary (which must serve bearers minted by either path) reads both through ONE helper that
|
|
21
|
+
* fails closed on a duplicate.
|
|
22
|
+
*
|
|
23
|
+
* There is NO allow-by-default anywhere: a missing row is a deny, an empty ledger denies everyone.
|
|
24
|
+
* Rows are keyed (owner, actor); the owner is the opaque derived `u_…` token — the ledger holds no
|
|
25
|
+
* IdP subject/email (grant-time derivation maps sub → owner; an optional operator label is for
|
|
26
|
+
* `list` legibility only). Reads are FRESH per call (the delivery-daemon posture): a grant/revoke is
|
|
27
|
+
* live at the very next exchange/connect with no daemon restart.
|
|
28
|
+
*
|
|
29
|
+
* Storage is ONE FILE PER ROW (`<space>/<owner>.<actor>.json`, atomic tmp+rename writes) — the mesh
|
|
30
|
+
* registry's lost-update posture: concurrent grant/revoke (an operator command racing the manager's
|
|
31
|
+
* spawn-time grant) never read-modify-write a shared file, and a crash damages at most one row.
|
|
32
|
+
* UNLIKE the mesh registry, a corrupt row FAILS CLOSED with a thrown sentence — an auth ledger never
|
|
33
|
+
* skips what it cannot read (a "skipped" row would silently revoke or, in a list, silently hide a
|
|
34
|
+
* live grant from the operator).
|
|
35
|
+
*/
|
|
36
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
37
|
+
import { existsSync, readdirSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
import { assertDerivedOwnerToken, assertValidChannel, assertValidOwnerToken, mkSecretDir, patternInAllow, writeSecretFile, } from "@cotal-ai/core";
|
|
40
|
+
const ACTORS_DIR = "actors";
|
|
41
|
+
const MANAGED_DIR = "managed-actors";
|
|
42
|
+
const LEDGER_VER = 1;
|
|
43
|
+
function spaceDir(dir, kind) {
|
|
44
|
+
return join(dir, kind === "interactive" ? ACTORS_DIR : MANAGED_DIR);
|
|
45
|
+
}
|
|
46
|
+
/** The row's filename IS its principal dot-form + `.json` — both segments are grammar-asserted
|
|
47
|
+
* (owner `u_` + base32, actor a plain token), so the name is filesystem-safe by construction. */
|
|
48
|
+
function rowPath(dir, kind, owner, actor) {
|
|
49
|
+
assertDerivedOwnerToken(owner);
|
|
50
|
+
assertValidOwnerToken(actor);
|
|
51
|
+
return join(spaceDir(dir, kind), `${owner}.${actor}.json`);
|
|
52
|
+
}
|
|
53
|
+
/** Read + validate one row file against ITS space's shape. FAIL-CLOSED: unreadable/malformed/
|
|
54
|
+
* unknown-version/wrong-shape throws a sentence naming the file — never a skip, never a
|
|
55
|
+
* reclassification (an interactive row carrying a token hash was written by the wrong path; a
|
|
56
|
+
* managed row without a valid one has a corrupted grant — both deny with the repair). */
|
|
57
|
+
function readRow(path, kind) {
|
|
58
|
+
let parsed;
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
throw new Error(`${path}: unreadable actor grant (${e instanceof Error ? e.message : String(e)}) - fix or remove the row; a broken row denies its actor and fails ledger listings`);
|
|
64
|
+
}
|
|
65
|
+
if (parsed === null || typeof parsed !== "object" || parsed.ver !== LEDGER_VER)
|
|
66
|
+
throw new Error(`${path}: unknown actor-grant version ${String(parsed?.ver)} (expected ${LEDGER_VER}) - refusing to guess at an authorization row`);
|
|
67
|
+
assertDerivedOwnerToken(parsed.owner);
|
|
68
|
+
assertValidOwnerToken(parsed.actor);
|
|
69
|
+
if (!Array.isArray(parsed.scope) || !Array.isArray(parsed.allowSubscribe) || !Array.isArray(parsed.allowPublish))
|
|
70
|
+
throw new Error(`${path}: actor grant is missing explicit scope/allowSubscribe/allowPublish lists`);
|
|
71
|
+
if (kind === "interactive" && parsed.tokenHash !== undefined)
|
|
72
|
+
throw new Error(`${path}: an interactive grant must not carry an agent token hash - it was written by the wrong path; remove the row and re-grant (\`cotal actor grant\`)`);
|
|
73
|
+
if (kind === "managed-agent" && !(typeof parsed.tokenHash === "string" && /^[0-9a-f]{64}$/.test(parsed.tokenHash)))
|
|
74
|
+
throw new Error(`${path}: managed-agent grant has a missing/corrupted secret hash - respawn the agent (\`cotal spawn\`) to rewrite it`);
|
|
75
|
+
const { ver: _ver, ...row } = parsed;
|
|
76
|
+
return row;
|
|
77
|
+
}
|
|
78
|
+
/** Every granted row in BOTH spaces, read fresh, tagged with its kind. Missing dirs = EMPTY ledger
|
|
79
|
+
* (deny-all). A row that cannot be read throws (fail closed) rather than being silently omitted
|
|
80
|
+
* from an authorization listing. */
|
|
81
|
+
export function loadActorLedger(dir) {
|
|
82
|
+
const out = [];
|
|
83
|
+
for (const kind of ["interactive", "managed-agent"]) {
|
|
84
|
+
const d = spaceDir(dir, kind);
|
|
85
|
+
if (!existsSync(d))
|
|
86
|
+
continue;
|
|
87
|
+
for (const f of readdirSync(d).filter((f) => f.endsWith(".json")).sort())
|
|
88
|
+
out.push({ ...readRow(join(d, f), kind), kind });
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
/** Find one row in ONE space, reading only that row's file. Undefined = not granted there. A
|
|
93
|
+
* corrupt file for THIS principal throws — deny with the reason, not a miss. */
|
|
94
|
+
function findIn(dir, kind, owner, actor) {
|
|
95
|
+
const p = rowPath(dir, kind, owner, actor);
|
|
96
|
+
if (!existsSync(p))
|
|
97
|
+
return undefined;
|
|
98
|
+
return readRow(p, kind);
|
|
99
|
+
}
|
|
100
|
+
export function findInteractiveActor(dir, owner, actor) {
|
|
101
|
+
return findIn(dir, "interactive", owner, actor);
|
|
102
|
+
}
|
|
103
|
+
export function findManagedActor(dir, owner, actor) {
|
|
104
|
+
return findIn(dir, "managed-agent", owner, actor);
|
|
105
|
+
}
|
|
106
|
+
/** The CONNECT boundary's unified read — a bearer minted by EITHER exchange path authorizes here,
|
|
107
|
+
* so both spaces are consulted. A (owner, actor) present in BOTH is a broken ledger (the writers
|
|
108
|
+
* refuse it; only manual tampering produces it) and DENIES, fail-closed, naming both files. */
|
|
109
|
+
export function findActorUnified(dir, owner, actor) {
|
|
110
|
+
const interactive = findIn(dir, "interactive", owner, actor);
|
|
111
|
+
const managed = findIn(dir, "managed-agent", owner, actor);
|
|
112
|
+
if (interactive && managed)
|
|
113
|
+
throw new Error(`actor "${actor}" is granted in BOTH the interactive and managed row spaces - a broken ledger denies; remove one of ${rowPath(dir, "interactive", owner, actor)} / ${rowPath(dir, "managed-agent", owner, actor)}`);
|
|
114
|
+
if (interactive)
|
|
115
|
+
return { ...interactive, kind: "interactive" };
|
|
116
|
+
if (managed)
|
|
117
|
+
return { ...managed, kind: "managed-agent" };
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
function writeRow(dir, kind, row) {
|
|
121
|
+
const path = rowPath(dir, kind, row.owner, row.actor);
|
|
122
|
+
mkSecretDir(dir);
|
|
123
|
+
mkSecretDir(spaceDir(dir, kind));
|
|
124
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
125
|
+
writeSecretFile(tmp, JSON.stringify({ ver: LEDGER_VER, ...row }, null, 2));
|
|
126
|
+
renameSync(tmp, path);
|
|
127
|
+
}
|
|
128
|
+
function assertRowInputs(row) {
|
|
129
|
+
if (row.parent !== undefined) {
|
|
130
|
+
const parts = row.parent.split(".");
|
|
131
|
+
if (parts.length !== 2)
|
|
132
|
+
throw new Error(`grantActor: parent "${row.parent}" is not a principal (<owner>.<actor>)`);
|
|
133
|
+
assertDerivedOwnerToken(parts[0]);
|
|
134
|
+
assertValidOwnerToken(parts[1]);
|
|
135
|
+
}
|
|
136
|
+
if (!Array.isArray(row.scope) || !Array.isArray(row.allowSubscribe) || !Array.isArray(row.allowPublish))
|
|
137
|
+
throw new Error("grantActor: explicit scope/allowSubscribe/allowPublish lists are required");
|
|
138
|
+
// Policy-grammar validation at the WRITE boundary (mirroring the mint chokepoint's re-assert in
|
|
139
|
+
// core `permissionsFor`): a row's ACL lists are the delegation envelope for everything under it,
|
|
140
|
+
// so a malformed entry (`a.>.b`) must never be stored where containment would later read it.
|
|
141
|
+
for (const ch of [...row.allowSubscribe, ...row.allowPublish])
|
|
142
|
+
assertValidChannel(ch);
|
|
143
|
+
// Scope entries are capability TOKENS (compared by equality, embedded in bearers and repair
|
|
144
|
+
// commands) — an open vocabulary (`spawn`, `admin`, `role:<r>`, …), but a closed grammar: no
|
|
145
|
+
// whitespace, no shell/subject metacharacters, nothing `--scope` CSV can't round-trip.
|
|
146
|
+
for (const s of row.scope)
|
|
147
|
+
if (!/^[A-Za-z0-9_:-]+$/.test(s))
|
|
148
|
+
throw new Error(`grantActor: scope entry "${s}" must be a plain capability token ([A-Za-z0-9_:-])`);
|
|
149
|
+
// The role is embedded in `role:<r>` capability tokens and `svc_<role>` durable names — same
|
|
150
|
+
// closed grammar, validated where it enters the ledger.
|
|
151
|
+
if (row.role !== undefined && !/^[A-Za-z0-9_-]+$/.test(row.role))
|
|
152
|
+
throw new Error(`grantActor: role "${row.role}" must be a plain token ([A-Za-z0-9_-])`);
|
|
153
|
+
}
|
|
154
|
+
/** Grant (or update — an upsert, so re-granting narrows/widens in place) an INTERACTIVE (owner,
|
|
155
|
+
* actor) row. Refuses a token hash (that's the managed space's shape, written only by the spawn
|
|
156
|
+
* path) and refuses to shadow an existing managed-agent row — the two spaces stay disjoint at the
|
|
157
|
+
* write, so the read sides never disambiguate.
|
|
158
|
+
*
|
|
159
|
+
* NOT attenuated by design: interactive rows are OPERATOR-authored (the local `cotal actor grant`
|
|
160
|
+
* CLI is the only writer), and the operator is the authority the envelope rule bottoms out in. An
|
|
161
|
+
* optional `parent` here is an audit link only — do not build a delegated-USER write path on this
|
|
162
|
+
* function; user-authored delegation belongs in the managed space, where the chain walk enforces
|
|
163
|
+
* the envelope (an interactive row that carries a parent still gets link-checked when a managed
|
|
164
|
+
* chain passes THROUGH it). */
|
|
165
|
+
export function grantActor(dir, row) {
|
|
166
|
+
assertRowInputs(row);
|
|
167
|
+
if (row.tokenHash !== undefined)
|
|
168
|
+
throw new Error("grantActor: an interactive grant cannot carry an agent token hash - managed-agent rows are written by the spawn path only");
|
|
169
|
+
const managedRefusal = () => new Error(`actor "${row.actor}" is a managed agent - its grant is owned by the spawn lifecycle (respawn rewrites it, despawn revokes it); pick another actor name for an interactive grant`);
|
|
170
|
+
if (findIn(dir, "managed-agent", row.owner, row.actor))
|
|
171
|
+
throw managedRefusal();
|
|
172
|
+
const full = { ...row, grantedAt: new Date().toISOString() };
|
|
173
|
+
writeRow(dir, "interactive", full);
|
|
174
|
+
// Post-write compensation for the check-then-write race (an operator grant racing a spawn for
|
|
175
|
+
// the same name): if the OTHER space's row appeared meanwhile, remove the just-written row and
|
|
176
|
+
// refuse — at most one row survives, without a cross-process lock protocol. The unified connect
|
|
177
|
+
// read's duplicate deny stays the backstop for a crash landing exactly between these two lines.
|
|
178
|
+
if (findIn(dir, "managed-agent", row.owner, row.actor)) {
|
|
179
|
+
revokeIn(dir, "interactive", row.owner, row.actor);
|
|
180
|
+
throw managedRefusal();
|
|
181
|
+
}
|
|
182
|
+
return full;
|
|
183
|
+
}
|
|
184
|
+
/** Delegation attenuation — the ENVELOPE rule: everything under an owner stays within the
|
|
185
|
+
* spawner's own grant. A spawn-scoped actor can delegate only a SUBSET of what it holds — channel
|
|
186
|
+
* ACLs by NATS-pattern containment ({@link patternInAllow}), capability scope by set inclusion —
|
|
187
|
+
* never more; a spawner whose row carries `admin` is the operator authority and is exempt, and a
|
|
188
|
+
* row with NO parent is an operator/roster boot (the operator is the authority). Enforced at BOTH
|
|
189
|
+
* managed-row boundaries: authorship ({@link grantManagedActor}) and every agent bearer exchange
|
|
190
|
+
* ({@link ledgerAuthorizeAgentExchange}) — so narrowing or revoking a spawner bites its agents at
|
|
191
|
+
* their next refresh (≤ {@link AGENT_BEARER_TTL_SEC}s), instead of leaving them orphaned. */
|
|
192
|
+
function assertWithinSpawnerGrant(dir, row, boundary) {
|
|
193
|
+
// Walk the WHOLE delegation chain, not just the immediate link: per-link containment composes
|
|
194
|
+
// transitively (child ⊆ parent at every hop ⇒ leaf ⊆ root), and every link must still EXIST — a
|
|
195
|
+
// single-hop check would let grandchildren outlive a revoked root (their immediate parent row
|
|
196
|
+
// survives the root's deletion) and let a revoked root's still-live child keep minting. The walk
|
|
197
|
+
// stops at an authority root: an admin-scoped ancestor or a parentless (operator/roster) row.
|
|
198
|
+
// `seen` is the cycle guard — legitimate upserts can close a parent loop (re-parent a root under
|
|
199
|
+
// its own descendant), which must deny, not spin.
|
|
200
|
+
const leaf = row.actor;
|
|
201
|
+
let child = row;
|
|
202
|
+
const seen = new Set([`${row.owner}.${row.actor}`]);
|
|
203
|
+
while (child.parent) {
|
|
204
|
+
const parentKey = child.parent;
|
|
205
|
+
const childKey = `${child.owner}.${child.actor}`;
|
|
206
|
+
const deep = child !== row;
|
|
207
|
+
if (seen.has(parentKey))
|
|
208
|
+
throw new Error(`agent "${leaf}": its delegation chain contains a cycle at "${parentKey}" - a broken ledger denies; repair the parent links (\`cotal actor list\`)`);
|
|
209
|
+
seen.add(parentKey);
|
|
210
|
+
const dot = parentKey.indexOf(".");
|
|
211
|
+
const pOwner = parentKey.slice(0, dot);
|
|
212
|
+
const pActor = parentKey.slice(dot + 1);
|
|
213
|
+
const parent = findActorUnified(dir, pOwner, pActor);
|
|
214
|
+
if (!parent)
|
|
215
|
+
throw new Error(boundary === "spawn"
|
|
216
|
+
? `spawner "${parentKey}"${deep ? ` (an ancestor of "${leaf}")` : ""} has no grant in this space - delegation flows from a granted spawner chain; grant it first (\`cotal actor grant ${pActor} --owner ${pOwner} --scope spawn\`)`
|
|
217
|
+
: `agent "${leaf}": spawner "${parentKey}"${deep ? ` (an ancestor)` : ""} is no longer granted - revoking a spawner revokes everything under it; re-grant it, then respawn (\`cotal spawn\`)`);
|
|
218
|
+
if (parent.scope.includes("admin"))
|
|
219
|
+
return;
|
|
220
|
+
if (child.owner !== pOwner)
|
|
221
|
+
throw new Error(`agent "${childKey}" cannot be delegated by spawner "${parentKey}" of a different owner - cross-owner spawns are operator (admin) launches only`);
|
|
222
|
+
const overScope = child.scope.filter((s) => !parent.scope.includes(s));
|
|
223
|
+
const overSub = child.allowSubscribe.filter((ch) => !patternInAllow(parent.allowSubscribe, ch));
|
|
224
|
+
const overPub = child.allowPublish.filter((ch) => !patternInAllow(parent.allowPublish, ch));
|
|
225
|
+
// A role is RECEIVE reach (bind/consume the shared `svc_<role>` task queue), so it is a
|
|
226
|
+
// delegated capability like any other: the spawner's scope must carry `role:<r>` to hand it
|
|
227
|
+
// down. Rides the scope list — no extra row field, and scope's own per-link inclusion makes
|
|
228
|
+
// role delegation transitive for free.
|
|
229
|
+
const needRole = child.role && !parent.scope.includes(`role:${child.role}`) ? `role:${child.role}` : undefined;
|
|
230
|
+
if (overScope.length || overSub.length || overPub.length || needRole) {
|
|
231
|
+
const wrongs = [
|
|
232
|
+
overScope.length ? `scope [${overScope.join(", ")}] beyond [${parent.scope.join(", ") || "none"}]` : "",
|
|
233
|
+
overSub.length ? `read [${overSub.join(", ")}] beyond [${parent.allowSubscribe.join(", ") || "none"}]` : "",
|
|
234
|
+
overPub.length ? `post [${overPub.join(", ")}] beyond [${parent.allowPublish.join(", ") || "none"}]` : "",
|
|
235
|
+
needRole ? `role "${child.role}" beyond scope [${parent.scope.join(", ") || "none"}] (a role is delegated with the \`${needRole}\` capability)` : "",
|
|
236
|
+
].filter(Boolean);
|
|
237
|
+
const widen = widenGrantCommand(pOwner, pActor, parent, [...overScope, ...(needRole ? [needRole] : [])], overSub, overPub);
|
|
238
|
+
const who = deep ? `agent "${leaf}": its ancestor "${childKey}"` : `agent "${leaf}"`;
|
|
239
|
+
throw new Error((boundary === "spawn"
|
|
240
|
+
? `${who} would exceed its spawner's grant - delegation only narrows: `
|
|
241
|
+
: `${who} exceeds its spawner's CURRENT grant (narrowed since spawn): `) +
|
|
242
|
+
wrongs.join("; ") +
|
|
243
|
+
` - the mesh operator widens the spawner with \`${widen}\`` +
|
|
244
|
+
(boundary === "spawn" ? ", then respawn" : ", or respawn within it"));
|
|
245
|
+
}
|
|
246
|
+
child = parent;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** The exact re-grant that would admit the refused delegation: the spawner's CURRENT row with the
|
|
250
|
+
* missing entries unioned in. A grant is an upsert of the WHOLE row, so the repair must carry
|
|
251
|
+
* every field — a bare `--allow-subscribe` would silently narrow the rest. */
|
|
252
|
+
function widenGrantCommand(pOwner, pActor, parent, addScope, addSub, addPub) {
|
|
253
|
+
const union = (base, add) => [...new Set([...base, ...add])];
|
|
254
|
+
// The command is offered for copy-paste into a shell, so every free-form field is POSIX
|
|
255
|
+
// single-quote escaped — a row label like `x'; rm -rf ~` must never become a live command.
|
|
256
|
+
const shq = (s) => `'${s.replaceAll("'", `'\\''`)}'`;
|
|
257
|
+
const parts = [`cotal actor grant ${pActor} --owner ${pOwner}`];
|
|
258
|
+
const scope = union(parent.scope, addScope);
|
|
259
|
+
if (scope.length)
|
|
260
|
+
parts.push(`--scope ${shq(scope.join(","))}`);
|
|
261
|
+
parts.push(`--allow-subscribe ${shq(union(parent.allowSubscribe, addSub).join(","))}`);
|
|
262
|
+
parts.push(`--allow-publish ${shq(union(parent.allowPublish, addPub).join(","))}`);
|
|
263
|
+
if (parent.role)
|
|
264
|
+
parts.push(`--role ${shq(parent.role)}`);
|
|
265
|
+
if (parent.label)
|
|
266
|
+
parts.push(`--label ${shq(parent.label)}`);
|
|
267
|
+
return parts.join(" ");
|
|
268
|
+
}
|
|
269
|
+
/** Author a MANAGED-AGENT row (spawn path only): the same upsert semantics, in the managed space,
|
|
270
|
+
* with the secret hash REQUIRED — and never shadowing an interactive row. */
|
|
271
|
+
export function grantManagedActor(dir, row) {
|
|
272
|
+
assertRowInputs(row);
|
|
273
|
+
if (!/^[0-9a-f]{64}$/.test(row.tokenHash))
|
|
274
|
+
throw new Error("grantManagedActor: tokenHash must be a sha256 hex digest");
|
|
275
|
+
assertWithinSpawnerGrant(dir, row, "spawn");
|
|
276
|
+
const shadowRefusal = () => new Error(`actor "${row.actor}" already has an interactive grant - a managed agent cannot shadow it; revoke it first (\`cotal actor revoke ${row.actor}\`) or spawn under another name`);
|
|
277
|
+
if (findIn(dir, "interactive", row.owner, row.actor))
|
|
278
|
+
throw shadowRefusal();
|
|
279
|
+
const full = { ...row, grantedAt: new Date().toISOString() };
|
|
280
|
+
writeRow(dir, "managed-agent", full);
|
|
281
|
+
// Symmetric post-write compensation (see grantActor) — at most one surviving row per principal.
|
|
282
|
+
if (findIn(dir, "interactive", row.owner, row.actor)) {
|
|
283
|
+
revokeIn(dir, "managed-agent", row.owner, row.actor);
|
|
284
|
+
throw shadowRefusal();
|
|
285
|
+
}
|
|
286
|
+
return full;
|
|
287
|
+
}
|
|
288
|
+
/** Revoke a row in one space. Returns false when there was nothing to revoke. NOTE: this stops NEW
|
|
289
|
+
* bearer mints and NEW connects immediately (both boundaries read fresh); an ALREADY-LIVE
|
|
290
|
+
* connection dies at its bearer-bound JWT expiry — live eviction is the D5 lever, not the ledger's. */
|
|
291
|
+
export function revokeActor(dir, owner, actor) {
|
|
292
|
+
return revokeIn(dir, "interactive", owner, actor);
|
|
293
|
+
}
|
|
294
|
+
export function revokeManagedActor(dir, owner, actor) {
|
|
295
|
+
return revokeIn(dir, "managed-agent", owner, actor);
|
|
296
|
+
}
|
|
297
|
+
function revokeIn(dir, kind, owner, actor) {
|
|
298
|
+
const p = rowPath(dir, kind, owner, actor);
|
|
299
|
+
if (!existsSync(p))
|
|
300
|
+
return false;
|
|
301
|
+
rmSync(p);
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
/** The IdP bridge's `authorizeActor` hook (bearer-MINT boundary) — INTERACTIVE rows only, by
|
|
305
|
+
* construction. A name that exists only as a managed agent gets the exact managed-path answer
|
|
306
|
+
* (never "not granted", which would read as a permissions problem, and never a mint). */
|
|
307
|
+
export function ledgerAuthorizeGrant(dir) {
|
|
308
|
+
return (owner, actor) => {
|
|
309
|
+
const row = findInteractiveActor(dir, owner, actor);
|
|
310
|
+
if (!row) {
|
|
311
|
+
if (findManagedActor(dir, owner, actor))
|
|
312
|
+
throw new Error(`actor "${actor}" is a managed agent - it authenticates with its own spawn-time secret; interact with it via the mesh, or respawn it with \`cotal spawn\``);
|
|
313
|
+
throw new Error(`actor "${actor}" is not granted for this user - the mesh operator lets them in with \`cotal actor grant ${actor} --owner ${owner}\` (or --sub <their IdP subject>, printed by their \`cotal login\`)`);
|
|
314
|
+
}
|
|
315
|
+
return { scope: row.scope, ...(row.parent ? { parent: row.parent } : {}) };
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/** The callout's `authorizeActor` hook (CONNECT boundary): the row must still exist — in EITHER
|
|
319
|
+
* space (bearers from both exchange paths connect here) — and the bearer's `act.scope` must sit
|
|
320
|
+
* within the row's CURRENT scope — a bearer minted before a scope narrowing is refused at
|
|
321
|
+
* connect, not honored until expiry. */
|
|
322
|
+
export function ledgerAuthorizeConnect(dir) {
|
|
323
|
+
return (t) => {
|
|
324
|
+
const row = findActorUnified(dir, t.owner, t.act.actor);
|
|
325
|
+
if (!row)
|
|
326
|
+
throw new Error(`actor "${t.act.actor}" is not (or no longer) granted for this owner`);
|
|
327
|
+
const granted = new Set(row.scope);
|
|
328
|
+
for (const s of t.act.scope ?? [])
|
|
329
|
+
if (!granted.has(s))
|
|
330
|
+
throw new Error(`bearer scope "${s}" exceeds the actor's current grant - re-login to mint a fresh bearer`);
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
/** The channel-ACL resolver over this ledger — the ONE resolver both the callout permission
|
|
334
|
+
* supplier uses today and the IdP bridge shares when it needs channel authority (gate 4's "shared
|
|
335
|
+
* by both"). Serves bearers from both spaces (unified read). A missing row throws (the callout
|
|
336
|
+
* turns it into a signed deny). */
|
|
337
|
+
export function ledgerAclResolver(dir) {
|
|
338
|
+
return (t) => {
|
|
339
|
+
const row = findActorUnified(dir, t.owner, t.act.actor);
|
|
340
|
+
if (!row)
|
|
341
|
+
throw new Error(`actor "${t.act.actor}" has no ledger row - no channel ACL to mint`);
|
|
342
|
+
return { allowSubscribe: row.allowSubscribe, allowPublish: row.allowPublish, ...(row.role ? { role: row.role } : {}) };
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
/** Ensure a filename-hostile owner/actor can never traverse (defense-in-depth behind the grammar
|
|
346
|
+
* asserts in {@link rowPath}) — exported for the smoke that pins the property. */
|
|
347
|
+
export function ledgerRowFilename(owner, actor) {
|
|
348
|
+
assertDerivedOwnerToken(owner);
|
|
349
|
+
assertValidOwnerToken(actor);
|
|
350
|
+
return `${owner}.${actor}.json`;
|
|
351
|
+
}
|
|
352
|
+
/** Where the per-row files live under a provider state dir (for tooling/tests). */
|
|
353
|
+
export function actorLedgerDir(dir) {
|
|
354
|
+
return spaceDir(dir, "interactive");
|
|
355
|
+
}
|
|
356
|
+
/** The managed-agent row space (for tooling/tests). */
|
|
357
|
+
export function managedActorLedgerDir(dir) {
|
|
358
|
+
return spaceDir(dir, "managed-agent");
|
|
359
|
+
}
|
|
360
|
+
/** Agent bearers are SHORT by design — a spawned agent's endpoint re-exchanges ahead of every
|
|
361
|
+
* expiry, so revocation (row deletion) bites a live connection within this window even before
|
|
362
|
+
* live eviction lands. There is no upstream IdP proof to cap to; this constant is that cap. */
|
|
363
|
+
export const AGENT_BEARER_TTL_SEC = 300;
|
|
364
|
+
/** Generate a fresh per-agent exchange secret (returned to the spawner ONCE) + its ledger hash. */
|
|
365
|
+
export function newActorToken() {
|
|
366
|
+
const actorToken = randomBytes(32).toString("base64url");
|
|
367
|
+
return { actorToken, tokenHash: hashActorToken(actorToken) };
|
|
368
|
+
}
|
|
369
|
+
export function hashActorToken(actorToken) {
|
|
370
|
+
return createHash("sha256").update(actorToken, "utf8").digest("hex");
|
|
371
|
+
}
|
|
372
|
+
/** Authorize one AGENT exchange (`{ owner, actor, actorToken }`, no IdP proof) — MANAGED rows only,
|
|
373
|
+
* by construction. The presented secret must hash to the row's (constant-time over the two fixed
|
|
374
|
+
* 32-byte digests). Every failure is the SAME sentence — a prober must not learn whether an
|
|
375
|
+
* (owner, actor) row exists, lives in the other space, or got the secret wrong (the sentence
|
|
376
|
+
* still names the operator's likely fix: respawn). */
|
|
377
|
+
export function ledgerAuthorizeAgentExchange(dir, owner, actor, actorToken) {
|
|
378
|
+
const deny = () => new Error("agent exchange refused: unknown agent or wrong secret - if this agent should exist, respawn it (`cotal spawn`) to rotate its grant");
|
|
379
|
+
let row;
|
|
380
|
+
try {
|
|
381
|
+
row = findManagedActor(dir, owner, actor);
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
throw deny(); // a corrupt row denies exactly like a missing one on this unauthenticated surface
|
|
385
|
+
}
|
|
386
|
+
if (!row?.tokenHash)
|
|
387
|
+
throw deny();
|
|
388
|
+
const presented = Buffer.from(hashActorToken(actorToken), "hex");
|
|
389
|
+
const stored = Buffer.from(row.tokenHash, "hex");
|
|
390
|
+
if (presented.length !== stored.length || !timingSafeEqual(presented, stored))
|
|
391
|
+
throw deny();
|
|
392
|
+
// Post-authentication (the secret matched), so a SPECIFIC refusal is safe on this surface — and
|
|
393
|
+
// required: rechecking the envelope here makes it a STANDING invariant (an operator narrowing or
|
|
394
|
+
// revoking the spawner bites its agents at their next ≤ AGENT_BEARER_TTL_SEC refresh), the same
|
|
395
|
+
// posture as the connect boundary's "bearer scope vs CURRENT row" check.
|
|
396
|
+
assertWithinSpawnerGrant(dir, row, "exchange");
|
|
397
|
+
return { scope: row.scope, ...(row.parent ? { parent: row.parent } : {}) };
|
|
398
|
+
}
|
|
399
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"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"}
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** A cached IdP login. `token` is the IdP session bearer (Better Auth: `session.token`) — an
|
|
2
|
+
* opaque revocable handle, never a JWT. `expiresAt` (unix seconds) is advisory for messages;
|
|
3
|
+
* the server is the authority (a revoked session dies earlier). */
|
|
4
|
+
export interface IdpSession {
|
|
5
|
+
token: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
/** The IdP subject this session proved at login (display + local owner derivation). Absent only
|
|
8
|
+
* in caches written by older builds — consumers that need it fail loud naming `cotal login`. */
|
|
9
|
+
sub?: string;
|
|
10
|
+
}
|
|
11
|
+
/** What the human must be shown to approve the sign-in. */
|
|
12
|
+
export interface DeviceLoginPrompt {
|
|
13
|
+
verificationUri: string;
|
|
14
|
+
verificationUriComplete: string;
|
|
15
|
+
userCode: string;
|
|
16
|
+
expiresInSec: number;
|
|
17
|
+
}
|
|
18
|
+
export interface DeviceLoginOpts {
|
|
19
|
+
/** The IdP auth base URL (Better Auth: `<origin>/api/auth`). */
|
|
20
|
+
idpUrl: string;
|
|
21
|
+
/** The OAuth client id this CLI presents; the IdP may pin it via its validateClient hook. */
|
|
22
|
+
clientId: string;
|
|
23
|
+
/** Shows the human the verification URL + code. Called exactly once, before polling starts. */
|
|
24
|
+
onPrompt: (prompt: DeviceLoginPrompt) => void;
|
|
25
|
+
}
|
|
26
|
+
/** Normalize + guard the IdP base URL: https (or loopback http for dev), no query/hash, no
|
|
27
|
+
* trailing slash — the normalized string is also the session-cache key, so `…/api/auth` and
|
|
28
|
+
* `…/api/auth/` must land on the same entry. */
|
|
29
|
+
export declare function normalizeIdpUrl(idpUrl: string): string;
|
|
30
|
+
/** Best-effort reachability + shape check of an IdP's JWKS. Used at the FIRST `--user-auth` enable
|
|
31
|
+
* so a dead or typo'd `--idp` fails loud BEFORE a space is provisioned around it, instead of only
|
|
32
|
+
* surfacing far away at the first user connect (the pin is written but the JWKS is fetched lazily).
|
|
33
|
+
* Normalizes the URL exactly as the pin does (`<base>/jwks`). Throws a legible sentence on an
|
|
34
|
+
* unreachable host, a non-2xx, or a body that is not a JWKS key set. */
|
|
35
|
+
export declare function probeIdpJwks(idpUrl: string): Promise<void>;
|
|
36
|
+
/** Sign in via the RFC 8628 device flow and return the IdP session. Fail-loud on every non-happy
|
|
37
|
+
* path: a deny, an expiry, or an unknown poll error is a thrown human sentence, never a retry
|
|
38
|
+
* loop. Blocks (polling at the server's stated interval) until the human approves. */
|
|
39
|
+
export declare function deviceLogin(opts: DeviceLoginOpts): Promise<IdpSession>;
|
|
40
|
+
/** Fetch a fresh short-lived IdP user JWT for the cached session — the input to the bridge
|
|
41
|
+
* exchange. A 401 means the session was revoked or expired at the IdP: the error says exactly
|
|
42
|
+
* how to recover. The JWT is returned, never stored. */
|
|
43
|
+
export declare function fetchIdpJwt(idpUrl: string, sessionToken: string): Promise<string>;
|
|
44
|
+
/** The whole login operation, in the only safe order: device sign-in, then PROVE the session
|
|
45
|
+
* mints a user JWT, and only then persist it. A session that can't produce a JWT must never
|
|
46
|
+
* land on disk — it would pass {@link requireIdpSession}'s no-fallback gate as a dud and defer
|
|
47
|
+
* the failure to some later connect. Returns the session plus the JWT's `sub`, and a human
|
|
48
|
+
* `label` (email/name/preferred_username when the IdP mints one) — BOTH display-only: the
|
|
49
|
+
* operator must be able to read WHICH human signed in, but verification is the bridge/callout's
|
|
50
|
+
* job, server-side. */
|
|
51
|
+
export declare function establishIdpSession(opts: DeviceLoginOpts & {
|
|
52
|
+
dir: string;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
session: IdpSession;
|
|
55
|
+
sub: string;
|
|
56
|
+
label?: string;
|
|
57
|
+
}>;
|
|
58
|
+
/** Revoke the session server-side (sign out). A 401 back means the session is already dead —
|
|
59
|
+
* the goal state, treated as success; any other failure is thrown because a still-live
|
|
60
|
+
* server-side session is a real leak the operator must hear about. */
|
|
61
|
+
export declare function revokeIdpSession(idpUrl: string, sessionToken: string): Promise<void>;
|
|
62
|
+
export declare function loadIdpSession(dir: string, idpUrl: string): IdpSession | undefined;
|
|
63
|
+
export declare function saveIdpSession(dir: string, idpUrl: string, session: IdpSession): void;
|
|
64
|
+
/** Remove the cached session. Returns false when there was nothing to remove. */
|
|
65
|
+
export declare function deleteIdpSession(dir: string, idpUrl: string): boolean;
|
|
66
|
+
/** The no-fallback gate the user-mode connect path consumes: a session or a thrown sentence that
|
|
67
|
+
* says exactly how to get one. There is no anonymous degradation when a space requires a user. */
|
|
68
|
+
export declare function requireIdpSession(dir: string, idpUrl: string): IdpSession;
|
|
69
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAkCA;;oEAEoE;AACpE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB;qGACiG;IACjG,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,2DAA2D;AAC3D,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,QAAQ,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC/C;AAED;;iDAEiD;AACjD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAsBtD;AAqDD;;;;yEAIyE;AACzE,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhE;AAcD;;uFAEuF;AACvF,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAwF5E;AAED;;yDAEyD;AACzD,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWvF;AAED;;;;;;wBAMwB;AACxB,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,eAAe,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAAC;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB/D;AAED;;uEAEuE;AACvE,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS1F;AAmCD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAUlF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CASrF;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQrE;AAED;mGACmG;AACnG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAQzE"}
|