@peac/protocol 0.13.4 → 0.14.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/dist/_internal/record-core/validation-gate.d.ts +102 -0
- package/dist/_internal/record-core/validation-gate.d.ts.map +1 -0
- package/dist/_internal/record-core/validators/schema-parse.d.ts +53 -23
- package/dist/_internal/record-core/validators/schema-parse.d.ts.map +1 -1
- package/dist/index.cjs +180 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +180 -35
- package/dist/index.mjs.map +1 -1
- package/dist/issue.d.ts.map +1 -1
- package/dist/verify-local.cjs +134 -21
- package/dist/verify-local.cjs.map +1 -1
- package/dist/verify-local.d.ts.map +1 -1
- package/dist/verify-local.mjs +134 -21
- package/dist/verify-local.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production-facing bounded validation gate.
|
|
3
|
+
*
|
|
4
|
+
* INTERNAL ONLY. Not re-exported from `packages/protocol/src/index.ts`.
|
|
5
|
+
*
|
|
6
|
+
* The gate is the only production wrapper for the bounded validation
|
|
7
|
+
* path. The pre-existing `runBoundedValidatorShadow` from
|
|
8
|
+
* `bounded-validator.ts` remains the entry point for shadow / corpus
|
|
9
|
+
* / parity-harness consumers and is not the primary admission path
|
|
10
|
+
* for the protocol entry points; the production-wrapper boundary is
|
|
11
|
+
* enforced by `tests/tooling/production-gate-boundary.test.ts`.
|
|
12
|
+
*
|
|
13
|
+
* The gate is entrypoint-aware: callers identify themselves with a
|
|
14
|
+
* `surface` discriminator, and the gate applies a per-surface
|
|
15
|
+
* production projection allowlist. Layers in the bounded validator's
|
|
16
|
+
* broader composition that fall outside the allowlist for a given
|
|
17
|
+
* surface stay available to shadow / parity tests through
|
|
18
|
+
* `runBoundedValidatorShadow` but are not surfaced as production
|
|
19
|
+
* failure or production warning here.
|
|
20
|
+
*
|
|
21
|
+
* Allowlist for surface 'issueWire02':
|
|
22
|
+
* - schema-parse only.
|
|
23
|
+
*
|
|
24
|
+
* Allowlist for surface 'verifyLocal':
|
|
25
|
+
* - kernel-constraints (via canonical `validateKernelConstraints`).
|
|
26
|
+
* - schema-parse (via the extended `validateSchemaParseInternal`).
|
|
27
|
+
*
|
|
28
|
+
* Out of scope here (kept inline-canonical on both branches by the
|
|
29
|
+
* caller): caller-option-bearing checks (issuer mismatch, subjectUri
|
|
30
|
+
* mismatch, policyDigest format), strictness routing for missing typ,
|
|
31
|
+
* iat-not-yet-valid, occurred_at temporal, type-extension warnings,
|
|
32
|
+
* type-extension enforcement, policy-binding compute, bindings
|
|
33
|
+
* construction, sortWarnings.
|
|
34
|
+
*
|
|
35
|
+
* The canonical materializer (claim encoding, JWS signing, JWS
|
|
36
|
+
* decoding, result-shape construction) is shared between the
|
|
37
|
+
* bounded-default and rollback branches and is not touched by the
|
|
38
|
+
* gate.
|
|
39
|
+
*/
|
|
40
|
+
import type { VerificationWarning } from '@peac/kernel';
|
|
41
|
+
import type { Wire02Claims } from '@peac/schema';
|
|
42
|
+
/**
|
|
43
|
+
* Discriminator identifying which protocol entry point invoked the
|
|
44
|
+
* gate. Drives the production projection allowlist. Adding a third
|
|
45
|
+
* surface requires a deliberate plan amendment, not an unannounced
|
|
46
|
+
* source change.
|
|
47
|
+
*/
|
|
48
|
+
export type GateSurface = 'issueWire02' | 'verifyLocal';
|
|
49
|
+
/** Sanitized parse-issue projection surfaced on rejection. */
|
|
50
|
+
export interface SanitizedParseIssue {
|
|
51
|
+
readonly path: string;
|
|
52
|
+
readonly message: string;
|
|
53
|
+
}
|
|
54
|
+
/** Parsed-claims projection surfaced on `verifyLocal` acceptance. */
|
|
55
|
+
export interface ValidationGateParsed {
|
|
56
|
+
readonly wireVersion: '0.2';
|
|
57
|
+
readonly claims: Wire02Claims;
|
|
58
|
+
readonly parserWarnings: readonly VerificationWarning[];
|
|
59
|
+
}
|
|
60
|
+
/** Failure-detail projection. Smaller than the bounded layer set. */
|
|
61
|
+
export interface ValidationGateFailureDetails {
|
|
62
|
+
readonly parse_code?: string;
|
|
63
|
+
readonly issues?: readonly SanitizedParseIssue[];
|
|
64
|
+
}
|
|
65
|
+
/** Successful gate result. */
|
|
66
|
+
export interface ValidationGateSuccess {
|
|
67
|
+
readonly ok: true;
|
|
68
|
+
readonly parsed?: ValidationGateParsed;
|
|
69
|
+
}
|
|
70
|
+
/** Failed gate result. */
|
|
71
|
+
export interface ValidationGateFailure {
|
|
72
|
+
readonly ok: false;
|
|
73
|
+
readonly code: string;
|
|
74
|
+
readonly message: string;
|
|
75
|
+
readonly details?: ValidationGateFailureDetails;
|
|
76
|
+
}
|
|
77
|
+
export type ValidationGateResult = ValidationGateSuccess | ValidationGateFailure;
|
|
78
|
+
/** Inputs to the gate. Only `surface` and `payload` are required. */
|
|
79
|
+
export interface ValidationGateInput {
|
|
80
|
+
readonly surface: GateSurface;
|
|
81
|
+
/**
|
|
82
|
+
* Full claims object. For surface 'issueWire02' this is the just-
|
|
83
|
+
* constructed `Wire02Claims` cast to a plain record (the same
|
|
84
|
+
* object that today flows through `Wire02ClaimsSchema.safeParse`).
|
|
85
|
+
* For surface 'verifyLocal' this is the decoded JWS payload (the
|
|
86
|
+
* same object that today flows through `validateKernelConstraints`
|
|
87
|
+
* and `parseReceiptClaims`).
|
|
88
|
+
*/
|
|
89
|
+
readonly payload: unknown;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Run the production projection of the bounded validation path.
|
|
93
|
+
*
|
|
94
|
+
* Behavior is byte-equivalent to the inline canonical sequences at
|
|
95
|
+
* `issue.ts` and `verify-local.ts` for every input on the covered
|
|
96
|
+
* runtime matrix. Any cross-branch divergence on JWS bytes, result
|
|
97
|
+
* shape, error code, warning order, thrown error class, success /
|
|
98
|
+
* failure classification, or observable default behavior is a
|
|
99
|
+
* validation-equivalence regression.
|
|
100
|
+
*/
|
|
101
|
+
export declare function runBoundedValidationGate(input: ValidationGateInput): ValidationGateResult;
|
|
102
|
+
//# sourceMappingURL=validation-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-gate.d.ts","sourceRoot":"","sources":["../../../src/_internal/record-core/validation-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;AAExD,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACzD;AAED,qEAAqE;AACrE,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAClD;AAED,8BAA8B;AAC9B,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC;AAED,0BAA0B;AAC1B,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,4BAA4B,CAAC;CACjD;AAED,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;AAEjF,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CAKzF"}
|
|
@@ -1,42 +1,72 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bounded internal schema-parse validator
|
|
2
|
+
* Bounded internal schema-parse validator.
|
|
3
3
|
*
|
|
4
4
|
* INTERNAL ONLY. Thin wrapper around the canonical
|
|
5
|
-
* `parseReceiptClaims` from `@peac/schema
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* `parseReceiptClaims` from `@peac/schema`. Projects the canonical
|
|
6
|
+
* accept/reject signal plus the full canonical projection (parsed
|
|
7
|
+
* claims, parser warnings, canonical error triple) so production
|
|
8
|
+
* callers can reproduce the canonical surface byte-equally without
|
|
9
|
+
* re-invoking `parseReceiptClaims`.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* without changing callers; the input/output shape is stable enough
|
|
13
|
-
* for a drop-in replacement should rigorous cross-implementation
|
|
14
|
-
* parity beyond observational evidence be required.
|
|
15
|
-
*
|
|
16
|
-
* Module is observational only; not re-exported from
|
|
17
|
-
* `packages/protocol/src/index.ts` and not wired into the public
|
|
18
|
-
* runtime path.
|
|
11
|
+
* Module is internal-only; not re-exported from
|
|
12
|
+
* `packages/protocol/src/index.ts`.
|
|
19
13
|
*
|
|
20
14
|
* SCOPE:
|
|
21
15
|
* - Run `parseReceiptClaims(payload)` and surface its accept/reject.
|
|
22
|
-
* - On
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* (
|
|
16
|
+
* - On acceptance: surface `wireVersion`, parsed `claims`, and
|
|
17
|
+
* parser `warnings` (e.g., `type_unregistered`,
|
|
18
|
+
* `unknown_extension_preserved`). Higher-layer aggregation merges
|
|
19
|
+
* these into the caller's warning array.
|
|
20
|
+
* - On rejection: surface the canonical error triple
|
|
21
|
+
* (`errorCode`, `errorMessage`, `errorIssues`) so callers can
|
|
22
|
+
* project the canonical `details: { parse_code, issues }` and
|
|
23
|
+
* `message: 'Receipt schema validation failed: <message>'`
|
|
24
|
+
* surface byte-equally.
|
|
28
25
|
*/
|
|
26
|
+
import type { ZodError } from 'zod';
|
|
27
|
+
import type { VerificationWarning } from '@peac/kernel';
|
|
29
28
|
import type { Wire02Claims } from '@peac/schema';
|
|
30
29
|
export interface SchemaParseResult {
|
|
31
30
|
readonly accepted: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Canonical parse-error code from `parseReceiptClaims` when the
|
|
33
|
+
* parse rejects. Mirrors `pr.error.code`.
|
|
34
|
+
*/
|
|
32
35
|
readonly errorCode?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Canonical parse-error message from `parseReceiptClaims` when the
|
|
38
|
+
* parse rejects. Mirrors `pr.error.message`. Required for callers
|
|
39
|
+
* that reproduce the canonical surface message
|
|
40
|
+
* `Receipt schema validation failed: <message>` byte-equally.
|
|
41
|
+
*/
|
|
42
|
+
readonly errorMessage?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Canonical parse-error issues from `parseReceiptClaims` when the
|
|
45
|
+
* parse rejects. Mirrors `pr.error.issues`. Callers downstream
|
|
46
|
+
* apply their own bounded sanitization (path-join, length cap)
|
|
47
|
+
* before surfacing on a public verifier-result `details` payload.
|
|
48
|
+
*/
|
|
49
|
+
readonly errorIssues?: ZodError['issues'];
|
|
33
50
|
/**
|
|
34
51
|
* Parsed Wire 0.2 claims when accepted. Internal-only; does not
|
|
35
|
-
* appear on any emitted record or public surface.
|
|
36
|
-
* a typed view of the parsed claims read this field; callers that
|
|
37
|
-
* only need the accept/reject signal ignore it.
|
|
52
|
+
* appear on any emitted record or public surface.
|
|
38
53
|
*/
|
|
39
54
|
readonly claims?: Wire02Claims;
|
|
55
|
+
/**
|
|
56
|
+
* Wire version surfaced from `parseReceiptClaims` on acceptance.
|
|
57
|
+
* The bounded surface only admits `'0.2'`; Wire 0.1 acceptance from
|
|
58
|
+
* the canonical parser is rejected at this layer with
|
|
59
|
+
* `E_UNSUPPORTED_WIRE_VERSION` because the bounded composition is
|
|
60
|
+
* keyed on Wire 0.2 claim shapes.
|
|
61
|
+
*/
|
|
62
|
+
readonly wireVersion?: '0.2';
|
|
63
|
+
/**
|
|
64
|
+
* Parser warnings surfaced on acceptance. Mirrors `pr.warnings` for
|
|
65
|
+
* Wire 0.2 acceptance. Callers that aggregate into a single
|
|
66
|
+
* canonical warning array merge this list at the canonical-equivalent
|
|
67
|
+
* flow position before the canonical sort.
|
|
68
|
+
*/
|
|
69
|
+
readonly warnings?: readonly VerificationWarning[];
|
|
40
70
|
}
|
|
41
71
|
export declare function validateSchemaParseInternal(payload: unknown): SchemaParseResult;
|
|
42
72
|
//# sourceMappingURL=schema-parse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-parse.d.ts","sourceRoot":"","sources":["../../../../src/_internal/record-core/validators/schema-parse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema-parse.d.ts","sourceRoot":"","sources":["../../../../src/_internal/record-core/validators/schema-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACpD;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAuB/E"}
|
package/dist/index.cjs
CHANGED
|
@@ -314,12 +314,26 @@ function validateExtensionBudgetInternal(extensions) {
|
|
|
314
314
|
function validateSchemaParseInternal(payload) {
|
|
315
315
|
const pr = schema.parseReceiptClaims(payload);
|
|
316
316
|
if (!pr.ok) {
|
|
317
|
-
return {
|
|
317
|
+
return {
|
|
318
|
+
accepted: false,
|
|
319
|
+
errorCode: pr.error.code,
|
|
320
|
+
errorMessage: pr.error.message,
|
|
321
|
+
...pr.error.issues !== void 0 && { errorIssues: pr.error.issues }
|
|
322
|
+
};
|
|
318
323
|
}
|
|
319
324
|
if (pr.wireVersion !== "0.2") {
|
|
320
|
-
return {
|
|
325
|
+
return {
|
|
326
|
+
accepted: false,
|
|
327
|
+
errorCode: "E_UNSUPPORTED_WIRE_VERSION",
|
|
328
|
+
errorMessage: `Unsupported wire version: ${pr.wireVersion}`
|
|
329
|
+
};
|
|
321
330
|
}
|
|
322
|
-
return {
|
|
331
|
+
return {
|
|
332
|
+
accepted: true,
|
|
333
|
+
claims: pr.claims,
|
|
334
|
+
wireVersion: "0.2",
|
|
335
|
+
warnings: pr.warnings
|
|
336
|
+
};
|
|
323
337
|
}
|
|
324
338
|
|
|
325
339
|
// src/_internal/record-core/validators/jose-typ-strictness.ts
|
|
@@ -559,6 +573,86 @@ function runBoundedValidatorShadow(input) {
|
|
|
559
573
|
warnings
|
|
560
574
|
};
|
|
561
575
|
}
|
|
576
|
+
var MAX_SANITIZED_ISSUES = 25;
|
|
577
|
+
function sanitizeIssues(issues) {
|
|
578
|
+
if (!Array.isArray(issues)) return void 0;
|
|
579
|
+
return issues.slice(0, MAX_SANITIZED_ISSUES).map((issue2) => {
|
|
580
|
+
const candidate = issue2;
|
|
581
|
+
const path = Array.isArray(candidate.path) ? candidate.path.map(
|
|
582
|
+
(segment) => typeof segment === "string" || typeof segment === "number" ? String(segment) : ""
|
|
583
|
+
).join(".") : "";
|
|
584
|
+
const message = typeof candidate.message === "string" ? candidate.message : String(candidate.message ?? issue2);
|
|
585
|
+
return { path, message };
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
function runBoundedValidationGate(input) {
|
|
589
|
+
if (input.surface === "issueWire02") {
|
|
590
|
+
return runIssueWire02(input.payload);
|
|
591
|
+
}
|
|
592
|
+
return runVerifyLocal(input.payload);
|
|
593
|
+
}
|
|
594
|
+
function runIssueWire02(payload) {
|
|
595
|
+
const schemaRes = validateSchemaParseInternal(payload);
|
|
596
|
+
if (!schemaRes.accepted) {
|
|
597
|
+
const firstIssueMessage = schemaRes.errorIssues?.[0]?.message;
|
|
598
|
+
return {
|
|
599
|
+
ok: false,
|
|
600
|
+
code: "E_INVALID_FORMAT",
|
|
601
|
+
message: `Wire 0.2 claims schema validation failed: ${firstIssueMessage ?? "unknown"}`
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
return { ok: true };
|
|
605
|
+
}
|
|
606
|
+
function runVerifyLocal(payload) {
|
|
607
|
+
const kernelRes = schema.validateKernelConstraints(payload);
|
|
608
|
+
if (!kernelRes.valid) {
|
|
609
|
+
const v = kernelRes.violations[0];
|
|
610
|
+
return {
|
|
611
|
+
ok: false,
|
|
612
|
+
code: "E_CONSTRAINT_VIOLATION",
|
|
613
|
+
message: `Kernel constraint violated: ${v.constraint} (actual: ${v.actual}, limit: ${v.limit})`
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
const schemaRes = validateSchemaParseInternal(payload);
|
|
617
|
+
if (!schemaRes.accepted) {
|
|
618
|
+
if (schemaRes.errorCode === "E_UNSUPPORTED_WIRE_VERSION") {
|
|
619
|
+
return {
|
|
620
|
+
ok: false,
|
|
621
|
+
code: "E_UNSUPPORTED_WIRE_VERSION",
|
|
622
|
+
message: "Wire 0.1 receipts are not supported. Re-issue as Wire 0.2 using issue()."
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
const sanitized = sanitizeIssues(schemaRes.errorIssues);
|
|
626
|
+
const details = {};
|
|
627
|
+
if (schemaRes.errorCode !== void 0) {
|
|
628
|
+
Object.assign(details, { parse_code: schemaRes.errorCode });
|
|
629
|
+
}
|
|
630
|
+
if (sanitized !== void 0) {
|
|
631
|
+
Object.assign(details, { issues: sanitized });
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
ok: false,
|
|
635
|
+
code: "E_INVALID_FORMAT",
|
|
636
|
+
message: `Receipt schema validation failed: ${schemaRes.errorMessage ?? "unknown"}`,
|
|
637
|
+
...Object.keys(details).length > 0 && { details }
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
if (schemaRes.wireVersion !== "0.2" || schemaRes.claims === void 0) {
|
|
641
|
+
return {
|
|
642
|
+
ok: false,
|
|
643
|
+
code: "E_UNSUPPORTED_WIRE_VERSION",
|
|
644
|
+
message: "Wire 0.1 receipts are not supported. Re-issue as Wire 0.2 using issue()."
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
ok: true,
|
|
649
|
+
parsed: {
|
|
650
|
+
wireVersion: "0.2",
|
|
651
|
+
claims: schemaRes.claims,
|
|
652
|
+
parserWarnings: schemaRes.warnings ?? []
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
562
656
|
var SECRET_PATTERNS = [
|
|
563
657
|
// Compact JWS / JWT (header.payload.signature with eyJ-prefixed header).
|
|
564
658
|
/eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
|
|
@@ -996,7 +1090,7 @@ async function issue(options) {
|
|
|
996
1090
|
return issueWire02(options);
|
|
997
1091
|
}
|
|
998
1092
|
async function issueWire02(options) {
|
|
999
|
-
|
|
1093
|
+
const legacyPath = readLegacyPathFlag(options);
|
|
1000
1094
|
if (!schema.isCanonicalIss(options.iss)) {
|
|
1001
1095
|
throw new IssueError({
|
|
1002
1096
|
code: "E_ISS_NOT_CANONICAL",
|
|
@@ -1025,22 +1119,39 @@ async function issueWire02(options) {
|
|
|
1025
1119
|
...options.policy !== void 0 && { policy: options.policy },
|
|
1026
1120
|
...options.extensions !== void 0 && { extensions: options.extensions }
|
|
1027
1121
|
};
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1122
|
+
if (legacyPath) {
|
|
1123
|
+
const parseResult = schema.Wire02ClaimsSchema.safeParse(claims);
|
|
1124
|
+
if (!parseResult.success) {
|
|
1125
|
+
const firstIssue = parseResult.error.issues[0];
|
|
1126
|
+
throw new IssueError({
|
|
1127
|
+
code: "E_INVALID_FORMAT",
|
|
1128
|
+
category: "validation",
|
|
1129
|
+
severity: "error",
|
|
1130
|
+
retryable: false,
|
|
1131
|
+
http_status: 400,
|
|
1132
|
+
details: {
|
|
1133
|
+
message: `Wire 0.2 claims schema validation failed: ${firstIssue?.message ?? "unknown"}`
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
} else {
|
|
1138
|
+
const gateResult = runBoundedValidationGate({
|
|
1139
|
+
surface: "issueWire02",
|
|
1140
|
+
payload: claims
|
|
1040
1141
|
});
|
|
1142
|
+
if (!gateResult.ok) {
|
|
1143
|
+
throw new IssueError({
|
|
1144
|
+
code: gateResult.code,
|
|
1145
|
+
category: "validation",
|
|
1146
|
+
severity: "error",
|
|
1147
|
+
retryable: false,
|
|
1148
|
+
http_status: 400,
|
|
1149
|
+
details: { message: gateResult.message }
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1041
1152
|
}
|
|
1042
1153
|
const jws = await defaultCodec.encode(claims, options.privateKey, options.kid);
|
|
1043
|
-
if (isShadowEnabled(options)) {
|
|
1154
|
+
if (legacyPath && isShadowEnabled(options)) {
|
|
1044
1155
|
scheduleShadow({
|
|
1045
1156
|
call: "issue",
|
|
1046
1157
|
realResult: realObservationForIssue(),
|
|
@@ -2277,7 +2388,7 @@ function sanitizeParseIssues(issues) {
|
|
|
2277
2388
|
}));
|
|
2278
2389
|
}
|
|
2279
2390
|
async function verifyLocal(jws, publicKey, options = {}) {
|
|
2280
|
-
|
|
2391
|
+
const legacyPath = readLegacyPathFlag(options);
|
|
2281
2392
|
const {
|
|
2282
2393
|
issuer,
|
|
2283
2394
|
subjectUri,
|
|
@@ -2310,22 +2421,56 @@ async function verifyLocal(jws, publicKey, options = {}) {
|
|
|
2310
2421
|
message: "JWS typ header is absent; accepted in interop mode"
|
|
2311
2422
|
});
|
|
2312
2423
|
}
|
|
2313
|
-
|
|
2314
|
-
if (
|
|
2315
|
-
const
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2424
|
+
let pr;
|
|
2425
|
+
if (legacyPath) {
|
|
2426
|
+
const constraintResult = schema.validateKernelConstraints(result.payload);
|
|
2427
|
+
if (!constraintResult.valid) {
|
|
2428
|
+
const v = constraintResult.violations[0];
|
|
2429
|
+
return {
|
|
2430
|
+
valid: false,
|
|
2431
|
+
code: "E_CONSTRAINT_VIOLATION",
|
|
2432
|
+
message: `Kernel constraint violated: ${v.constraint} (actual: ${v.actual}, limit: ${v.limit})`
|
|
2433
|
+
};
|
|
2434
|
+
}
|
|
2435
|
+
const parsed = schema.parseReceiptClaims(result.payload);
|
|
2436
|
+
if (!parsed.ok) {
|
|
2437
|
+
return {
|
|
2438
|
+
valid: false,
|
|
2439
|
+
code: "E_INVALID_FORMAT",
|
|
2440
|
+
message: `Receipt schema validation failed: ${parsed.error.message}`,
|
|
2441
|
+
details: {
|
|
2442
|
+
parse_code: parsed.error.code,
|
|
2443
|
+
issues: sanitizeParseIssues(parsed.error.issues)
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
pr = parsed;
|
|
2448
|
+
} else {
|
|
2449
|
+
const gateResult = runBoundedValidationGate({
|
|
2450
|
+
surface: "verifyLocal",
|
|
2451
|
+
payload: result.payload
|
|
2452
|
+
});
|
|
2453
|
+
if (!gateResult.ok) {
|
|
2454
|
+
return {
|
|
2455
|
+
valid: false,
|
|
2456
|
+
code: gateResult.code,
|
|
2457
|
+
message: gateResult.message,
|
|
2458
|
+
...gateResult.details !== void 0 && { details: gateResult.details }
|
|
2459
|
+
};
|
|
2460
|
+
}
|
|
2461
|
+
const parsedFromGate = gateResult.parsed;
|
|
2462
|
+
if (parsedFromGate === void 0) {
|
|
2463
|
+
return {
|
|
2464
|
+
valid: false,
|
|
2465
|
+
code: "E_INTERNAL",
|
|
2466
|
+
message: "Bounded validation gate accepted without surfacing parsed claims"
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
pr = {
|
|
2470
|
+
ok: true,
|
|
2471
|
+
wireVersion: parsedFromGate.wireVersion,
|
|
2472
|
+
warnings: parsedFromGate.parserWarnings,
|
|
2473
|
+
claims: parsedFromGate.claims
|
|
2329
2474
|
};
|
|
2330
2475
|
}
|
|
2331
2476
|
if (pr.wireVersion === "0.2") {
|
|
@@ -2442,7 +2587,7 @@ async function verifyLocal(jws, publicKey, options = {}) {
|
|
|
2442
2587
|
...callerBindings?.documents !== void 0 && callerBindings.documents.length > 0 && { documents: callerBindings.documents }
|
|
2443
2588
|
};
|
|
2444
2589
|
const sortedWarnings = schema.sortWarnings(accumulatedWarnings);
|
|
2445
|
-
if (isShadowEnabled(options)) {
|
|
2590
|
+
if (legacyPath && isShadowEnabled(options)) {
|
|
2446
2591
|
const headerSnapshot = { ...result.header };
|
|
2447
2592
|
scheduleShadow({
|
|
2448
2593
|
call: "verifyLocal",
|