@agent-custody/receipts 0.2.0 → 0.4.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/README.md +24 -12
- package/dist/cli.js +26 -6
- package/dist/config.d.ts +134 -0
- package/dist/config.js +34 -2
- package/dist/gateway.d.ts +9 -1
- package/dist/gateway.js +45 -16
- package/dist/index.d.ts +8 -0
- package/dist/index.js +3 -0
- package/dist/issue.d.ts +9 -2
- package/dist/issue.js +13 -2
- package/dist/log-sink.d.ts +15 -0
- package/dist/log-sink.js +31 -18
- package/dist/log.d.ts +8 -0
- package/dist/log.js +17 -3
- package/dist/otel.d.ts +28 -0
- package/dist/otel.js +87 -0
- package/dist/receipt.d.ts +37 -0
- package/dist/receipt.js +10 -0
- package/dist/rest.d.ts +27 -0
- package/dist/rest.js +52 -0
- package/dist/sdk/index.js +2 -1
- package/dist/verify.d.ts +3 -1
- package/dist/verify.js +37 -2
- package/docs/sdk.md +2 -0
- package/docs/tutorials.md +3 -0
- package/docs/usage.md +26 -1
- package/docs/verification.md +9 -2
- package/package.json +1 -1
- package/vectors/audit.json +27 -27
- package/vectors/canonical.json +5 -5
- package/vectors/receipts.json +440 -162
package/docs/sdk.md
CHANGED
|
@@ -30,6 +30,8 @@ Use the SDK for reach. Use the gateway for anything that moves money, touches pr
|
|
|
30
30
|
|
|
31
31
|
`policyFile` and `principalId` are optional. Without a policy the SDK records and never denies. Paths resolve relative to the config file. Instead of `logFile`, `"log": { "url": "https://log.example.com/", "tokenEnv": "AGENT_CUSTODY_LOG_TOKEN" }` sends every leaf to a log run by someone else, whose key then signs the tree heads; see [usage.md](usage.md) for what that changes and [verification.md](verification.md) for what it proves. Generate the key with `node src/cli.ts keygen --dir keys --name app`.
|
|
32
32
|
|
|
33
|
+
`"otel": { "url": "http://localhost:4318" }` additionally exports every receipt as one span to that OTLP/HTTP collector, after the receipt is written, with the receipt id as the trace id; see the [usage guide](usage.md#setup-step-by-step) for the fields. Export never blocks or fails a receipt.
|
|
34
|
+
|
|
33
35
|
Policies see `context.args` and an empty `context.facts`. A policy that reads `context.facts` or `context.grant` errors, which is a deny. That is intended: an SDK policy cannot pretend it checked something outside the agent's process.
|
|
34
36
|
|
|
35
37
|
## Claude Code
|
package/docs/tutorials.md
CHANGED
|
@@ -25,6 +25,9 @@ Suggested reading order is the numbering. Output lands in `examples-out/`, which
|
|
|
25
25
|
| 13 | a log run by someone else | [13-remote-log.ts](../examples/13-remote-log.ts) | the reference log server on a free port, an SDK config that logs to it, a tree head signed by the log's key, verification failing without that key and passing with it, the root endpoint, a refused token | `src/log-sink.ts` |
|
|
26
26
|
| 14 | proving history was not rewritten | [14-audit-history.ts](../examples/14-audit-history.ts) | three receipts and a kept tree head, a consistency proof that passes, the operator rewriting one leaf and appending a fourth call, the audit failing while the fourth receipt still verifies alone | `src/log.ts`, `src/verify.ts` |
|
|
27
27
|
| 15 | agents in other languages | [15-sidecar.ts](../examples/15-sidecar.ts) | the sidecar on a free port, a client written as a Python or Go program would write it: decide, run, record; a denial recorded without running the tool; both receipts verified | `src/sidecar.ts` |
|
|
28
|
+
| 16 | consequential tools, committed first | [16-precommit.ts](../examples/16-precommit.ts) | a refund named in `precommit`: the authorization leaf before the receipt leaf, the five authorization checks in the report, and the same call withheld when the log refuses | `src/gateway.ts`, `src/issue.ts`, `src/verify.ts` |
|
|
29
|
+
| 17 | a REST API as an upstream | [17-rest-upstream.ts](../examples/17-rest-upstream.ts) | a stand-in payments API described as two tools, the token from the environment, a refund allowed on the gateway's own lookup and one denied before reaching the API, the receipt verified | `src/rest.ts`, `src/gateway.ts` |
|
|
30
|
+
| 18 | OpenTelemetry export | [18-opentelemetry.ts](../examples/18-opentelemetry.ts) | a stand-in OTLP collector, `otel` in the config, one span per receipt with the receipt id as trace id, the collector going away and the next receipt still issued | `src/otel.ts`, `src/issue.ts` |
|
|
28
31
|
|
|
29
32
|
## How policies are defined, in one paragraph
|
|
30
33
|
|
package/docs/usage.md
CHANGED
|
@@ -72,6 +72,7 @@ when {
|
|
|
72
72
|
"forTools": ["stripe.refund"]
|
|
73
73
|
}
|
|
74
74
|
],
|
|
75
|
+
"precommit": ["stripe.refund"],
|
|
75
76
|
"receiptsDir": "receipts",
|
|
76
77
|
"logFile": "log.jsonl"
|
|
77
78
|
}
|
|
@@ -79,16 +80,39 @@ when {
|
|
|
79
80
|
|
|
80
81
|
`upstream` is spawned by the gateway exactly as an MCP host would spawn it. `env` is passed through, which is where upstream credentials go. The agent never sees them. Several upstreams sit behind one gateway and one grant with `"upstreams": [{ "name": "memory", "command": ..., "args": [...] }, { "name": "payments", "url": ... }]` in place of `upstream`. Each tool name must be offered by exactly one of them, checked at startup; the receipt's `tool.upstream` says which served the call, and consumed facts flow across them, so a refund made after a memory read carries the facts the agent had been shown. An upstream that is already running is reached instead with `"upstream": { "url": "https://memory.internal/mcp", "tokenEnv": "MEMORY_TOKEN" }`, over Streamable HTTP with a bearer token from the environment; the shared memory server in `@agent-custody/state` is the usual case.
|
|
81
82
|
|
|
83
|
+
An upstream need not be an MCP server. A plain HTTP API is described as tools:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
"upstream": {
|
|
87
|
+
"rest": {
|
|
88
|
+
"baseUrl": "https://api.stripe.com",
|
|
89
|
+
"headerEnv": { "authorization": "STRIPE_BEARER" },
|
|
90
|
+
"tools": [
|
|
91
|
+
{ "name": "customer.lookup", "method": "GET", "path": "/v1/customers/{customer_id}",
|
|
92
|
+
"inputSchema": { "type": "object", "properties": { "customer_id": { "type": "string" } }, "required": ["customer_id"] } },
|
|
93
|
+
{ "name": "stripe.refund", "method": "POST", "path": "/v1/refunds", "description": "Refund a customer, amount in minor units",
|
|
94
|
+
"inputSchema": { "type": "object", "properties": { "customer_id": { "type": "string" }, "amount": { "type": "integer" } }, "required": ["customer_id", "amount"] } }
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`{name}` segments in `path` are filled from the call's arguments; the remaining arguments go to the query string on GET and DELETE and to a JSON body otherwise, or `query` names the ones that go to the query and `body: "none"` sends no body. `headers` are sent as written; `headerEnv` maps a header to an environment variable read once at startup, so the credential is never in the file and never reaches the agent, and a missing variable fails at startup. The response body is the tool result, JSON kept as JSON, and a non-2xx status is a failed execution with the API's answer in the receipt. Everything else is unchanged: the tools appear in the grant's scopes, `facts` may name a REST tool for a lookup, `precommit` applies, and each call has a receipt. `rest` can be one of several `upstreams` beside MCP servers. This is how an agent's direct HTTP calls come under custody: they become tool calls through the gateway. Tutorial 17 runs one against a stand-in API.
|
|
101
|
+
|
|
82
102
|
`logFile` is the local Merkle log, with tree heads signed by the gateway's own key. To log to a server the operator does not control, replace it with `log`:
|
|
83
103
|
|
|
84
104
|
```json
|
|
85
105
|
"log": { "url": "https://log.example.com/", "tokenEnv": "AGENT_CUSTODY_LOG_TOKEN" }
|
|
86
106
|
```
|
|
87
107
|
|
|
88
|
-
Exactly one of the two. The bearer token comes from the named environment variable, never from the file, and a missing variable fails at startup. With a remote log the tree head in each receipt is signed by the log's key, and a verifier must be given that key with `--log-key`. If the log refuses a leaf, the receipt is not issued and the call returns an error to the agent
|
|
108
|
+
Exactly one of the two. The bearer token comes from the named environment variable, never from the file, and a missing variable fails at startup. Add `"hashOnly": true` for any log run by someone else: the gateway then sends only the leaf hash, sha256 of the receipt envelope with the RFC 6962 prefix, so the log commits to the receipt without ever holding it, and the receipts with their arguments and results stay in `receiptsDir`. The verifier does not change; it hashes the envelope itself. A log that serves several tenants is reached at `<url>/t/<tenant>/`, and each of its tree heads names its log, which a verifier checks with `--log-id`. With a remote log the tree head in each receipt is signed by the log's key, and a verifier must be given that key with `--log-key`. If the log refuses a leaf, the receipt is not issued and the call returns an error to the agent. For an ordinary call the upstream action has already happened by then, and the error says so; a receipt that was never logged must not be handed out. For a tool named in `precommit` the order is reversed, below, and the action never happens. The reference log server is `node src/cli.ts log --file log.jsonl --key keys/log.key --port 8787 --token-env AGENT_CUSTODY_LOG_TOKEN [--log-id <id>] [--tenants tenants.json]`. It serves `POST /append` with `{leaf}` or `{leafHash}` (token required when one is configured), `GET /root?size=N`, `GET /consistency?old=M&new=N`, and `GET /head`; [verification.md](verification.md) says what each proves. `--log-id` writes that id into every tree head. `--tenants` names a JSON file, `{ "acme": { "file": "acme.jsonl", "tokenEnv": "ACME_TOKEN", "logId": "acme-eu" } }`, and each tenant is its own log at `/t/acme/…` with its own token and id; the default log stays at the root paths. [deploy/](../../deploy/README.md) runs the server as a container.
|
|
109
|
+
|
|
110
|
+
`otel`, optional in both the gateway and SDK configs, sends every receipt to the collector you already run as one span over OTLP/HTTP, after the receipt is issued: `"otel": { "url": "http://localhost:4318", "headersEnv": { "x-api-key": "OTEL_KEY" }, "serviceName": "support-agents" }`. The span's trace id is the receipt id, its attributes carry the tool, agent, principal, execution status, policy decision, and log position, and its status is an error only when the upstream failed or errored, since a denial is the policy working. Export is best effort: a collector that is down or refuses costs a line on stderr, never a receipt. Tutorial 18 shows it against a stand-in collector.
|
|
89
111
|
|
|
90
112
|
`facts` tells the gateway which upstream tool to call before evaluating policy for a given tool. `$args.<key>` copies a value from the intercepted call. The result appears in Cedar as `context.facts.<name>` and in the receipt with its own digest, labelled `observed`. If a fact lookup fails, the call is denied and the receipt says why. A lookup with `"optional": true` is skipped when a `$args.<key>` it needs is absent from the call, and the fact is then simply not present, which a policy tests with `context.facts has <name>`; this is how a policy sees the fact a `memory.write` is about to supersede without denying every write that supersedes nothing.
|
|
91
113
|
|
|
114
|
+
`precommit` names the consequential tools, or `["*"]` for all of them. For every other tool the gateway forwards the call and then records it, so if the log is unreachable at that moment the side effect exists before its evidence does. For a tool in `precommit` the gateway first signs an authorization statement, everything the receipt will say except the outcome, and appends it to the log. Only if the log took it does the call go upstream. The receipt then embeds that authorization with its own inclusion proof, and a verifier checks that it names this call and sits in the log before the receipt does. If the log will not take it, the call is not forwarded, the agent is told `Not executed`, and the receipt records `execution.status: "withheld"` with the policy's `allow` beside it. The authorization is also written on its own as `receipts/<receiptId>.authorization.json`, which is the evidence that survives if the gateway dies between forwarding and the receipt. Use it for money, for anything irreversible, and for anything a counterparty could later dispute; the cost is one extra log append per call.
|
|
115
|
+
|
|
92
116
|
**5. Run the gateway.** It speaks MCP on stdin/stdout and logs to stderr only.
|
|
93
117
|
|
|
94
118
|
```bash
|
|
@@ -203,5 +227,6 @@ The upstream can answer in kind. A result whose `_meta` carries `agent-custody/f
|
|
|
203
227
|
- **Money is integer minor units.** Cedar has no floating point. A float in `args` that a policy touches is an evaluation error, which is a deny.
|
|
204
228
|
- **The gateway key is the trust root for receipts.** Keep it out of the agent's reach. The upstream credentials in `upstream.env` are likewise never exposed to the agent.
|
|
205
229
|
- **Rotate keys by adding, not replacing.** The verifier accepts a list of gateway keys and principal keys and matches by keyid, so old receipts stay verifiable.
|
|
230
|
+
- **Evidence before the side effect, for the calls that matter.** Without `precommit`, a call is forwarded and then logged, and a log outage at that moment leaves an executed action with no receipt (the agent gets an error saying so). With `precommit`, the authorization is logged first and the call is withheld if that fails. The receipt of a withheld call shows `allow` next to `withheld`, so an auditor can tell a log outage from a denial.
|
|
206
231
|
- **The log is append-only by convention, not enforcement.** Copy it somewhere the operator cannot rewrite, on a schedule. The receipts' tree heads let an auditor check that the copy matches.
|
|
207
232
|
- **stdout is the MCP channel.** Anything the gateway prints goes to stderr. Do not add `console.log` to gateway code paths.
|
package/docs/verification.md
CHANGED
|
@@ -77,12 +77,18 @@ execution observed executed
|
|
|
77
77
|
| request args digest | the args in the predicate hash to the digest in the subject | edited arguments |
|
|
78
78
|
| policy decision consistent with execution | allow went with executed or failed; deny went with denied. Skipped when no policy was evaluated | an issuer that executed after a deny |
|
|
79
79
|
| no policy errors on an allow | an allow was not produced while Cedar reported errors | broken fail-closed behaviour |
|
|
80
|
+
| authorization signature (issuer key) | pre-commit receipts only: the embedded authorization statement was signed by the same issuer key as the receipt | an authorization from another gateway, or none the issuer signed |
|
|
81
|
+
| authorization names this call | the committed authorization names this receipt id, tool, argument digest, agent, and principal, and recorded an allow | an authorization spliced in from a different call |
|
|
82
|
+
| authorization tree head signature | the authorization's own tree head is signed by a trusted log or issuer key | a fabricated log position for the authorization |
|
|
83
|
+
| authorization log inclusion proof | the authorization statement is a leaf of that tree | an authorization that was never logged |
|
|
84
|
+
| authorization logged before execution | the authorization's leaf precedes the receipt's leaf, at a tree size no larger than the receipt's | evidence written after the side effect, dressed up as before |
|
|
80
85
|
| tree head signature | the tree head was signed by a trusted issuer key | forged log position |
|
|
86
|
+
| tree head names the expected log | with `--log-id`: the tree head carries that log id, so a head from another tenant's log on the same server cannot be presented as this one's | a receipt logged to a different log than claimed |
|
|
81
87
|
| tree head matches inclusion proof size | the proof and the tree head describe the same tree | mismatched bundle parts |
|
|
82
88
|
| log inclusion proof | this exact envelope is a leaf of the tree with that root | receipt never logged, or logged then changed |
|
|
83
89
|
| log file root matches tree head | recomputing the root from your copy of the log at that size gives the same value | your log copy and the issuer's history diverge: deletion, reordering, or edit |
|
|
84
90
|
|
|
85
|
-
Gateway receipts run seventeen checks, eighteen with a log file. SDK receipts run fewer, because there is no delegation to check, and the report says so on the `principal is claimed` line.
|
|
91
|
+
Gateway receipts run seventeen checks, eighteen with a log file, and five more when the tool was committed before it ran (`precommit` in the gateway config). SDK receipts run fewer, because there is no delegation to check, and the report says so on the `principal is claimed` line.
|
|
86
92
|
|
|
87
93
|
## What a verified receipt lets you conclude
|
|
88
94
|
|
|
@@ -95,6 +101,7 @@ For an SDK receipt the statement is shorter: a process holding the application k
|
|
|
95
101
|
A gateway receipt does **not** support:
|
|
96
102
|
|
|
97
103
|
- that Stripe really executed the refund. The upstream result is `observed`, not signed by Stripe. That is the first roadmap item.
|
|
104
|
+
- that the side effect exists because the receipt does, unless the receipt carries an authorization. Without one, the call was forwarded first and logged second. With one, the five `authorization` checks establish that the gateway had committed the call to the log before it went out, and a `withheld` execution establishes that it never went out.
|
|
98
105
|
- that the arguments were correct. They are `claimed`: they are what the agent asked for, which is what a receipt should record.
|
|
99
106
|
- that the model named in `model` produced the call. No hosted provider signs model identity.
|
|
100
107
|
- that the gateway operator is honest. The operator holds the gateway key. Against a dishonest operator you need a log copy taken out of their control, or a signer they do not control. See the threat model table in the README.
|
|
@@ -154,7 +161,7 @@ An inclusion proof says a receipt was in the log at one moment. It does not say
|
|
|
154
161
|
|
|
155
162
|
```bash
|
|
156
163
|
node src/cli.ts audit --older receipts/<earlier>.json --newer receipts/<later>.json --log log.jsonl --issuer-key keys/gateway.pub
|
|
157
|
-
node src/cli.ts audit --older receipts/<earlier>.json --newer receipts/<later>.json --log-url https://log.example.com/ --log-key keys/log.pub
|
|
164
|
+
node src/cli.ts audit --older receipts/<earlier>.json --newer receipts/<later>.json --log-url https://log.example.com/t/acme/ --log-key keys/log.pub --log-id acme
|
|
158
165
|
```
|
|
159
166
|
|
|
160
167
|
Both tree heads must be signed by a trusted key. With `--log` the proof is computed from a copy of the log; with `--log-url` it is fetched from the log's `GET /consistency?old=M&new=N`. Exit code 0 means the newer log extends the older one. A failure means either history was rewritten between the two heads or the proof belongs to other tree heads; example 14 shows a rewritten log failing this way while every individual receipt still verifies.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-custody/receipts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Chain of custody for AI agents: signed, independently verifiable receipts for tool calls. MCP gateway + Cedar policy + Merkle transparency log",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
package/vectors/audit.json
CHANGED
|
@@ -7,26 +7,26 @@
|
|
|
7
7
|
"description": "The tree head from the first remote receipt and the log's later head, with the proof the log served.",
|
|
8
8
|
"older": {
|
|
9
9
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
10
|
-
"payload": "
|
|
10
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODViYjZhMjk1YzYxYmIzMzg5MWYyNTFiNWNiZGQ4NzNjNGVkYTU5OTBkMWE4MzVjNDRjYjZiMDgwNTBhY2U2MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjkzWiIsInRyZWVTaXplIjoxfQ==",
|
|
11
11
|
"signatures": [
|
|
12
12
|
{
|
|
13
|
-
"keyid": "
|
|
14
|
-
"sig": "
|
|
13
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
14
|
+
"sig": "xhkG/l7l3ElnvGnxrFfK2nYUCkRo0ktj0+6ctv6V1qKiXihMYexcOu/qepdqWWN0mWFq2u8/Aqo6kbdoWhiFDQ=="
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
},
|
|
18
18
|
"newer": {
|
|
19
19
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
20
|
-
"payload": "
|
|
20
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODY0N2E0MTczNTIxYzE5Mzg4NTg2Y2U1MzYyNGU3MGZiYWEyMzc0NGRiYjIzNTQ0ZDU2N2Q5NDY0NmE0ZTM3MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjk3WiIsInRyZWVTaXplIjoyfQ==",
|
|
21
21
|
"signatures": [
|
|
22
22
|
{
|
|
23
|
-
"keyid": "
|
|
24
|
-
"sig": "
|
|
23
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
24
|
+
"sig": "iaweKtCddKNA0R+dkq+0qyzwe8RhZdKgK6y9o21adUCjhMAGlpl+YDe1chzn4NvT7jIZvn+HDdll136TmqcmCQ=="
|
|
25
25
|
}
|
|
26
26
|
]
|
|
27
27
|
},
|
|
28
28
|
"proof": [
|
|
29
|
-
"
|
|
29
|
+
"f8e988293efa93dd5e5ea2af96b88588f4a1fba5c786848e997aa985c95e2f81"
|
|
30
30
|
],
|
|
31
31
|
"keys": [
|
|
32
32
|
"log"
|
|
@@ -41,26 +41,26 @@
|
|
|
41
41
|
"description": "The same heads the wrong way round.",
|
|
42
42
|
"older": {
|
|
43
43
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
44
|
-
"payload": "
|
|
44
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODY0N2E0MTczNTIxYzE5Mzg4NTg2Y2U1MzYyNGU3MGZiYWEyMzc0NGRiYjIzNTQ0ZDU2N2Q5NDY0NmE0ZTM3MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjk3WiIsInRyZWVTaXplIjoyfQ==",
|
|
45
45
|
"signatures": [
|
|
46
46
|
{
|
|
47
|
-
"keyid": "
|
|
48
|
-
"sig": "
|
|
47
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
48
|
+
"sig": "iaweKtCddKNA0R+dkq+0qyzwe8RhZdKgK6y9o21adUCjhMAGlpl+YDe1chzn4NvT7jIZvn+HDdll136TmqcmCQ=="
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
},
|
|
52
52
|
"newer": {
|
|
53
53
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
54
|
-
"payload": "
|
|
54
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODViYjZhMjk1YzYxYmIzMzg5MWYyNTFiNWNiZGQ4NzNjNGVkYTU5OTBkMWE4MzVjNDRjYjZiMDgwNTBhY2U2MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjkzWiIsInRyZWVTaXplIjoxfQ==",
|
|
55
55
|
"signatures": [
|
|
56
56
|
{
|
|
57
|
-
"keyid": "
|
|
58
|
-
"sig": "
|
|
57
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
58
|
+
"sig": "xhkG/l7l3ElnvGnxrFfK2nYUCkRo0ktj0+6ctv6V1qKiXihMYexcOu/qepdqWWN0mWFq2u8/Aqo6kbdoWhiFDQ=="
|
|
59
59
|
}
|
|
60
60
|
]
|
|
61
61
|
},
|
|
62
62
|
"proof": [
|
|
63
|
-
"
|
|
63
|
+
"f8e988293efa93dd5e5ea2af96b88588f4a1fba5c786848e997aa985c95e2f81"
|
|
64
64
|
],
|
|
65
65
|
"keys": [
|
|
66
66
|
"log"
|
|
@@ -77,26 +77,26 @@
|
|
|
77
77
|
"description": "Tree heads checked against the app key, which did not sign them.",
|
|
78
78
|
"older": {
|
|
79
79
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
80
|
-
"payload": "
|
|
80
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODViYjZhMjk1YzYxYmIzMzg5MWYyNTFiNWNiZGQ4NzNjNGVkYTU5OTBkMWE4MzVjNDRjYjZiMDgwNTBhY2U2MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjkzWiIsInRyZWVTaXplIjoxfQ==",
|
|
81
81
|
"signatures": [
|
|
82
82
|
{
|
|
83
|
-
"keyid": "
|
|
84
|
-
"sig": "
|
|
83
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
84
|
+
"sig": "xhkG/l7l3ElnvGnxrFfK2nYUCkRo0ktj0+6ctv6V1qKiXihMYexcOu/qepdqWWN0mWFq2u8/Aqo6kbdoWhiFDQ=="
|
|
85
85
|
}
|
|
86
86
|
]
|
|
87
87
|
},
|
|
88
88
|
"newer": {
|
|
89
89
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
90
|
-
"payload": "
|
|
90
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODY0N2E0MTczNTIxYzE5Mzg4NTg2Y2U1MzYyNGU3MGZiYWEyMzc0NGRiYjIzNTQ0ZDU2N2Q5NDY0NmE0ZTM3MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjk3WiIsInRyZWVTaXplIjoyfQ==",
|
|
91
91
|
"signatures": [
|
|
92
92
|
{
|
|
93
|
-
"keyid": "
|
|
94
|
-
"sig": "
|
|
93
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
94
|
+
"sig": "iaweKtCddKNA0R+dkq+0qyzwe8RhZdKgK6y9o21adUCjhMAGlpl+YDe1chzn4NvT7jIZvn+HDdll136TmqcmCQ=="
|
|
95
95
|
}
|
|
96
96
|
]
|
|
97
97
|
},
|
|
98
98
|
"proof": [
|
|
99
|
-
"
|
|
99
|
+
"f8e988293efa93dd5e5ea2af96b88588f4a1fba5c786848e997aa985c95e2f81"
|
|
100
100
|
],
|
|
101
101
|
"keys": [
|
|
102
102
|
"app"
|
|
@@ -114,21 +114,21 @@
|
|
|
114
114
|
"description": "A proof with a hash removed.",
|
|
115
115
|
"older": {
|
|
116
116
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
117
|
-
"payload": "
|
|
117
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODViYjZhMjk1YzYxYmIzMzg5MWYyNTFiNWNiZGQ4NzNjNGVkYTU5OTBkMWE4MzVjNDRjYjZiMDgwNTBhY2U2MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjkzWiIsInRyZWVTaXplIjoxfQ==",
|
|
118
118
|
"signatures": [
|
|
119
119
|
{
|
|
120
|
-
"keyid": "
|
|
121
|
-
"sig": "
|
|
120
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
121
|
+
"sig": "xhkG/l7l3ElnvGnxrFfK2nYUCkRo0ktj0+6ctv6V1qKiXihMYexcOu/qepdqWWN0mWFq2u8/Aqo6kbdoWhiFDQ=="
|
|
122
122
|
}
|
|
123
123
|
]
|
|
124
124
|
},
|
|
125
125
|
"newer": {
|
|
126
126
|
"payloadType": "application/vnd.agent-custody.treehead+json",
|
|
127
|
-
"payload": "
|
|
127
|
+
"payload": "eyJsb2ciOiJ2ZWN0b3JzLWxvZyIsInJvb3RIYXNoIjoiODY0N2E0MTczNTIxYzE5Mzg4NTg2Y2U1MzYyNGU3MGZiYWEyMzc0NGRiYjIzNTQ0ZDU2N2Q5NDY0NmE0ZTM3MiIsInRpbWVzdGFtcCI6IjIwMjYtMDktMDhUMDY6MzA6MDQuNjk3WiIsInRyZWVTaXplIjoyfQ==",
|
|
128
128
|
"signatures": [
|
|
129
129
|
{
|
|
130
|
-
"keyid": "
|
|
131
|
-
"sig": "
|
|
130
|
+
"keyid": "74356bcffe957c1c3a3bde6702505f536d4e8bab2aac3b0f36419e846da1a8d5",
|
|
131
|
+
"sig": "iaweKtCddKNA0R+dkq+0qyzwe8RhZdKgK6y9o21adUCjhMAGlpl+YDe1chzn4NvT7jIZvn+HDdll136TmqcmCQ=="
|
|
132
132
|
}
|
|
133
133
|
]
|
|
134
134
|
},
|
package/vectors/canonical.json
CHANGED
|
@@ -53,18 +53,18 @@
|
|
|
53
53
|
}
|
|
54
54
|
],
|
|
55
55
|
"keyid": {
|
|
56
|
-
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\
|
|
57
|
-
"keyid": "
|
|
56
|
+
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA0ZCk/vXbGqi5xjdFAok3XGPWbCT9yO2OeGbMF1nvH5w=\n-----END PUBLIC KEY-----\n",
|
|
57
|
+
"keyid": "3df0af0ec3abda622a30f7a3273fc6ca4eda229404122f02e2cae12923a861ad"
|
|
58
58
|
},
|
|
59
59
|
"dsse": {
|
|
60
|
-
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\
|
|
60
|
+
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA0ZCk/vXbGqi5xjdFAok3XGPWbCT9yO2OeGbMF1nvH5w=\n-----END PUBLIC KEY-----\n",
|
|
61
61
|
"envelope": {
|
|
62
62
|
"payloadType": "application/vnd.example+json",
|
|
63
63
|
"payload": "eyJoZWxsbyI6IndvcmxkIn0=",
|
|
64
64
|
"signatures": [
|
|
65
65
|
{
|
|
66
|
-
"keyid": "
|
|
67
|
-
"sig": "
|
|
66
|
+
"keyid": "3df0af0ec3abda622a30f7a3273fc6ca4eda229404122f02e2cae12923a861ad",
|
|
67
|
+
"sig": "aGI6lAPRJs17z+UUezv/7iGyZ1rHbjKRWBELgeC4YjLGytQLUZsH+2jwFKhmTasJIyssry1ob+HMt4V20WCzBQ=="
|
|
68
68
|
}
|
|
69
69
|
]
|
|
70
70
|
},
|