@kya-os/contracts 1.10.0 → 1.12.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/dist/agentshield-api/schemas.d.ts +14 -0
- package/dist/cli.d.ts +93 -0
- package/dist/cli.js +108 -1
- package/dist/handshake.d.ts +77 -0
- package/dist/handshake.js +73 -1
- package/dist/index.js +1 -0
- package/dist/molti/schemas.d.ts +1 -1
- package/dist/policy/schemas.d.ts +160 -160
- package/dist/proof.d.ts +30 -0
- package/dist/proof.js +6 -0
- package/dist/reputation/api.d.ts +0 -17
- package/dist/reputation/api.js +1 -21
- package/dist/review/canonicalize.d.ts +87 -0
- package/dist/review/canonicalize.js +122 -0
- package/dist/review/fix-attestation.d.ts +151 -0
- package/dist/review/fix-attestation.js +105 -0
- package/dist/review/index.d.ts +9 -0
- package/dist/review/index.js +25 -0
- package/dist/review/registry.d.ts +328 -0
- package/dist/review/registry.js +269 -0
- package/dist/review/schemas.d.ts +249 -0
- package/dist/review/schemas.js +102 -0
- package/dist/review/verify.d.ts +37 -0
- package/dist/review/verify.js +58 -0
- package/dist/test.d.ts +12 -12
- package/dist/vault/schemas.d.ts +2 -2
- package/package.json +9 -1
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review Verdict Schemas
|
|
3
|
+
*
|
|
4
|
+
* Types and Zod schemas for PR review verdicts posted by reviewer agents
|
|
5
|
+
* over DIDComm (see `packages/compute/src/didcomm/`). A verdict binds an
|
|
6
|
+
* approve/request-changes/comment decision to a single commit
|
|
7
|
+
* (`subject.headSha`): a push changes head, so every prior verdict's
|
|
8
|
+
* subject stops matching and stale approvals become uncountable rather than
|
|
9
|
+
* needing dismissal logic. That is a deliberate, load-bearing tradeoff, not
|
|
10
|
+
* an oversight — see the module doc on `canonicalize.ts` for the signing
|
|
11
|
+
* scheme this schema's `findingsDigest` and `proof` fields depend on.
|
|
12
|
+
*
|
|
13
|
+
* Pure Zod schemas only. Crypto-dependent canonicalization lives in
|
|
14
|
+
* `canonicalize.ts` so this module stays portable across every runtime that
|
|
15
|
+
* consumes `@kya-os/contracts` (see that file's doc comment for why).
|
|
16
|
+
*
|
|
17
|
+
* @package @kya-os/contracts/review
|
|
18
|
+
*/
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
/**
|
|
21
|
+
* Review Subject Schema
|
|
22
|
+
*
|
|
23
|
+
* Binds a verdict to a single commit on a single PR.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ReviewSubjectSchema: z.ZodObject<{
|
|
26
|
+
/** "owner/repo", e.g. "modelcontextprotocol-identity/xmcp-i" */
|
|
27
|
+
repo: z.ZodString;
|
|
28
|
+
/** GitHub PR number */
|
|
29
|
+
prNumber: z.ZodNumber;
|
|
30
|
+
/** Full 40-character SHA, lowercase */
|
|
31
|
+
headSha: z.ZodString;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
repo: string;
|
|
34
|
+
prNumber: number;
|
|
35
|
+
headSha: string;
|
|
36
|
+
}, {
|
|
37
|
+
repo: string;
|
|
38
|
+
prNumber: number;
|
|
39
|
+
headSha: string;
|
|
40
|
+
}>;
|
|
41
|
+
export type ReviewSubject = z.infer<typeof ReviewSubjectSchema>;
|
|
42
|
+
/**
|
|
43
|
+
* Review Verdict Schema
|
|
44
|
+
*/
|
|
45
|
+
export declare const ReviewVerdictSchema: z.ZodEnum<["approve", "request-changes", "comment"]>;
|
|
46
|
+
export type ReviewVerdict = z.infer<typeof ReviewVerdictSchema>;
|
|
47
|
+
/**
|
|
48
|
+
* Review Finding Severity Schema
|
|
49
|
+
*/
|
|
50
|
+
export declare const ReviewFindingSeveritySchema: z.ZodEnum<["blocking", "major", "minor", "nit"]>;
|
|
51
|
+
export type ReviewFindingSeverity = z.infer<typeof ReviewFindingSeveritySchema>;
|
|
52
|
+
/**
|
|
53
|
+
* Review Finding Schema
|
|
54
|
+
*/
|
|
55
|
+
export declare const ReviewFindingSchema: z.ZodObject<{
|
|
56
|
+
path: z.ZodOptional<z.ZodString>;
|
|
57
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
severity: z.ZodEnum<["blocking", "major", "minor", "nit"]>;
|
|
59
|
+
summary: z.ZodString;
|
|
60
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
summary: string;
|
|
63
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
64
|
+
path?: string | undefined;
|
|
65
|
+
line?: number | undefined;
|
|
66
|
+
detail?: string | undefined;
|
|
67
|
+
}, {
|
|
68
|
+
summary: string;
|
|
69
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
70
|
+
path?: string | undefined;
|
|
71
|
+
line?: number | undefined;
|
|
72
|
+
detail?: string | undefined;
|
|
73
|
+
}>;
|
|
74
|
+
export type ReviewFinding = z.infer<typeof ReviewFindingSchema>;
|
|
75
|
+
/**
|
|
76
|
+
* Review Verdict Body Schema
|
|
77
|
+
*
|
|
78
|
+
* Full verdict payload a reviewer agent posts over DIDComm.
|
|
79
|
+
*
|
|
80
|
+
* `findingsDigest` and `proof` are NOT derived by this schema — Zod
|
|
81
|
+
* validates shape, not that the digest actually matches `findings` or that
|
|
82
|
+
* the signature actually verifies. Producers must compute `findingsDigest`
|
|
83
|
+
* with `computeFindingsDigest` (in `canonicalize.ts`) and sign
|
|
84
|
+
* `getVerdictCanonicalSigningString(subject, verdict, findingsDigest)`;
|
|
85
|
+
* verifiers must recompute both and compare rather than trusting the wire
|
|
86
|
+
* value. Do not hand-roll either at a call site.
|
|
87
|
+
*/
|
|
88
|
+
export declare const ReviewVerdictBodySchema: z.ZodObject<{
|
|
89
|
+
taskId: z.ZodString;
|
|
90
|
+
subject: z.ZodObject<{
|
|
91
|
+
/** "owner/repo", e.g. "modelcontextprotocol-identity/xmcp-i" */
|
|
92
|
+
repo: z.ZodString;
|
|
93
|
+
/** GitHub PR number */
|
|
94
|
+
prNumber: z.ZodNumber;
|
|
95
|
+
/** Full 40-character SHA, lowercase */
|
|
96
|
+
headSha: z.ZodString;
|
|
97
|
+
}, "strip", z.ZodTypeAny, {
|
|
98
|
+
repo: string;
|
|
99
|
+
prNumber: number;
|
|
100
|
+
headSha: string;
|
|
101
|
+
}, {
|
|
102
|
+
repo: string;
|
|
103
|
+
prNumber: number;
|
|
104
|
+
headSha: string;
|
|
105
|
+
}>;
|
|
106
|
+
verdict: z.ZodEnum<["approve", "request-changes", "comment"]>;
|
|
107
|
+
/**
|
|
108
|
+
* Capped at 500: `computeFindingsDigest` (canonicalize.ts) does O(n) work
|
|
109
|
+
* per entry, and this is the array size a DIDComm-delivered payload from
|
|
110
|
+
* a reviewer agent controls. No real review produces more findings than
|
|
111
|
+
* this; a payload that does is malformed, not thorough.
|
|
112
|
+
*/
|
|
113
|
+
findings: z.ZodArray<z.ZodObject<{
|
|
114
|
+
path: z.ZodOptional<z.ZodString>;
|
|
115
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
116
|
+
severity: z.ZodEnum<["blocking", "major", "minor", "nit"]>;
|
|
117
|
+
summary: z.ZodString;
|
|
118
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, "strip", z.ZodTypeAny, {
|
|
120
|
+
summary: string;
|
|
121
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
122
|
+
path?: string | undefined;
|
|
123
|
+
line?: number | undefined;
|
|
124
|
+
detail?: string | undefined;
|
|
125
|
+
}, {
|
|
126
|
+
summary: string;
|
|
127
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
128
|
+
path?: string | undefined;
|
|
129
|
+
line?: number | undefined;
|
|
130
|
+
detail?: string | undefined;
|
|
131
|
+
}>, "many">;
|
|
132
|
+
/**
|
|
133
|
+
* base64url SHA-256 over canonicalized `findings`; see canonicalize.ts.
|
|
134
|
+
* Fixed at 43 chars — the exact length of an unpadded base64url SHA-256
|
|
135
|
+
* digest — matching the exact-length convention every other hash field
|
|
136
|
+
* in this package uses (e.g. `registry.ts`'s `contentHash`, `proof.ts`'s
|
|
137
|
+
* `requestHash`/`responseHash`).
|
|
138
|
+
*/
|
|
139
|
+
findingsDigest: z.ZodString;
|
|
140
|
+
/** Detached JWS over subject + verdict + findingsDigest; see canonicalize.ts */
|
|
141
|
+
proof: z.ZodObject<{
|
|
142
|
+
alg: z.ZodEnum<["Ed25519", "ES256"]>;
|
|
143
|
+
kid: z.ZodOptional<z.ZodString>;
|
|
144
|
+
signature: z.ZodString;
|
|
145
|
+
}, "strip", z.ZodTypeAny, {
|
|
146
|
+
signature: string;
|
|
147
|
+
alg: "Ed25519" | "ES256";
|
|
148
|
+
kid?: string | undefined;
|
|
149
|
+
}, {
|
|
150
|
+
signature: string;
|
|
151
|
+
alg: "Ed25519" | "ES256";
|
|
152
|
+
kid?: string | undefined;
|
|
153
|
+
}>;
|
|
154
|
+
}, "strip", z.ZodTypeAny, {
|
|
155
|
+
subject: {
|
|
156
|
+
repo: string;
|
|
157
|
+
prNumber: number;
|
|
158
|
+
headSha: string;
|
|
159
|
+
};
|
|
160
|
+
proof: {
|
|
161
|
+
signature: string;
|
|
162
|
+
alg: "Ed25519" | "ES256";
|
|
163
|
+
kid?: string | undefined;
|
|
164
|
+
};
|
|
165
|
+
taskId: string;
|
|
166
|
+
verdict: "approve" | "request-changes" | "comment";
|
|
167
|
+
findings: {
|
|
168
|
+
summary: string;
|
|
169
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
170
|
+
path?: string | undefined;
|
|
171
|
+
line?: number | undefined;
|
|
172
|
+
detail?: string | undefined;
|
|
173
|
+
}[];
|
|
174
|
+
findingsDigest: string;
|
|
175
|
+
}, {
|
|
176
|
+
subject: {
|
|
177
|
+
repo: string;
|
|
178
|
+
prNumber: number;
|
|
179
|
+
headSha: string;
|
|
180
|
+
};
|
|
181
|
+
proof: {
|
|
182
|
+
signature: string;
|
|
183
|
+
alg: "Ed25519" | "ES256";
|
|
184
|
+
kid?: string | undefined;
|
|
185
|
+
};
|
|
186
|
+
taskId: string;
|
|
187
|
+
verdict: "approve" | "request-changes" | "comment";
|
|
188
|
+
findings: {
|
|
189
|
+
summary: string;
|
|
190
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
191
|
+
path?: string | undefined;
|
|
192
|
+
line?: number | undefined;
|
|
193
|
+
detail?: string | undefined;
|
|
194
|
+
}[];
|
|
195
|
+
findingsDigest: string;
|
|
196
|
+
}>;
|
|
197
|
+
export type ReviewVerdictBody = z.infer<typeof ReviewVerdictBodySchema>;
|
|
198
|
+
/**
|
|
199
|
+
* Validation Helpers
|
|
200
|
+
*/
|
|
201
|
+
/**
|
|
202
|
+
* Validate a review verdict body
|
|
203
|
+
*
|
|
204
|
+
* @param body - The body to validate
|
|
205
|
+
* @returns Validation result
|
|
206
|
+
*/
|
|
207
|
+
export declare function validateReviewVerdictBody(body: unknown): z.SafeParseReturnType<{
|
|
208
|
+
subject: {
|
|
209
|
+
repo: string;
|
|
210
|
+
prNumber: number;
|
|
211
|
+
headSha: string;
|
|
212
|
+
};
|
|
213
|
+
proof: {
|
|
214
|
+
signature: string;
|
|
215
|
+
alg: "Ed25519" | "ES256";
|
|
216
|
+
kid?: string | undefined;
|
|
217
|
+
};
|
|
218
|
+
taskId: string;
|
|
219
|
+
verdict: "approve" | "request-changes" | "comment";
|
|
220
|
+
findings: {
|
|
221
|
+
summary: string;
|
|
222
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
223
|
+
path?: string | undefined;
|
|
224
|
+
line?: number | undefined;
|
|
225
|
+
detail?: string | undefined;
|
|
226
|
+
}[];
|
|
227
|
+
findingsDigest: string;
|
|
228
|
+
}, {
|
|
229
|
+
subject: {
|
|
230
|
+
repo: string;
|
|
231
|
+
prNumber: number;
|
|
232
|
+
headSha: string;
|
|
233
|
+
};
|
|
234
|
+
proof: {
|
|
235
|
+
signature: string;
|
|
236
|
+
alg: "Ed25519" | "ES256";
|
|
237
|
+
kid?: string | undefined;
|
|
238
|
+
};
|
|
239
|
+
taskId: string;
|
|
240
|
+
verdict: "approve" | "request-changes" | "comment";
|
|
241
|
+
findings: {
|
|
242
|
+
summary: string;
|
|
243
|
+
severity: "blocking" | "major" | "minor" | "nit";
|
|
244
|
+
path?: string | undefined;
|
|
245
|
+
line?: number | undefined;
|
|
246
|
+
detail?: string | undefined;
|
|
247
|
+
}[];
|
|
248
|
+
findingsDigest: string;
|
|
249
|
+
}>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Review Verdict Schemas
|
|
4
|
+
*
|
|
5
|
+
* Types and Zod schemas for PR review verdicts posted by reviewer agents
|
|
6
|
+
* over DIDComm (see `packages/compute/src/didcomm/`). A verdict binds an
|
|
7
|
+
* approve/request-changes/comment decision to a single commit
|
|
8
|
+
* (`subject.headSha`): a push changes head, so every prior verdict's
|
|
9
|
+
* subject stops matching and stale approvals become uncountable rather than
|
|
10
|
+
* needing dismissal logic. That is a deliberate, load-bearing tradeoff, not
|
|
11
|
+
* an oversight — see the module doc on `canonicalize.ts` for the signing
|
|
12
|
+
* scheme this schema's `findingsDigest` and `proof` fields depend on.
|
|
13
|
+
*
|
|
14
|
+
* Pure Zod schemas only. Crypto-dependent canonicalization lives in
|
|
15
|
+
* `canonicalize.ts` so this module stays portable across every runtime that
|
|
16
|
+
* consumes `@kya-os/contracts` (see that file's doc comment for why).
|
|
17
|
+
*
|
|
18
|
+
* @package @kya-os/contracts/review
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.ReviewVerdictBodySchema = exports.ReviewFindingSchema = exports.ReviewFindingSeveritySchema = exports.ReviewVerdictSchema = exports.ReviewSubjectSchema = void 0;
|
|
22
|
+
exports.validateReviewVerdictBody = validateReviewVerdictBody;
|
|
23
|
+
const zod_1 = require("zod");
|
|
24
|
+
const signing_spec_js_1 = require("../proof/signing-spec.js");
|
|
25
|
+
/**
|
|
26
|
+
* Review Subject Schema
|
|
27
|
+
*
|
|
28
|
+
* Binds a verdict to a single commit on a single PR.
|
|
29
|
+
*/
|
|
30
|
+
exports.ReviewSubjectSchema = zod_1.z.object({
|
|
31
|
+
/** "owner/repo", e.g. "modelcontextprotocol-identity/xmcp-i" */
|
|
32
|
+
repo: zod_1.z.string().min(1),
|
|
33
|
+
/** GitHub PR number */
|
|
34
|
+
prNumber: zod_1.z.number().int().positive(),
|
|
35
|
+
/** Full 40-character SHA, lowercase */
|
|
36
|
+
headSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/),
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Review Verdict Schema
|
|
40
|
+
*/
|
|
41
|
+
exports.ReviewVerdictSchema = zod_1.z.enum(['approve', 'request-changes', 'comment']);
|
|
42
|
+
/**
|
|
43
|
+
* Review Finding Severity Schema
|
|
44
|
+
*/
|
|
45
|
+
exports.ReviewFindingSeveritySchema = zod_1.z.enum(['blocking', 'major', 'minor', 'nit']);
|
|
46
|
+
/**
|
|
47
|
+
* Review Finding Schema
|
|
48
|
+
*/
|
|
49
|
+
exports.ReviewFindingSchema = zod_1.z.object({
|
|
50
|
+
path: zod_1.z.string().min(1).optional(),
|
|
51
|
+
line: zod_1.z.number().int().positive().optional(),
|
|
52
|
+
severity: exports.ReviewFindingSeveritySchema,
|
|
53
|
+
summary: zod_1.z.string().min(1),
|
|
54
|
+
detail: zod_1.z.string().min(1).optional(),
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Review Verdict Body Schema
|
|
58
|
+
*
|
|
59
|
+
* Full verdict payload a reviewer agent posts over DIDComm.
|
|
60
|
+
*
|
|
61
|
+
* `findingsDigest` and `proof` are NOT derived by this schema — Zod
|
|
62
|
+
* validates shape, not that the digest actually matches `findings` or that
|
|
63
|
+
* the signature actually verifies. Producers must compute `findingsDigest`
|
|
64
|
+
* with `computeFindingsDigest` (in `canonicalize.ts`) and sign
|
|
65
|
+
* `getVerdictCanonicalSigningString(subject, verdict, findingsDigest)`;
|
|
66
|
+
* verifiers must recompute both and compare rather than trusting the wire
|
|
67
|
+
* value. Do not hand-roll either at a call site.
|
|
68
|
+
*/
|
|
69
|
+
exports.ReviewVerdictBodySchema = zod_1.z.object({
|
|
70
|
+
taskId: zod_1.z.string().min(1),
|
|
71
|
+
subject: exports.ReviewSubjectSchema,
|
|
72
|
+
verdict: exports.ReviewVerdictSchema,
|
|
73
|
+
/**
|
|
74
|
+
* Capped at 500: `computeFindingsDigest` (canonicalize.ts) does O(n) work
|
|
75
|
+
* per entry, and this is the array size a DIDComm-delivered payload from
|
|
76
|
+
* a reviewer agent controls. No real review produces more findings than
|
|
77
|
+
* this; a payload that does is malformed, not thorough.
|
|
78
|
+
*/
|
|
79
|
+
findings: zod_1.z.array(exports.ReviewFindingSchema).max(500),
|
|
80
|
+
/**
|
|
81
|
+
* base64url SHA-256 over canonicalized `findings`; see canonicalize.ts.
|
|
82
|
+
* Fixed at 43 chars — the exact length of an unpadded base64url SHA-256
|
|
83
|
+
* digest — matching the exact-length convention every other hash field
|
|
84
|
+
* in this package uses (e.g. `registry.ts`'s `contentHash`, `proof.ts`'s
|
|
85
|
+
* `requestHash`/`responseHash`).
|
|
86
|
+
*/
|
|
87
|
+
findingsDigest: zod_1.z.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
88
|
+
/** Detached JWS over subject + verdict + findingsDigest; see canonicalize.ts */
|
|
89
|
+
proof: signing_spec_js_1.DetachedJwsSchema,
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* Validation Helpers
|
|
93
|
+
*/
|
|
94
|
+
/**
|
|
95
|
+
* Validate a review verdict body
|
|
96
|
+
*
|
|
97
|
+
* @param body - The body to validate
|
|
98
|
+
* @returns Validation result
|
|
99
|
+
*/
|
|
100
|
+
function validateReviewVerdictBody(body) {
|
|
101
|
+
return exports.ReviewVerdictBodySchema.safeParse(body);
|
|
102
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fix Attestation Verification
|
|
3
|
+
*
|
|
4
|
+
* Raw Ed25519 verify for `FixAttestation` (see `fix-attestation.ts`), kept
|
|
5
|
+
* in its own subpath (`@kya-os/contracts/review/verify`) rather than the
|
|
6
|
+
* `./review` barrel: this file's `node:crypto` import would otherwise be
|
|
7
|
+
* pulled into every edge/browser consumer of the review subpath just to
|
|
8
|
+
* reach the pure schemas and canonicalization it doesn't need. Import this
|
|
9
|
+
* module directly wherever the verify function itself is actually needed.
|
|
10
|
+
*
|
|
11
|
+
* (P9's review-verdict counterpart, `verifyReviewVerdictProof`, has not
|
|
12
|
+
* landed in this package as of this commit — see
|
|
13
|
+
* `packages/compute/src/didcomm/review.ts`'s `verifyReviewVerdictSignature`
|
|
14
|
+
* for the same Ed25519-verify pattern applied to `ReviewVerdictBody`. When
|
|
15
|
+
* it lands here, the two belong as siblings in this file's own subpath.)
|
|
16
|
+
*
|
|
17
|
+
* @package @kya-os/contracts/review/verify
|
|
18
|
+
*/
|
|
19
|
+
import { type FixAttestation } from './fix-attestation.js';
|
|
20
|
+
/**
|
|
21
|
+
* Verify a fix attestation's detached Ed25519 signature: that
|
|
22
|
+
* `attestation.proof.signature` was produced by the private half of
|
|
23
|
+
* `publicKeyRaw` (raw 32-byte Ed25519 public key, e.g. `ssh-key.ts`'s
|
|
24
|
+
* `deriveEd25519PublicKey` output) over
|
|
25
|
+
* `getFixAttestationSigningString(attestation.subject, attestation.respondsToHeadSha)`.
|
|
26
|
+
*
|
|
27
|
+
* This does NOT check that `attestation.subject.fixedHeadSha` is actually
|
|
28
|
+
* the current head of the PR, or that `respondsToHeadSha` is actually the
|
|
29
|
+
* headSha a real review verdict requested changes on — it verifies one
|
|
30
|
+
* fact (possession + integrity of the signed tuple), not the whole review
|
|
31
|
+
* loop's state. Callers cross-check those against live PR/verdict data.
|
|
32
|
+
*
|
|
33
|
+
* Fail-closed: any malformed input, key-import failure, or signature
|
|
34
|
+
* mismatch returns `false` rather than throwing — never admit on an
|
|
35
|
+
* unverifiable proof.
|
|
36
|
+
*/
|
|
37
|
+
export declare function verifyFixAttestationProof(attestation: FixAttestation, publicKeyRaw: Buffer): boolean;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fix Attestation Verification
|
|
4
|
+
*
|
|
5
|
+
* Raw Ed25519 verify for `FixAttestation` (see `fix-attestation.ts`), kept
|
|
6
|
+
* in its own subpath (`@kya-os/contracts/review/verify`) rather than the
|
|
7
|
+
* `./review` barrel: this file's `node:crypto` import would otherwise be
|
|
8
|
+
* pulled into every edge/browser consumer of the review subpath just to
|
|
9
|
+
* reach the pure schemas and canonicalization it doesn't need. Import this
|
|
10
|
+
* module directly wherever the verify function itself is actually needed.
|
|
11
|
+
*
|
|
12
|
+
* (P9's review-verdict counterpart, `verifyReviewVerdictProof`, has not
|
|
13
|
+
* landed in this package as of this commit — see
|
|
14
|
+
* `packages/compute/src/didcomm/review.ts`'s `verifyReviewVerdictSignature`
|
|
15
|
+
* for the same Ed25519-verify pattern applied to `ReviewVerdictBody`. When
|
|
16
|
+
* it lands here, the two belong as siblings in this file's own subpath.)
|
|
17
|
+
*
|
|
18
|
+
* @package @kya-os/contracts/review/verify
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.verifyFixAttestationProof = verifyFixAttestationProof;
|
|
22
|
+
const node_crypto_1 = require("node:crypto");
|
|
23
|
+
const fix_attestation_js_1 = require("./fix-attestation.js");
|
|
24
|
+
// DER prefix that turns a raw 32-byte Ed25519 public key into an SPKI key,
|
|
25
|
+
// the same wrapping `@kya-os/mcp-i`'s `NodeCryptoProvider.verify` and
|
|
26
|
+
// `utils/dco/ssh-key.ts`'s PKCS8 sibling prefix use for the private half.
|
|
27
|
+
const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
|
|
28
|
+
/**
|
|
29
|
+
* Verify a fix attestation's detached Ed25519 signature: that
|
|
30
|
+
* `attestation.proof.signature` was produced by the private half of
|
|
31
|
+
* `publicKeyRaw` (raw 32-byte Ed25519 public key, e.g. `ssh-key.ts`'s
|
|
32
|
+
* `deriveEd25519PublicKey` output) over
|
|
33
|
+
* `getFixAttestationSigningString(attestation.subject, attestation.respondsToHeadSha)`.
|
|
34
|
+
*
|
|
35
|
+
* This does NOT check that `attestation.subject.fixedHeadSha` is actually
|
|
36
|
+
* the current head of the PR, or that `respondsToHeadSha` is actually the
|
|
37
|
+
* headSha a real review verdict requested changes on — it verifies one
|
|
38
|
+
* fact (possession + integrity of the signed tuple), not the whole review
|
|
39
|
+
* loop's state. Callers cross-check those against live PR/verdict data.
|
|
40
|
+
*
|
|
41
|
+
* Fail-closed: any malformed input, key-import failure, or signature
|
|
42
|
+
* mismatch returns `false` rather than throwing — never admit on an
|
|
43
|
+
* unverifiable proof.
|
|
44
|
+
*/
|
|
45
|
+
function verifyFixAttestationProof(attestation, publicKeyRaw) {
|
|
46
|
+
try {
|
|
47
|
+
const signingString = (0, fix_attestation_js_1.getFixAttestationSigningString)(attestation.subject, attestation.respondsToHeadSha);
|
|
48
|
+
const publicKey = (0, node_crypto_1.createPublicKey)({
|
|
49
|
+
key: Buffer.concat([ED25519_SPKI_PREFIX, publicKeyRaw]),
|
|
50
|
+
format: 'der',
|
|
51
|
+
type: 'spki',
|
|
52
|
+
});
|
|
53
|
+
return (0, node_crypto_1.verify)(null, Buffer.from(signingString, 'utf8'), publicKey, Buffer.from(attestation.proof.signature, 'base64url'));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false; // fail-closed — never admit on an unverifiable proof
|
|
57
|
+
}
|
|
58
|
+
}
|
package/dist/test.d.ts
CHANGED
|
@@ -173,6 +173,13 @@ export declare const LocalVerificationResultSchema: z.ZodObject<{
|
|
|
173
173
|
}, "strip", z.ZodTypeAny, {
|
|
174
174
|
valid: boolean;
|
|
175
175
|
warnings: string[];
|
|
176
|
+
proof: {
|
|
177
|
+
valid: boolean;
|
|
178
|
+
structure: boolean;
|
|
179
|
+
timestamps: boolean;
|
|
180
|
+
hashes: boolean;
|
|
181
|
+
error?: string | undefined;
|
|
182
|
+
};
|
|
176
183
|
session: {
|
|
177
184
|
valid: boolean;
|
|
178
185
|
expired: boolean;
|
|
@@ -183,6 +190,11 @@ export declare const LocalVerificationResultSchema: z.ZodObject<{
|
|
|
183
190
|
algorithm: string;
|
|
184
191
|
error?: string | undefined;
|
|
185
192
|
};
|
|
193
|
+
errors: string[];
|
|
194
|
+
did?: string | undefined;
|
|
195
|
+
kid?: string | undefined;
|
|
196
|
+
}, {
|
|
197
|
+
valid: boolean;
|
|
186
198
|
proof: {
|
|
187
199
|
valid: boolean;
|
|
188
200
|
structure: boolean;
|
|
@@ -190,11 +202,6 @@ export declare const LocalVerificationResultSchema: z.ZodObject<{
|
|
|
190
202
|
hashes: boolean;
|
|
191
203
|
error?: string | undefined;
|
|
192
204
|
};
|
|
193
|
-
errors: string[];
|
|
194
|
-
did?: string | undefined;
|
|
195
|
-
kid?: string | undefined;
|
|
196
|
-
}, {
|
|
197
|
-
valid: boolean;
|
|
198
205
|
session: {
|
|
199
206
|
valid: boolean;
|
|
200
207
|
expired: boolean;
|
|
@@ -205,13 +212,6 @@ export declare const LocalVerificationResultSchema: z.ZodObject<{
|
|
|
205
212
|
algorithm: string;
|
|
206
213
|
error?: string | undefined;
|
|
207
214
|
};
|
|
208
|
-
proof: {
|
|
209
|
-
valid: boolean;
|
|
210
|
-
structure: boolean;
|
|
211
|
-
timestamps: boolean;
|
|
212
|
-
hashes: boolean;
|
|
213
|
-
error?: string | undefined;
|
|
214
|
-
};
|
|
215
215
|
did?: string | undefined;
|
|
216
216
|
kid?: string | undefined;
|
|
217
217
|
warnings?: string[] | undefined;
|
package/dist/vault/schemas.d.ts
CHANGED
|
@@ -46,13 +46,13 @@ export declare const resolveSecretsRequestSchema: z.ZodObject<{
|
|
|
46
46
|
assertion: z.ZodString;
|
|
47
47
|
}, "strip", z.ZodTypeAny, {
|
|
48
48
|
userDid: string;
|
|
49
|
-
envVarNames: string[];
|
|
50
49
|
toolName: string;
|
|
50
|
+
envVarNames: string[];
|
|
51
51
|
assertion: string;
|
|
52
52
|
}, {
|
|
53
53
|
userDid: string;
|
|
54
|
-
envVarNames: string[];
|
|
55
54
|
toolName: string;
|
|
55
|
+
envVarNames: string[];
|
|
56
56
|
assertion: string;
|
|
57
57
|
}>;
|
|
58
58
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kya-os/contracts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "Shared contracts, types, and schemas for MCP-I framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,6 +33,14 @@
|
|
|
33
33
|
"types": "./dist/proof/index.d.ts",
|
|
34
34
|
"default": "./dist/proof/index.js"
|
|
35
35
|
},
|
|
36
|
+
"./review": {
|
|
37
|
+
"types": "./dist/review/index.d.ts",
|
|
38
|
+
"default": "./dist/review/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./review/verify": {
|
|
41
|
+
"types": "./dist/review/verify.d.ts",
|
|
42
|
+
"default": "./dist/review/verify.js"
|
|
43
|
+
},
|
|
36
44
|
"./tool-protection": {
|
|
37
45
|
"types": "./dist/tool-protection/index.d.ts",
|
|
38
46
|
"default": "./dist/tool-protection/index.js"
|