agent-authority 0.1.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/CHANGELOG.md +118 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +91 -0
- package/README.md +553 -0
- package/dist/a2a.d.ts +73 -0
- package/dist/a2a.d.ts.map +1 -0
- package/dist/a2a.js +117 -0
- package/dist/a2a.js.map +1 -0
- package/dist/audit.d.ts +12 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +52 -0
- package/dist/audit.js.map +1 -0
- package/dist/behalf.d.ts +173 -0
- package/dist/behalf.d.ts.map +1 -0
- package/dist/behalf.js +475 -0
- package/dist/behalf.js.map +1 -0
- package/dist/capability.d.ts +56 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +176 -0
- package/dist/capability.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +273 -0
- package/dist/cli.js.map +1 -0
- package/dist/control-plane.d.ts +57 -0
- package/dist/control-plane.d.ts.map +1 -0
- package/dist/control-plane.js +332 -0
- package/dist/control-plane.js.map +1 -0
- package/dist/crypto.d.ts +68 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +105 -0
- package/dist/crypto.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/lint.d.ts +17 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +75 -0
- package/dist/lint.js.map +1 -0
- package/dist/mandate.d.ts +99 -0
- package/dist/mandate.d.ts.map +1 -0
- package/dist/mandate.js +141 -0
- package/dist/mandate.js.map +1 -0
- package/dist/mcp-server.d.ts +26 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +111 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp.d.ts +63 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +123 -0
- package/dist/mcp.js.map +1 -0
- package/dist/persist.d.ts +51 -0
- package/dist/persist.d.ts.map +1 -0
- package/dist/persist.js +150 -0
- package/dist/persist.js.map +1 -0
- package/dist/quickstart.d.ts +63 -0
- package/dist/quickstart.d.ts.map +1 -0
- package/dist/quickstart.js +171 -0
- package/dist/quickstart.js.map +1 -0
- package/dist/remote.d.ts +93 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +120 -0
- package/dist/remote.js.map +1 -0
- package/dist/seal.d.ts +12 -0
- package/dist/seal.d.ts.map +1 -0
- package/dist/seal.js +96 -0
- package/dist/seal.js.map +1 -0
- package/dist/store.d.ts +119 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +139 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +173 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/llms.txt +106 -0
- package/package.json +107 -0
- package/schemas/capability.schema.json +14 -0
- package/schemas/mandate.schema.json +68 -0
- package/vectors/mandate-vector.json +63 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { CapabilityParseError } from "./errors.js";
|
|
2
|
+
const OP_RE = "<=|>=|<|>|=";
|
|
3
|
+
const MAIN_RE = new RegExp(`^([^:\\s]+):([^<>=\\s]+)(?:(${OP_RE})([0-9]*\\.?[0-9]+))?$`);
|
|
4
|
+
const RATE_RE = new RegExp(`^rate(${OP_RE})([0-9]*\\.?[0-9]+)(?:\\/([smhd]))?$`);
|
|
5
|
+
/** Parse a capability string into structured form. Throws on malformed input. */
|
|
6
|
+
export function parse(raw) {
|
|
7
|
+
const trimmed = raw.trim();
|
|
8
|
+
if (trimmed.length === 0) {
|
|
9
|
+
throw new CapabilityParseError(raw, "empty");
|
|
10
|
+
}
|
|
11
|
+
if (trimmed === "*") {
|
|
12
|
+
return { raw: trimmed, wildcard: true, verb: "*", resource: "*" };
|
|
13
|
+
}
|
|
14
|
+
const parts = trimmed.split(/\s+/);
|
|
15
|
+
const main = parts[0];
|
|
16
|
+
const m = MAIN_RE.exec(main);
|
|
17
|
+
if (!m) {
|
|
18
|
+
throw new CapabilityParseError(raw, 'expected "<verb>:<resource>" optionally with a constraint');
|
|
19
|
+
}
|
|
20
|
+
const cap = {
|
|
21
|
+
raw: trimmed,
|
|
22
|
+
wildcard: false,
|
|
23
|
+
verb: m[1],
|
|
24
|
+
resource: m[2],
|
|
25
|
+
};
|
|
26
|
+
if (m[3]) {
|
|
27
|
+
cap.amount = { op: m[3], value: Number(m[4]) };
|
|
28
|
+
}
|
|
29
|
+
for (const extra of parts.slice(1)) {
|
|
30
|
+
const r = RATE_RE.exec(extra);
|
|
31
|
+
if (!r) {
|
|
32
|
+
throw new CapabilityParseError(raw, `unrecognized constraint "${extra}"`);
|
|
33
|
+
}
|
|
34
|
+
cap.rate = { op: r[1], value: Number(r[2]), per: r[3] ?? "h" };
|
|
35
|
+
}
|
|
36
|
+
return cap;
|
|
37
|
+
}
|
|
38
|
+
/** Window length in milliseconds for a rate unit. */
|
|
39
|
+
export function windowMs(per) {
|
|
40
|
+
switch (per) {
|
|
41
|
+
case "s":
|
|
42
|
+
return 1000;
|
|
43
|
+
case "m":
|
|
44
|
+
return 60_000;
|
|
45
|
+
case "h":
|
|
46
|
+
return 3_600_000;
|
|
47
|
+
case "d":
|
|
48
|
+
return 86_400_000;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function applyOp(value, op, limit) {
|
|
52
|
+
switch (op) {
|
|
53
|
+
case "<=":
|
|
54
|
+
return value <= limit;
|
|
55
|
+
case ">=":
|
|
56
|
+
return value >= limit;
|
|
57
|
+
case "<":
|
|
58
|
+
return value < limit;
|
|
59
|
+
case ">":
|
|
60
|
+
return value > limit;
|
|
61
|
+
case "=":
|
|
62
|
+
return value === limit;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Does grant's resource path cover the request's? Segment-prefix + wildcard. */
|
|
66
|
+
function resourceCovers(grant, request) {
|
|
67
|
+
if (grant === "*" || grant === request)
|
|
68
|
+
return true;
|
|
69
|
+
if (grant.endsWith("/*")) {
|
|
70
|
+
const base = grant.slice(0, -2);
|
|
71
|
+
return request === base || request.startsWith(base + "/");
|
|
72
|
+
}
|
|
73
|
+
// Bare prefix segment: "repo" covers "repo/acme-app".
|
|
74
|
+
return request.startsWith(grant + "/");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Does the `grant` capability permit the `request` action?
|
|
78
|
+
*
|
|
79
|
+
* The request is the concrete action being attempted (e.g. `spend:usd=20`); the
|
|
80
|
+
* grant is the authority held (e.g. `spend:usd<=50`). Rate limits are *not*
|
|
81
|
+
* evaluated here — they require call history and are enforced by the engine.
|
|
82
|
+
*/
|
|
83
|
+
export function satisfies(grant, request) {
|
|
84
|
+
if (grant.wildcard)
|
|
85
|
+
return true;
|
|
86
|
+
if (request.wildcard)
|
|
87
|
+
return false; // can't request unbounded against a bounded grant
|
|
88
|
+
if (grant.verb !== request.verb)
|
|
89
|
+
return false;
|
|
90
|
+
if (!resourceCovers(grant.resource, request.resource))
|
|
91
|
+
return false;
|
|
92
|
+
if (grant.amount) {
|
|
93
|
+
// The grant imposes a quantitative cap; the request must name an amount
|
|
94
|
+
// that falls within it.
|
|
95
|
+
if (!request.amount)
|
|
96
|
+
return false;
|
|
97
|
+
if (!applyOp(request.amount.value, grant.amount.op, grant.amount.value)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
/** Convenience: parse both sides then check satisfaction. */
|
|
104
|
+
export function permits(grant, request) {
|
|
105
|
+
return satisfies(parse(grant), parse(request));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Is every capability in `child` covered by some capability in `parent`?
|
|
109
|
+
* Used to reject widening at attenuation time (the chain enforces it too, but
|
|
110
|
+
* this gives a clear, early error).
|
|
111
|
+
*/
|
|
112
|
+
export function isNarrowing(parent, child) {
|
|
113
|
+
const parents = parent.map(parse);
|
|
114
|
+
for (const c of child) {
|
|
115
|
+
const childCap = parse(c);
|
|
116
|
+
const covered = parents.some((p) => coversCapability(p, childCap));
|
|
117
|
+
if (!covered)
|
|
118
|
+
return { ok: false, offending: c };
|
|
119
|
+
}
|
|
120
|
+
return { ok: true };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Is `child`'s quantitative bound a genuine tightening of `grant`'s, in the same
|
|
124
|
+
* direction? An upper bound (`<=`/`<`) may only be narrowed by another upper
|
|
125
|
+
* bound or an exact value within it; a lower bound (`>=`/`>`) likewise; `=` must
|
|
126
|
+
* match. This rejects direction flips like narrowing `usd<=50` to `usd>=10`.
|
|
127
|
+
*/
|
|
128
|
+
function amountNarrows(grant, child) {
|
|
129
|
+
const isUpper = (op) => op === "<=" || op === "<";
|
|
130
|
+
const isLower = (op) => op === ">=" || op === ">";
|
|
131
|
+
if (grant.op === "=")
|
|
132
|
+
return child.op === "=" && child.value === grant.value;
|
|
133
|
+
if (isUpper(grant.op)) {
|
|
134
|
+
if (!isUpper(child.op) && child.op !== "=")
|
|
135
|
+
return false;
|
|
136
|
+
return applyOp(child.value, grant.op, grant.value);
|
|
137
|
+
}
|
|
138
|
+
if (isLower(grant.op)) {
|
|
139
|
+
if (!isLower(child.op) && child.op !== "=")
|
|
140
|
+
return false;
|
|
141
|
+
return applyOp(child.value, grant.op, grant.value);
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Does grant cover a *narrower capability* (not a concrete action)? This is the
|
|
147
|
+
* attenuation check: e.g. `spend:usd<=50` covers `spend:usd<=20` but not
|
|
148
|
+
* `spend:usd<=80`, and `read:calendar` covers `read:calendar`.
|
|
149
|
+
*/
|
|
150
|
+
function coversCapability(grant, child) {
|
|
151
|
+
if (grant.wildcard)
|
|
152
|
+
return true;
|
|
153
|
+
if (child.wildcard)
|
|
154
|
+
return false;
|
|
155
|
+
if (grant.verb !== child.verb)
|
|
156
|
+
return false;
|
|
157
|
+
if (!resourceCovers(grant.resource, child.resource))
|
|
158
|
+
return false;
|
|
159
|
+
if (grant.amount) {
|
|
160
|
+
if (!child.amount)
|
|
161
|
+
return false; // child must also be bounded
|
|
162
|
+
// The child must narrow in the SAME direction as the grant — a `<=` cap may
|
|
163
|
+
// only be tightened by another upper bound (or `=`), never flipped to `>=`.
|
|
164
|
+
if (!amountNarrows(grant.amount, child.amount))
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
if (grant.rate) {
|
|
168
|
+
if (!child.rate)
|
|
169
|
+
return false;
|
|
170
|
+
if (child.rate.value / windowMs(child.rate.per) > grant.rate.value / windowMs(grant.rate.per)) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
5
|
+
import { createBehalf } from "./behalf.js";
|
|
6
|
+
import { newKeyPair, exportPublicKey, exportPrivateKey, importPublicKey, importPrivateKey, } from "./crypto.js";
|
|
7
|
+
import { FileRevocationStore, FileAuditStore } from "./persist.js";
|
|
8
|
+
import { AuthorizationError } from "./errors.js";
|
|
9
|
+
import { lint } from "./lint.js";
|
|
10
|
+
import { generateQuickstart, findSurface, listSurfaces, } from "./quickstart.js";
|
|
11
|
+
/**
|
|
12
|
+
* `agent-authority` CLI — grant, inspect, authorize, revoke, and audit mandates from the
|
|
13
|
+
* terminal. State (issuer keypair, revocation list, audit log) lives under
|
|
14
|
+
* $BEHALF_HOME (default ~/.behalf), so mandates issued in one invocation can be
|
|
15
|
+
* checked and revoked in the next.
|
|
16
|
+
*/
|
|
17
|
+
const HOME = process.env.BEHALF_HOME ?? join(homedir(), ".behalf");
|
|
18
|
+
const KEY_FILE = join(HOME, "key.json");
|
|
19
|
+
const REV_FILE = join(HOME, "revocations.json");
|
|
20
|
+
const AUDIT_FILE = join(HOME, "audit.jsonl");
|
|
21
|
+
function loadEngine() {
|
|
22
|
+
if (!existsSync(HOME))
|
|
23
|
+
mkdirSync(HOME, { recursive: true });
|
|
24
|
+
let keyPair;
|
|
25
|
+
if (existsSync(KEY_FILE)) {
|
|
26
|
+
const { priv, pub } = JSON.parse(readFileSync(KEY_FILE, "utf8"));
|
|
27
|
+
keyPair = { privateKey: importPrivateKey(priv, pub), publicKey: importPublicKey(pub) };
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
keyPair = newKeyPair();
|
|
31
|
+
writeFileSync(KEY_FILE, JSON.stringify({
|
|
32
|
+
priv: exportPrivateKey(keyPair.privateKey),
|
|
33
|
+
pub: exportPublicKey(keyPair.publicKey),
|
|
34
|
+
}), "utf8");
|
|
35
|
+
}
|
|
36
|
+
return createBehalf({
|
|
37
|
+
rootKeyPair: keyPair,
|
|
38
|
+
revocations: new FileRevocationStore(REV_FILE),
|
|
39
|
+
audit: new FileAuditStore(AUDIT_FILE),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Tiny flag parser: collects --flag value, repeats into arrays, _ for positionals. */
|
|
43
|
+
function parseArgs(argv) {
|
|
44
|
+
const out = { _: [] };
|
|
45
|
+
for (let i = 0; i < argv.length; i++) {
|
|
46
|
+
const a = argv[i];
|
|
47
|
+
if (a.startsWith("--")) {
|
|
48
|
+
const key = a.slice(2);
|
|
49
|
+
const val = argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[++i] : "true";
|
|
50
|
+
const existing = out[key];
|
|
51
|
+
if (existing === undefined)
|
|
52
|
+
out[key] = val;
|
|
53
|
+
else if (Array.isArray(existing))
|
|
54
|
+
existing.push(val);
|
|
55
|
+
else
|
|
56
|
+
out[key] = [existing, val];
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
out._.push(a);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function asArray(v) {
|
|
65
|
+
if (v === undefined)
|
|
66
|
+
return [];
|
|
67
|
+
return Array.isArray(v) ? v : [v];
|
|
68
|
+
}
|
|
69
|
+
const USAGE = `agent-authority — agent authority CLI
|
|
70
|
+
|
|
71
|
+
Usage:
|
|
72
|
+
agent-authority pubkey
|
|
73
|
+
agent-authority grant --principal <id> --agent <id> --can <cap> [--can <cap> ...] --expires <dur>
|
|
74
|
+
agent-authority inspect <mandate>
|
|
75
|
+
agent-authority authorize <mandate> <action>
|
|
76
|
+
agent-authority revoke <mandate-id>
|
|
77
|
+
agent-authority audit <mandate-id>
|
|
78
|
+
agent-authority lint <cap> [<cap> ...]
|
|
79
|
+
agent-authority quickstart <surface> (e.g. claude-code, cursor, copilot, gpt, gemini)
|
|
80
|
+
agent-authority quickstart --list (list every surface; any AI is configurable)
|
|
81
|
+
|
|
82
|
+
State dir: ${HOME} (override with $BEHALF_HOME)`;
|
|
83
|
+
/** Commands that need no key store or engine: lint, quickstart. */
|
|
84
|
+
function runStateless(cmd, args) {
|
|
85
|
+
if (cmd === "lint") {
|
|
86
|
+
const caps = args._;
|
|
87
|
+
if (caps.length === 0) {
|
|
88
|
+
console.error("lint requires at least one capability");
|
|
89
|
+
return 2;
|
|
90
|
+
}
|
|
91
|
+
const findings = lint(caps);
|
|
92
|
+
for (const f of findings) {
|
|
93
|
+
console.log(`${f.level.toUpperCase().padEnd(5)} ${f.capability} ${f.message}`);
|
|
94
|
+
}
|
|
95
|
+
const hasProblem = findings.some((f) => f.level !== "info");
|
|
96
|
+
console.log(`\n${findings.length} finding(s)`);
|
|
97
|
+
return hasProblem ? 1 : 0;
|
|
98
|
+
}
|
|
99
|
+
// quickstart
|
|
100
|
+
const extra = loadCustomSurfaces(args.surfaces);
|
|
101
|
+
if (args.list !== undefined || args._[0] === "list") {
|
|
102
|
+
for (const s of listSurfaces(extra))
|
|
103
|
+
console.log(`${s.id.padEnd(16)} ${s.name}`);
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
const id = args._[0];
|
|
107
|
+
if (!id) {
|
|
108
|
+
console.error("quickstart requires a surface id, or --list. e.g. agent-authority quickstart claude-code");
|
|
109
|
+
return 2;
|
|
110
|
+
}
|
|
111
|
+
const surface = findSurface(id, extra);
|
|
112
|
+
if (!surface) {
|
|
113
|
+
console.error(`unknown surface "${id}". Run: agent-authority quickstart --list`);
|
|
114
|
+
return 2;
|
|
115
|
+
}
|
|
116
|
+
const command = args.local !== undefined ? "node" : args.command ?? undefined;
|
|
117
|
+
const cliArgs = args.local !== undefined ? ["dist/mcp-server.js"] : asArray(args.arg);
|
|
118
|
+
const env = {};
|
|
119
|
+
for (const e of asArray(args.env)) {
|
|
120
|
+
const i = e.indexOf("=");
|
|
121
|
+
if (i > 0)
|
|
122
|
+
env[e.slice(0, i)] = e.slice(i + 1);
|
|
123
|
+
}
|
|
124
|
+
const qs = generateQuickstart(surface, {
|
|
125
|
+
name: args.name ?? undefined,
|
|
126
|
+
command,
|
|
127
|
+
args: cliArgs.length ? cliArgs : undefined,
|
|
128
|
+
env: Object.keys(env).length ? env : undefined,
|
|
129
|
+
});
|
|
130
|
+
console.log(args.format === "json" ? JSON.stringify(qs, null, 2) : qs.text);
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
function loadCustomSurfaces(file) {
|
|
134
|
+
if (!file)
|
|
135
|
+
return [];
|
|
136
|
+
try {
|
|
137
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
138
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
console.error(`could not read surfaces file "${file}": ${e.message}`);
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function main() {
|
|
146
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
147
|
+
if (!cmd || cmd === "help" || cmd === "--help") {
|
|
148
|
+
console.log(USAGE);
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
const args = parseArgs(rest);
|
|
152
|
+
// Commands that don't touch mandate state shouldn't create the key store.
|
|
153
|
+
if (cmd === "lint" || cmd === "quickstart") {
|
|
154
|
+
return runStateless(cmd, args);
|
|
155
|
+
}
|
|
156
|
+
const engine = loadEngine();
|
|
157
|
+
switch (cmd) {
|
|
158
|
+
case "pubkey": {
|
|
159
|
+
console.log(engine.publicKey);
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
case "grant": {
|
|
163
|
+
const principal = args.principal;
|
|
164
|
+
const agent = args.agent;
|
|
165
|
+
const can = asArray(args.can);
|
|
166
|
+
const expiresIn = args.expires ?? "1h";
|
|
167
|
+
if (!principal || !agent || can.length === 0) {
|
|
168
|
+
console.error("grant requires --principal, --agent, and at least one --can");
|
|
169
|
+
return 2;
|
|
170
|
+
}
|
|
171
|
+
// Warn (on stderr, so stdout stays a clean mandate) about loose scopes.
|
|
172
|
+
for (const f of lint(can)) {
|
|
173
|
+
process.stderr.write(`[lint:${f.level}] ${f.capability}: ${f.message}\n`);
|
|
174
|
+
}
|
|
175
|
+
const m = engine.grant({ principal, agent, can, expiresIn });
|
|
176
|
+
if (args.public !== undefined) {
|
|
177
|
+
// Presentation-only token (cannot authorize — no delegation key).
|
|
178
|
+
console.log(m.serialize());
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
process.stderr.write("note: output is a HOLDER credential (includes the delegation key) — treat it as a secret.\n" +
|
|
182
|
+
" Use --public for the presentation-only token.\n");
|
|
183
|
+
console.log(m.serializeWithKey());
|
|
184
|
+
}
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
case "inspect": {
|
|
188
|
+
const m = engine.import(args._[0]);
|
|
189
|
+
try {
|
|
190
|
+
engine.verifySignature(m.token);
|
|
191
|
+
const scope = m.token.blocks
|
|
192
|
+
.flatMap((b) => b.caveats)
|
|
193
|
+
.filter((c) => c.t === "cap")
|
|
194
|
+
.map((c) => c.can);
|
|
195
|
+
console.log(JSON.stringify({
|
|
196
|
+
valid: true,
|
|
197
|
+
id: m.id,
|
|
198
|
+
principal: m.principal,
|
|
199
|
+
agent: m.agent,
|
|
200
|
+
expiresAt: m.expiresAt ? new Date(m.expiresAt).toISOString() : undefined,
|
|
201
|
+
chain: m.chain,
|
|
202
|
+
scope,
|
|
203
|
+
}, null, 2));
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
catch (e) {
|
|
207
|
+
console.log(JSON.stringify({ valid: false, reason: e.message }, null, 2));
|
|
208
|
+
return 1;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
case "authorize": {
|
|
212
|
+
const [mandate, action] = args._;
|
|
213
|
+
if (!mandate || !action) {
|
|
214
|
+
console.error("authorize requires <mandate> <action>");
|
|
215
|
+
return 2;
|
|
216
|
+
}
|
|
217
|
+
const m = engine.import(mandate);
|
|
218
|
+
if (m.canDelegate) {
|
|
219
|
+
// Holder credential: full authorize with proof of possession.
|
|
220
|
+
try {
|
|
221
|
+
await m.authorize(action);
|
|
222
|
+
console.log(`ALLOW ${action}`);
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
const reason = e instanceof AuthorizationError ? e.reason : String(e);
|
|
227
|
+
console.log(`DENY ${action} (${reason})`);
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Public token only: advisory scope check (possession not proven).
|
|
232
|
+
const result = await engine.inspect(m.token, action);
|
|
233
|
+
if (result.allowed) {
|
|
234
|
+
console.log(`ALLOW ${action} (advisory; possession not checked)`);
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
console.log(`DENY ${action} (${result.reason})`);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
case "revoke": {
|
|
241
|
+
const id = args._[0];
|
|
242
|
+
if (!id) {
|
|
243
|
+
console.error("revoke requires <mandate-id>");
|
|
244
|
+
return 2;
|
|
245
|
+
}
|
|
246
|
+
await engine.revoke(id);
|
|
247
|
+
console.log(`revoked ${id}`);
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
case "audit": {
|
|
251
|
+
const id = args._[0];
|
|
252
|
+
if (!id) {
|
|
253
|
+
console.error("audit requires <mandate-id>");
|
|
254
|
+
return 2;
|
|
255
|
+
}
|
|
256
|
+
const trail = await engine.audit(id);
|
|
257
|
+
for (const e of trail) {
|
|
258
|
+
const ts = new Date(e.ts).toISOString();
|
|
259
|
+
console.log(`${ts} ${e.decision.toUpperCase().padEnd(5)} ${e.action}${e.reason ? ` (${e.reason})` : ""}`);
|
|
260
|
+
}
|
|
261
|
+
console.log(`\n${trail.length} record(s)`);
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
default:
|
|
265
|
+
console.error(`unknown command "${cmd}"\n\n${USAGE}`);
|
|
266
|
+
return 2;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
main().then((code) => process.exit(code), (e) => {
|
|
270
|
+
console.error(e);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
});
|
|
273
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
3
|
+
import { type AuditStore, type RevocationStore, type RateStore, type ConsentStore, type PolicyStore } from "./store.js";
|
|
4
|
+
export type { ConsentRecord } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* The Behalf control plane (Phase 2 / open-core hosted surface).
|
|
7
|
+
*
|
|
8
|
+
* It centralizes the three things that benefit from being shared across agents
|
|
9
|
+
* and processes: revocation propagation (revoke once, everyone sees it), audit
|
|
10
|
+
* retention (one tamper-evident log of every decision), and a consent/policy
|
|
11
|
+
* surface (just-in-time human approval + named tool→capability policies). It's a
|
|
12
|
+
* thin HTTP service over the same pluggable stores the library already uses, so
|
|
13
|
+
* it can be backed by the in-memory defaults or the file stores for durability.
|
|
14
|
+
*
|
|
15
|
+
* Agents talk to it through `HttpRevocationStore` / `HttpAuditStore` (see
|
|
16
|
+
* `behalf/remote`), so the five-verb API and enforcement are unchanged — only
|
|
17
|
+
* where revocation/audit live moves.
|
|
18
|
+
*/
|
|
19
|
+
export interface ControlPlaneOptions {
|
|
20
|
+
revocations?: RevocationStore;
|
|
21
|
+
audit?: AuditStore;
|
|
22
|
+
rate?: RateStore;
|
|
23
|
+
/** Consent record storage. Defaults to in-memory; use a file store to persist. */
|
|
24
|
+
consents?: ConsentStore;
|
|
25
|
+
/** Named-policy storage. Defaults to in-memory; use a file store to persist. */
|
|
26
|
+
policies?: PolicyStore;
|
|
27
|
+
/**
|
|
28
|
+
* Multi-tenant mode: require audit queries to name an `?issuer=`, and refuse
|
|
29
|
+
* the unscoped "all entries" list (and omit it from the dashboard). Keeps one
|
|
30
|
+
* tenant from reading another's audit through a shared control plane.
|
|
31
|
+
*/
|
|
32
|
+
tenantScoped?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Per-tenant bearer tokens: a map of `token -> issuer public key`. A tenant
|
|
35
|
+
* token may only read/write audit for its own issuer (any `?issuer=` is
|
|
36
|
+
* ignored, cross-issuer writes are refused) and gets a private policy
|
|
37
|
+
* namespace. Combine with `token` (an admin credential with full, unscoped
|
|
38
|
+
* access). When either is set, every request must authenticate.
|
|
39
|
+
*/
|
|
40
|
+
tenants?: Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Pending consent requests older than this are marked "expired" (a terminal
|
|
43
|
+
* deny for the consent provider). Disabled when unset.
|
|
44
|
+
*/
|
|
45
|
+
consentTtlMs?: number;
|
|
46
|
+
/** Admin credential — full, unscoped access. */
|
|
47
|
+
token?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ControlPlane {
|
|
50
|
+
/** Raw request listener — handy for tests without binding a socket. */
|
|
51
|
+
handler: (req: IncomingMessage, res: ServerResponse) => void;
|
|
52
|
+
/** Bind to a port; resolves with the chosen port (0 picks a free one). */
|
|
53
|
+
listen(port?: number): Promise<number>;
|
|
54
|
+
close(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
export declare function createControlPlane(options?: ControlPlaneOptions): ControlPlane;
|
|
57
|
+
//# sourceMappingURL=control-plane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-plane.d.ts","sourceRoot":"","sources":["../src/control-plane.ts"],"names":[],"mappings":";AACA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAe,MAAM,WAAW,CAAC;AAGjG,OAAO,EAML,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7D,0EAA0E;IAC1E,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CA6OlF"}
|