@atrib/verify 0.3.7 → 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.
- package/README.md +95 -24
- package/dist/ap2-vi-evidence.d.ts +47 -0
- package/dist/ap2-vi-evidence.d.ts.map +1 -1
- package/dist/ap2-vi-evidence.js +713 -9
- package/dist/ap2-vi-evidence.js.map +1 -1
- package/dist/handoff.d.ts +94 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +371 -0
- package/dist/handoff.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/verifier.d.ts +14 -1
- package/dist/verifier.d.ts.map +1 -1
- package/dist/verifier.js +29 -1
- package/dist/verifier.js.map +1 -1
- package/dist/verify-record.d.ts +30 -8
- package/dist/verify-record.d.ts.map +1 -1
- package/dist/verify-record.js +75 -16
- package/dist/verify-record.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -58,18 +58,18 @@ Per the [§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58
|
|
|
58
58
|
|
|
59
59
|
### `new AtribVerifier(options)`
|
|
60
60
|
|
|
61
|
-
| Field | Type | Default
|
|
62
|
-
| ----------------- | -------- |
|
|
63
|
-
| `logEndpoint` | `string` | `https://log.atrib.dev/v1` | The Merkle log to fetch checkpoints and proofs from.
|
|
64
|
-
| `graphEndpoint` | `string` | `https://graph.atrib.dev/v1` | The graph query endpoint (spec [§3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#3-graph-query-interface)).
|
|
65
|
-
| `resolveEndpoint` | `string` | `https://resolve.atrib.dev/v1` | Reserved for v2 remote calculation.
|
|
66
|
-
| `merchantKey` | `string` | unset
|
|
61
|
+
| Field | Type | Default | Description |
|
|
62
|
+
| ----------------- | -------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `logEndpoint` | `string` | `https://log.atrib.dev/v1` | The Merkle log to fetch checkpoints and proofs from. |
|
|
64
|
+
| `graphEndpoint` | `string` | `https://graph.atrib.dev/v1` | The graph query endpoint (spec [§3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#3-graph-query-interface)). |
|
|
65
|
+
| `resolveEndpoint` | `string` | `https://resolve.atrib.dev/v1` | Reserved for v2 remote calculation. |
|
|
66
|
+
| `merchantKey` | `string` | unset | Base64url Ed25519 32-byte seed. Optional. `verify()` works without it. |
|
|
67
67
|
|
|
68
|
-
### `verify(doc): Promise<VerificationResult>`
|
|
68
|
+
### `verify(doc, options): Promise<VerificationResult>`
|
|
69
69
|
|
|
70
70
|
Independently re-runs the [§4.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#46-the-calculation-algorithm) calculation and verifies the document signature. Always returns a result object; never throws. Inspect `valid`, `signatureOk`, `calcMatch`, and `warnings` to understand the outcome.
|
|
71
71
|
|
|
72
|
-
This method operates on `RecommendationDocument` shapes (settlement-recommendation flow per spec [§5.5.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#552-verify)). For verifying individual `AtribRecord`s, see `verifyRecord` below.
|
|
72
|
+
This method operates on `RecommendationDocument` shapes (settlement-recommendation flow per spec [§5.5.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#552-verify)). When the caller supplies `ap2ViEvidence`, the verifier attaches the async AP2 / VI result as `ap2_vi_evidence`. That block is tiered and does not change the base recommendation signature or calculation checks. For verifying individual `AtribRecord`s, see `verifyRecord` below.
|
|
73
73
|
|
|
74
74
|
### `verifyRecord(record, options): Promise<RecordVerificationResult>`
|
|
75
75
|
|
|
@@ -79,9 +79,11 @@ Per-record verification. Verifies a single signed record's Ed25519 signature and
|
|
|
79
79
|
import { verifyRecord } from '@atrib/verify'
|
|
80
80
|
|
|
81
81
|
const result = await verifyRecord(record, {
|
|
82
|
-
upstreamCandidate,
|
|
83
|
-
informedByCandidates: [],
|
|
84
|
-
identityClaim,
|
|
82
|
+
upstreamCandidate, // optional, for provenance_token resolution
|
|
83
|
+
informedByCandidates: [], // optional, for informed_by[] resolution
|
|
84
|
+
identityClaim, // optional, for capability_check (caller does directory lookup)
|
|
85
|
+
ap2ViEvidence, // optional, transaction-only AP2 / VI evidence bundle
|
|
86
|
+
ap2ViEvidenceOptions, // optional, passed to verifyAp2ViEvidenceAsync()
|
|
85
87
|
})
|
|
86
88
|
// result: {
|
|
87
89
|
// valid: boolean
|
|
@@ -90,6 +92,7 @@ const result = await verifyRecord(record, {
|
|
|
90
92
|
// provenance?: { token, upstream_record_hash, upstream_resolved }
|
|
91
93
|
// informed_by_resolution?: { resolved: string[], dangling: string[] }
|
|
92
94
|
// capability_check?: { envelope, in_envelope, mismatches, unresolvable }
|
|
95
|
+
// ap2_vi_evidence?: Ap2ViEvidenceVerification
|
|
93
96
|
// warnings: string[]
|
|
94
97
|
// }
|
|
95
98
|
```
|
|
@@ -100,15 +103,65 @@ const result = await verifyRecord(record, {
|
|
|
100
103
|
- `informed_by_resolution`: `{ resolved: string[], dangling: string[] }` per record carrying `informed_by` ([D041](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d041-informed_by-linking-primitive-and-informed_by-edge-type) / [§1.2.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#125-informed_by)). Dangling references are flagged but do not fail verification: they signal "the verifier has not seen upstream context," not "the record is invalid."
|
|
101
104
|
- `posture`: `{ timestamp_granularity, timestamp_consistent, timestamp_granularity_explicit, args_commitment_form, result_commitment_form, tool_name_form }` ([D045](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d045-privacy-postures-normative-spec-section) / [D061](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d061-add-tool_name-args_hash-result_hash-fields-to-§121) / [§8.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#82-opaque-name-posture) / [§8.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#83-salted-commitment-posture) / [§8.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#84-coarsened-timing-posture)). Always populated. Surfaces (a) the declared timing granularity, whether the timestamp value structurally matches the spec's trailing-zero invariant, and whether the field was explicitly set vs defaulted; (b) the structurally-detected `args_hash` / `result_hash` commitment scheme: `'salted-sha256'` when `args_salt` / `result_salt` is present, `'plain-sha256'` otherwise (the `'hmac-sha256'` variant from [§8.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#83-salted-commitment-posture) is signaled out-of-band and is not structurally detectable); and (c) the [§8.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#82-opaque-name-posture) `tool_name_form`: `'hashed'` when `tool_name` matches `^sha256:[0-9a-f]{64}$`, `'plain'` for any other present value, `null` when the field is absent. Per [D061](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d061-add-tool_name-args_hash-result_hash-fields-to-121) the [§8.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#82-opaque-name-posture) verbatim-vs-opaque distinction is NOT structurally detectable, both surface as `'plain'`.
|
|
102
105
|
- `capability_check`: `{ envelope, in_envelope, mismatches, unresolvable }` ([D051](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d051-capability-scoped-records-via-directory-published-envelopes) / [§6.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#67-capability-declarations)). Populated only when the caller passes a resolved `identityClaim` in options. Checks the record's `event_type` against the envelope's `event_types` allowlist and the record's `timestamp` against `expires_at`. `tool_names` (against tool_call records), `max_amount`, and `counterparties` (against transaction records) flag `unresolvable: true` because the constraints depend on data not yet on the standard record shape (`tool_name`) or out-of-band protocol events (payment amount + counterparty). Per [§6.7.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#673-out-of-envelope-records) out-of-envelope is a signal, not invalidation: mismatches do not flip `valid` to false. The caller is responsible for fetching the active envelope at the record's timestamp via `@atrib/directory`'s `lookup()` (or a cached equivalent); `@atrib/verify` intentionally has no `@atrib/directory` dependency.
|
|
103
|
-
- `cross_attestation`: `{ signers_count, signers_valid, missing }` ([D052](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d052-cross-attestation-requirement-for-transaction-records) / [§1.7.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records)). Populated only on transaction records (`event_type = transaction`). Each entry in `signers[]` is verified against the cross-attestation canonical bytes (JCS form with `signers: []` and the top-level `signature` field omitted, per [§1.7.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records)). `missing: true` when fewer than 2
|
|
106
|
+
- `cross_attestation`: `{ signers_count, signers_valid, missing }` ([D052](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d052-cross-attestation-requirement-for-transaction-records) / [§1.7.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records)). Populated only on transaction records (`event_type = transaction`). Each entry in `signers[]` is verified against the cross-attestation canonical bytes (JCS form with `signers: []` and the top-level `signature` field omitted, per [§1.7.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records)). `signatureOk` requires a valid signer entry whose `creator_key` matches the record's top-level `creator_key`; unrelated counterparty signers do not validate the record on behalf of its creator. `missing: true` when fewer than 2 distinct signer keys verify, atrib's normative minimum. Duplicate entries from one key do not inflate `signers_valid`. Per [§1.7.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records) missing is a signal, not invalidation: `valid` stays true if the underlying signature path holds. Agent-side Path 2 fallback records usually surface as `signers_count: 1, missing: true` until a counterparty signs the same bytes. Legacy single-signer transaction records (no `signers[]` array, only top-level `signature`) surface as `signers_count: 0, missing: true` so consumers can flag them while accepting the cryptographic validity.
|
|
107
|
+
- `ap2_vi_evidence`: the async AP2 / VI verifier result ([D094](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d094-ap2--vi-evidence-attaches-to-verifier-results-as-a-tiered-block) / [§5.5.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#554-ap2--verifiable-intent-evidence-checks)). Populated only when the caller passes `ap2ViEvidence` for a transaction record. It does not alter `valid`, `signatureOk`, or `cross_attestation`; consumers inspect `ap2_vi_evidence.valid` for AP2 authorization evidence.
|
|
104
108
|
|
|
105
109
|
**Pending per-record annotations** (tracked as a Pending decision in [DECISIONS.md P005](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#p005-reconcile-atribverify-readme-per-record-annotations-with-actual-code-surface)):
|
|
106
110
|
|
|
107
111
|
- `cross_log_proof_count` / `cross_log_threshold_met` / `cross_log_equivocation_detected` ([D050](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d050-cross-log-replication-for-equivocation-defense) / [§2.11](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#211-cross-log-replication)): requires multi-log proof-bundle parsing and trusted-log-set config.
|
|
108
|
-
(Note: `tool_name_form`, `args_commitment_form`, and `result_commitment_form` per [§8.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#82-opaque-name-posture)/[§8.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#83-salted-commitment-posture) are all now implemented under `posture` above. [D061](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d061-add-tool_name-args_hash-result_hash-fields-to-121) added `tool_name`, `args_hash`, and `result_hash` to the [§1.2.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#121-field-definitions) canonical record schema, completing the structural inputs.)
|
|
112
|
+
(Note: `tool_name_form`, `args_commitment_form`, and `result_commitment_form` per [§8.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#82-opaque-name-posture)/[§8.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#83-salted-commitment-posture) are all now implemented under `posture` above. [D061](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d061-add-tool_name-args_hash-result_hash-fields-to-121) added `tool_name`, `args_hash`, and `result_hash` to the [§1.2.1](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#121-field-definitions) canonical record schema, completing the structural inputs.)
|
|
109
113
|
|
|
110
114
|
Each pending annotation is its own ADR scope when external consumers need it.
|
|
111
115
|
|
|
116
|
+
### `verifyHandoffClaims(claims, options): Promise<HandoffVerificationResult>`
|
|
117
|
+
|
|
118
|
+
Verifier-side Pattern 3 handoff acceptance. Use this when one agent receives another agent's `record_hash` claim and needs to verify the supplied record, private body material, and proof before signing its own `informed_by` follow-up.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { handoffClaimsFromEvidencePacket, verifyHandoffClaims } from '@atrib/verify'
|
|
122
|
+
|
|
123
|
+
const claims = handoffClaimsFromEvidencePacket({
|
|
124
|
+
required_record_hashes: [record_hash],
|
|
125
|
+
records: [
|
|
126
|
+
{
|
|
127
|
+
record_hash,
|
|
128
|
+
record,
|
|
129
|
+
proof,
|
|
130
|
+
_local: { content: body },
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const handoff = await verifyHandoffClaims(claims, {
|
|
136
|
+
trusted_creator_keys: [agentAPublicKey],
|
|
137
|
+
allowed_context_ids: [expectedContextId],
|
|
138
|
+
require_body: true,
|
|
139
|
+
require_body_commitment: true,
|
|
140
|
+
require_log_inclusion: true,
|
|
141
|
+
log_public_key: logPublicKey,
|
|
142
|
+
max_age_ms: 60_000,
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
if (handoff.all_accepted) {
|
|
146
|
+
const informedBy = handoff.accepted_record_hashes
|
|
147
|
+
// Sign the receiving agent's next record with informed_by: informedBy.
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Checks performed:
|
|
152
|
+
|
|
153
|
+
- Record hash binding: supplied record hash must equal the claimed `record_hash`.
|
|
154
|
+
- Signature: `verifyRecord()` must accept the signed record.
|
|
155
|
+
- Trust set: `creator_key` must be in `trusted_creator_keys` when supplied.
|
|
156
|
+
- Context policy: `context_id` must be in `allowed_context_ids` when supplied.
|
|
157
|
+
- Freshness: record timestamp must be within `max_age_ms` when supplied.
|
|
158
|
+
- Body commitments: supplied `body`, `args`, or `result` must match `args_hash` / `result_hash` when required.
|
|
159
|
+
- Log proof: supplied proof must bind to the serialized log entry for that record, verify the inclusion path, and verify the C2SP checkpoint signature when `log_public_key` is supplied.
|
|
160
|
+
|
|
161
|
+
`handoffClaimsFromEvidencePacket()` accepts parsed [D062](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d062-local-mirror-sidecar--two-tier-private-local--public-canonical-persistence) local mirror envelopes, private continuation packets, or arrays of evidence entries. It preserves missing required hashes as verifier rejections. The helper never fetches private material. Callers provide records, body material, and proof bundles from a local mirror, private handoff packet, Record Body Archive Layer, log lookup, or another channel. Rejected claims carry named reasons such as `wrong_signer`, `wrong_context`, `stale`, `body_hash_mismatch`, and `proof_invalid`.
|
|
162
|
+
|
|
163
|
+
The library helper backs the `@atrib/verify-mcp` `atrib-verify` primitive promoted by [D106](https://github.com/creatornader/atrib/blob/main/DECISIONS.md#d106-verify-is-promoted-to-cognitive-primitive-7). The MCP wrapper handles agent-facing use; this package remains the verifier library.
|
|
164
|
+
|
|
112
165
|
### `verifyAp2ViEvidence(...)` and `verifyAp2ViEvidenceAsync(...)`
|
|
113
166
|
|
|
114
167
|
AP2 / Verifiable Intent evidence checking for merchants and auditors. This runs outside the transaction detector path. It does not alter the graph, the settlement calculation, or record validity. It answers a narrower question: did the AP2 receipts and VI mandate chain form a coherent evidence bundle?
|
|
@@ -160,14 +213,30 @@ Checks performed when evidence is present:
|
|
|
160
213
|
|
|
161
214
|
- AP2 PaymentReceipt / CheckoutReceipt success, required fields, and `reference` binding to a closed mandate serialization or explicit closed-mandate hash.
|
|
162
215
|
- Compact AP2 receipt JWT verification with `jose`, using trusted local JWKS, `jwksUrl`, or verifier metadata containing inline `jwks` or `jwks_uri`.
|
|
216
|
+
- Receipt JWT hardening for unsupported `alg`, `alg: "none"`, missing `kid`, unexpected `crit`, malformed compact JWTs, unsupported JWKS keys, duplicate `kid`, metadata precedence, issuer key isolation, and clock-edge behavior.
|
|
163
217
|
- VI SD-JWT parsing for L1, L2, L3 payment, and L3 checkout credentials.
|
|
218
|
+
- Async VI SD-JWT / SD-JWT VC conformance with OpenWallet `@sd-jwt/core` and `@sd-jwt/sd-jwt-vc`.
|
|
219
|
+
- VI SD-JWT structural checks for duplicate disclosures, duplicate digest references, unused disclosures, unsupported `_sd_alg`, and future `nbf`.
|
|
164
220
|
- ES256 signatures: L1 via trusted issuer keys, L2 via L1 `cnf.jwk`, L3 via the L2 delegated agent key.
|
|
165
221
|
- `sd_hash` links, disclosure digest links, autonomous L2 `cnf.jwk` consistency, and final checkout/payment binding.
|
|
222
|
+
- Typed AP2 mandate constraints: merchant allowlists, checkout line items, payment amount ranges, allowed payees, allowed payment instruments, allowed PISPs, execution windows, and `payment.reference`.
|
|
166
223
|
|
|
167
224
|
The default signature policy is `require`. Missing keys or invalid signatures make `valid` false while still returning a structured result. Use `signaturePolicy: "best-effort"` for structural triage where issuer keys are not yet available.
|
|
168
225
|
|
|
169
226
|
The default receipt JWT policy is also `require`. Invalid receipt JWTs make `valid` false. Use `receiptJwtPolicy: "best-effort"` when decoded receipt objects are already available and JWT verification is an advisory signal.
|
|
170
227
|
|
|
228
|
+
The async verifier also defaults `sdJwtConformancePolicy` to `require` when VI credentials are present. Each credential result includes `sdJwtConformance.status`, `profile`, and an optional reason. Use `sdJwtConformancePolicy: "best-effort"` for advisory conformance checks, or `"off"` to keep the async result aligned with the decoded structural verifier. The default profile is `sd-jwt-vc`; callers may pass `sdJwtConformanceProfile: "sd-jwt"` for the core SD-JWT profile.
|
|
229
|
+
|
|
230
|
+
VC type metadata and status-list fetches are explicit. If a caller enables `sdJwtVc.loadTypeMetadata` or submits credentials with VC status references, it should provide `sdJwtVc.vctFetcher` or `sdJwtVc.statusListFetcher`. The verifier does not perform hidden network fetches for those checks.
|
|
231
|
+
|
|
232
|
+
The default constraint policy is `require`. Failed, unresolved, or unsupported disclosed AP2 constraints make `valid` false. Use `constraintPolicy: "best-effort"` to keep those findings advisory, or `"off"` to skip them. The lower-level `evaluateAp2ViConstraints(input, disclosures?)` helper is exported for decoded mandate material and fixture replay.
|
|
233
|
+
|
|
234
|
+
Checkout line-item checks accept both atrib's decoded `line_items[]` fixture shape and VI checkout JWT payloads that carry purchased products under `cart.items[].sku`. `payment.reference` is evaluated against the open checkout mandate disclosure digest and the same final checkout-payment binding surfaced as `checkoutPaymentBindingOk`.
|
|
235
|
+
|
|
236
|
+
The local AP2 / VI evidence corpus lives under `packages/agent/test/fixtures/ap2/`. It includes signed immediate evidence, signed autonomous success evidence, a decoded constraint replay case, and a named autonomous negative matrix. The integration package also carries upstream-generated AP2 / VI artifacts under `packages/integration/test/fixtures/ap2-vi-reference/`. The crypto conformance corpus lives under `spec/conformance/ap2-vi-crypto/`. It pins offline JOSE, JWKS, metadata, SD-JWT, and clock-edge cases for the async verifier.
|
|
237
|
+
|
|
238
|
+
The same evidence bundle can be passed to `verifyRecord(record, { ap2ViEvidence, ap2ViEvidenceOptions })` for transaction records or to `verifier.verify(doc, { ap2ViEvidence, ap2ViEvidenceOptions })` for settlement recommendation verification. Both APIs attach the result as `ap2_vi_evidence`; neither API fetches AP2 / VI material on its own.
|
|
239
|
+
|
|
171
240
|
### `calculate(options): Promise<RecommendationDocument>`
|
|
172
241
|
|
|
173
242
|
Post-hoc calculation when no agent SDK was present. Always returns a fully-shaped document, unsigned with a warning if the merchant key is missing.
|
|
@@ -181,8 +250,10 @@ For advanced use (custom calculators, alternative signing flows), the package al
|
|
|
181
250
|
- `isValidPolicy(doc)`: schema check for `PolicyDocument`
|
|
182
251
|
- `signRecommendation(unsigned, privateKey)`: JCS + Ed25519 signing
|
|
183
252
|
- `verifyRecommendationSignature(doc, publicKey)`: signature verification
|
|
253
|
+
- `evaluateAp2ViConstraints(input, disclosures?)`: decoded AP2 open-mandate constraint checking
|
|
184
254
|
- `verifyAp2ViEvidence(bundle, options?)`: decoded AP2 / VI receipt and mandate-chain evidence checking
|
|
185
|
-
- `verifyAp2ViEvidenceAsync(bundle, options?)`: compact AP2 receipt JWT verification plus
|
|
255
|
+
- `verifyAp2ViEvidenceAsync(bundle, options?)`: compact AP2 receipt JWT verification, async VI SD-JWT / VC conformance, plus decoded evidence checks. `verifyRecord()` and `AtribVerifier.verify()` call this when supplied with `ap2ViEvidence`
|
|
256
|
+
- `verifyHandoffClaims(claims, options?)`: Pattern 3 handoff claim acceptance before a receiving agent signs an `informed_by` follow-up
|
|
186
257
|
- `recommendationSigningInput(doc)`: the canonical bytes that get signed
|
|
187
258
|
- `distributionsMatch(a, b)`: float-tolerant equality (within `1e-9` per recipient)
|
|
188
259
|
- `fetchGraph(endpoint, contextId, treeSize?)`, `fetchSessionPolicyRecord`, `fetchPolicyDocument`
|
|
@@ -210,21 +281,21 @@ The merchant's payment pipeline never crashes because of an atrib problem. It ju
|
|
|
210
281
|
|
|
211
282
|
## Test coverage
|
|
212
283
|
|
|
213
|
-
|
|
284
|
+
The test suite covers the [§4.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#46-the-calculation-algorithm) calculation algorithm, graph endpoint client, JCS canonicalization, Ed25519 signing, settlement recommendations, policy templates, policy builder, calculation edge cases, property-based testing with fast-check, AP2 / VI evidence checking, AP2 / VI crypto conformance, tiered AP2 / VI verifier attachment, and full `verify()` / `calculate()` paths including [§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract) degradation.
|
|
214
285
|
|
|
215
286
|
Run them with `pnpm --filter @atrib/verify test`.
|
|
216
287
|
|
|
217
288
|
## Spec references
|
|
218
289
|
|
|
219
|
-
| Spec section
|
|
220
|
-
|
|
|
221
|
-
| [§3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#3-graph-query-interface)
|
|
222
|
-
| [§4.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#43-the-default-policy)
|
|
223
|
-
| [§4.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#46-the-calculation-algorithm)
|
|
224
|
-
| [§4.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#47-settlement-recommendation-document)
|
|
225
|
-
| [§5.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#55-atribverify-merchant-verification-library)
|
|
226
|
-
| [§5.5.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#554-ap2--verifiable-intent-evidence-checks) | AP2 / VI evidence checks
|
|
227
|
-
| [§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract)
|
|
290
|
+
| Spec section | What this package implements |
|
|
291
|
+
| ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- |
|
|
292
|
+
| [§3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#3-graph-query-interface) | Graph query interface (client side) |
|
|
293
|
+
| [§4.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#43-the-default-policy) | Default policy document |
|
|
294
|
+
| [§4.6](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#46-the-calculation-algorithm) | Pure calculation algorithm |
|
|
295
|
+
| [§4.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#47-settlement-recommendation-document) | Recommendation document signing/verification |
|
|
296
|
+
| [§5.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#55-atribverify-merchant-verification-library) | `AtribVerifier` class. `verify()` and `calculate()` |
|
|
297
|
+
| [§5.5.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#554-ap2--verifiable-intent-evidence-checks) | AP2 / VI evidence checks |
|
|
298
|
+
| [§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract) | Degradation contract; failures never break the host |
|
|
228
299
|
|
|
229
300
|
The full protocol spec is at [`atrib-spec.md`](https://github.com/creatornader/atrib/blob/main/atrib-spec.md).
|
|
230
301
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import type { StatusListFetcher, StatusValidator, VcTFetcher } from '@sd-jwt/sd-jwt-vc';
|
|
1
2
|
export type ViCredentialLayer = 'L1' | 'L2' | 'L3_PAYMENT' | 'L3_CHECKOUT';
|
|
2
3
|
export type ViMode = 'immediate' | 'autonomous' | 'unknown';
|
|
4
|
+
export type SdJwtConformancePolicy = 'require' | 'best-effort' | 'off';
|
|
5
|
+
export type SdJwtConformanceProfile = 'sd-jwt' | 'sd-jwt-vc';
|
|
6
|
+
export type Ap2ConstraintPolicy = 'require' | 'best-effort' | 'off';
|
|
7
|
+
export type Ap2ConstraintDomain = 'checkout' | 'payment';
|
|
8
|
+
export type Ap2ConstraintCheckStatus = 'passed' | 'failed' | 'unresolved' | 'unsupported';
|
|
9
|
+
export type Ap2ConstraintEvaluationStatus = 'passed' | 'failed' | 'unresolved' | 'not_applicable' | 'not_checked';
|
|
3
10
|
export interface ViCredentialInput {
|
|
4
11
|
layer: ViCredentialLayer;
|
|
5
12
|
sdJwt: string;
|
|
@@ -10,6 +17,7 @@ export interface Ap2EvidenceInput {
|
|
|
10
17
|
checkoutReceipt?: unknown;
|
|
11
18
|
paymentReceiptJwt?: string;
|
|
12
19
|
checkoutReceiptJwt?: string;
|
|
20
|
+
checkoutPayload?: unknown;
|
|
13
21
|
closedPaymentMandate?: string;
|
|
14
22
|
closedCheckoutMandate?: string;
|
|
15
23
|
closedPaymentMandateHash?: string;
|
|
@@ -24,6 +32,13 @@ export interface Ap2ReceiptJwtIssuer {
|
|
|
24
32
|
jwksUrl?: string;
|
|
25
33
|
metadataUrl?: string;
|
|
26
34
|
}
|
|
35
|
+
export interface SdJwtVcConformanceOptions {
|
|
36
|
+
loadTypeMetadata?: boolean;
|
|
37
|
+
vctFetcher?: VcTFetcher;
|
|
38
|
+
statusListFetcher?: StatusListFetcher;
|
|
39
|
+
statusValidator?: StatusValidator;
|
|
40
|
+
maxVctExtendsDepth?: number;
|
|
41
|
+
}
|
|
27
42
|
export interface Ap2ViEvidenceBundle {
|
|
28
43
|
ap2?: Ap2EvidenceInput;
|
|
29
44
|
vi?: {
|
|
@@ -37,6 +52,10 @@ export interface VerifyAp2ViEvidenceOptions {
|
|
|
37
52
|
receiptJwtIssuers?: Ap2ReceiptJwtIssuer[];
|
|
38
53
|
receiptJwtPolicy?: 'require' | 'best-effort';
|
|
39
54
|
signaturePolicy?: 'require' | 'best-effort';
|
|
55
|
+
sdJwtConformancePolicy?: SdJwtConformancePolicy;
|
|
56
|
+
sdJwtConformanceProfile?: SdJwtConformanceProfile;
|
|
57
|
+
constraintPolicy?: Ap2ConstraintPolicy;
|
|
58
|
+
sdJwtVc?: SdJwtVcConformanceOptions;
|
|
40
59
|
nowSeconds?: number;
|
|
41
60
|
clockSkewSeconds?: number;
|
|
42
61
|
fetch?: typeof fetch;
|
|
@@ -45,12 +64,18 @@ export interface SignatureCheck {
|
|
|
45
64
|
status: 'verified' | 'invalid' | 'not_checked';
|
|
46
65
|
reason?: string;
|
|
47
66
|
}
|
|
67
|
+
export interface SdJwtConformanceCheck {
|
|
68
|
+
status: 'verified' | 'invalid' | 'not_checked';
|
|
69
|
+
profile: SdJwtConformanceProfile | null;
|
|
70
|
+
reason?: string;
|
|
71
|
+
}
|
|
48
72
|
export interface ViCredentialCheck {
|
|
49
73
|
layer: ViCredentialLayer;
|
|
50
74
|
alg: string | null;
|
|
51
75
|
typ: string | null;
|
|
52
76
|
kid: string | null;
|
|
53
77
|
signature: SignatureCheck;
|
|
78
|
+
sdJwtConformance: SdJwtConformanceCheck;
|
|
54
79
|
sdHashOk: boolean | null;
|
|
55
80
|
disclosuresOk: boolean | null;
|
|
56
81
|
mandateVcts: string[];
|
|
@@ -73,6 +98,26 @@ export interface Ap2ReceiptJwtCheck {
|
|
|
73
98
|
jwksSource: 'static' | 'jwks_url' | 'metadata' | null;
|
|
74
99
|
error?: string;
|
|
75
100
|
}
|
|
101
|
+
export interface Ap2MandateConstraintCheck {
|
|
102
|
+
type: string;
|
|
103
|
+
domain: Ap2ConstraintDomain;
|
|
104
|
+
status: Ap2ConstraintCheckStatus;
|
|
105
|
+
reason?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface Ap2MandateConstraintEvaluation {
|
|
108
|
+
status: Ap2ConstraintEvaluationStatus;
|
|
109
|
+
checks: Ap2MandateConstraintCheck[];
|
|
110
|
+
}
|
|
111
|
+
export interface Ap2MandateConstraintInput {
|
|
112
|
+
openCheckoutMandates?: unknown[];
|
|
113
|
+
openCheckoutMandateDigests?: string[];
|
|
114
|
+
closedCheckoutMandates?: unknown[];
|
|
115
|
+
openPaymentMandates?: unknown[];
|
|
116
|
+
closedPaymentMandates?: unknown[];
|
|
117
|
+
checkoutPayload?: unknown;
|
|
118
|
+
checkoutPaymentBindingOk?: boolean | null;
|
|
119
|
+
nowSeconds?: number;
|
|
120
|
+
}
|
|
76
121
|
export interface Ap2EvidenceCheck {
|
|
77
122
|
paymentReceipt?: Ap2ReceiptCheck;
|
|
78
123
|
checkoutReceipt?: Ap2ReceiptCheck;
|
|
@@ -82,6 +127,7 @@ export interface ViEvidenceCheck {
|
|
|
82
127
|
credentials: ViCredentialCheck[];
|
|
83
128
|
delegationOk: boolean | null;
|
|
84
129
|
checkoutPaymentBindingOk: boolean | null;
|
|
130
|
+
constraints: Ap2MandateConstraintEvaluation;
|
|
85
131
|
}
|
|
86
132
|
export interface Ap2ViEvidenceVerification {
|
|
87
133
|
valid: boolean;
|
|
@@ -91,6 +137,7 @@ export interface Ap2ViEvidenceVerification {
|
|
|
91
137
|
errors: string[];
|
|
92
138
|
warnings: string[];
|
|
93
139
|
}
|
|
140
|
+
export declare function evaluateAp2ViConstraints(input: Ap2MandateConstraintInput, disclosures?: Map<string, unknown>): Ap2MandateConstraintEvaluation;
|
|
94
141
|
export declare function verifyAp2ViEvidence(bundle: Ap2ViEvidenceBundle, options?: VerifyAp2ViEvidenceOptions): Ap2ViEvidenceVerification;
|
|
95
142
|
export declare function verifyAp2ViEvidenceAsync(bundle: Ap2ViEvidenceBundle, options?: VerifyAp2ViEvidenceOptions): Promise<Ap2ViEvidenceVerification>;
|
|
96
143
|
//# sourceMappingURL=ap2-vi-evidence.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ap2-vi-evidence.d.ts","sourceRoot":"","sources":["../src/ap2-vi-evidence.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ap2-vi-evidence.d.ts","sourceRoot":"","sources":["../src/ap2-vi-evidence.ts"],"names":[],"mappings":"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"}
|