@adtl/gateway 0.7.0 → 0.8.1
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/README.md +143 -11
- package/dist/audit.d.ts +3 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/cli.js +10 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +167 -713
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +64 -7
- package/dist/config.js.map +1 -1
- package/dist/elicitation.d.ts +7 -1
- package/dist/elicitation.d.ts.map +1 -1
- package/dist/elicitation.js +21 -14
- package/dist/elicitation.js.map +1 -1
- package/dist/gateway.d.ts +11 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +13 -5
- package/dist/gateway.js.map +1 -1
- package/dist/hooks/agentLinks.d.ts +18 -0
- package/dist/hooks/agentLinks.d.ts.map +1 -0
- package/dist/hooks/agentLinks.js +48 -0
- package/dist/hooks/agentLinks.js.map +1 -0
- package/dist/hooks/claudeCode.d.ts +4 -0
- package/dist/hooks/claudeCode.d.ts.map +1 -1
- package/dist/hooks/claudeCode.js +35 -8
- package/dist/hooks/claudeCode.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/run.d.ts.map +1 -1
- package/dist/hooks/run.js +5 -2
- package/dist/hooks/run.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/init/suggest.d.ts +3 -1
- package/dist/init/suggest.d.ts.map +1 -1
- package/dist/init/suggest.js +8 -0
- package/dist/init/suggest.js.map +1 -1
- package/dist/invoker.d.ts +56 -6
- package/dist/invoker.d.ts.map +1 -1
- package/dist/invoker.js +121 -19
- package/dist/invoker.js.map +1 -1
- package/dist/openfga.d.ts +13 -0
- package/dist/openfga.d.ts.map +1 -0
- package/dist/openfga.js +101 -0
- package/dist/openfga.js.map +1 -0
- package/dist/startup.d.ts +10 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +82 -11
- package/dist/startup.js.map +1 -1
- package/dist/totp.d.ts +42 -0
- package/dist/totp.d.ts.map +1 -0
- package/dist/totp.js +176 -0
- package/dist/totp.js.map +1 -0
- package/dist/totpCli.d.ts +11 -0
- package/dist/totpCli.d.ts.map +1 -0
- package/dist/totpCli.js +46 -0
- package/dist/totpCli.js.map +1 -0
- package/package.json +8 -7
- package/playground/server.mjs +13 -3
- package/src/audit.ts +3 -1
- package/src/cli.ts +10 -1
- package/src/config.ts +71 -7
- package/src/elicitation.ts +35 -17
- package/src/gateway.ts +18 -5
- package/src/hooks/agentLinks.ts +58 -0
- package/src/hooks/claudeCode.ts +40 -9
- package/src/hooks/index.ts +1 -0
- package/src/hooks/run.ts +5 -2
- package/src/index.ts +3 -0
- package/src/init/suggest.ts +10 -1
- package/src/invoker.ts +153 -21
- package/src/openfga.ts +101 -0
- package/src/startup.ts +79 -11
- package/src/totp.ts +191 -0
- package/src/totpCli.ts +52 -0
- package/src/types/qrcode-terminal.d.ts +4 -0
package/README.md
CHANGED
|
@@ -75,6 +75,20 @@ One file holds both the labels and the gateway settings.
|
|
|
75
75
|
|
|
76
76
|
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`.
|
|
77
77
|
|
|
78
|
+
#### Tools that describe themselves: action-metadata
|
|
79
|
+
|
|
80
|
+
Some servers annotate their tools with the Tool Annotations IG's draft [`action-metadata`](https://github.com/modelcontextprotocol/experimental-ext-tool-annotations/blob/main/specification/draft/action-metadata.mdx) extension (`annotations["io.modelcontextprotocol/action-metadata"]`). The gateway reads it as the server's own claim:
|
|
81
|
+
|
|
82
|
+
| Field | Used as | From any server | Only with `acceptServerClaims: true` |
|
|
83
|
+
|---|---|---|---|
|
|
84
|
+
| `returnMetadata.source` | result integrity | `open-world` makes it `untrusted` | `first-party` makes it `trusted` |
|
|
85
|
+
| `returnMetadata.sensitivity` | result confidentiality | anything but `public` makes it at least `private` (`credentials` / `secret`: `secret`) | `public` |
|
|
86
|
+
| `inputMetadata.destination` | egress | `external` / `public`, or anything stricter than your rule | `local` / `internal` (as `internal`), `none` |
|
|
87
|
+
| `outcome` | policy condition `tool.outcome` | yes | |
|
|
88
|
+
| `requiresReview` | `ask` before the call | yes | |
|
|
89
|
+
|
|
90
|
+
Your rules still come first: a claim can make them stricter, never looser. Unknown values are ignored. The extension is a draft, so its values may change.
|
|
91
|
+
|
|
78
92
|
#### Drafting rules with `init`
|
|
79
93
|
|
|
80
94
|
List your servers under `gateway.upstreams`, then let `init` draft a rule for every tool:
|
|
@@ -87,7 +101,7 @@ adtl-gateway init -c adtl.yaml --write # update the file (original kept as adt
|
|
|
87
101
|
`init` connects to each upstream and lists its tools.
|
|
88
102
|
|
|
89
103
|
- **Presets** cover the GitHub (`github-mcp-server`), filesystem and fetch servers, Slack (`@modelcontextprotocol/server-slack` and `slack-mcp-server`) and Gmail (`@gongrzhe/server-gmail-autoauth-mcp`). A preset says what the server's reads and writes mean; the server's `readOnlyHint` decides which tools are reads, so new tools are covered too. For servers without hints, the preset lists their tools by name. Slack messages and email are untrusted and private; posting to Slack is external egress, and so are sending email and Gmail filters, which can forward mail.
|
|
90
|
-
- **Other servers** get rules from their MCP tool hints.
|
|
104
|
+
- **Other servers** get rules from their action-metadata destination if they declare one, else their MCP tool hints. Either only sets egress, because they are the server's own claims: every result stays `untrusted` and `private` until you change it. These lines are marked `review`.
|
|
91
105
|
- Entries already in the file are never changed, so you can re-run `init` after a server adds tools. Tools the server no longer offers are reported, not removed.
|
|
92
106
|
- Edits keep your comments, but the YAML may be reformatted slightly (e.g. `[a]` becomes `[ a ]`).
|
|
93
107
|
|
|
@@ -114,7 +128,7 @@ Labels only get stricter as a session goes on. A session that has read anything
|
|
|
114
128
|
|
|
115
129
|
### Policy
|
|
116
130
|
|
|
117
|
-
Rules match on `session.integrity`, `session.confidentiality`, `tool.egress
|
|
131
|
+
Rules match on `session.integrity`, `session.confidentiality`, `tool.egress`, `tool` (`server.tool` globs such as `github.*`), and, for tools that declare [action-metadata](#tools-that-describe-themselves-action-metadata), `tool.outcome` (`benign`, `consequential`, `irreversible`) and `tool.requiresReview`. They decide `allow`, `ask` or `block`. When several rules match, the most restrictive decision wins. A tool that says `requiresReview: true` gets `ask` when no rule blocks it; set `policy.honorRequiresReview: false` to turn that off. `ask` waits for a human when [approvals](#approvals) are configured, and blocks otherwise.
|
|
118
132
|
|
|
119
133
|
### Gateway
|
|
120
134
|
|
|
@@ -125,14 +139,48 @@ Rules match on `session.integrity`, `session.confidentiality`, `tool.egress` and
|
|
|
125
139
|
| `gateway.mode` | `active` (default) or `audit`. See [Trying a policy safely](#trying-a-policy-safely). |
|
|
126
140
|
| `gateway.approvals` | Ask a human about `ask` decisions. See [Approvals](#approvals). |
|
|
127
141
|
| `gateway.interceptorTimeoutMs` | Timeout per interceptor call (default 5000) |
|
|
142
|
+
| `gateway.interceptorOverrides.<name>` | Execution policy for one interceptor, overriding what it declares: `failOpen`, `priorityHint`, `mode`, `timeoutMs`, and `hooks` (may only narrow the declared hooks). See [Interceptor overrides](#interceptor-overrides). |
|
|
128
143
|
| `gateway.interceptors` | Custom interceptor server command (default: the bundled `@adtl/interceptors`) |
|
|
144
|
+
| `gateway.interceptorServers.<id>` | More interceptor servers, stdio or Streamable HTTP, whose interceptors run beside ADTL's. See [More interceptor servers](#more-interceptor-servers). |
|
|
129
145
|
| `gateway.principal` | Who runs this gateway: `{ id, type?, claims? }`. `${VAR}` works in `id`. Default: anonymous. See [Authorization](#authorization). |
|
|
130
146
|
| `gateway.roles` | Who may use which tools, prompts and resources. Deny by default once present. See [Authorization](#authorization). |
|
|
131
147
|
| `gateway.cedar` | Cedar policies for attribute-based rules: `{ policies, entities?, timeZone? }`. See [Cedar policies](#cedar-policies). |
|
|
148
|
+
| `gateway.openfga` | OpenFGA checks for relationship rules: `{ url, storeId, modelId?, token?, relation?, timeoutMs?, tools? }`. See [OpenFGA](#openfga). |
|
|
149
|
+
|
|
150
|
+
#### More interceptor servers
|
|
151
|
+
|
|
152
|
+
SEP-2624 interceptors can come from several servers. Add other people's interceptors (PII redaction, logging, your own checks) next to ADTL's:
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
gateway:
|
|
156
|
+
interceptorServers:
|
|
157
|
+
pii: { command: npx, args: ["-y", "some-pii-interceptor"] } # local, over stdio
|
|
158
|
+
audit: { url: https://audit.example.com/mcp, headers: { Authorization: "Bearer ${AUDIT_TOKEN}" } }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- Each interceptor is invoked on the server that advertised it, in the usual order: mutators by priority then name, validators in parallel.
|
|
162
|
+
- They get the call's payload and context, but not ADTL's per-call `config` (server, tool, annotations), so their own defaults apply.
|
|
163
|
+
- The gateway refuses to start if a server can't be reached, doesn't declare the interceptors extension, or offers an interceptor whose name another server already uses.
|
|
164
|
+
- `adtl.label` runs late (priority 1000) so its label describes the final content. A mutator that would run after it gets a warning at startup, since it could change or drop the label; give it a lower `priorityHint` with an [override](#interceptor-overrides).
|
|
165
|
+
|
|
166
|
+
#### Interceptor overrides
|
|
167
|
+
|
|
168
|
+
SEP-2624 lets the gateway owner change how each interceptor runs without changing the interceptor server. Key them by interceptor name:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
gateway:
|
|
172
|
+
interceptorOverrides:
|
|
173
|
+
adtl.label: { timeoutMs: 10000 } # a slow ledger on a network drive
|
|
174
|
+
pii.redact: # a third-party interceptor
|
|
175
|
+
priorityHint: -50000
|
|
176
|
+
hooks: [{ events: ["tools/call"], phase: response }]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The gateway refuses to start if an override names an interceptor the server doesn't offer, or lists hooks the interceptor doesn't declare: hooks can only be narrowed. `gateway.mode: audit` (or `--audit`) still wins over a per-interceptor `mode`. Overrides that relax `adtl.policy` or `adtl.label` (`mode: audit`, `failOpen: true`, or narrowed `hooks`) are allowed, with a warning at startup.
|
|
132
180
|
|
|
133
181
|
#### Checking the audit log
|
|
134
182
|
|
|
135
|
-
Each entry lists the interceptors that ran for the call, with the execution policy each ran under, as SEP-2624 asks: `interceptors: [{ name, phase, mode, modeFrom, failOpen, failOpenFrom, failed? }]`, where `*From` is `override` (set by the gateway
|
|
183
|
+
Each entry lists the interceptors that ran for the call, with the execution policy each ran under, as SEP-2624 asks: `interceptors: [{ name, phase, mode, modeFrom, failOpen, failOpenFrom, timeoutMs, failed? }]`, where `*From` is `override` (set by the gateway: `--audit` or `interceptorOverrides`) or `default` (declared by the interceptor).
|
|
136
184
|
|
|
137
185
|
Each line carries `prev`, the hash of the line before, and `hash`, over the line itself. Check the chain with:
|
|
138
186
|
|
|
@@ -206,6 +254,27 @@ gateway:
|
|
|
206
254
|
- It's off by default because a client that accepts elicitations by itself, without a person, would approve calls. Turn it on only for clients that always show the prompt to you.
|
|
207
255
|
- It's never used for rules with named approvers: the client can't say who answered.
|
|
208
256
|
|
|
257
|
+
#### Approving with an authenticator app
|
|
258
|
+
|
|
259
|
+
For a stronger answer than a click, ask for a 6-digit code from an authenticator app (Google Authenticator, 1Password, ...). Codes are made offline on your phone, and a client that accepts prompts by itself can't produce one.
|
|
260
|
+
|
|
261
|
+
```sh
|
|
262
|
+
adtl-gateway totp setup # shows a QR code to scan; --force replaces an existing secret
|
|
263
|
+
adtl-gateway totp check 123456 # does this code match right now? (doesn't use it up)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
gateway:
|
|
268
|
+
approvals:
|
|
269
|
+
totp: true # wins over elicitation: true
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
- The prompt appears in the client, as with elicitation, and asks for the code. The model never sees the prompt or the code. Three wrong codes, declining or no answer stops the call.
|
|
273
|
+
- A code works for the one pending call, once, within one 30-second step either way. The last used step is kept next to the secret, so a code can't be replayed after a restart.
|
|
274
|
+
- The secret is kept in the macOS Keychain, or elsewhere in a file only you can read (`ADTL_TOTP_FILE`, default `~/.adtl/totp-secret`). The gateway won't start with `totp: true` and no secret.
|
|
275
|
+
- Clients without elicitation support aren't asked: other configured channels still work, and with none the call is blocked. It's never used for rules with named approvers.
|
|
276
|
+
- An agent with shell access as the same user may still be able to read the secret. The hooks refuse writes to these files and ask before commands that mention them, but that's a speed bump. To rule it out, run the gateway on another machine.
|
|
277
|
+
|
|
209
278
|
#### Who may approve
|
|
210
279
|
|
|
211
280
|
By default, whoever can read the shared topic can approve, and ADTL can't tell who did. A policy rule can name the roles whose members may answer instead. Each member gets their own topic:
|
|
@@ -252,7 +321,8 @@ The gateway only sees MCP calls. Claude Code's own tools (`WebFetch`, `WebSearch
|
|
|
252
321
|
"hooks": {
|
|
253
322
|
"PreToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10, "onFailure": "block" }] }],
|
|
254
323
|
"PostToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10 }] }],
|
|
255
|
-
"PostToolUseFailure": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10 }] }]
|
|
324
|
+
"PostToolUseFailure": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10 }] }],
|
|
325
|
+
"SubagentStart": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10 }] }]
|
|
256
326
|
}
|
|
257
327
|
}
|
|
258
328
|
```
|
|
@@ -266,7 +336,7 @@ What it does:
|
|
|
266
336
|
- **It shares one session label with the gateway.** Claude Code gives the gateway its session id (`CLAUDE_CODE_SESSION_ID`), and both keep the label in `~/.adtl/sessions/<id>.jsonl` (set `ADTL_SESSIONS_DIR` to change the directory). A `WebFetch` taints the session for `github__add_comment`, and a private file read through the gateway counts against a later `Bash` call. Labels last for the whole Claude Code session, including `--resume`.
|
|
267
337
|
- **It covers MCP servers that skip the gateway**, such as connectors added in claude.ai. Their tools are labeled as their server name (`mcp__<server>__<tool>` → server `<server>`), so you can describe them under `servers:` like any upstream. The gateway's own tools (`mcp__adtl__*`) are skipped; pass `--gateway-server <name>` if you registered the gateway under another name.
|
|
268
338
|
- **It fails closed.** If the hook can't decide, it exits with code 2, which stops the call.
|
|
269
|
-
- **It writes to the same audit log** (`gateway.audit`) with `"via": "claude-code-hook"`, and follows `gateway.mode: audit`. Calls made inside a
|
|
339
|
+
- **It writes to the same audit log** (`gateway.audit`) with `"via": "claude-code-hook"`, and follows `gateway.mode: audit`. Calls made inside a sub-agent carry `"agent": { id, type }`; see [Sub-agents](#sub-agents). The config needs no `gateway:` section if you only use the hooks.
|
|
270
340
|
|
|
271
341
|
Built-in labels, which you can override under `servers.claude-code.tools`:
|
|
272
342
|
|
|
@@ -283,6 +353,20 @@ With the [example policy](../../examples/adtl.yaml), `Bash` and `WebFetch` run f
|
|
|
283
353
|
|
|
284
354
|
The hook also refuses `Write` and `Edit` on your ADTL config and session files, and asks before shell commands that mention the session directory, so the agent can't simply clear its own taint. This is a speed bump, not a sandbox.
|
|
285
355
|
|
|
356
|
+
### Sub-agents
|
|
357
|
+
|
|
358
|
+
A sub-agent starts from its parent's label, and what it reads taints the parent: the two share one session label. A sub-agent's answer mixes everything it saw, so sharing is the only safe default.
|
|
359
|
+
|
|
360
|
+
- **Claude Code.** MCP calls from sub-agents go through the same gateway, so they share its session anyway. For built-in tools, the `SubagentStart` hook (in the snippet above) records which session each sub-agent was started in. Its later hook calls then use the parent's label even if Claude Code reports a session id of its own for them; Claude Code's docs suggest it reports the parent's. Audit entries name the sub-agent: `"agent": { "id": "…", "type": "Explore" }`.
|
|
361
|
+
- **Other frameworks.** Start each sub-agent's gateway with its parent's session id and its own agent id:
|
|
362
|
+
|
|
363
|
+
```sh
|
|
364
|
+
ADTL_SESSION_ID=<parent session> ADTL_AGENT_ID=researcher-1 ADTL_AGENT_TYPE=researcher \
|
|
365
|
+
npx -y @adtl/gateway --config adtl.yaml
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
`ADTL_SESSION_ID` keeps the label in the shared session files (`ADTL_SESSIONS_DIR`, default `~/.adtl/sessions`), like `CLAUDE_CODE_SESSION_ID` does, and wins over it. `ADTL_AGENT_ID` and `ADTL_AGENT_TYPE` go on every audit entry.
|
|
369
|
+
|
|
286
370
|
## Label ledger
|
|
287
371
|
|
|
288
372
|
Session labels end with the session. If an agent writes untrusted content to a file, a fresh session reading that file tomorrow would trust it. The ledger remembers who wrote what:
|
|
@@ -322,16 +406,35 @@ Some memory servers extract facts with a model on write, or merge records, so wh
|
|
|
322
406
|
servers:
|
|
323
407
|
memory:
|
|
324
408
|
tools:
|
|
325
|
-
add_memory: { egress: internal, labelInto: metadata, scopeInto: run_id }
|
|
326
|
-
update_memory: { egress: internal, labelInto: metadata }
|
|
327
|
-
search_memory: { integrity: trusted, confidentiality: public, egress: none, readLabels: true }
|
|
409
|
+
add_memory: { egress: internal, labelInto: metadata, scopeInto: run_id, recordIds: id }
|
|
410
|
+
update_memory: { egress: internal, labelInto: metadata, recordIds: id }
|
|
411
|
+
search_memory: { integrity: trusted, confidentiality: public, egress: none, readLabels: true, recordIds: id }
|
|
328
412
|
```
|
|
329
413
|
|
|
330
414
|
- **Write.** On every `add_memory` and `update_memory` call the gateway sets `metadata["adtl/record-label/<session>"]` to `{ integrity, confidentiality, writer }` from the session, and drops any stamp keys the agent put there. Each session stamps under its own key, so on a server that lays an update's metadata over the stored metadata (as Mem0 does), a clean session's update adds a stamp instead of replacing a tainted one.
|
|
331
415
|
- **Read.** 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.
|
|
332
416
|
- **Scope.** Some servers also keep recent raw messages per scope, without metadata, and resolve references in a new message from them: Mem0 keeps the last 10 per `user_id`/`agent_id`/`run_id` and asks its extractor to resolve pronouns from them. A clean session writing under a tainted session's ids could then store a fact built from the tainted text, with a clean stamp. With `scopeInto: run_id`, a tainted session's writes get a run id named after its label (`<run_id>:adtl-untrusted-public`, or just `adtl-untrusted-public`), so the server keeps its messages apart. Clean sessions keep their ids, minus any label mark the agent added, so they can't join a tainted scope. Mem0 filters searches by the ids a call sets: a read that names the agent's own `run_id` doesn't see the tainted session's records, and one by `user_id` alone sees them all, with their stamps.
|
|
333
417
|
- **Tools that return text without metadata** can't carry the label, and the ledger can't recognize extracted text. Give them a strict rule, such as `integrity: untrusted`. In Mem0 that is `history()`, and on Mem0's hosted MCP server `list_events` and `get_event_status`.
|
|
334
|
-
- **
|
|
418
|
+
- **Record ids.** With `recordIds: id` (and the ledger on), the gateway also remembers a tainted session's writes by record id: the ids a write tool is given (`update_memory`'s `id`) and returns (`add_memory`'s `ids`). Reads join the label back for any id they return, and the audit entry gets `recordIds: { matched, writers }`. This keeps the label when a server's update replaces the metadata instead of merging it, which [Mem0's hosted docs](https://github.com/probita-ai/adtl/issues/48) describe for `update_memory`.
|
|
419
|
+
- **Merges.** A server that folds records together (Mem0's hosted Merge) keeps the label when the merged text still holds the tainted text as a whole line or paragraph (the ledger recognizes it), and the hidden, merged-away record keeps it by id. A merge that rewords the text loses it: if your account runs Merge, give the read tools a strict rule.
|
|
420
|
+
- **Servers that drop or replace metadata** without returning record ids (when they consolidate records into new ones, for example) can't carry the label either. Give their read tools a strict rule.
|
|
421
|
+
|
|
422
|
+
## FIDES and fides-gateway
|
|
423
|
+
|
|
424
|
+
ADTL's labels map onto [FIDES](https://arxiv.org/abs/2505.23643), the information-flow model behind Microsoft's [fides-gateway](https://github.com/microsoft/fides-gateway), so the two can sit in one chain.
|
|
425
|
+
|
|
426
|
+
- **Reading** is always on. Results that carry fides-gateway labels (`_meta["com.github.ifc/labels"]`, JSONPath → `{ integrity, confidentiality: [readers] }`) count as the server's own claims, like trust-annotations: they can make a label stricter, and relax it only with `acceptServerClaims: true`. Any reader list without `"public"` means `private`, and the strictest path wins.
|
|
427
|
+
- **Writing** is opt-in:
|
|
428
|
+
|
|
429
|
+
```yaml
|
|
430
|
+
fides:
|
|
431
|
+
emit: true
|
|
432
|
+
readers: [alice@example.com] # optional: who may read private data; default: gateway.principal.id, else nobody
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Results then also carry the label in fides-gateway's form, and every outgoing tool call carries the session's label in its `_meta` (one `"$"` entry, which covers the name and every argument), so a fides-gateway behind ADTL can enforce on it.
|
|
436
|
+
|
|
437
|
+
FIDES has two integrity levels, so `unknown` becomes `untrusted`. It has reader sets instead of levels, so `private` and `secret` both become the configured readers. To check the mapping against fides-gateway's own code, see [examples/fides-interop](../../examples/fides-interop).
|
|
335
438
|
|
|
336
439
|
## How it works
|
|
337
440
|
|
|
@@ -411,6 +514,33 @@ Each call becomes a Cedar request:
|
|
|
411
514
|
- Arguments are passed without nulls, with fractions as strings. Objects with `__entity` or `__extn` are passed as JSON strings, so a tool argument can't name an entity.
|
|
412
515
|
- With `roles` set too, both must allow. A policy file that doesn't parse stops the gateway at startup; an evaluation error denies the call.
|
|
413
516
|
|
|
517
|
+
#### OpenFGA
|
|
518
|
+
|
|
519
|
+
For relationship rules such as "bob can comment on repos in org acme", point the gateway at an [OpenFGA](https://openfga.dev/) server (or Auth0 FGA). It needs no extra package.
|
|
520
|
+
|
|
521
|
+
```yaml
|
|
522
|
+
gateway:
|
|
523
|
+
principal: { id: "${USER}" }
|
|
524
|
+
openfga:
|
|
525
|
+
url: http://localhost:8080
|
|
526
|
+
storeId: "${FGA_STORE_ID}"
|
|
527
|
+
modelId: "${FGA_MODEL_ID}" # optional: pin an authorization model
|
|
528
|
+
token: "${FGA_TOKEN}" # optional: bearer token
|
|
529
|
+
relation: can_use # optional: the default relation
|
|
530
|
+
tools: # optional: per-resource rules, from the call's arguments
|
|
531
|
+
github.add_issue_comment: { relation: can_comment, object: "repo:{owner}/{repo}" }
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Each call becomes one OpenFGA check:
|
|
535
|
+
|
|
536
|
+
| | Value |
|
|
537
|
+
|---|---|
|
|
538
|
+
| user | `user:<id>`, `service:<id>`, or `user:anonymous` |
|
|
539
|
+
| relation | the tool's rule, else `relation` |
|
|
540
|
+
| object | the tool's rule, else `tool:<server>.<tool>`, `prompt:<server>.<name>` or `resource:<uri>` |
|
|
541
|
+
|
|
542
|
+
Ids are percent-encoded, since OpenFGA ids can't hold `:`, `#`, `@` or spaces, so `{owner}/{repo}` is stored as `repo:acme%2Fwebsite`; write your tuples the same way. A missing or non-scalar `{argument}` denies the call. Tool lists have no arguments, so tools whose object needs them stay listed and are checked when called. If OpenFGA errors or can't be reached within `timeoutMs` (2000 by default), the call is denied. With `roles` or `cedar` as well, every one must allow.
|
|
543
|
+
|
|
414
544
|
#### Your own authorizer
|
|
415
545
|
|
|
416
546
|
Or your own `Authorizer` in code:
|
|
@@ -442,10 +572,12 @@ The gateway fails closed. If an interceptor errors or times out, the call is sto
|
|
|
442
572
|
|
|
443
573
|
- Tools, resources and prompts are proxied. Resource subscriptions, `list_changed` notifications and completions are not passed through yet.
|
|
444
574
|
- 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.
|
|
445
|
-
- Approvals come from ntfy, email notices and,
|
|
446
|
-
- 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
|
|
575
|
+
- Approvals come from ntfy, email notices and, through the MCP client, a prompt (`elicitation: true`) or an authenticator code (`totp: true`).
|
|
576
|
+
- 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, and [sub-agents](#sub-agents) share their parent's label, but the gateway doesn't sign or read [A2A](../../docs/a2a-trust-labels-v1.md) messages itself yet. 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.
|
|
447
577
|
- 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.
|
|
448
578
|
- Labels are set by your config. Servers' own trust claims can only make labels stricter, unless you set `acceptServerClaims: true`.
|
|
579
|
+
- [action-metadata](#tools-that-describe-themselves-action-metadata) needs the tool's annotations from `tools/list`, so it applies to tools behind the gateway. MCP tools that only the Claude Code hooks see are checked without it: `requiresReview` and `tool.outcome` have no effect on them.
|
|
580
|
+
- The playground takes `gateway.interceptorOverrides` from your config but no other `gateway:` setting, and never `interceptorServers`, so a web page can't start commands.
|
|
449
581
|
|
|
450
582
|
## Links
|
|
451
583
|
|
package/dist/audit.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface AuditEntry {
|
|
|
12
12
|
outcome: "forwarded" | "blocked" | "asked" | "upstream_error";
|
|
13
13
|
/** Present when the entry was written by the Claude Code hook rather than the gateway. */
|
|
14
14
|
via?: "claude-code-hook";
|
|
15
|
-
/** Present when a
|
|
15
|
+
/** Present when a sub-agent made the call: its id and type (e.g. "Explore"), from Claude Code or `ADTL_AGENT_ID`. */
|
|
16
16
|
agent?: {
|
|
17
17
|
id: string;
|
|
18
18
|
type?: string;
|
|
@@ -41,6 +41,8 @@ export interface AuditEntry {
|
|
|
41
41
|
ledger?: unknown;
|
|
42
42
|
/** Present when the result carried record label stamps: how many, and which sessions wrote them. */
|
|
43
43
|
records?: unknown;
|
|
44
|
+
/** Present when the ledger knew record ids in the result (tool rule `recordIds`): how many, and which sessions wrote them. */
|
|
45
|
+
recordIds?: unknown;
|
|
44
46
|
sessionLabel?: unknown;
|
|
45
47
|
/** Every interceptor invocation for this call, with its resolved mode and failOpen and where each came from (SEP-2624). */
|
|
46
48
|
interceptors?: InterceptorRun[];
|
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,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,
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,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,qHAAqH;IACrH,KAAK,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,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,8HAA8H;IAC9H,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2HAA2H;IAC3H,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC,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.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7H,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* adtl-gateway receipt list|<session>|verify <file>
|
|
12
12
|
* adtl-gateway key
|
|
13
13
|
* adtl-gateway playground [--port 4317] [--no-open]
|
|
14
|
+
* adtl-gateway totp setup [--force]
|
|
14
15
|
*
|
|
15
16
|
* Point your MCP client (e.g. Claude Code's .mcp.json) at this command.
|
|
16
17
|
* Logs go to stderr; stdout carries MCP JSON-RPC only.
|
|
@@ -21,6 +22,7 @@ import { GATEWAY_VERSION } from "./gateway.js";
|
|
|
21
22
|
import { runAuditCommand } from "./auditCli.js";
|
|
22
23
|
import { runKeyCommand, runReceiptCommand } from "./receiptCli.js";
|
|
23
24
|
import { runPlayground } from "./playgroundCli.js";
|
|
25
|
+
import { runTotpCommand } from "./totpCli.js";
|
|
24
26
|
import { runHook } from "./hooks/run.js";
|
|
25
27
|
import { runLedgerCommand } from "./ledgerCli.js";
|
|
26
28
|
import { runInit } from "./init/run.js";
|
|
@@ -33,6 +35,7 @@ const USAGE = `Usage: adtl-gateway --config <adtl.yaml> [--audit]
|
|
|
33
35
|
adtl-gateway receipt list|<session>|verify <file> (see: adtl-gateway receipt --help)
|
|
34
36
|
adtl-gateway key
|
|
35
37
|
adtl-gateway playground [--port <n>] [--no-open] (a local web UI with fake servers)
|
|
38
|
+
adtl-gateway totp setup [--force] (authenticator-app approvals; see: adtl-gateway totp --help)
|
|
36
39
|
|
|
37
40
|
Runs an MCP server over stdio that forwards tool calls to the upstream
|
|
38
41
|
servers in the config, checking and labeling each call with ADTL.
|
|
@@ -110,6 +113,12 @@ async function main() {
|
|
|
110
113
|
}
|
|
111
114
|
if (process.argv[2] === "playground")
|
|
112
115
|
return runPlayground(process.argv.slice(3));
|
|
116
|
+
if (process.argv[2] === "totp") {
|
|
117
|
+
const r = await runTotpCommand(process.argv.slice(3));
|
|
118
|
+
console.log(r.stdout);
|
|
119
|
+
process.exitCode = r.exitCode;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
113
122
|
if (process.argv[2] === "receipt" || process.argv[2] === "key") {
|
|
114
123
|
const r = process.argv[2] === "key" ? await runKeyCommand() : await runReceiptCommand(process.argv.slice(3));
|
|
115
124
|
console.log(r.stdout);
|
|
@@ -218,7 +227,7 @@ async function init(path, write, from) {
|
|
|
218
227
|
process.exitCode = 1;
|
|
219
228
|
}
|
|
220
229
|
main().catch((err) => {
|
|
221
|
-
const known = err instanceof GatewayConfigError || err instanceof EnvExpansionError || ["ledger", "audit", "receipt", "key", "playground"].includes(process.argv[2] ?? "");
|
|
230
|
+
const known = err instanceof GatewayConfigError || err instanceof EnvExpansionError || ["ledger", "audit", "receipt", "key", "playground", "totp"].includes(process.argv[2] ?? "");
|
|
222
231
|
console.error(known ? `[adtl-gateway] ${err.message}` : err);
|
|
223
232
|
// For Claude Code hooks only exit code 2 stops the call; any other code lets it run.
|
|
224
233
|
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":";AACA
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|