@adtl/gateway 0.4.0 → 0.5.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 (49) hide show
  1. package/README.md +61 -4
  2. package/dist/audit.d.ts +21 -0
  3. package/dist/audit.d.ts.map +1 -1
  4. package/dist/audit.js +137 -2
  5. package/dist/audit.js.map +1 -1
  6. package/dist/auditCli.d.ts +7 -0
  7. package/dist/auditCli.d.ts.map +1 -0
  8. package/dist/auditCli.js +54 -0
  9. package/dist/auditCli.js.map +1 -0
  10. package/dist/authorizer.d.ts +50 -0
  11. package/dist/authorizer.d.ts.map +1 -0
  12. package/dist/authorizer.js +15 -0
  13. package/dist/authorizer.js.map +1 -0
  14. package/dist/cli.js +12 -3
  15. package/dist/cli.js.map +1 -1
  16. package/dist/gateway.d.ts +12 -3
  17. package/dist/gateway.d.ts.map +1 -1
  18. package/dist/gateway.js +88 -15
  19. package/dist/gateway.js.map +1 -1
  20. package/dist/hooks/claudeCode.d.ts +1 -0
  21. package/dist/hooks/claudeCode.d.ts.map +1 -1
  22. package/dist/hooks/claudeCode.js +8 -1
  23. package/dist/hooks/claudeCode.js.map +1 -1
  24. package/dist/hooks/run.d.ts.map +1 -1
  25. package/dist/hooks/run.js +3 -2
  26. package/dist/hooks/run.js.map +1 -1
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/invoker.d.ts +9 -6
  32. package/dist/invoker.d.ts.map +1 -1
  33. package/dist/invoker.js +11 -9
  34. package/dist/invoker.js.map +1 -1
  35. package/dist/ledgerCli.d.ts +1 -1
  36. package/dist/ledgerCli.d.ts.map +1 -1
  37. package/dist/ledgerCli.js +26 -6
  38. package/dist/ledgerCli.js.map +1 -1
  39. package/package.json +4 -4
  40. package/src/audit.ts +142 -2
  41. package/src/auditCli.ts +53 -0
  42. package/src/authorizer.ts +60 -0
  43. package/src/cli.ts +12 -3
  44. package/src/gateway.ts +95 -17
  45. package/src/hooks/claudeCode.ts +9 -2
  46. package/src/hooks/run.ts +3 -2
  47. package/src/index.ts +2 -0
  48. package/src/invoker.ts +24 -17
  49. package/src/ledgerCli.ts +22 -6
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > **Experimental.** ADTL is a personal open-source project built on draft MCP proposals ([trust-annotations](https://github.com/modelcontextprotocol/experimental-ext-tool-annotations), [SEP-2624 interceptors](https://github.com/modelcontextprotocol/experimental-ext-interceptors)) that are still changing. It is not a security guarantee: don't rely on it to protect production systems yet. Feedback is very welcome.
4
4
 
5
+ ![How ADTL fits between your agent and its tools](https://raw.githubusercontent.com/probita-ai/adtl/main/docs/adtl-sketch-v3.png)
6
+
5
7
  An MCP gateway for AI agents. It sits between your agent (Claude Code, Cursor, any MCP client) and your MCP servers, and:
6
8
 
7
9
  - **labels every tool result**: where it came from, whether it can be trusted, how sensitive it is (MCP's draft `trust-annotations` format)
@@ -57,6 +59,8 @@ One file holds both the labels and the gateway settings.
57
59
  | `integrity` | `trusted`, `untrusted` | Can the tool's *result* be trusted to influence actions? Content from strangers (issues, emails, web pages) is untrusted. |
58
60
  | `confidentiality` | `public`, `private`, `secret` | Who may see the tool's *result*? |
59
61
  | `egress` | `none`, `internal`, `external`, `public` | Where *calling* the tool can send data. |
62
+ | `labelInto` | an argument name, e.g. `metadata` | Write tools of servers that store an object per record: stamp the session label into it. See [labels on records](#labels-on-records). |
63
+ | `readLabels` | `true` | Read tools of those servers: join the stamps found on returned records into the result's label. |
60
64
 
61
65
  Tools without a rule use the defaults (`untrusted`, `private`, egress `unknown`). That's safe but strict, so describe the tools you use. Resources and prompts use the server's `defaults`.
62
66
 
@@ -106,12 +110,22 @@ Rules match on `session.integrity`, `session.confidentiality`, `tool.egress` and
106
110
  | Key | Meaning |
107
111
  |---|---|
108
112
  | `gateway.upstreams.<id>` | A stdio server (`command`, `args`, `env`, `cwd`) or an HTTP server (`url`, `headers`). The `<id>` must match the key under `servers:`. |
109
- | `gateway.audit` | Path of a JSONL audit log, relative to the config file |
113
+ | `gateway.audit` | Path of a JSONL audit log, relative to the config file. Hash-chained; see [Checking the audit log](#checking-the-audit-log). |
110
114
  | `gateway.mode` | `active` (default) or `audit`. See [Trying a policy safely](#trying-a-policy-safely). |
111
115
  | `gateway.approvals` | Ask a human about `ask` decisions. See [Approvals](#approvals). |
112
116
  | `gateway.interceptorTimeoutMs` | Timeout per interceptor call (default 5000) |
113
117
  | `gateway.interceptors` | Custom interceptor server command (default: the bundled `@adtl/interceptors`) |
114
118
 
119
+ #### Checking the audit log
120
+
121
+ Each line carries `prev`, the hash of the line before, and `hash`, over the line itself. Check the chain with:
122
+
123
+ ```sh
124
+ adtl-gateway audit verify -c adtl.yaml # or: adtl-gateway audit verify ./adtl-audit.jsonl
125
+ ```
126
+
127
+ It exits 1 if a line was edited, removed, reordered or inserted, and prints the hash of the last line. Cutting lines off the end is not detected, so note that hash somewhere else if you need to check later. Lines written by 0.4 or earlier are reported as written before the chain. The gateway and the Claude Code hook append through a lock file (`<log>.lock`), so their lines stay in one chain. The hook blocks `Write`/`Edit` on the log and asks before shell commands that mention it. The chain has no secret: an agent with shell access could still rewrite the whole file consistently. Signed session receipts are planned for that ([#26](https://github.com/probita-ai/adtl/issues/26)).
128
+
115
129
  `${VAR}` in commands, args, env, URLs and headers is read from the environment, so secrets stay out of the file.
116
130
 
117
131
  ### Approvals
@@ -215,13 +229,33 @@ Look after it with:
215
229
  ```sh
216
230
  adtl-gateway ledger stats
217
231
  adtl-gateway ledger verify # exit 1 if an entry was changed or removed
218
- adtl-gateway ledger declassify notes.md # after checking it: clear the label of its current content
232
+ adtl-gateway ledger declassify notes.md --reason "checked by hand, no instructions"
233
+ # after checking it: clear the label of its current content
234
+ adtl-gateway ledger declassified # recent declassifications: when, who, what and why
219
235
  ```
220
236
 
221
- Matching is by normalized chunks (whole text, paragraphs, lines of 32+ characters), so text copied into a bigger file still matches, and text the agent rewrote was already recorded with its session's label. Text a person rewrites by hand, binary files, and content an MCP server returns in another encoding (such as base64) are not matched. The Claude Code hook blocks `Write`/`Edit` on the ledger file and asks before shell commands that mention it or `ledger declassify`. Entries are hash-chained, not signed: an agent with shell access could still rebuild the file, which `verify` cannot detect. Signed entries are planned with labels that travel between agents (v0.5).
237
+ `--reason` is required. Declassifying is where taint tracking tends to erode, as it turns into a reflex, so each one is kept with who did it, the file and the reason, for review with `declassified`.
238
+
239
+ Matching is by normalized chunks (whole text, paragraphs, lines of 32+ characters), so text copied into a bigger file still matches, and text the agent rewrote was already recorded with its session's label. Text a person rewrites by hand, binary files, and content an MCP server returns in another encoding (such as base64) are not matched. The Claude Code hook blocks `Write`/`Edit` on the ledger file and asks before shell commands that mention it or `ledger declassify`. Entries are hash-chained, not signed: an agent with shell access could still rebuild the file, which `verify` cannot detect. Signed entries are planned with labels that travel between agents (v0.6).
222
240
 
223
241
  See [the delayed-injection demo](../../examples/delayed-injection-demo) (`npm run demo:ledger`).
224
242
 
243
+ ### Labels on records
244
+
245
+ Some memory servers extract facts with a model on write, or merge records, so what comes back matches no text the session sent and the ledger can't recognize it. If the server stores a metadata object with each record and returns it on read, let the label travel with the record:
246
+
247
+ ```yaml
248
+ servers:
249
+ memory:
250
+ tools:
251
+ add_memory: { egress: internal, labelInto: metadata }
252
+ search_memory: { integrity: trusted, confidentiality: public, egress: none, readLabels: true }
253
+ ```
254
+
255
+ - On every `add_memory` call the gateway sets `metadata["adtl/record-label"]` to `{ integrity, confidentiality, writer }` from the session, replacing anything the agent put there.
256
+ - On `search_memory`, stamps anywhere in the result (also inside JSON text) are joined into its label, with the origin `adtl-record` / `session:<id>`, and the audit entry gets `records: { stamps, writers }`. Anyone who can write to the store can write a stamp, so stamps only make a label stricter. A malformed stamp counts as the global defaults.
257
+ - A server that drops or rewrites metadata (for example when it consolidates records) can't carry the label. Give its read tools a strict rule, such as `integrity: untrusted`, once in the config.
258
+
225
259
  ## How it works
226
260
 
227
261
  ```
@@ -232,6 +266,29 @@ agent ──▶ adtl-gateway ──▶ upstream MCP servers
232
266
  adtl.label labels the result after it returns
233
267
  ```
234
268
 
269
+ ### Authorization
270
+
271
+ Labels and the policy decide whether a call may run given what the session has seen. An `Authorizer` decides before that whether the caller may use the tool, resource or prompt at all. It is a library interface for now; role-based rules in the config are planned ([#8](https://github.com/probita-ai/adtl/issues/8)).
272
+
273
+ ```ts
274
+ import { AdtlGateway, type Authorizer } from "@adtl/gateway";
275
+
276
+ const readOnly: Authorizer = {
277
+ name: "read-only",
278
+ check: ({ principal, server, tool }) =>
279
+ tool?.startsWith("get_") || tool?.startsWith("read_")
280
+ ? { allow: true }
281
+ : { allow: false, reason: `${principal.id ?? "anonymous"} may only read from ${server}` },
282
+ };
283
+
284
+ new AdtlGateway({ upstreams, invoker, authorizer: readOnly, principal: { type: "user", id: "alice" } });
285
+ ```
286
+
287
+ - It runs on every `tools/call`, `resources/read` and `prompts/get`, before the interceptors. A denial stops the call whatever the policy says; an allow still leaves the call to the policy.
288
+ - It gets `{ principal, event, server, tool | resource | prompt, arguments }`. The principal is also passed to the interceptors as SEP-2624 `context.principal`. Over stdio it is whoever started the gateway (anonymous unless set).
289
+ - Denials are audited with `denied: { by, reason }`. An authorizer that throws denies the call. In audit mode denials are logged and the call still runs.
290
+ - The Claude Code hooks don't use it yet.
291
+
235
292
  The gateway fails closed. If an interceptor errors or times out, the call is stopped. If a result can't be labeled, it is withheld. If the interceptors are missing, the gateway refuses to start. (In audit mode such failures are logged as warnings instead.)
236
293
 
237
294
  ## Limits of this version
@@ -239,7 +296,7 @@ The gateway fails closed. If an interceptor errors or times out, the call is sto
239
296
  - Tools, resources and prompts are proxied. Resource subscriptions, `list_changed` notifications and completions are not passed through yet.
240
297
  - Resources and prompts are labeled by server defaults (`servers.<id>.defaults`) or the global defaults; there are no per-resource or per-prompt rules yet. A resource URI that two upstreams could serve is refused rather than guessed.
241
298
  - Approvals come from one push channel (ntfy). Other channels, approvals inside the MCP client, and approver roles are planned.
242
- - Session labels last for one agent session: one gateway process, or under Claude Code one Claude Code session (shared with the hooks). The [label ledger](#label-ledger) carries them into files, memory servers and sub-agents by content, but not across machines or other agents yet (v0.5).
299
+ - Session labels last for one agent session: one gateway process, or under Claude Code one Claude Code session (shared with the hooks). The [label ledger](#label-ledger) carries them into files, memory servers and sub-agents by content, but not across machines or other agents yet (v0.6). Memory servers that extract facts or merge records on write return text the ledger cannot recognize; use [labels on records](#labels-on-records), or a strict rule for servers that don't keep metadata.
243
300
  - The Claude Code hooks label tools by name, not by what they touched: a `Read` of a downloaded file is as trusted as a `Read` of your own code.
244
301
  - Labels are set by your config. Servers' own trust claims can only make labels stricter, unless you set `acceptServerClaims: true`.
245
302
 
package/dist/audit.d.ts CHANGED
@@ -15,6 +15,11 @@ export interface AuditEntry {
15
15
  decision?: string;
16
16
  /** Present when the gateway ran in audit mode: nothing was stopped or changed. */
17
17
  mode?: "audit";
18
+ /** Present when the authorizer denied the caller: which one, and why. In audit mode the call still ran. */
19
+ denied?: {
20
+ by: string;
21
+ reason: string;
22
+ };
18
23
  /** Present when a human was asked: outcome, channel, approver (if known) and wait time. */
19
24
  approval?: {
20
25
  outcome: string;
@@ -28,6 +33,8 @@ export interface AuditEntry {
28
33
  label?: unknown;
29
34
  /** Present when the label ledger recognized content in the result: how many chunks matched, and which sessions wrote them. */
30
35
  ledger?: unknown;
36
+ /** Present when the result carried record label stamps: how many, and which sessions wrote them. */
37
+ records?: unknown;
31
38
  sessionLabel?: unknown;
32
39
  warnings?: string[];
33
40
  durationMs: number;
@@ -35,11 +42,25 @@ export interface AuditEntry {
35
42
  export interface AuditSink {
36
43
  write(entry: AuditEntry): void;
37
44
  }
45
+ /** `prev` of the first line of a log. */
46
+ export declare const AUDIT_GENESIS: string;
38
47
  export declare class JsonlAuditLog implements AuditSink {
39
48
  readonly path: string;
40
49
  constructor(path: string);
41
50
  write(entry: AuditEntry): void;
42
51
  }
52
+ export interface AuditVerifyResult {
53
+ ok: boolean;
54
+ /** Lines checked. */
55
+ lines: number;
56
+ /** Lines at the start written before the chain (ADTL 0.4 and earlier). */
57
+ unchained: number;
58
+ /** Hash of the last line: note it to detect lines cut off the end later. */
59
+ last?: string;
60
+ problem?: string;
61
+ }
62
+ /** Check every line's hash and its link to the line before. */
63
+ export declare function verifyAuditLog(path: string): AuditVerifyResult;
43
64
  export declare class MemoryAuditLog implements AuditSink {
44
65
  readonly entries: AuditEntry[];
45
66
  write(entry: AuditEntry): void;
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,aAAa,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAC9D,0FAA0F;IAC1F,GAAG,CAAC,EAAE,kBAAkB,CAAC;IACzB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2FAA2F;IAC3F,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8HAA8H;IAC9H,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,qBAAa,aAAc,YAAW,SAAS;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAIjC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B;AAED,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAM;IACpC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,aAAa,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAC9D,0FAA0F;IAC1F,GAAG,CAAC,EAAE,kBAAkB,CAAC;IACzB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2GAA2G;IAC3G,MAAM,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,2FAA2F;IAC3F,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8HAA8H;IAC9H,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,yCAAyC;AACzC,eAAO,MAAM,aAAa,QAA6B,CAAC;AAsExD,qBAAa,aAAc,YAAW,SAAS;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAIjC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAc/B;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA4B9D;AAED,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAM;IACpC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B"}
package/dist/audit.js CHANGED
@@ -3,9 +3,97 @@
3
3
  *
4
4
  * Arguments and results are never written; the call is identified by its
5
5
  * hash, so the log can be shared without leaking the data it describes.
6
+ *
7
+ * Lines are hash-chained: each carries `prev` (the hash of the line before)
8
+ * and `hash` (over the canonical form of the line without `hash`), so
9
+ * `adtl-gateway audit verify` detects lines that were edited, removed,
10
+ * reordered or inserted. The gateway and the Claude Code hook (a new process
11
+ * per tool call) write the same file, so appends take a lock file
12
+ * (`<log>.lock`) to keep the chain from forking.
13
+ *
14
+ * The chain has no secret: an agent with shell access could rewrite the whole
15
+ * file consistently, and cutting lines off the end is not detected. Signed
16
+ * session receipts are planned for that.
6
17
  */
7
- import { appendFileSync, mkdirSync } from "node:fs";
18
+ import { closeSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, statSync, unlinkSync, writeSync } from "node:fs";
8
19
  import { dirname } from "node:path";
20
+ import { digest, sha256Hex } from "@adtl/labels";
21
+ /** `prev` of the first line of a log. */
22
+ export const AUDIT_GENESIS = `sha256:${"0".repeat(64)}`;
23
+ const LOCK_TIMEOUT_MS = 5000;
24
+ /** A lock older than this was left by a process that died while holding it. */
25
+ const LOCK_STALE_MS = 10_000;
26
+ function sleepSync(ms) {
27
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
28
+ }
29
+ function withLock(lockPath, fn) {
30
+ const deadline = Date.now() + LOCK_TIMEOUT_MS;
31
+ for (;;) {
32
+ try {
33
+ closeSync(openSync(lockPath, "wx"));
34
+ break;
35
+ }
36
+ catch (err) {
37
+ if (err.code !== "EEXIST")
38
+ throw err;
39
+ try {
40
+ if (Date.now() - statSync(lockPath).mtimeMs > LOCK_STALE_MS)
41
+ unlinkSync(lockPath);
42
+ }
43
+ catch {
44
+ // Released meanwhile; try again.
45
+ }
46
+ if (Date.now() > deadline)
47
+ throw new Error(`Timed out waiting for the audit log lock ${lockPath}`);
48
+ sleepSync(5);
49
+ }
50
+ }
51
+ try {
52
+ return fn();
53
+ }
54
+ finally {
55
+ try {
56
+ unlinkSync(lockPath);
57
+ }
58
+ catch {
59
+ // Already gone.
60
+ }
61
+ }
62
+ }
63
+ /** Last line of the file (without its newline), and whether the file ends with one. */
64
+ function tail(fd) {
65
+ const size = fstatSync(fd).size;
66
+ if (size === 0)
67
+ return { endsWithNewline: true };
68
+ const chunks = [];
69
+ let pos = size;
70
+ let text = "";
71
+ while (pos > 0) {
72
+ const n = Math.min(65536, pos);
73
+ pos -= n;
74
+ const buf = Buffer.alloc(n);
75
+ readSync(fd, buf, 0, n, pos);
76
+ chunks.unshift(buf);
77
+ text = Buffer.concat(chunks).toString("utf8");
78
+ if (text.slice(0, -1).includes("\n"))
79
+ break;
80
+ }
81
+ const endsWithNewline = text.endsWith("\n");
82
+ const body = endsWithNewline ? text.slice(0, -1) : text;
83
+ return { line: body.slice(body.lastIndexOf("\n") + 1), endsWithNewline };
84
+ }
85
+ /** Hash a line links to: its `hash`, or for lines written before the chain, the hash of the raw line. */
86
+ function linkHash(raw) {
87
+ try {
88
+ const v = JSON.parse(raw);
89
+ if (typeof v.hash === "string")
90
+ return v.hash;
91
+ }
92
+ catch {
93
+ // Not JSON: link to the raw text.
94
+ }
95
+ return `sha256:${sha256Hex(raw)}`;
96
+ }
9
97
  export class JsonlAuditLog {
10
98
  path;
11
99
  constructor(path) {
@@ -13,8 +101,55 @@ export class JsonlAuditLog {
13
101
  mkdirSync(dirname(path), { recursive: true });
14
102
  }
15
103
  write(entry) {
16
- appendFileSync(this.path, `${JSON.stringify(entry)}\n`, "utf8");
104
+ withLock(`${this.path}.lock`, () => {
105
+ const fd = openSync(this.path, "a+");
106
+ try {
107
+ const t = tail(fd);
108
+ const prev = t.line === undefined ? AUDIT_GENESIS : linkHash(t.line);
109
+ const chained = { ...entry, prev };
110
+ const line = JSON.stringify({ ...chained, hash: digest(chained) });
111
+ writeSync(fd, `${t.endsWithNewline ? "" : "\n"}${line}\n`);
112
+ }
113
+ finally {
114
+ closeSync(fd);
115
+ }
116
+ });
117
+ }
118
+ }
119
+ /** Check every line's hash and its link to the line before. */
120
+ export function verifyAuditLog(path) {
121
+ const lines = readFileSync(path, "utf8").split("\n");
122
+ if (lines.at(-1) === "")
123
+ lines.pop();
124
+ let prev = AUDIT_GENESIS;
125
+ let unchained = 0;
126
+ let chained = false;
127
+ for (const [i, raw] of lines.entries()) {
128
+ const n = i + 1;
129
+ const fail = (problem) => ({ ok: false, lines: n, unchained, problem: `line ${n} ${problem}` });
130
+ let v;
131
+ try {
132
+ v = JSON.parse(raw);
133
+ }
134
+ catch {
135
+ return fail("is not valid JSON");
136
+ }
137
+ const { hash, ...rest } = v;
138
+ if (typeof hash !== "string") {
139
+ if (chained)
140
+ return fail("has no hash: it was inserted or edited");
141
+ unchained++;
142
+ prev = linkHash(raw);
143
+ continue;
144
+ }
145
+ chained = true;
146
+ if (rest.prev !== prev)
147
+ return fail(`doesn't follow line ${n - 1 || "(start)"}: a line was removed, reordered or inserted`);
148
+ if (digest(rest) !== hash)
149
+ return fail("was changed after it was written");
150
+ prev = hash;
17
151
  }
152
+ return { ok: true, lines: lines.length, unchained, ...(lines.length ? { last: prev } : {}) };
18
153
  }
19
154
  export class MemoryAuditLog {
20
155
  entries = [];
package/dist/audit.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCpC,MAAM,OAAO,aAAa;IACH;IAArB,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QAC/B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,KAAiB;QACrB,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;CACF;AAED,MAAM,OAAO,cAAc;IAChB,OAAO,GAAiB,EAAE,CAAC;IACpC,KAAK,CAAC,KAAiB;QACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;CACF"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const AUDIT_USAGE = "Usage: adtl-gateway audit verify [<file>] [-c <adtl.yaml>]\n\nThe audit log is hash-chained. verify checks that no line was edited,\nremoved, reordered or inserted (exit 1 if one was), and prints the hash of\nthe last line. Lines cut off the end are not detected; note that hash\nsomewhere else if you need to check later. Without <file>, the log is\ngateway.audit from the config.";
2
+ export interface AuditCommandResult {
3
+ stdout: string;
4
+ exitCode: number;
5
+ }
6
+ export declare function runAuditCommand(argv: string[]): Promise<AuditCommandResult>;
7
+ //# sourceMappingURL=auditCli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditCli.d.ts","sourceRoot":"","sources":["../src/auditCli.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,WAAW,kYAMO,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA2BjF"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `adtl-gateway audit`: check the audit log by hand.
3
+ *
4
+ * adtl-gateway audit verify [<file>] [-c adtl.yaml]
5
+ *
6
+ * Without a file, the log is `gateway.audit` from the config.
7
+ */
8
+ import { readFile } from "node:fs/promises";
9
+ import { dirname, resolve } from "node:path";
10
+ import { parse as parseYaml } from "yaml";
11
+ import { verifyAuditLog } from "./audit.js";
12
+ export const AUDIT_USAGE = `Usage: adtl-gateway audit verify [<file>] [-c <adtl.yaml>]
13
+
14
+ The audit log is hash-chained. verify checks that no line was edited,
15
+ removed, reordered or inserted (exit 1 if one was), and prints the hash of
16
+ the last line. Lines cut off the end are not detected; note that hash
17
+ somewhere else if you need to check later. Without <file>, the log is
18
+ gateway.audit from the config.`;
19
+ export async function runAuditCommand(argv) {
20
+ const [cmd, ...rest] = argv;
21
+ let config;
22
+ const files = [];
23
+ for (let i = 0; i < rest.length; i++) {
24
+ const a = rest[i];
25
+ if (a === "-c" || a === "--config")
26
+ config = rest[++i];
27
+ else if (a.startsWith("-"))
28
+ throw new Error(`Unknown argument: ${a}\n\n${AUDIT_USAGE}`);
29
+ else
30
+ files.push(a);
31
+ }
32
+ if (cmd === undefined || cmd === "-h" || cmd === "--help")
33
+ return { stdout: AUDIT_USAGE, exitCode: 0 };
34
+ if (cmd !== "verify")
35
+ throw new Error(`Unknown audit command: ${cmd}\n\n${AUDIT_USAGE}`);
36
+ if (files.length > 1)
37
+ throw new Error(`Unexpected argument: ${files[1]}\n\n${AUDIT_USAGE}`);
38
+ let path = files[0] && resolve(files[0]);
39
+ if (!path) {
40
+ if (!config)
41
+ throw new Error(`Give the audit log file, or -c <adtl.yaml> with gateway.audit set\n\n${AUDIT_USAGE}`);
42
+ const abs = resolve(config);
43
+ const gw = (parseYaml(await readFile(abs, "utf8")) ?? {}).gateway ?? {};
44
+ if (typeof gw.audit !== "string")
45
+ throw new Error(`${config} has no gateway.audit`);
46
+ path = resolve(dirname(abs), gw.audit);
47
+ }
48
+ const v = verifyAuditLog(path);
49
+ if (!v.ok)
50
+ return { stdout: `${path}: TAMPERED: ${v.problem}`, exitCode: 1 };
51
+ const before = v.unchained ? ` (${v.unchained} written before the chain)` : "";
52
+ return { stdout: `${path}: ${v.lines} lines${before}, chain intact${v.last ? `\nlast: ${v.last}` : ""}`, exitCode: 0 };
53
+ }
54
+ //# sourceMappingURL=auditCli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditCli.js","sourceRoot":"","sources":["../src/auditCli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Authorization: may this caller use this tool, resource or prompt at all?
3
+ *
4
+ * Labels and the policy answer "may this call run, given what the session has
5
+ * seen?". An Authorizer answers the question before it, from who is calling.
6
+ * The gateway asks it on every tools/call, resources/read and prompts/get,
7
+ * before the request interceptors run, and the stricter answer wins: a denial
8
+ * stops the call whatever the policy would say, and an allow still leaves the
9
+ * call to the policy.
10
+ *
11
+ * The caller is the SEP-2624 `context.principal` the gateway passes to the
12
+ * interceptors. Over stdio that is whoever started the gateway (anonymous
13
+ * unless configured); authenticated transports can fill it in per request.
14
+ *
15
+ * An authorizer that throws denies the call (fails closed). In audit mode
16
+ * denials are logged and not enforced, like policy decisions.
17
+ */
18
+ import type { InvocationContext } from "@adtl/interceptors";
19
+ export type Principal = NonNullable<InvocationContext["principal"]>;
20
+ export interface AuthorizationRequest {
21
+ principal: Principal;
22
+ event: "tools/call" | "resources/read" | "prompts/get";
23
+ /** Upstream server id, as named in the config. */
24
+ server: string;
25
+ /** Exactly one of tool, resource or prompt is set, matching `event`. */
26
+ tool?: string;
27
+ resource?: string;
28
+ prompt?: string;
29
+ /** Tool or prompt arguments, for authorizers that decide on them. */
30
+ arguments?: Record<string, unknown>;
31
+ }
32
+ export type AuthorizationDecision = {
33
+ allow: true;
34
+ } | {
35
+ allow: false;
36
+ reason: string;
37
+ };
38
+ export interface Authorizer {
39
+ /** Shown in audit entries and error messages, e.g. "rbac". */
40
+ readonly name: string;
41
+ check(request: AuthorizationRequest): AuthorizationDecision | Promise<AuthorizationDecision>;
42
+ }
43
+ /** A denial: which authorizer said no, and why. */
44
+ export interface Denial {
45
+ by: string;
46
+ reason: string;
47
+ }
48
+ /** Ask `authorizer`, failing closed. Returns the denial, or undefined if allowed. */
49
+ export declare function authorize(authorizer: Authorizer, request: AuthorizationRequest): Promise<Denial | undefined>;
50
+ //# sourceMappingURL=authorizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorizer.d.ts","sourceRoot":"","sources":["../src/authorizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,aAAa,CAAC;IACvD,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,MAAM,qBAAqB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,OAAO,EAAE,oBAAoB,GAAG,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC9F;AAED,mDAAmD;AACnD,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qFAAqF;AACrF,wBAAsB,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAUlH"}
@@ -0,0 +1,15 @@
1
+ /** Ask `authorizer`, failing closed. Returns the denial, or undefined if allowed. */
2
+ export async function authorize(authorizer, request) {
3
+ let d;
4
+ try {
5
+ d = await authorizer.check(request);
6
+ }
7
+ catch (err) {
8
+ return { by: authorizer.name, reason: `${authorizer.name} failed: ${err instanceof Error ? err.message : String(err)}` };
9
+ }
10
+ if (d?.allow === true)
11
+ return undefined;
12
+ const reason = d && "reason" in d && typeof d.reason === "string" && d.reason ? d.reason : `${authorizer.name} denied the call`;
13
+ return { by: authorizer.name, reason };
14
+ }
15
+ //# sourceMappingURL=authorizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorizer.js","sourceRoot":"","sources":["../src/authorizer.ts"],"names":[],"mappings":"AAgDA,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,UAAsB,EAAE,OAA6B;IACnF,IAAI,CAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,CAAC,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IAC3H,CAAC;IACD,IAAI,CAAC,EAAE,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,kBAAkB,CAAC;IAChI,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;AACzC,CAAC"}
package/dist/cli.js CHANGED
@@ -6,7 +6,8 @@
6
6
  * adtl-gateway --config adtl.yaml [--audit]
7
7
  * adtl-gateway init --config adtl.yaml [--from .mcp.json] [--write]
8
8
  * adtl-gateway hook --config adtl.yaml [--gateway-server adtl]
9
- * adtl-gateway ledger stats|verify|declassify <file>
9
+ * adtl-gateway ledger stats|verify|declassify|declassified
10
+ * adtl-gateway audit verify [<file>]
10
11
  *
11
12
  * Point your MCP client (e.g. Claude Code's .mcp.json) at this command.
12
13
  * Logs go to stderr; stdout carries MCP JSON-RPC only.
@@ -14,6 +15,7 @@
14
15
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
15
16
  import { EnvExpansionError } from "./config.js";
16
17
  import { GATEWAY_VERSION } from "./gateway.js";
18
+ import { runAuditCommand } from "./auditCli.js";
17
19
  import { runHook } from "./hooks/run.js";
18
20
  import { runLedgerCommand } from "./ledgerCli.js";
19
21
  import { runInit } from "./init/run.js";
@@ -21,7 +23,8 @@ import { GatewayConfigError, loadGatewayConfig, startGateway } from "./startup.j
21
23
  const USAGE = `Usage: adtl-gateway --config <adtl.yaml> [--audit]
22
24
  adtl-gateway init --config <adtl.yaml> [--from <.mcp.json>] [--write]
23
25
  adtl-gateway hook --config <adtl.yaml> [--gateway-server <name>]
24
- adtl-gateway ledger stats|verify|declassify <file> (see: adtl-gateway ledger --help)
26
+ adtl-gateway ledger stats|verify|declassify|declassified (see: adtl-gateway ledger --help)
27
+ adtl-gateway audit verify [<file>] (see: adtl-gateway audit --help)
25
28
 
26
29
  Runs an MCP server over stdio that forwards tool calls to the upstream
27
30
  servers in the config, checking and labeling each call with ADTL.
@@ -91,6 +94,12 @@ async function main() {
91
94
  process.exitCode = r.exitCode;
92
95
  return;
93
96
  }
97
+ if (process.argv[2] === "audit") {
98
+ const r = await runAuditCommand(process.argv.slice(3));
99
+ console.log(r.stdout);
100
+ process.exitCode = r.exitCode;
101
+ return;
102
+ }
94
103
  const args = parseArgs(process.argv.slice(2));
95
104
  // --help and --version print to stdout and exit; MCP is never served in these modes.
96
105
  if (args.help)
@@ -193,7 +202,7 @@ async function init(path, write, from) {
193
202
  process.exitCode = 1;
194
203
  }
195
204
  main().catch((err) => {
196
- const known = err instanceof GatewayConfigError || err instanceof EnvExpansionError || process.argv[2] === "ledger";
205
+ const known = err instanceof GatewayConfigError || err instanceof EnvExpansionError || ["ledger", "audit"].includes(process.argv[2] ?? "");
197
206
  console.error(known ? `[adtl-gateway] ${err.message}` : err);
198
207
  // For Claude Code hooks only exit code 2 stops the call; any other code lets it run.
199
208
  process.exit(process.argv[2] === "hook" ? 2 : 1);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/gateway.d.ts CHANGED
@@ -3,8 +3,9 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { type CallToolResult, type GetPromptResult, type Prompt, type ReadResourceResult, type Resource, type ResourceTemplate, type Tool } from "@modelcontextprotocol/sdk/types.js";
4
4
  import type { ApprovalBroker } from "./approvals.js";
5
5
  import type { AuditSink } from "./audit.js";
6
+ import { type Authorizer, type Principal } from "./authorizer.js";
6
7
  import type { InterceptorInvoker } from "./invoker.js";
7
- export declare const GATEWAY_VERSION = "0.4.0";
8
+ export declare const GATEWAY_VERSION = "0.5.0";
8
9
  /** `_meta` key on gateway-generated error results describing why a call was stopped. */
9
10
  export declare const GATEWAY_DECISION_KEY = "adtl/gateway";
10
11
  export interface GatewayLogger {
@@ -20,6 +21,10 @@ export interface AdtlGatewayOptions {
20
21
  logger?: GatewayLogger;
21
22
  /** Asks humans about "ask" decisions and sends notices. */
22
23
  approvals?: ApprovalBroker;
24
+ /** Decides whether the caller may use a tool, resource or prompt at all, before the policy. */
25
+ authorizer?: Authorizer;
26
+ /** The caller, passed to the authorizer and the interceptors. Default: anonymous. */
27
+ principal?: Principal;
23
28
  }
24
29
  export interface CallOptions {
25
30
  /** Report progress to the client while a call waits for approval. */
@@ -32,12 +37,16 @@ export declare class AdtlGateway {
32
37
  private readonly audit;
33
38
  private readonly log;
34
39
  private readonly approvals;
40
+ private readonly authorizer;
41
+ private readonly principal;
35
42
  private routes;
36
43
  private promptRoutes;
37
44
  /** Resource URI → the upstreams that list it. */
38
45
  private resourceRoutes;
39
46
  private templateRoutes;
40
47
  constructor(opts: AdtlGatewayOptions);
48
+ /** Ask the authorizer, if any. Returns the denial; in audit mode the caller logs it and carries on. */
49
+ private authorize;
41
50
  /** The downstream MCP server the agent connects to. */
42
51
  createServer(): Server;
43
52
  /** Every upstream's items from one list method, following cursors. Upstreams that fail are skipped with a warning. */
@@ -51,8 +60,8 @@ export declare class AdtlGateway {
51
60
  readResource(uri: string): Promise<ReadResourceResult>;
52
61
  getPrompt(name: string, args?: Record<string, string>): Promise<GetPromptResult>;
53
62
  /**
54
- * Forward a resources/read or prompts/get request through the interceptor
55
- * chain: request interceptors → upstream → response interceptors (adtl.label).
63
+ * Forward a resources/read or prompts/get request through the interceptors:
64
+ * request interceptors → upstream → response interceptors (adtl.label).
56
65
  * These requests have no tool result to carry an error, so a stopped request
57
66
  * becomes a JSON-RPC error.
58
67
  */