@decionis/agent-safe-pipeline 0.2.0 → 0.3.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 +1 -0
- package/dist/Index.d.ts +1 -0
- package/dist/Index.d.ts.map +1 -1
- package/dist/Index.js +1 -0
- package/dist/Index.js.map +1 -1
- package/dist/execution/ActionRegistry.d.ts +11 -0
- package/dist/execution/ActionRegistry.d.ts.map +1 -1
- package/dist/execution/ActionRegistry.js +13 -3
- package/dist/execution/ActionRegistry.js.map +1 -1
- package/dist/execution/AuthorizationVerifier.d.ts +27 -0
- package/dist/execution/AuthorizationVerifier.d.ts.map +1 -1
- package/dist/execution/AuthorizationVerifier.js +34 -5
- package/dist/execution/AuthorizationVerifier.js.map +1 -1
- package/dist/execution/SafeExecutor.d.ts +2 -1
- package/dist/execution/SafeExecutor.d.ts.map +1 -1
- package/dist/execution/SafeExecutor.js +7 -5
- package/dist/execution/SafeExecutor.js.map +1 -1
- package/dist/intent/IntentBindingSchema.d.ts +50 -0
- package/dist/intent/IntentBindingSchema.d.ts.map +1 -0
- package/dist/intent/IntentBindingSchema.js +73 -0
- package/dist/intent/IntentBindingSchema.js.map +1 -0
- package/dist/intent/JsonValue.d.ts +5 -0
- package/dist/intent/JsonValue.d.ts.map +1 -1
- package/dist/intent/JsonValue.js +9 -2
- package/dist/intent/JsonValue.js.map +1 -1
- package/dist/testing/Index.d.ts +1 -1
- package/dist/testing/Index.d.ts.map +1 -1
- package/dist/testing/Index.js +1 -1
- package/dist/testing/Index.js.map +1 -1
- package/dist/testing/LocalAuthority.d.ts +67 -0
- package/dist/testing/LocalAuthority.d.ts.map +1 -1
- package/dist/testing/LocalAuthority.js +203 -3
- package/dist/testing/LocalAuthority.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { JsonObjectSchema, JsonValueSchema } from "./JsonValue.js";
|
|
3
|
+
/** Where the published schema of the binding lives; the `$id` it carries. */
|
|
4
|
+
export const INTENT_SCHEMA_ID = "https://github.com/decionis/agent-safe-pipeline/blob/master/spec/intent/v1/schema.json";
|
|
5
|
+
const identifier = z.string().min(1).max(200);
|
|
6
|
+
const actionType = z
|
|
7
|
+
.string()
|
|
8
|
+
.min(1)
|
|
9
|
+
.max(120)
|
|
10
|
+
.regex(/^[a-z][a-z0-9._:-]*$/);
|
|
11
|
+
const sha256Digest = z.string().regex(/^sha256:[0-9a-f]{64}$/);
|
|
12
|
+
/**
|
|
13
|
+
* The `agent-safe.intent/1` binding as it is hashed and sent, as a strict
|
|
14
|
+
* schema: what `CanonicalIntentHasher.bindingOf` produces, and what an
|
|
15
|
+
* implementation in another language must produce byte for byte before
|
|
16
|
+
* canonicalization. Nothing here trims or coerces, because a validator that
|
|
17
|
+
* altered a binding would be validating different bytes than it hashes.
|
|
18
|
+
* `context` is any JSON object that carries the trusted runtime's
|
|
19
|
+
* `idempotency_key`; every other object refuses a key it does not name.
|
|
20
|
+
*/
|
|
21
|
+
export const AuthorityIntentBindingSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
protocol_version: z.literal("agent-safe.intent/1"),
|
|
24
|
+
tenant_id: z.string().uuid(),
|
|
25
|
+
intent_id: z.string().uuid(),
|
|
26
|
+
captured_at: z.string().datetime(),
|
|
27
|
+
expires_at: z.string().datetime(),
|
|
28
|
+
actor: z
|
|
29
|
+
.object({
|
|
30
|
+
id: identifier,
|
|
31
|
+
type: identifier,
|
|
32
|
+
runtime: identifier.optional(),
|
|
33
|
+
trust_level: z.string().min(1).max(80).optional(),
|
|
34
|
+
})
|
|
35
|
+
.strict(),
|
|
36
|
+
action: z
|
|
37
|
+
.object({
|
|
38
|
+
type: actionType,
|
|
39
|
+
resource: z.string().min(1).max(500),
|
|
40
|
+
parameters: JsonObjectSchema,
|
|
41
|
+
})
|
|
42
|
+
.strict(),
|
|
43
|
+
context: z.object({ idempotency_key: z.string().min(1).max(180) }).catchall(JsonValueSchema),
|
|
44
|
+
downstream_target: z
|
|
45
|
+
.object({
|
|
46
|
+
system: identifier,
|
|
47
|
+
operation: identifier,
|
|
48
|
+
environment: identifier.optional(),
|
|
49
|
+
endpoint: z.string().min(1).max(500).optional(),
|
|
50
|
+
})
|
|
51
|
+
.strict(),
|
|
52
|
+
expected_effect_digest: sha256Digest.optional(),
|
|
53
|
+
})
|
|
54
|
+
.strict()
|
|
55
|
+
.meta({
|
|
56
|
+
title: "agent-safe.intent/1 binding",
|
|
57
|
+
description: "The execution intent as the authority receives it and as it is hashed: keys sorted by UTF-16 code unit, encoded as JSON without whitespace, and digested with SHA-256. Every property is inside the hash.",
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* The binding's JSON Schema (draft 2020-12), the document published at
|
|
61
|
+
* `spec/intent/v1/schema.json`. It is derived from the schema above, so the
|
|
62
|
+
* published file and the validator cannot disagree; a test holds the file to
|
|
63
|
+
* this output.
|
|
64
|
+
*/
|
|
65
|
+
export function intentBindingJsonSchema() {
|
|
66
|
+
const generated = z.toJSONSchema(AuthorityIntentBindingSchema, {
|
|
67
|
+
target: "draft-2020-12",
|
|
68
|
+
io: "input",
|
|
69
|
+
});
|
|
70
|
+
const { $schema, ...rest } = generated;
|
|
71
|
+
return { $schema, $id: INTENT_SCHEMA_ID, ...rest };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=IntentBindingSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntentBindingSchema.js","sourceRoot":"","sources":["../../src/intent/IntentBindingSchema.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,11 @@ export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
|
6
6
|
export type JsonObject = {
|
|
7
7
|
[key: string]: JsonValue;
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* Named in the schema registry so that the published JSON Schema of the
|
|
11
|
+
* intent binding (`intentBindingJsonSchema`) refers to it as `JsonValue`
|
|
12
|
+
* rather than by a generated name; parsing is unaffected.
|
|
13
|
+
*/
|
|
9
14
|
export declare const JsonValueSchema: z.ZodType<JsonValue>;
|
|
10
15
|
export declare const JsonObjectSchema: z.ZodType<JsonObject>;
|
|
11
16
|
//# sourceMappingURL=JsonValue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonValue.d.ts","sourceRoot":"","sources":["../../src/intent/JsonValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAC7D,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AACnF,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"JsonValue.d.ts","sourceRoot":"","sources":["../../src/intent/JsonValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAC7D,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AACnF,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAW+B,CAAC;AAEjF,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAyC,CAAC"}
|
package/dist/intent/JsonValue.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Named in the schema registry so that the published JSON Schema of the
|
|
4
|
+
* intent binding (`intentBindingJsonSchema`) refers to it as `JsonValue`
|
|
5
|
+
* rather than by a generated name; parsing is unaffected.
|
|
6
|
+
*/
|
|
7
|
+
export const JsonValueSchema = z
|
|
8
|
+
.lazy(() => z.union([
|
|
3
9
|
z.boolean(),
|
|
4
10
|
z.number().finite(),
|
|
5
11
|
z.string(),
|
|
6
12
|
z.null(),
|
|
7
13
|
z.array(JsonValueSchema),
|
|
8
14
|
z.record(z.string(), JsonValueSchema),
|
|
9
|
-
]))
|
|
15
|
+
]))
|
|
16
|
+
.meta({ id: "JsonValue", description: "Any JSON value; numbers are finite." });
|
|
10
17
|
export const JsonObjectSchema = z.record(z.string(), JsonValueSchema);
|
|
11
18
|
//# sourceMappingURL=JsonValue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonValue.js","sourceRoot":"","sources":["../../src/intent/JsonValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,MAAM,CAAC,MAAM,eAAe,GAAyB,CAAC,
|
|
1
|
+
{"version":3,"file":"JsonValue.js","sourceRoot":"","sources":["../../src/intent/JsonValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAyB,CAAC;KACnD,IAAI,CAAC,GAAG,EAAE,CACT,CAAC,CAAC,KAAK,CAAC;IACN,CAAC,CAAC,OAAO,EAAE;IACX,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE;IACnB,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,IAAI,EAAE;IACR,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;IACxB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC;CACtC,CAAC,CACH;KACA,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,qCAAqC,EAAE,CAAC,CAAC;AAEjF,MAAM,CAAC,MAAM,gBAAgB,GAA0B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC"}
|
package/dist/testing/Index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
export { FixtureAuthorizationVerifier, FixtureDecisionAuthority, createFixtureAuthorityPair, type FixtureAuthorityPair, type FixtureCommitRecord, type FixtureVerdictResolver, type UnsafeFixtureAuthorityOptions, } from "../decision/FixtureDecisionAuthority.js";
|
|
9
9
|
export { InMemoryReplayStore } from "../execution/ReplayStore.js";
|
|
10
10
|
export { LocalPresence, LOCAL_PRESENCE_API_KEY, readBody, type LocalAuthenticator, type LocalCeremonyResponse, type LocalPresenceOptions, type LocalPresenceRequestRecord, type LocalReceipt, type LocalReceiptBinding, type LocalReceiptVerification, type LocalVerificationRecord, type LocalVerificationStatus, } from "./LocalPresence.js";
|
|
11
|
-
export { AUTONOMOUS_LIMIT_MINOR, CLAIM_ATTESTATION_TYPE, HUMAN_LIMIT_MINOR, LocalAuthority, LOCAL_AUTHORITY_API_KEY, LOCAL_AUTHORITY_ISSUER, LOCAL_AUTHORITY_JWKS_PATH, hashBinding, stableStringify, type LocalAuthorityOptions, type LocalClaimAttestationClaims, type LocalAuthorityPolicy, type LocalAuthorityRequestRecord, type LocalGrantRecord, type LocalManagedEscalationRecord, type LocalRouteOverride, } from "./LocalAuthority.js";
|
|
11
|
+
export { AUTONOMOUS_LIMIT_MINOR, CLAIM_ATTESTATION_TYPE, EFFECT_RECEIPT_TYPE, HUMAN_LIMIT_MINOR, LocalAuthority, LOCAL_AUTHORITY_API_KEY, LOCAL_AUTHORITY_ISSUER, LOCAL_AUTHORITY_JWKS_PATH, hashBinding, stableStringify, type LocalAuthorityOptions, type LocalClaimAttestationClaims, type LocalEffectReceiptCode, type LocalEffectReceiptRecord, type LocalProviderKey, type LocalAuthorityPolicy, type LocalAuthorityRequestRecord, type LocalGrantRecord, type LocalManagedEscalationRecord, type LocalRouteOverride, } from "./LocalAuthority.js";
|
|
12
12
|
//# sourceMappingURL=Index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Index.d.ts","sourceRoot":"","sources":["../../src/testing/Index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,GACnC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"Index.d.ts","sourceRoot":"","sources":["../../src/testing/Index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,GACnC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC"}
|
package/dist/testing/Index.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
export { FixtureAuthorizationVerifier, FixtureDecisionAuthority, createFixtureAuthorityPair, } from "../decision/FixtureDecisionAuthority.js";
|
|
9
9
|
export { InMemoryReplayStore } from "../execution/ReplayStore.js";
|
|
10
10
|
export { LocalPresence, LOCAL_PRESENCE_API_KEY, readBody, } from "./LocalPresence.js";
|
|
11
|
-
export { AUTONOMOUS_LIMIT_MINOR, CLAIM_ATTESTATION_TYPE, HUMAN_LIMIT_MINOR, LocalAuthority, LOCAL_AUTHORITY_API_KEY, LOCAL_AUTHORITY_ISSUER, LOCAL_AUTHORITY_JWKS_PATH, hashBinding, stableStringify, } from "./LocalAuthority.js";
|
|
11
|
+
export { AUTONOMOUS_LIMIT_MINOR, CLAIM_ATTESTATION_TYPE, EFFECT_RECEIPT_TYPE, HUMAN_LIMIT_MINOR, LocalAuthority, LOCAL_AUTHORITY_API_KEY, LOCAL_AUTHORITY_ISSUER, LOCAL_AUTHORITY_JWKS_PATH, hashBinding, stableStringify, } from "./LocalAuthority.js";
|
|
12
12
|
//# sourceMappingURL=Index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Index.js","sourceRoot":"","sources":["../../src/testing/Index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,0BAA0B,GAK3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,QAAQ,GAUT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,eAAe,
|
|
1
|
+
{"version":3,"file":"Index.js","sourceRoot":"","sources":["../../src/testing/Index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,0BAA0B,GAK3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,QAAQ,GAUT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,eAAe,GAWhB,MAAM,qBAAqB,CAAC"}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loopback stand-in for the Decionis execution-authority routes that
|
|
3
|
+
* `@decionis/agent-safe-pipeline` consumes: enforce-and-bind (including
|
|
4
|
+
* shadow mode and managed escalation), escalation status and cancellation,
|
|
5
|
+
* claim-token with its consume-token alias, and finalize-token.
|
|
6
|
+
*
|
|
7
|
+
* It validates every request against the published OpenAPI contract with its
|
|
8
|
+
* own canonicalizer, so a hash it recomputes is independent evidence that the
|
|
9
|
+
* package binds intents the way Decionis does. Direct Presence evidence is
|
|
10
|
+
* verified against a `LocalPresence`, and a managed escalation is orchestrated
|
|
11
|
+
* through that same `LocalPresence` the way Decionis orchestrates Presence:
|
|
12
|
+
* create a request bound to the exact intent hash, wait for the ceremony,
|
|
13
|
+
* verify the receipt, re-evaluate policy, then expose a normal grant.
|
|
14
|
+
*
|
|
15
|
+
* Grants, claims, escalations, and commit outcomes are synthetic in-memory
|
|
16
|
+
* state. Nothing here is a real policy, tenant, or credential.
|
|
17
|
+
*/
|
|
18
|
+
import { type KeyObject } from "node:crypto";
|
|
1
19
|
import { z } from "zod";
|
|
2
20
|
import { type LocalPresence } from "./LocalPresence.js";
|
|
3
21
|
export declare const LOCAL_AUTHORITY_API_KEY = "test-key";
|
|
@@ -8,6 +26,8 @@ export declare const LOCAL_AUTHORITY_ISSUER = "synthetic-authority";
|
|
|
8
26
|
/** Where the fixture publishes its attestation key, at the path Decionis documents. */
|
|
9
27
|
export declare const LOCAL_AUTHORITY_JWKS_PATH = "/.well-known/decionis-execution-grant-jwks.json";
|
|
10
28
|
export declare const CLAIM_ATTESTATION_TYPE = "decionis-claim-attestation+jwt";
|
|
29
|
+
/** The protected header `typ` of a verifying provider's effect receipt (VP-3). */
|
|
30
|
+
export declare const EFFECT_RECEIPT_TYPE = "decionis-effect-receipt+jwt";
|
|
11
31
|
/** `ExecutionAuthorityRequest`: the binding plus hash, mode, evidence, and managed constraints. */
|
|
12
32
|
declare const AuthorityRequestSchema: z.ZodObject<{
|
|
13
33
|
intent_hash: z.ZodString;
|
|
@@ -119,6 +139,28 @@ export interface LocalGrantRecord {
|
|
|
119
139
|
correlationId: string | null;
|
|
120
140
|
consumedBy: string | null;
|
|
121
141
|
finalized: "COMMITTED" | "FAILED" | "INDETERMINATE" | null;
|
|
142
|
+
/** The provider's effect receipt as this authority read it at finalization, when one came. */
|
|
143
|
+
receipt: LocalEffectReceiptRecord | null;
|
|
144
|
+
}
|
|
145
|
+
/** The verdict codes the hosted authority records for a receipt, and this double with it. */
|
|
146
|
+
export type LocalEffectReceiptCode = "EFFECT_RECEIPT_VERIFIED" | "EFFECT_RECEIPT_MALFORMED" | "EFFECT_RECEIPT_KEY_UNKNOWN" | "EFFECT_RECEIPT_SIGNATURE_INVALID" | "EFFECT_RECEIPT_BINDING_MISMATCH";
|
|
147
|
+
export interface LocalEffectReceiptRecord {
|
|
148
|
+
readonly token: string;
|
|
149
|
+
readonly verified: boolean;
|
|
150
|
+
readonly verification_code: LocalEffectReceiptCode;
|
|
151
|
+
readonly provider_key_id: string | null;
|
|
152
|
+
readonly issuer: string | null;
|
|
153
|
+
readonly effect_status: "EFFECTED" | "REFUSED" | "INDETERMINATE" | null;
|
|
154
|
+
readonly effect_digest: string | null;
|
|
155
|
+
readonly effect_reference: string | null;
|
|
156
|
+
readonly effected_at: string | null;
|
|
157
|
+
}
|
|
158
|
+
/** A verifying provider's registered receipt key: the public half, its `kid`, the `iss` it signs as. */
|
|
159
|
+
export interface LocalProviderKey {
|
|
160
|
+
readonly kid: string;
|
|
161
|
+
readonly issuer: string;
|
|
162
|
+
readonly publicKey: KeyObject;
|
|
163
|
+
readonly label: string | null;
|
|
122
164
|
}
|
|
123
165
|
export interface LocalManagedEscalationRecord {
|
|
124
166
|
readonly escalationId: string;
|
|
@@ -200,6 +242,8 @@ export declare class LocalAuthority {
|
|
|
200
242
|
readonly grants: Map<string, LocalGrantRecord>;
|
|
201
243
|
/** Managed escalations keyed by their opaque identifier. */
|
|
202
244
|
readonly escalations: Map<string, LocalManagedEscalationRecord>;
|
|
245
|
+
/** The verifying providers' receipt keys, by `kid`, as `/v1/execution/provider-keys` registers them. */
|
|
246
|
+
readonly providerKeys: Map<string, LocalProviderKey>;
|
|
203
247
|
private readonly apiKey;
|
|
204
248
|
private readonly presence;
|
|
205
249
|
private readonly legacyVerifyReceipt;
|
|
@@ -237,6 +281,27 @@ export declare class LocalAuthority {
|
|
|
237
281
|
* `node:crypto` alone so the fixture stays an independent implementation.
|
|
238
282
|
*/
|
|
239
283
|
private attest;
|
|
284
|
+
/**
|
|
285
|
+
* Registers the public half of a provider's receipt key, as the hosted
|
|
286
|
+
* `POST /v1/execution/provider-keys` does; a test or a demo provider calls
|
|
287
|
+
* it directly rather than over HTTP.
|
|
288
|
+
*/
|
|
289
|
+
registerProviderKey(input: {
|
|
290
|
+
readonly kid: string;
|
|
291
|
+
readonly issuer: string;
|
|
292
|
+
readonly publicJwk: JsonWebKey;
|
|
293
|
+
readonly label?: string;
|
|
294
|
+
}): void;
|
|
295
|
+
/**
|
|
296
|
+
* Reads a receipt the way the hosted authority does: the protected header
|
|
297
|
+
* names an Ed25519 key the organisation registered; the signature verifies
|
|
298
|
+
* under it; the issuer is the one registered with the key and the audience
|
|
299
|
+
* is this authority; and the claims describe this grant and this claim,
|
|
300
|
+
* through `sub`, the decision and dossier ids and the digest of the claim
|
|
301
|
+
* token being finalized. Anything else is recorded with its code, and the
|
|
302
|
+
* finalization proceeds regardless.
|
|
303
|
+
*/
|
|
304
|
+
private readEffectReceipt;
|
|
240
305
|
get baseUrl(): string;
|
|
241
306
|
start(): Promise<void>;
|
|
242
307
|
stop(): Promise<void>;
|
|
@@ -249,6 +314,8 @@ export declare class LocalAuthority {
|
|
|
249
314
|
/** Statuses returned, in order, for the next managed escalation instead of orchestration. */
|
|
250
315
|
scriptNextManagedLifecycle(statuses: readonly LifecycleEntry[]): void;
|
|
251
316
|
private handle;
|
|
317
|
+
/** `POST /v1/execution/provider-keys`: the public half only, or a 400 naming why. */
|
|
318
|
+
private registerProviderKeyRoute;
|
|
252
319
|
private enforceAndBind;
|
|
253
320
|
/** Keeps a minted decision for its dossier route, with the envelope when links are on. */
|
|
254
321
|
private remember;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalAuthority.d.ts","sourceRoot":"","sources":["../../src/testing/LocalAuthority.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LocalAuthority.d.ts","sourceRoot":"","sources":["../../src/testing/LocalAuthority.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Grants, claims, escalations, and commit outcomes are synthetic in-memory
|
|
16
16
|
* state. Nothing here is a real policy, tenant, or credential.
|
|
17
17
|
*/
|
|
18
|
-
import { createHash, generateKeyPairSync, randomBytes, randomUUID, sign, } from "node:crypto";
|
|
18
|
+
import { createHash, createPublicKey, generateKeyPairSync, randomBytes, randomUUID, sign, verify, } from "node:crypto";
|
|
19
19
|
import { createServer } from "node:http";
|
|
20
20
|
import { z } from "zod";
|
|
21
21
|
import { readBody } from "./LocalPresence.js";
|
|
@@ -33,6 +33,9 @@ export const LOCAL_AUTHORITY_ISSUER = "synthetic-authority";
|
|
|
33
33
|
/** Where the fixture publishes its attestation key, at the path Decionis documents. */
|
|
34
34
|
export const LOCAL_AUTHORITY_JWKS_PATH = "/.well-known/decionis-execution-grant-jwks.json";
|
|
35
35
|
export const CLAIM_ATTESTATION_TYPE = "decionis-claim-attestation+jwt";
|
|
36
|
+
/** The protected header `typ` of a verifying provider's effect receipt (VP-3). */
|
|
37
|
+
export const EFFECT_RECEIPT_TYPE = "decionis-effect-receipt+jwt";
|
|
38
|
+
const COMPACT_JWS = /^[\w-]+\.[\w-]+\.[\w-]+$/;
|
|
36
39
|
/** The profile the fixture digests parameters under; the only one the pipeline reproduces. */
|
|
37
40
|
const JCS_PROFILE = "RFC8785/JCS";
|
|
38
41
|
const boundedId = z.string().trim().min(1).max(200);
|
|
@@ -179,8 +182,30 @@ const FinalizeRequestSchema = z.strictObject({
|
|
|
179
182
|
// evidence with a 409 and a reason code, not with a 400 request rejection,
|
|
180
183
|
// so the shape is checked where that answer is produced.
|
|
181
184
|
effect_evidence: z.unknown().optional(),
|
|
185
|
+
// The provider's receipt: only its shape is a request error. What it says
|
|
186
|
+
// is verified and recorded, never a reason to refuse the finalization.
|
|
187
|
+
effect_receipt: z.string().min(1).max(20_000).regex(COMPACT_JWS).optional(),
|
|
188
|
+
});
|
|
189
|
+
/** `ExecutionProviderKeyRegistrationRequest`: the public half of an Ed25519 key. */
|
|
190
|
+
const ProviderKeyRegistrationSchema = z.strictObject({
|
|
191
|
+
org_id: z.uuid().optional(),
|
|
192
|
+
kid: boundedId,
|
|
193
|
+
issuer: z.string().trim().min(1).max(500),
|
|
194
|
+
algorithm: z.literal("EdDSA"),
|
|
195
|
+
public_jwk: z.strictObject({
|
|
196
|
+
kty: z.literal("OKP"),
|
|
197
|
+
crv: z.literal("Ed25519"),
|
|
198
|
+
x: z.string().regex(/^[\w-]{43}$/),
|
|
199
|
+
kid: z.string().optional(),
|
|
200
|
+
alg: z.literal("EdDSA").optional(),
|
|
201
|
+
use: z.literal("sig").optional(),
|
|
202
|
+
}),
|
|
203
|
+
label: z.string().max(200).optional(),
|
|
182
204
|
});
|
|
183
205
|
const BINDING_KEYS = Object.keys(IntentBindingSchema.shape);
|
|
206
|
+
function effectStatus(value) {
|
|
207
|
+
return value === "EFFECTED" || value === "REFUSED" || value === "INDETERMINATE" ? value : null;
|
|
208
|
+
}
|
|
184
209
|
/** The organization a provisioned synthetic workspace belongs to. */
|
|
185
210
|
export const LOCAL_AUTHORITY_PROVISIONAL_ORG_ID = "00000000-0000-4000-8000-000000000008";
|
|
186
211
|
/**
|
|
@@ -232,6 +257,8 @@ export class LocalAuthority {
|
|
|
232
257
|
grants = new Map();
|
|
233
258
|
/** Managed escalations keyed by their opaque identifier. */
|
|
234
259
|
escalations = new Map();
|
|
260
|
+
/** The verifying providers' receipt keys, by `kid`, as `/v1/execution/provider-keys` registers them. */
|
|
261
|
+
providerKeys = new Map();
|
|
235
262
|
apiKey;
|
|
236
263
|
presence;
|
|
237
264
|
legacyVerifyReceipt;
|
|
@@ -330,6 +357,103 @@ export class LocalAuthority {
|
|
|
330
357
|
const signature = sign(null, Buffer.from(`${header}.${payload}`, "ascii"), this.attestationKey.privateKey);
|
|
331
358
|
return `${header}.${payload}.${signature.toString("base64url")}`;
|
|
332
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Registers the public half of a provider's receipt key, as the hosted
|
|
362
|
+
* `POST /v1/execution/provider-keys` does; a test or a demo provider calls
|
|
363
|
+
* it directly rather than over HTTP.
|
|
364
|
+
*/
|
|
365
|
+
registerProviderKey(input) {
|
|
366
|
+
this.providerKeys.set(input.kid, {
|
|
367
|
+
kid: input.kid,
|
|
368
|
+
issuer: input.issuer,
|
|
369
|
+
publicKey: createPublicKey({ key: input.publicJwk, format: "jwk" }),
|
|
370
|
+
label: input.label ?? null,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Reads a receipt the way the hosted authority does: the protected header
|
|
375
|
+
* names an Ed25519 key the organisation registered; the signature verifies
|
|
376
|
+
* under it; the issuer is the one registered with the key and the audience
|
|
377
|
+
* is this authority; and the claims describe this grant and this claim,
|
|
378
|
+
* through `sub`, the decision and dossier ids and the digest of the claim
|
|
379
|
+
* token being finalized. Anything else is recorded with its code, and the
|
|
380
|
+
* finalization proceeds regardless.
|
|
381
|
+
*/
|
|
382
|
+
readEffectReceipt(token, grant, claimToken) {
|
|
383
|
+
const record = (code, partial = {}) => ({
|
|
384
|
+
token,
|
|
385
|
+
verified: code === "EFFECT_RECEIPT_VERIFIED",
|
|
386
|
+
verification_code: code,
|
|
387
|
+
provider_key_id: null,
|
|
388
|
+
issuer: null,
|
|
389
|
+
effect_status: null,
|
|
390
|
+
effect_digest: null,
|
|
391
|
+
effect_reference: null,
|
|
392
|
+
effected_at: null,
|
|
393
|
+
...partial,
|
|
394
|
+
});
|
|
395
|
+
const [encodedHeader = "", encodedPayload = "", encodedSignature = ""] = token.split(".");
|
|
396
|
+
let header;
|
|
397
|
+
let payload;
|
|
398
|
+
try {
|
|
399
|
+
header = JSON.parse(Buffer.from(encodedHeader, "base64url").toString("utf8"));
|
|
400
|
+
payload = JSON.parse(Buffer.from(encodedPayload, "base64url").toString("utf8"));
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
return record("EFFECT_RECEIPT_MALFORMED");
|
|
404
|
+
}
|
|
405
|
+
if (header.alg !== "EdDSA" ||
|
|
406
|
+
header.typ !== EFFECT_RECEIPT_TYPE ||
|
|
407
|
+
typeof header.kid !== "string" ||
|
|
408
|
+
header.kid.length === 0) {
|
|
409
|
+
return record("EFFECT_RECEIPT_MALFORMED");
|
|
410
|
+
}
|
|
411
|
+
const key = this.providerKeys.get(header.kid);
|
|
412
|
+
if (key === undefined) {
|
|
413
|
+
return record("EFFECT_RECEIPT_KEY_UNKNOWN", { provider_key_id: header.kid });
|
|
414
|
+
}
|
|
415
|
+
const known = { provider_key_id: key.kid, issuer: key.issuer };
|
|
416
|
+
const signed = Buffer.from(`${encodedHeader}.${encodedPayload}`, "ascii");
|
|
417
|
+
if (!verify(null, signed, key.publicKey, Buffer.from(encodedSignature, "base64url")) ||
|
|
418
|
+
payload.iss !== key.issuer ||
|
|
419
|
+
payload.aud !== LOCAL_AUTHORITY_ISSUER) {
|
|
420
|
+
return record("EFFECT_RECEIPT_SIGNATURE_INVALID", known);
|
|
421
|
+
}
|
|
422
|
+
const effect = typeof payload.effect === "object" && payload.effect !== null
|
|
423
|
+
? payload.effect
|
|
424
|
+
: null;
|
|
425
|
+
const status = effectStatus(effect?.status);
|
|
426
|
+
const digest = effect?.digest;
|
|
427
|
+
const effectedAt = effect?.effected_at;
|
|
428
|
+
if (typeof payload.sub !== "string" ||
|
|
429
|
+
typeof payload.decision_id !== "string" ||
|
|
430
|
+
typeof payload.dossier_id !== "string" ||
|
|
431
|
+
typeof payload.claim_token_digest !== "string" ||
|
|
432
|
+
typeof payload.jti !== "string" ||
|
|
433
|
+
typeof payload.iat !== "number" ||
|
|
434
|
+
status === null ||
|
|
435
|
+
(digest !== undefined && !sha256Digest.safeParse(digest).success) ||
|
|
436
|
+
typeof effectedAt !== "string" ||
|
|
437
|
+
Number.isNaN(Date.parse(effectedAt))) {
|
|
438
|
+
return record("EFFECT_RECEIPT_MALFORMED", known);
|
|
439
|
+
}
|
|
440
|
+
const described = {
|
|
441
|
+
...known,
|
|
442
|
+
effect_status: status,
|
|
443
|
+
effect_digest: typeof digest === "string" ? digest : null,
|
|
444
|
+
effect_reference: typeof effect?.reference === "string" ? effect.reference : null,
|
|
445
|
+
effected_at: new Date(effectedAt).toISOString(),
|
|
446
|
+
};
|
|
447
|
+
const claimTokenDigest = `sha256:${createHash("sha256").update(claimToken, "utf8").digest("hex")}`;
|
|
448
|
+
if (payload.sub !== grant.jti ||
|
|
449
|
+
payload.decision_id !== grant.decisionId ||
|
|
450
|
+
payload.dossier_id !== grant.dossierId ||
|
|
451
|
+
payload.claim_token_digest !== claimTokenDigest ||
|
|
452
|
+
(typeof payload.intent_hash === "string" && payload.intent_hash !== grant.intentHash)) {
|
|
453
|
+
return record("EFFECT_RECEIPT_BINDING_MISMATCH", described);
|
|
454
|
+
}
|
|
455
|
+
return record("EFFECT_RECEIPT_VERIFIED", described);
|
|
456
|
+
}
|
|
333
457
|
get baseUrl() {
|
|
334
458
|
return `${LOOPBACK_ORIGIN}:${this.port}`;
|
|
335
459
|
}
|
|
@@ -372,6 +496,9 @@ export class LocalAuthority {
|
|
|
372
496
|
authorization: headerString(req.headers.authorization),
|
|
373
497
|
"content-type": headerString(req.headers["content-type"]),
|
|
374
498
|
"idempotency-key": headerString(req.headers["idempotency-key"]),
|
|
499
|
+
// What the client says about itself, so a test can see the version
|
|
500
|
+
// and the surface a call carried; the double never acts on it.
|
|
501
|
+
"user-agent": headerString(req.headers["user-agent"]),
|
|
375
502
|
},
|
|
376
503
|
body: null,
|
|
377
504
|
recomputedHash: null,
|
|
@@ -434,6 +561,8 @@ export class LocalAuthority {
|
|
|
434
561
|
return this.send(res, record, 415, { error: "UNSUPPORTED_MEDIA_TYPE" });
|
|
435
562
|
}
|
|
436
563
|
switch (url.pathname) {
|
|
564
|
+
case "/v1/execution/provider-keys":
|
|
565
|
+
return this.send(res, record, ...this.registerProviderKeyRoute(record));
|
|
437
566
|
case "/v1/authority/enforce-and-bind":
|
|
438
567
|
return this.respond(res, record, "enforce", this.enforceAndBind(record));
|
|
439
568
|
case "/v1/execution/claim-token":
|
|
@@ -445,6 +574,31 @@ export class LocalAuthority {
|
|
|
445
574
|
return this.send(res, record, 404, { error: "NOT_FOUND" });
|
|
446
575
|
}
|
|
447
576
|
}
|
|
577
|
+
/** `POST /v1/execution/provider-keys`: the public half only, or a 400 naming why. */
|
|
578
|
+
registerProviderKeyRoute(record) {
|
|
579
|
+
const parsed = ProviderKeyRegistrationSchema.safeParse(record.body);
|
|
580
|
+
if (!parsed.success)
|
|
581
|
+
return [400, { error: "INVALID_BODY" }];
|
|
582
|
+
const body = parsed.data;
|
|
583
|
+
this.registerProviderKey({
|
|
584
|
+
kid: body.kid,
|
|
585
|
+
issuer: body.issuer,
|
|
586
|
+
publicJwk: { kty: body.public_jwk.kty, crv: body.public_jwk.crv, x: body.public_jwk.x },
|
|
587
|
+
...(body.label === undefined ? {} : { label: body.label }),
|
|
588
|
+
});
|
|
589
|
+
return [
|
|
590
|
+
201,
|
|
591
|
+
{
|
|
592
|
+
service: "decionis",
|
|
593
|
+
kid: body.kid,
|
|
594
|
+
issuer: body.issuer,
|
|
595
|
+
algorithm: "EdDSA",
|
|
596
|
+
label: body.label ?? null,
|
|
597
|
+
created_at: new Date(this.clock()).toISOString(),
|
|
598
|
+
revoked_at: null,
|
|
599
|
+
},
|
|
600
|
+
];
|
|
601
|
+
}
|
|
448
602
|
enforceAndBind(record) {
|
|
449
603
|
const parsed = AuthorityRequestSchema.safeParse(record.body);
|
|
450
604
|
if (!parsed.success)
|
|
@@ -620,6 +774,7 @@ export class LocalAuthority {
|
|
|
620
774
|
receiptDossierId: approval?.receiptDossierId ?? null,
|
|
621
775
|
claimed: false,
|
|
622
776
|
claimToken: null,
|
|
777
|
+
receipt: null,
|
|
623
778
|
correlationId: null,
|
|
624
779
|
consumedBy: null,
|
|
625
780
|
finalized: null,
|
|
@@ -973,9 +1128,37 @@ export class LocalAuthority {
|
|
|
973
1128
|
}
|
|
974
1129
|
if (grant.finalized !== null)
|
|
975
1130
|
return rejected("NONCE_REPLAY_DETECTED");
|
|
1131
|
+
// The receipt is read first and recorded whatever it says; when the grant
|
|
1132
|
+
// named the effect it expected and the executor supplied no observation of
|
|
1133
|
+
// its own, a verified receipt with a digest stands in as SIGNED_RECEIPT
|
|
1134
|
+
// evidence by the provider's key, exactly as the hosted route reads it.
|
|
1135
|
+
const receipt = parsed.data.effect_receipt === undefined
|
|
1136
|
+
? null
|
|
1137
|
+
: this.readEffectReceipt(parsed.data.effect_receipt, grant, parsed.data.claim_token);
|
|
1138
|
+
let supplied = parsed.data.effect_evidence;
|
|
1139
|
+
if (supplied === undefined &&
|
|
1140
|
+
receipt?.verified === true &&
|
|
1141
|
+
grant.expectedEffectDigest !== null &&
|
|
1142
|
+
receipt.effect_digest !== null) {
|
|
1143
|
+
supplied = {
|
|
1144
|
+
version: "1.0",
|
|
1145
|
+
status: receipt.effect_status === "EFFECTED" &&
|
|
1146
|
+
receipt.effect_digest === grant.expectedEffectDigest &&
|
|
1147
|
+
parsed.data.outcome === "COMMITTED"
|
|
1148
|
+
? "CONFIRMED"
|
|
1149
|
+
: "UNCONFIRMED",
|
|
1150
|
+
observation_method: "SIGNED_RECEIPT",
|
|
1151
|
+
observer: { id: receipt.provider_key_id, version: EFFECT_RECEIPT_TYPE },
|
|
1152
|
+
expected_effect_digest: grant.expectedEffectDigest,
|
|
1153
|
+
observed_effect_digest: receipt.effect_digest,
|
|
1154
|
+
observed_at: receipt.effected_at,
|
|
1155
|
+
evidence_digest: `sha256:${createHash("sha256").update(receipt.token, "utf8").digest("hex")}`,
|
|
1156
|
+
evidence_reference: receipt.effect_reference,
|
|
1157
|
+
execution_correlation_id: parsed.data.commit_correlation_id,
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
976
1160
|
// The hosted authority refuses the whole finalization for evidence it
|
|
977
1161
|
// cannot bind, in exactly this order, before the commit transition.
|
|
978
|
-
const supplied = parsed.data.effect_evidence;
|
|
979
1162
|
let evidence;
|
|
980
1163
|
if (supplied !== undefined) {
|
|
981
1164
|
const parsedEvidence = EffectEvidenceSchema.safeParse(supplied);
|
|
@@ -995,7 +1178,13 @@ export class LocalAuthority {
|
|
|
995
1178
|
return rejected("EFFECT_EVIDENCE_OUTCOME_MISMATCH");
|
|
996
1179
|
}
|
|
997
1180
|
if (evidence.status === "CONFIRMED") {
|
|
998
|
-
|
|
1181
|
+
// A verified receipt's key is an observer for this finalization only.
|
|
1182
|
+
const trusted = [
|
|
1183
|
+
...this.effectObserverIds(),
|
|
1184
|
+
...(receipt?.verified === true && receipt.provider_key_id !== null
|
|
1185
|
+
? [receipt.provider_key_id]
|
|
1186
|
+
: []),
|
|
1187
|
+
];
|
|
999
1188
|
if (trusted.length === 0) {
|
|
1000
1189
|
return rejected("EFFECT_OBSERVER_PROVENANCE_UNAVAILABLE");
|
|
1001
1190
|
}
|
|
@@ -1005,6 +1194,7 @@ export class LocalAuthority {
|
|
|
1005
1194
|
}
|
|
1006
1195
|
}
|
|
1007
1196
|
grant.finalized = parsed.data.outcome;
|
|
1197
|
+
grant.receipt = receipt;
|
|
1008
1198
|
// Byte-for-byte the hosted success body: the commit's own decision-chain
|
|
1009
1199
|
// evidence is queued, not yet recorded, so a successful finalization still
|
|
1010
1200
|
// carries `COMMIT_EVIDENCE_PENDING`.
|
|
@@ -1018,6 +1208,16 @@ export class LocalAuthority {
|
|
|
1018
1208
|
evidence_recorded: false,
|
|
1019
1209
|
effect_evidence_recorded: evidence !== undefined,
|
|
1020
1210
|
effect_confirmation: evidence?.status === "CONFIRMED" ? "CONFIRMED" : "UNCONFIRMED",
|
|
1211
|
+
...(receipt === null
|
|
1212
|
+
? {}
|
|
1213
|
+
: {
|
|
1214
|
+
effect_receipt: {
|
|
1215
|
+
verified: receipt.verified,
|
|
1216
|
+
verification_code: receipt.verification_code,
|
|
1217
|
+
provider_key_id: receipt.provider_key_id,
|
|
1218
|
+
recorded: true,
|
|
1219
|
+
},
|
|
1220
|
+
}),
|
|
1021
1221
|
reason_codes: ["COMMIT_EVIDENCE_PENDING"],
|
|
1022
1222
|
},
|
|
1023
1223
|
};
|