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
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
|
+
```
|