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.
Files changed (85) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/LICENSE +21 -0
  3. package/QUICKSTART.md +91 -0
  4. package/README.md +553 -0
  5. package/dist/a2a.d.ts +73 -0
  6. package/dist/a2a.d.ts.map +1 -0
  7. package/dist/a2a.js +117 -0
  8. package/dist/a2a.js.map +1 -0
  9. package/dist/audit.d.ts +12 -0
  10. package/dist/audit.d.ts.map +1 -0
  11. package/dist/audit.js +52 -0
  12. package/dist/audit.js.map +1 -0
  13. package/dist/behalf.d.ts +173 -0
  14. package/dist/behalf.d.ts.map +1 -0
  15. package/dist/behalf.js +475 -0
  16. package/dist/behalf.js.map +1 -0
  17. package/dist/capability.d.ts +56 -0
  18. package/dist/capability.d.ts.map +1 -0
  19. package/dist/capability.js +176 -0
  20. package/dist/capability.js.map +1 -0
  21. package/dist/cli.d.ts +3 -0
  22. package/dist/cli.d.ts.map +1 -0
  23. package/dist/cli.js +273 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/control-plane.d.ts +57 -0
  26. package/dist/control-plane.d.ts.map +1 -0
  27. package/dist/control-plane.js +332 -0
  28. package/dist/control-plane.js.map +1 -0
  29. package/dist/crypto.d.ts +68 -0
  30. package/dist/crypto.d.ts.map +1 -0
  31. package/dist/crypto.js +105 -0
  32. package/dist/crypto.js.map +1 -0
  33. package/dist/errors.d.ts +25 -0
  34. package/dist/errors.d.ts.map +1 -0
  35. package/dist/errors.js +40 -0
  36. package/dist/errors.js.map +1 -0
  37. package/dist/index.d.ts +35 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +34 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/lint.d.ts +17 -0
  42. package/dist/lint.d.ts.map +1 -0
  43. package/dist/lint.js +75 -0
  44. package/dist/lint.js.map +1 -0
  45. package/dist/mandate.d.ts +99 -0
  46. package/dist/mandate.d.ts.map +1 -0
  47. package/dist/mandate.js +141 -0
  48. package/dist/mandate.js.map +1 -0
  49. package/dist/mcp-server.d.ts +26 -0
  50. package/dist/mcp-server.d.ts.map +1 -0
  51. package/dist/mcp-server.js +111 -0
  52. package/dist/mcp-server.js.map +1 -0
  53. package/dist/mcp.d.ts +63 -0
  54. package/dist/mcp.d.ts.map +1 -0
  55. package/dist/mcp.js +123 -0
  56. package/dist/mcp.js.map +1 -0
  57. package/dist/persist.d.ts +51 -0
  58. package/dist/persist.d.ts.map +1 -0
  59. package/dist/persist.js +150 -0
  60. package/dist/persist.js.map +1 -0
  61. package/dist/quickstart.d.ts +63 -0
  62. package/dist/quickstart.d.ts.map +1 -0
  63. package/dist/quickstart.js +171 -0
  64. package/dist/quickstart.js.map +1 -0
  65. package/dist/remote.d.ts +93 -0
  66. package/dist/remote.d.ts.map +1 -0
  67. package/dist/remote.js +120 -0
  68. package/dist/remote.js.map +1 -0
  69. package/dist/seal.d.ts +12 -0
  70. package/dist/seal.d.ts.map +1 -0
  71. package/dist/seal.js +96 -0
  72. package/dist/seal.js.map +1 -0
  73. package/dist/store.d.ts +119 -0
  74. package/dist/store.d.ts.map +1 -0
  75. package/dist/store.js +139 -0
  76. package/dist/store.js.map +1 -0
  77. package/dist/types.d.ts +173 -0
  78. package/dist/types.d.ts.map +1 -0
  79. package/dist/types.js +17 -0
  80. package/dist/types.js.map +1 -0
  81. package/llms.txt +106 -0
  82. package/package.json +107 -0
  83. package/schemas/capability.schema.json +14 -0
  84. package/schemas/mandate.schema.json +68 -0
  85. package/vectors/mandate-vector.json +63 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,118 @@
1
+ # Changelog
2
+
3
+ All notable changes to Behalf are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/), and the project aims to adhere
5
+ to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Security
10
+
11
+ - **Proof of possession at authorize (fixes C-1, critical).** A serialized
12
+ mandate is no longer a bearer credential, and a delegatee can no longer
13
+ **truncate** its chain to recover a parent's wider scope. Authorizing now
14
+ requires proving possession of the chain's terminal key: `mandate.authorize()`
15
+ does this in-process; across a boundary the holder presents a proof
16
+ (`mandate.prove()` / `agent-authority/a2a`'s `present()`) and the verifier checks it
17
+ with `engine.authorize(token, action, proof)`. Advisory, no-possession checks
18
+ use the new `engine.inspect(token, action)`.
19
+ - **Attenuation operator direction (fixes M-1).** The narrowing check now
20
+ rejects direction flips (e.g. narrowing `spend:usd<=50` to `spend:usd>=10`); a
21
+ bound may only be tightened in the same direction or to an exact value within.
22
+ - **Sorted-key canonical JSON (hardens L-1).** Signed bytes use recursively
23
+ sorted-key canonical JSON in both ports, so cross-implementation drift is
24
+ structurally impossible. A committed cross-language fixture
25
+ (`vectors/mandate-vector.json`) is verified by both test suites.
26
+
27
+ ### Security (hardening)
28
+
29
+ - **Single-use nonce challenges (anti-replay).** `engine.challenge()` issues a
30
+ nonce the holder binds into its proof (`prove(action, { nonce })`); it is
31
+ consumed on use, so a captured proof can never be replayed. Engines created
32
+ with `requireNonce: true` refuse nonce-less proofs.
33
+ - **Full per-tenant isolation on the control plane.** Tenant tokens now
34
+ namespace revocation ids, rate keys, and consent records (in addition to
35
+ audit and policy); admin revocations remain global.
36
+ - **Consent TTL** (`consentTtlMs`): pending requests expire to a terminal
37
+ "expired" state. **Audit pagination**: `GET /v1/audit?offset&limit` with
38
+ `total`. **FileRateStore**: rate windows survive restarts.
39
+ - **Holder credentials.** `serializeWithKey()` / `import` transfer a delegated
40
+ mandate (token + key) across process boundaries; MCP `request_mandate` and
41
+ the CLI now issue usable credentials (post-PoP regression fixes).
42
+
43
+ ### Security (hardening, continued)
44
+
45
+ - **Issuer key rotation (B5).** `engine.rotate()` returns a fresh-keyed engine
46
+ sharing stores and trusting the old key for an overlap window; end it with
47
+ `untrustKey(oldKey)`. `trustKey`/`trustedKeys` manage the trust set.
48
+ - **Signed audit checkpoints (C4).** `checkpointAudit()` /
49
+ `verifyAuditCheckpoint()` anchor the log head under the issuer key, making
50
+ tail-deletion and rewrites detectable when checkpoints are stored out of the
51
+ writer's reach.
52
+ - Fixed: `python -m agent_authority.control_plane` exited immediately (missing
53
+ `__main__` guard); the console script was unaffected.
54
+ - **Sealed holder credentials (#8).** `mandate.sealForRecipient(pub)` encrypts a
55
+ holder credential to a recipient's X25519 sealing key; `engine.importSealed`
56
+ opens it. Scheme `seal-1` (ephemeral X25519 → HKDF-SHA256 → AES-256-GCM) is
57
+ wire-compatible across both ports — seal in one, open in the other. Native in
58
+ Node; Python uses the optional `cryptography` package and raises a clear error
59
+ if it's absent (the rest of the port stays dependency-free). Defense-in-depth
60
+ for the delivery channel, complementary to `bindAgent`. New helpers
61
+ `newSealKeyPair` / `seal` / `unseal`; pinned by `test/seal.test.ts`,
62
+ `python/tests/test_seal.py`, and a cross-language interop case.
63
+ - **Optional hardened crypto backend (Python).** The Python port auto-selects a
64
+ constant-time native Ed25519 backend when importable (`cryptography`, then
65
+ `PyNaCl`), falling back to the pure-Python reference; `agent_authority.crypto.backend()`
66
+ reports the active one. The selector self-checks byte-compatibility with the
67
+ reference (and tolerates a broken native lib, including Rust panics, without
68
+ noise) so cross-port tokens stay valid. No new required dependency.
69
+ - **Token-bucket rate limiting.** `TokenBucketRateStore` is a burst-shaping
70
+ alternative to the default sliding-count `MemoryRateStore` — drop-in for any
71
+ `RateStore` slot (engine or control plane).
72
+ - **Cross-language delegation verified.** A holder credential
73
+ (`serializeWithKey`) issued in one port can be imported **and attenuated** in
74
+ the other; the interop check now pins `PY->TS->PY` and `TS->PY->TS`
75
+ delegated-chain cases (previously documented as verify-only).
76
+ - **Cryptographic agent identity binding (C3, SVID-style).** Grant or attenuate
77
+ with `bindAgent` (the agent's public key) to add an `agentKey` caveat;
78
+ authorize then requires a proof of possession of the matching private key
79
+ (`mandate.prove(action, { agentKeys })`, or an engine configured with
80
+ `agentKey` on the in-process path). A stolen `serializeWithKey` credential can
81
+ no longer act on its own. Bindings are **conjunctive** — every `agentKey`
82
+ caveat must be satisfied — so a thief cannot strip one or shadow it by
83
+ appending their own. Pinned by `test/agent-binding.test.ts` and
84
+ `python/tests/test_agent_binding.py`; `agent` remains an advisory label.
85
+
86
+ ### Added
87
+
88
+ - **Core (TypeScript + Python).** The five-verb Mandate API — `grant`,
89
+ `authorize`, `attenuate`, `revoke`, `audit` — over one primitive.
90
+ - **Capability grammar.** Verbs, resource paths, quantitative limits
91
+ (`spend:usd<=50`) and rate limits (`send:email rate<=10/h`), with linting.
92
+ - **Asymmetric, attenuable tokens.** Ed25519 signature chain (biscuit-style):
93
+ offline third-party verification with only the issuer's public key;
94
+ attenuation-only delegation that structurally blocks widening and splicing.
95
+ - **Tamper-evident audit.** Hash-chained log with O(1), single-writer sealing
96
+ that stays intact under concurrent writers.
97
+ - **MCP + A2A.** `withBehalf` middleware, a dependency-free stdio MCP server, and
98
+ an HTTP A2A transport that carries the verifiable chain between agents.
99
+ - **Control plane.** Revocation propagation, central audit retention, shared
100
+ rate limiting, and a consent/policy surface with a dashboard — all over
101
+ pluggable stores (in-memory, file-backed, or HTTP client).
102
+ - **Consent wiring.** `controlPlaneConsent` plugs just-in-time human approval
103
+ into the middleware.
104
+ - **Per-issuer audit scoping** and a `tenantScoped` control-plane mode.
105
+ - **`CachingRevocationStore`** — bounded-staleness revocation cache.
106
+ - **Tooling.** `agent-authority` CLI (grant/inspect/authorize/revoke/audit/lint/
107
+ quickstart), `agent-authority-mcp` and `agent-authority-control-plane` binaries, dynamic
108
+ per-surface quickstarts for any AI, `llms.txt`, and JSON schemas.
109
+ - **Cross-language wire interop** — a mandate issued in one port verifies in the
110
+ other.
111
+
112
+ ### Notes
113
+
114
+ This is pre-release (0.x): the five-verb API is stable, but storage interfaces
115
+ and the control-plane HTTP surface may still change. See the README's
116
+ "Limitations & roadmap" for known trade-offs.
117
+
118
+ [Unreleased]: https://github.com/novaai0401-ui/agent-authority/commits/main
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Behalf contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/QUICKSTART.md ADDED
@@ -0,0 +1,91 @@
1
+ # Behalf quickstarts — wire it into any AI
2
+
3
+ Behalf wires into an AI surface in one of two shapes:
4
+
5
+ - **MCP server** — Claude Code, Claude Desktop, Cursor, GitHub Copilot (VS Code),
6
+ Windsurf, Gemini CLI, OpenAI Agents SDK, and most agent runtimes.
7
+ - **Function-calling tools** — the OpenAI and Gemini APIs (and anything that
8
+ accepts JSON-schema tool definitions).
9
+
10
+ Rather than maintain a doc per tool, the snippets are **generated** from a
11
+ surface registry, so the three mains (Claude Code, Cursor, Copilot), Gemini and
12
+ GPT are built in — and **any other AI is configurable** via a custom surface or
13
+ the generic MCP template.
14
+
15
+ ```bash
16
+ agent-authority quickstart --list # every built-in surface
17
+ agent-authority quickstart claude-code # print the config to paste
18
+ agent-authority quickstart copilot
19
+ agent-authority quickstart gpt # OpenAI function tools
20
+ agent-authority quickstart gemini # Gemini functionDeclarations
21
+
22
+ # customise the launch command / name / env
23
+ agent-authority quickstart cursor --local # node dist/mcp-server.js
24
+ agent-authority quickstart cursor --command npx --arg -y --arg agent-authority-mcp
25
+ agent-authority quickstart claude-code --name auth --env BEHALF_HOME=/data/behalf
26
+ agent-authority quickstart <surface> --format json # machine-readable
27
+ ```
28
+
29
+ ## The three mains
30
+
31
+ ### Claude Code
32
+
33
+ ```bash
34
+ claude mcp add agent-authority -- npx -y agent-authority-mcp
35
+ ```
36
+
37
+ or `.mcp.json` / `~/.claude.json`:
38
+
39
+ ```json
40
+ { "mcpServers": { "agent-authority": { "command": "npx", "args": ["-y", "agent-authority-mcp"] } } }
41
+ ```
42
+
43
+ ### Cursor — `.cursor/mcp.json`
44
+
45
+ ```json
46
+ { "mcpServers": { "agent-authority": { "command": "npx", "args": ["-y", "agent-authority-mcp"] } } }
47
+ ```
48
+
49
+ ### GitHub Copilot (VS Code) — `.vscode/mcp.json`
50
+
51
+ ```json
52
+ { "servers": { "agent-authority": { "command": "npx", "args": ["-y", "agent-authority-mcp"], "type": "stdio" } } }
53
+ ```
54
+
55
+ ## GPT and Gemini (and any function-calling model)
56
+
57
+ `agent-authority quickstart gpt` / `agent-authority quickstart gemini` emit the three discovery
58
+ tools — `request_mandate`, `present_mandate`, `check_authority` — as OpenAI
59
+ `tools` or Gemini `functionDeclarations`. Have the model call `check_authority`
60
+ before any sensitive action, then enforce with `mandate.authorize(...)` server-side.
61
+
62
+ ## Any AI — bring your own surface
63
+
64
+ Every surface is just data. Describe a new one in JSON and pass it with
65
+ `--surfaces`:
66
+
67
+ ```json
68
+ [
69
+ {
70
+ "id": "my-agent",
71
+ "name": "My In-House Agent",
72
+ "kind": "mcp",
73
+ "configFile": "my-agent/config.json",
74
+ "configKey": "mcpServers"
75
+ }
76
+ ]
77
+ ```
78
+
79
+ ```bash
80
+ agent-authority quickstart my-agent --surfaces ./surfaces.json
81
+ ```
82
+
83
+ For an MCP client whose config you don't know yet, `agent-authority quickstart
84
+ generic-mcp` prints the near-universal `mcpServers` stdio form. Programmatic use
85
+ mirrors the CLI:
86
+
87
+ ```ts
88
+ import { generateQuickstart, findSurface } from "agent-authority";
89
+ const qs = generateQuickstart(findSurface("cursor")!, { command: "npx", args: ["-y", "agent-authority-mcp"] });
90
+ console.log(qs.snippet); // the JSON to paste
91
+ ```