hachure 0.2.0 → 0.2.2

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 CHANGED
@@ -226,6 +226,19 @@ validates TrustBundle input against these schemas via `validateTrustBundle()`.
226
226
 
227
227
  ---
228
228
 
229
+ ## Profiles
230
+
231
+ The core specification covers record shapes and status semantics. Profiles are
232
+ optional, independently adoptable conventions for interop and transport. Adopting
233
+ a profile requires no changes to core record shapes or the status function.
234
+
235
+ | Profile | File | What it covers |
236
+ |---|---|---|
237
+ | in-toto interop | [interop-in-toto.md](interop-in-toto.md) | Wrapping a TrustBundle as a signed in-toto Statement v1 / DSSE envelope. |
238
+ | Verification endpoint | [verification-endpoint.md](verification-endpoint.md) | Producer-served HTTP endpoint for receivers to fetch post-export event deltas. |
239
+
240
+ ---
241
+
229
242
  ## Out of scope: future extension profiles
230
243
 
231
244
  The following producer domains are explicitly out of scope for this core specification.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hachure",
3
- "version": "0.2.0",
4
- "description": "Hachure canonical distribution of the open trust format: normative JSON schemas, conformance test vectors, and spec constants.",
3
+ "version": "0.2.2",
4
+ "description": "Hachure \u2014 canonical distribution of the open trust format: normative JSON schemas, conformance test vectors, and spec constants.",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
7
7
  "exports": {
@@ -15,7 +15,8 @@
15
15
  "index.mjs",
16
16
  "README.md",
17
17
  "status-function.md",
18
- "interop-in-toto.md"
18
+ "interop-in-toto.md",
19
+ "verification-endpoint.md"
19
20
  ],
20
21
  "scripts": {
21
22
  "test": "node --test test/index.test.mjs"
@@ -30,5 +31,9 @@
30
31
  "license": "MIT",
31
32
  "publishConfig": {
32
33
  "access": "public"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/hachure-org/spec.git"
33
38
  }
34
- }
39
+ }
@@ -0,0 +1,152 @@
1
+ # Verification Endpoint — Extension Profile
2
+
3
+ **Profile type:** OPTIONAL extension
4
+ **Status:** draft
5
+ **Namespace:** `hachure.org/v1`
6
+ **Depends on:** core record shapes, [status-function.md](status-function.md), [interop-in-toto.md](interop-in-toto.md)
7
+
8
+ ---
9
+
10
+ ## Problem
11
+
12
+ A TrustBundle is a point-in-time snapshot. Once exported, it carries no channel
13
+ back to the producer. A receiver holding a bundle from last week has no way to
14
+ learn that an authority trace was revoked yesterday, that a blocking evidence item
15
+ was added the day after export, or that a claim has since been superseded. The
16
+ receiver can re-run the status function as many times as it likes, but can only
17
+ produce the same answer from the same stale inputs.
18
+
19
+ This profile defines a lightweight channel for receivers to ask a producer: *what
20
+ has changed since this bundle was issued?* The response delivers fresh inputs for
21
+ the receiver's own status recomputation. It is testimony with a timestamp — a
22
+ record of what the producer asserted at the moment of response. It is never a
23
+ verdict the receiver is expected to obey.
24
+
25
+ ---
26
+
27
+ ## Discovery
28
+
29
+ Producers supporting this profile expose a verification endpoint at a well-known
30
+ path on the same host that issued the bundle:
31
+
32
+ ```
33
+ GET https://<producer-host>/.well-known/hachure/verify?ref=<integrityRef>[&ref=...]
34
+ ```
35
+
36
+ Multiple refs may be passed as repeated `ref` query parameters. For large sets,
37
+ a POST variant is also allowed:
38
+
39
+ ```
40
+ POST https://<producer-host>/.well-known/hachure/verify
41
+ Content-Type: application/json
42
+
43
+ { "refs": ["<integrityRef>", ...] }
44
+ ```
45
+
46
+ `integrityRef` is the integrity anchor value carried on a claim or bundle
47
+ (`claim.integrityRef` or a bundle-level `integrityAnchor.value`).
48
+
49
+ Producers MAY require authentication before serving a response. The response
50
+ semantics defined in this profile are unchanged by the presence or absence of
51
+ authentication; the receiver simply may not be able to reach the endpoint
52
+ without valid credentials.
53
+
54
+ ---
55
+
56
+ ## Response shape
57
+
58
+ The response body is a TrustBundle (see `schemas/trust-bundle.schema.json`)
59
+ scoped to the records matching the requested refs, plus a `metadata` extension
60
+ block. The bundle carries:
61
+
62
+ - **`source`** — the producer identifier, matching `source` in the original bundle.
63
+ - **`claims`** — all claims whose `integrityRef` was among the requested refs.
64
+ Each claim is returned in its current form as the producer knows it.
65
+ - **`evidence`** and **`events`** — the delta since issuance where the producer
66
+ can supply it: new evidence items, new verification events, revocation events,
67
+ dispute events. Producers that do not track a delta MAY return the full current
68
+ set for the matched claims; receivers MUST NOT assume the absence of an item
69
+ means it was never present in the original bundle.
70
+ - **`authorityTrace`** — current authority traces relevant to the matched claims,
71
+ including any that have been revoked since the original bundle was issued.
72
+ - **`metadata`** — a free-form object on the bundle. This profile defines four
73
+ reserved keys within `metadata`:
74
+
75
+ | Key | Type | Required | Meaning |
76
+ |---|---|---|---|
77
+ | `respondedAt` | ISO 8601 string | yes | The timestamp at which the producer assembled this response. |
78
+ | `statusFunctionVersion` | string | yes | The status function version active at the producer at response time. |
79
+ | `requestedRefs` | string[] | yes | The full list of refs from the request, in order. |
80
+ | `unknownRefs` | string[] | yes | Refs from the request that the producer does not recognise. Must be present even if empty. |
81
+
82
+ Unknown refs are reported in `unknownRefs` honestly. A producer MUST NOT silently
83
+ omit a ref it does not recognise; it MUST include it in `unknownRefs` so the
84
+ receiver can distinguish "no changes" from "not found."
85
+
86
+ ---
87
+
88
+ ## Assurance levels
89
+
90
+ A response may be signed or unsigned. The two carry different weight.
91
+
92
+ **Signed response.** A producer that wraps the response bundle in a DSSE envelope
93
+ (per [interop-in-toto.md](interop-in-toto.md)) or attaches a `proof` block provides
94
+ independently verifiable testimony. The receiver can verify the signature using the
95
+ producer's public key before trusting any of the returned data. A signed response is
96
+ as trustworthy as the key and the in-toto statement it protects.
97
+
98
+ **Unsigned response.** A response delivered without a signature is producer-asserted
99
+ only. Receivers SHOULD treat an unsigned response exactly as they would treat an
100
+ unsigned TrustBundle received over a trusted channel: the transport provides some
101
+ assurance, but the content itself is not independently verifiable. Do not give an
102
+ unsigned response higher trust than the connection that delivered it.
103
+
104
+ Key distribution and rotation are out of scope for this profile. The same backlog
105
+ item that defers cryptographic signing for testimony records (ADR 0004, §Backlog)
106
+ applies here: until key-management infrastructure exists, signing is OPTIONAL and
107
+ unsigned responses are valid.
108
+
109
+ ---
110
+
111
+ ## Receiver rules
112
+
113
+ 1. **Re-run the status function.** Merge the response bundle's events and evidence
114
+ with the records in the held bundle, then call the status function over the
115
+ combined input at your own `now`. Do not treat any status value in the response
116
+ as a pre-computed verdict.
117
+
118
+ 2. **Fix `now` before evaluating.** The status function is `f(claim, evidence,
119
+ events, policy, authorityTrace, now)`. The response supplies updated inputs; the
120
+ receiver controls `now`. Two receivers evaluating the same response at different
121
+ instants may derive different statuses — that is expected and correct.
122
+
123
+ 3. **Cache by `respondedAt`; honour `max-age`.** A receiver MAY cache a response
124
+ keyed on the set of requested refs and the `respondedAt` timestamp. Producers MAY
125
+ include a standard HTTP `Cache-Control: max-age=<seconds>` header as a hint for
126
+ how long the response is expected to remain fresh. The hint is advisory; the
127
+ receiver decides its own staleness policy.
128
+
129
+ 4. **Retain the response as a record.** A verification response is itself a record
130
+ worth keeping. It is testimony: evidence of what the producer asserted at
131
+ `respondedAt`. A receiver that retains responses can reconstruct the history of
132
+ its knowledge — when it learned of a revocation, when a dispute event appeared —
133
+ which is useful for audit and for re-evaluating past InquiryRecords.
134
+
135
+ 5. **Treat signed and unsigned responses differently.** Apply the assurance-level
136
+ rules above before deciding how to weight the response in a combined evaluation.
137
+
138
+ ---
139
+
140
+ ## Non-goals
141
+
142
+ - **Transport beyond HTTPS.** This profile specifies only the HTTP/HTTPS request
143
+ and response shape. Other transport mechanisms (gRPC, message queues, file
144
+ exchange) are not covered.
145
+ - **Push and webhooks.** This profile is pull-only. Producers notify receivers
146
+ only when asked. Push notification channels are a separate concern.
147
+ - **Transparency-log inclusion.** Including verification responses in a public
148
+ transparency log (Rekor or equivalent) is complementary and encouraged for
149
+ high-assurance scenarios, but it is not required by this profile and is not
150
+ specified here.
151
+ - **Key management.** Public-key distribution, rotation, and revocation are out
152
+ of scope. See the ADR 0004 backlog note above.