@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/proof.d.ts CHANGED
@@ -39,6 +39,8 @@ export declare const ProofMetaSchema: z.ZodObject<{
39
39
  scopeId: z.ZodOptional<z.ZodString>;
40
40
  delegationRef: z.ZodOptional<z.ZodString>;
41
41
  clientDid: z.ZodOptional<z.ZodString>;
42
+ toolName: z.ZodOptional<z.ZodString>;
43
+ submissionOutcome: z.ZodOptional<z.ZodEnum<["success", "failure", "denied"]>>;
42
44
  }, "strip", z.ZodTypeAny, {
43
45
  did: string;
44
46
  kid: string;
@@ -52,6 +54,8 @@ export declare const ProofMetaSchema: z.ZodObject<{
52
54
  delegationRef?: string | undefined;
53
55
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
54
56
  scopeId?: string | undefined;
57
+ toolName?: string | undefined;
58
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
55
59
  }, {
56
60
  did: string;
57
61
  kid: string;
@@ -65,6 +69,8 @@ export declare const ProofMetaSchema: z.ZodObject<{
65
69
  delegationRef?: string | undefined;
66
70
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
67
71
  scopeId?: string | undefined;
72
+ toolName?: string | undefined;
73
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
68
74
  }>;
69
75
  export declare const DetachedProofSchema: z.ZodObject<{
70
76
  jws: z.ZodString;
@@ -81,6 +87,8 @@ export declare const DetachedProofSchema: z.ZodObject<{
81
87
  scopeId: z.ZodOptional<z.ZodString>;
82
88
  delegationRef: z.ZodOptional<z.ZodString>;
83
89
  clientDid: z.ZodOptional<z.ZodString>;
90
+ toolName: z.ZodOptional<z.ZodString>;
91
+ submissionOutcome: z.ZodOptional<z.ZodEnum<["success", "failure", "denied"]>>;
84
92
  }, "strip", z.ZodTypeAny, {
85
93
  did: string;
86
94
  kid: string;
@@ -94,6 +102,8 @@ export declare const DetachedProofSchema: z.ZodObject<{
94
102
  delegationRef?: string | undefined;
95
103
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
96
104
  scopeId?: string | undefined;
105
+ toolName?: string | undefined;
106
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
97
107
  }, {
98
108
  did: string;
99
109
  kid: string;
@@ -107,6 +117,8 @@ export declare const DetachedProofSchema: z.ZodObject<{
107
117
  delegationRef?: string | undefined;
108
118
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
109
119
  scopeId?: string | undefined;
120
+ toolName?: string | undefined;
121
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
110
122
  }>;
111
123
  }, "strip", z.ZodTypeAny, {
112
124
  jws: string;
@@ -123,6 +135,8 @@ export declare const DetachedProofSchema: z.ZodObject<{
123
135
  delegationRef?: string | undefined;
124
136
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
125
137
  scopeId?: string | undefined;
138
+ toolName?: string | undefined;
139
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
126
140
  };
127
141
  }, {
128
142
  jws: string;
@@ -139,6 +153,8 @@ export declare const DetachedProofSchema: z.ZodObject<{
139
153
  delegationRef?: string | undefined;
140
154
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
141
155
  scopeId?: string | undefined;
156
+ toolName?: string | undefined;
157
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
142
158
  };
143
159
  }>;
144
160
  export declare const CanonicalHashesSchema: z.ZodObject<{
@@ -280,6 +296,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
280
296
  scopeId: z.ZodOptional<z.ZodString>;
281
297
  delegationRef: z.ZodOptional<z.ZodString>;
282
298
  clientDid: z.ZodOptional<z.ZodString>;
299
+ toolName: z.ZodOptional<z.ZodString>;
300
+ submissionOutcome: z.ZodOptional<z.ZodEnum<["success", "failure", "denied"]>>;
283
301
  }, "strip", z.ZodTypeAny, {
284
302
  did: string;
285
303
  kid: string;
@@ -293,6 +311,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
293
311
  delegationRef?: string | undefined;
294
312
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
295
313
  scopeId?: string | undefined;
314
+ toolName?: string | undefined;
315
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
296
316
  }, {
297
317
  did: string;
298
318
  kid: string;
@@ -306,6 +326,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
306
326
  delegationRef?: string | undefined;
307
327
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
308
328
  scopeId?: string | undefined;
329
+ toolName?: string | undefined;
330
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
309
331
  }>;
310
332
  }, "strip", z.ZodTypeAny, {
311
333
  jws: string;
@@ -322,6 +344,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
322
344
  delegationRef?: string | undefined;
323
345
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
324
346
  scopeId?: string | undefined;
347
+ toolName?: string | undefined;
348
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
325
349
  };
326
350
  }, {
327
351
  jws: string;
@@ -338,6 +362,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
338
362
  delegationRef?: string | undefined;
339
363
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
340
364
  scopeId?: string | undefined;
365
+ toolName?: string | undefined;
366
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
341
367
  };
342
368
  }>, "many">;
343
369
  context: z.ZodOptional<z.ZodObject<{
@@ -397,6 +423,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
397
423
  delegationRef?: string | undefined;
398
424
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
399
425
  scopeId?: string | undefined;
426
+ toolName?: string | undefined;
427
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
400
428
  };
401
429
  }[];
402
430
  delegation_id?: string | null | undefined;
@@ -427,6 +455,8 @@ export declare const ProofSubmissionRequestSchema: z.ZodObject<{
427
455
  delegationRef?: string | undefined;
428
456
  outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
429
457
  scopeId?: string | undefined;
458
+ toolName?: string | undefined;
459
+ submissionOutcome?: "success" | "denied" | "failure" | undefined;
430
460
  };
431
461
  }[];
432
462
  delegation_id?: string | null | undefined;
package/dist/proof.js CHANGED
@@ -52,6 +52,12 @@ exports.ProofMetaSchema = zod_1.z.object({
52
52
  scopeId: zod_1.z.string().optional(),
53
53
  delegationRef: zod_1.z.string().optional(),
54
54
  clientDid: zod_1.z.string().optional(), // Optional for backward compatibility
55
+ toolName: zod_1.z.string().min(1).optional(),
56
+ // KTA's "did the tool call itself succeed" concept -- distinct from
57
+ // `outcome` above (the ratified DIF policy-decision field). Only at JWS
58
+ // payload serialization time does this get mapped onto the literal wire
59
+ // key `outcome`; the two never share a validation enum here.
60
+ submissionOutcome: zod_1.z.enum(["success", "failure", "denied"]).optional(),
55
61
  });
56
62
  exports.DetachedProofSchema = zod_1.z.object({
57
63
  jws: zod_1.z.string().min(1), // Full compact JWS format (header.payload.signature)
@@ -2864,20 +2864,3 @@ export declare const REPUTATION_ENV_VARS: {
2864
2864
  * Default reputation threshold for trust decisions
2865
2865
  */
2866
2866
  export declare const DEFAULT_REPUTATION_THRESHOLD: 76;
2867
- /**
2868
- * Built-in API key for Know That AI Reputation Engine
2869
- *
2870
- * This key is maintained by @kya-os package maintainers.
2871
- * Users do NOT need to configure this - registration with KTA is the gate.
2872
- *
2873
- * The key is used by ProofService to authenticate reputation updates.
2874
- * Only agents with `identity.kta.registered === true` will send updates.
2875
- *
2876
- * SECURITY NOTE: This is a write-only key for submitting metrics.
2877
- * It cannot be used to read reputation data without the agent's DID.
2878
- */
2879
- /**
2880
- * Production API key for MCP-I framework
2881
- * Provisioned by Know That AI team
2882
- */
2883
- export declare const BUILT_IN_REPUTATION_API_KEY: "Dn/qCC/0udWcGpdnt+IzA5GpWl9JF2g/avuBxlzB";
@@ -14,7 +14,7 @@
14
14
  * Related Spec: MCP-I §5.2 (Reputation API)
15
15
  */
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.BUILT_IN_REPUTATION_API_KEY = exports.DEFAULT_REPUTATION_THRESHOLD = exports.REPUTATION_ENV_VARS = exports.REPUTATION_API_LIMITS = exports.REPUTATION_API_PATHS = exports.REGISTRY_URL = exports.ReputationUpdateRequestSchema = exports.ShadowRegisterResponseSchema = exports.ShadowRegisterRequestSchema = exports.ReputationErrorResponseSchema = exports.ReputationErrorCodeSchema = exports.GetReputationResponseSchema = exports.GetReputationRequestSchema = exports.PredictScoreChangeResponseSchema = exports.PredictScoreChangeRequestSchema = exports.BatchCalculateResponseSchema = exports.BatchResultItemSchema = exports.BatchCalculateRequestSchema = exports.CalculateReputationResponseSchema = exports.CalculateReputationRequestSchema = void 0;
17
+ exports.DEFAULT_REPUTATION_THRESHOLD = exports.REPUTATION_ENV_VARS = exports.REPUTATION_API_LIMITS = exports.REPUTATION_API_PATHS = exports.REGISTRY_URL = exports.ReputationUpdateRequestSchema = exports.ShadowRegisterResponseSchema = exports.ShadowRegisterRequestSchema = exports.ReputationErrorResponseSchema = exports.ReputationErrorCodeSchema = exports.GetReputationResponseSchema = exports.GetReputationRequestSchema = exports.PredictScoreChangeResponseSchema = exports.PredictScoreChangeRequestSchema = exports.BatchCalculateResponseSchema = exports.BatchResultItemSchema = exports.BatchCalculateRequestSchema = exports.CalculateReputationResponseSchema = exports.CalculateReputationRequestSchema = void 0;
18
18
  exports.validateCalculateRequest = validateCalculateRequest;
19
19
  exports.validateBatchCalculateRequest = validateBatchCalculateRequest;
20
20
  exports.validatePredictRequest = validatePredictRequest;
@@ -395,23 +395,3 @@ exports.REPUTATION_ENV_VARS = {
395
395
  * Default reputation threshold for trust decisions
396
396
  */
397
397
  exports.DEFAULT_REPUTATION_THRESHOLD = 76;
398
- // ============================================================================
399
- // BUILT-IN API KEY
400
- // ============================================================================
401
- /**
402
- * Built-in API key for Know That AI Reputation Engine
403
- *
404
- * This key is maintained by @kya-os package maintainers.
405
- * Users do NOT need to configure this - registration with KTA is the gate.
406
- *
407
- * The key is used by ProofService to authenticate reputation updates.
408
- * Only agents with `identity.kta.registered === true` will send updates.
409
- *
410
- * SECURITY NOTE: This is a write-only key for submitting metrics.
411
- * It cannot be used to read reputation data without the agent's DID.
412
- */
413
- /**
414
- * Production API key for MCP-I framework
415
- * Provisioned by Know That AI team
416
- */
417
- exports.BUILT_IN_REPUTATION_API_KEY = "Dn/qCC/0udWcGpdnt+IzA5GpWl9JF2g/avuBxlzB";
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Review Verdict Canonicalization
3
+ *
4
+ * Canonical string construction and digest computation for review
5
+ * verdicts. Isolated from `schemas.ts` so the Zod schemas there stay free
6
+ * of Node.js dependencies — same split as `agent-deployment-utils.ts` vs
7
+ * `agent-deployment.ts` in this package — while every producer and
8
+ * verifier of a `ReviewVerdictBody` computes `findingsDigest` and the
9
+ * signing input from this one implementation. Two implementations that
10
+ * canonicalize differently produce signatures that verify on one side and
11
+ * fail on the other; that failure presents as a security incident, not a
12
+ * serialization bug, so do not re-derive this logic at a call site.
13
+ *
14
+ * **Node.js only** — uses `crypto.createHash`. This runs in the DIDComm
15
+ * reviewer/hub path (`packages/compute`), which is server-side. If an
16
+ * edge/browser producer or verifier is ever needed, port to
17
+ * `crypto.subtle.digest` and add a parity test asserting byte-identical
18
+ * output against this implementation (see `didToSlug`'s JSDoc in
19
+ * `agent-deployment-utils.ts` for the same caveat on the same tradeoff).
20
+ *
21
+ * ## Canonicalization scheme
22
+ *
23
+ * Every scalar field value is passed through `JSON.stringify`: strings are
24
+ * quoted and escaped (so a raw `\n`, `"`, or unicode control character in
25
+ * `summary`/`detail` can never appear literally in the output), and numbers
26
+ * print as plain digits. An **absent** optional field becomes the empty
27
+ * string `''`, which can never collide with a **present** field —
28
+ * `JSON.stringify` never returns `''` for a defined value (an empty string
29
+ * value stringifies to `'""'`, two characters). Because no token can ever
30
+ * contain a raw `\n` (JSON.stringify escapes it inside the string), joining
31
+ * tokens with `\n` is unambiguous: two different `findings` arrays can
32
+ * never produce the same token stream.
33
+ *
34
+ * Field order per finding: `path, line, severity, summary, detail`
35
+ * (`FINDING_FIELD_ORDER`), matching the order `ReviewFinding` is declared
36
+ * in `schemas.ts`.
37
+ *
38
+ * ### Worked example
39
+ *
40
+ * ```ts
41
+ * const findings: ReviewFinding[] = [
42
+ * { path: 'src/foo.ts', line: 42, severity: 'major', summary: 'off by one' },
43
+ * ];
44
+ * // detail is absent -> its token is ''
45
+ * // tokens: '"src/foo.ts"', '42', '"major"', '"off by one"', ''
46
+ * canonicalizeFindings(findings)
47
+ * // => '"src/foo.ts"\n42\n"major"\n"off by one"\n'
48
+ * computeFindingsDigest(findings)
49
+ * // => base64url(SHA-256('"src/foo.ts"\n42\n"major"\n"off by one"\n'))
50
+ * ```
51
+ *
52
+ * The verdict signing input follows the identical scheme over the fixed
53
+ * field order `[repo, prNumber, headSha, verdict, findingsDigest]`
54
+ * (`VERDICT_SIGNING_ORDER`) — see `getVerdictCanonicalSigningString`.
55
+ *
56
+ * @package @kya-os/contracts/review
57
+ */
58
+ import type { ReviewFinding, ReviewSubject, ReviewVerdict } from './schemas.js';
59
+ /**
60
+ * Field order for a single `ReviewFinding`. Changing this order changes
61
+ * every existing `findingsDigest`.
62
+ */
63
+ export declare const FINDING_FIELD_ORDER: readonly ["path", "line", "severity", "summary", "detail"];
64
+ /**
65
+ * Field order for the verdict signing input. Changing this order changes
66
+ * every existing signature.
67
+ */
68
+ export declare const VERDICT_SIGNING_ORDER: readonly ["repo", "prNumber", "headSha", "verdict", "findingsDigest"];
69
+ /**
70
+ * Build the canonical string for a `findings` array. Exported so callers
71
+ * that need to reason about the exact bytes being hashed (tests, audit
72
+ * tooling) do not have to re-derive it.
73
+ */
74
+ export declare function canonicalizeFindings(findings: readonly ReviewFinding[]): string;
75
+ /**
76
+ * Compute `findingsDigest`: base64url SHA-256 over the canonicalized
77
+ * `findings` array. This is the single implementation every producer and
78
+ * verifier of a `ReviewVerdictBody` must call.
79
+ */
80
+ export declare function computeFindingsDigest(findings: readonly ReviewFinding[]): string;
81
+ /**
82
+ * Build the canonical signing input for a review verdict's detached JWS:
83
+ * `subject.repo`, `subject.prNumber`, `subject.headSha`, `verdict`,
84
+ * `findingsDigest`, in that fixed order (`VERDICT_SIGNING_ORDER`). The
85
+ * `proof` in `ReviewVerdictBody` signs exactly this string.
86
+ */
87
+ export declare function getVerdictCanonicalSigningString(subject: ReviewSubject, verdict: ReviewVerdict, findingsDigest: string): string;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /**
3
+ * Review Verdict Canonicalization
4
+ *
5
+ * Canonical string construction and digest computation for review
6
+ * verdicts. Isolated from `schemas.ts` so the Zod schemas there stay free
7
+ * of Node.js dependencies — same split as `agent-deployment-utils.ts` vs
8
+ * `agent-deployment.ts` in this package — while every producer and
9
+ * verifier of a `ReviewVerdictBody` computes `findingsDigest` and the
10
+ * signing input from this one implementation. Two implementations that
11
+ * canonicalize differently produce signatures that verify on one side and
12
+ * fail on the other; that failure presents as a security incident, not a
13
+ * serialization bug, so do not re-derive this logic at a call site.
14
+ *
15
+ * **Node.js only** — uses `crypto.createHash`. This runs in the DIDComm
16
+ * reviewer/hub path (`packages/compute`), which is server-side. If an
17
+ * edge/browser producer or verifier is ever needed, port to
18
+ * `crypto.subtle.digest` and add a parity test asserting byte-identical
19
+ * output against this implementation (see `didToSlug`'s JSDoc in
20
+ * `agent-deployment-utils.ts` for the same caveat on the same tradeoff).
21
+ *
22
+ * ## Canonicalization scheme
23
+ *
24
+ * Every scalar field value is passed through `JSON.stringify`: strings are
25
+ * quoted and escaped (so a raw `\n`, `"`, or unicode control character in
26
+ * `summary`/`detail` can never appear literally in the output), and numbers
27
+ * print as plain digits. An **absent** optional field becomes the empty
28
+ * string `''`, which can never collide with a **present** field —
29
+ * `JSON.stringify` never returns `''` for a defined value (an empty string
30
+ * value stringifies to `'""'`, two characters). Because no token can ever
31
+ * contain a raw `\n` (JSON.stringify escapes it inside the string), joining
32
+ * tokens with `\n` is unambiguous: two different `findings` arrays can
33
+ * never produce the same token stream.
34
+ *
35
+ * Field order per finding: `path, line, severity, summary, detail`
36
+ * (`FINDING_FIELD_ORDER`), matching the order `ReviewFinding` is declared
37
+ * in `schemas.ts`.
38
+ *
39
+ * ### Worked example
40
+ *
41
+ * ```ts
42
+ * const findings: ReviewFinding[] = [
43
+ * { path: 'src/foo.ts', line: 42, severity: 'major', summary: 'off by one' },
44
+ * ];
45
+ * // detail is absent -> its token is ''
46
+ * // tokens: '"src/foo.ts"', '42', '"major"', '"off by one"', ''
47
+ * canonicalizeFindings(findings)
48
+ * // => '"src/foo.ts"\n42\n"major"\n"off by one"\n'
49
+ * computeFindingsDigest(findings)
50
+ * // => base64url(SHA-256('"src/foo.ts"\n42\n"major"\n"off by one"\n'))
51
+ * ```
52
+ *
53
+ * The verdict signing input follows the identical scheme over the fixed
54
+ * field order `[repo, prNumber, headSha, verdict, findingsDigest]`
55
+ * (`VERDICT_SIGNING_ORDER`) — see `getVerdictCanonicalSigningString`.
56
+ *
57
+ * @package @kya-os/contracts/review
58
+ */
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ exports.VERDICT_SIGNING_ORDER = exports.FINDING_FIELD_ORDER = void 0;
61
+ exports.canonicalizeFindings = canonicalizeFindings;
62
+ exports.computeFindingsDigest = computeFindingsDigest;
63
+ exports.getVerdictCanonicalSigningString = getVerdictCanonicalSigningString;
64
+ const crypto_1 = require("crypto");
65
+ /**
66
+ * Field order for a single `ReviewFinding`. Changing this order changes
67
+ * every existing `findingsDigest`.
68
+ */
69
+ exports.FINDING_FIELD_ORDER = ['path', 'line', 'severity', 'summary', 'detail'];
70
+ /**
71
+ * Field order for the verdict signing input. Changing this order changes
72
+ * every existing signature.
73
+ */
74
+ exports.VERDICT_SIGNING_ORDER = [
75
+ 'repo',
76
+ 'prNumber',
77
+ 'headSha',
78
+ 'verdict',
79
+ 'findingsDigest',
80
+ ];
81
+ /** A single canonicalization token: `''` for an absent field, else `JSON.stringify(value)`. */
82
+ function canonicalToken(value) {
83
+ return value === undefined ? '' : JSON.stringify(value);
84
+ }
85
+ /**
86
+ * Build the canonical string for a `findings` array. Exported so callers
87
+ * that need to reason about the exact bytes being hashed (tests, audit
88
+ * tooling) do not have to re-derive it.
89
+ */
90
+ function canonicalizeFindings(findings) {
91
+ const tokens = [];
92
+ for (const finding of findings) {
93
+ for (const field of exports.FINDING_FIELD_ORDER) {
94
+ tokens.push(canonicalToken(finding[field]));
95
+ }
96
+ }
97
+ return tokens.join('\n');
98
+ }
99
+ /**
100
+ * Compute `findingsDigest`: base64url SHA-256 over the canonicalized
101
+ * `findings` array. This is the single implementation every producer and
102
+ * verifier of a `ReviewVerdictBody` must call.
103
+ */
104
+ function computeFindingsDigest(findings) {
105
+ return (0, crypto_1.createHash)('sha256').update(canonicalizeFindings(findings), 'utf8').digest('base64url');
106
+ }
107
+ /**
108
+ * Build the canonical signing input for a review verdict's detached JWS:
109
+ * `subject.repo`, `subject.prNumber`, `subject.headSha`, `verdict`,
110
+ * `findingsDigest`, in that fixed order (`VERDICT_SIGNING_ORDER`). The
111
+ * `proof` in `ReviewVerdictBody` signs exactly this string.
112
+ */
113
+ function getVerdictCanonicalSigningString(subject, verdict, findingsDigest) {
114
+ const values = {
115
+ repo: subject.repo,
116
+ prNumber: subject.prNumber,
117
+ headSha: subject.headSha,
118
+ verdict,
119
+ findingsDigest,
120
+ };
121
+ return exports.VERDICT_SIGNING_ORDER.map((field) => canonicalToken(values[field])).join('\n');
122
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Fix Attestation Schema
3
+ *
4
+ * A fix attestation is the answer to a `ReviewVerdictBody` that requested
5
+ * changes: a verdict says "I reviewed `respondsToHeadSha` and found these
6
+ * findings"; a fix attestation says "I pushed `subject.fixedHeadSha` on
7
+ * `subject.repo`#`subject.prNumber` in response to that review." Posted as a
8
+ * signed PR comment (see `dco fix` in `@kya-os/cli`) so the audit trail
9
+ * closes the loop without trusting an unsigned comment body.
10
+ *
11
+ * Pure Zod schemas plus canonicalization only, no `node:crypto` — this
12
+ * module (and this package's `./review` barrel, which re-exports it) stays
13
+ * importable from an edge/browser runtime. The Ed25519 verify counterpart,
14
+ * `verifyFixAttestationProof`, lives in the separate `./review/verify`
15
+ * subpath instead of here for exactly that reason: it needs `node:crypto`
16
+ * for raw Ed25519 verification, and a subpath barrel must not force that
17
+ * dependency on every consumer who only needs the schema/signing-string
18
+ * (see `verify.ts`'s own module doc).
19
+ *
20
+ * @package @kya-os/contracts/review
21
+ */
22
+ import { z } from 'zod';
23
+ export declare const FixAttestationSubjectSchema: z.ZodObject<{
24
+ /**
25
+ * "owner/repo", e.g. "modelcontextprotocol-identity/xmcp-i". Constrained
26
+ * to GitHub's actual owner/repo character set (alphanumeric, hyphen,
27
+ * underscore, period) rather than a bare non-empty string: this value
28
+ * gets interpolated into a PR-comment marker
29
+ * (`buildFixAttestationCommentBody` in `@kya-os/cli`'s `dco fix`), and a
30
+ * bare `.min(1)` would let a backtick or an HTML comment-closing `-->`
31
+ * through into that markdown.
32
+ */
33
+ repo: z.ZodString;
34
+ /** GitHub PR number */
35
+ prNumber: z.ZodNumber;
36
+ /** Full 40-character SHA, lowercase — the commit this attestation covers */
37
+ fixedHeadSha: z.ZodString;
38
+ }, "strip", z.ZodTypeAny, {
39
+ repo: string;
40
+ prNumber: number;
41
+ fixedHeadSha: string;
42
+ }, {
43
+ repo: string;
44
+ prNumber: number;
45
+ fixedHeadSha: string;
46
+ }>;
47
+ export type FixAttestationSubject = z.infer<typeof FixAttestationSubjectSchema>;
48
+ export declare const FixAttestationSchema: z.ZodObject<{
49
+ subject: z.ZodObject<{
50
+ /**
51
+ * "owner/repo", e.g. "modelcontextprotocol-identity/xmcp-i". Constrained
52
+ * to GitHub's actual owner/repo character set (alphanumeric, hyphen,
53
+ * underscore, period) rather than a bare non-empty string: this value
54
+ * gets interpolated into a PR-comment marker
55
+ * (`buildFixAttestationCommentBody` in `@kya-os/cli`'s `dco fix`), and a
56
+ * bare `.min(1)` would let a backtick or an HTML comment-closing `-->`
57
+ * through into that markdown.
58
+ */
59
+ repo: z.ZodString;
60
+ /** GitHub PR number */
61
+ prNumber: z.ZodNumber;
62
+ /** Full 40-character SHA, lowercase — the commit this attestation covers */
63
+ fixedHeadSha: z.ZodString;
64
+ }, "strip", z.ZodTypeAny, {
65
+ repo: string;
66
+ prNumber: number;
67
+ fixedHeadSha: string;
68
+ }, {
69
+ repo: string;
70
+ prNumber: number;
71
+ fixedHeadSha: string;
72
+ }>;
73
+ /** Full 40-character SHA, lowercase — the reviewed head that requested changes */
74
+ respondsToHeadSha: z.ZodString;
75
+ /** The DIDComm fix task this attestation was dispatched for, when applicable */
76
+ taskId: z.ZodOptional<z.ZodString>;
77
+ /** did:<method>:<method-specific-id>, e.g. did:web:knowthat.ai:agents:acme-bot */
78
+ agentDid: z.ZodString;
79
+ /** Detached JWS over `getFixAttestationSigningString(subject, respondsToHeadSha)` */
80
+ proof: z.ZodObject<{
81
+ alg: z.ZodEnum<["Ed25519", "ES256"]>;
82
+ kid: z.ZodOptional<z.ZodString>;
83
+ signature: z.ZodString;
84
+ }, "strip", z.ZodTypeAny, {
85
+ signature: string;
86
+ alg: "Ed25519" | "ES256";
87
+ kid?: string | undefined;
88
+ }, {
89
+ signature: string;
90
+ alg: "Ed25519" | "ES256";
91
+ kid?: string | undefined;
92
+ }>;
93
+ }, "strip", z.ZodTypeAny, {
94
+ agentDid: string;
95
+ subject: {
96
+ repo: string;
97
+ prNumber: number;
98
+ fixedHeadSha: string;
99
+ };
100
+ proof: {
101
+ signature: string;
102
+ alg: "Ed25519" | "ES256";
103
+ kid?: string | undefined;
104
+ };
105
+ respondsToHeadSha: string;
106
+ taskId?: string | undefined;
107
+ }, {
108
+ agentDid: string;
109
+ subject: {
110
+ repo: string;
111
+ prNumber: number;
112
+ fixedHeadSha: string;
113
+ };
114
+ proof: {
115
+ signature: string;
116
+ alg: "Ed25519" | "ES256";
117
+ kid?: string | undefined;
118
+ };
119
+ respondsToHeadSha: string;
120
+ taskId?: string | undefined;
121
+ }>;
122
+ export type FixAttestation = z.infer<typeof FixAttestationSchema>;
123
+ /**
124
+ * Field order for the fix-attestation signing input, fixed forever: changing
125
+ * it changes every existing signature. `"fix-attestation:v1"` is a version
126
+ * tag, not a subject field — bumping the scheme (e.g. adding a field) must
127
+ * bump this string too, so an old signature can never be replayed against a
128
+ * new canonicalization.
129
+ */
130
+ export declare const FIX_ATTESTATION_SIGNING_ORDER: readonly ["version", "repo", "prNumber", "fixedHeadSha", "respondsToHeadSha"];
131
+ /**
132
+ * Build the canonical signing string for a fix attestation's detached JWS:
133
+ * newline-joined `"fix-attestation:v1"`, `subject.repo`, `subject.prNumber`
134
+ * (decimal), `subject.fixedHeadSha`, `respondsToHeadSha`, in that fixed
135
+ * order (`FIX_ATTESTATION_SIGNING_ORDER`). Every field is required here (no
136
+ * optional-field ambiguity to resolve, unlike `getVerdictCanonicalSigningString`'s
137
+ * findings tokens), so each token is simply `JSON.stringify(value)`.
138
+ *
139
+ * ### Worked example
140
+ *
141
+ * ```ts
142
+ * const subject: FixAttestationSubject = {
143
+ * repo: 'acme/demo',
144
+ * prNumber: 42,
145
+ * fixedHeadSha: 'a'.repeat(40),
146
+ * };
147
+ * getFixAttestationSigningString(subject, 'b'.repeat(40))
148
+ * // => '"fix-attestation:v1"\n"acme/demo"\n42\n"aaaa...aaaa"\n"bbbb...bbbb"'
149
+ * ```
150
+ */
151
+ export declare function getFixAttestationSigningString(subject: FixAttestationSubject, respondsToHeadSha: string): string;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ /**
3
+ * Fix Attestation Schema
4
+ *
5
+ * A fix attestation is the answer to a `ReviewVerdictBody` that requested
6
+ * changes: a verdict says "I reviewed `respondsToHeadSha` and found these
7
+ * findings"; a fix attestation says "I pushed `subject.fixedHeadSha` on
8
+ * `subject.repo`#`subject.prNumber` in response to that review." Posted as a
9
+ * signed PR comment (see `dco fix` in `@kya-os/cli`) so the audit trail
10
+ * closes the loop without trusting an unsigned comment body.
11
+ *
12
+ * Pure Zod schemas plus canonicalization only, no `node:crypto` — this
13
+ * module (and this package's `./review` barrel, which re-exports it) stays
14
+ * importable from an edge/browser runtime. The Ed25519 verify counterpart,
15
+ * `verifyFixAttestationProof`, lives in the separate `./review/verify`
16
+ * subpath instead of here for exactly that reason: it needs `node:crypto`
17
+ * for raw Ed25519 verification, and a subpath barrel must not force that
18
+ * dependency on every consumer who only needs the schema/signing-string
19
+ * (see `verify.ts`'s own module doc).
20
+ *
21
+ * @package @kya-os/contracts/review
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.FIX_ATTESTATION_SIGNING_ORDER = exports.FixAttestationSchema = exports.FixAttestationSubjectSchema = void 0;
25
+ exports.getFixAttestationSigningString = getFixAttestationSigningString;
26
+ const zod_1 = require("zod");
27
+ const agent_deployment_js_1 = require("../agent-deployment.js");
28
+ // Reached via the same relative path `schemas.ts` already uses, not a
29
+ // self-package import of `@kya-os/contracts/proof`.
30
+ const signing_spec_js_1 = require("../proof/signing-spec.js");
31
+ exports.FixAttestationSubjectSchema = zod_1.z.object({
32
+ /**
33
+ * "owner/repo", e.g. "modelcontextprotocol-identity/xmcp-i". Constrained
34
+ * to GitHub's actual owner/repo character set (alphanumeric, hyphen,
35
+ * underscore, period) rather than a bare non-empty string: this value
36
+ * gets interpolated into a PR-comment marker
37
+ * (`buildFixAttestationCommentBody` in `@kya-os/cli`'s `dco fix`), and a
38
+ * bare `.min(1)` would let a backtick or an HTML comment-closing `-->`
39
+ * through into that markdown.
40
+ */
41
+ repo: zod_1.z.string().regex(/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?\/[A-Za-z0-9._-]+$/),
42
+ /** GitHub PR number */
43
+ prNumber: zod_1.z.number().int().positive(),
44
+ /** Full 40-character SHA, lowercase — the commit this attestation covers */
45
+ fixedHeadSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/),
46
+ });
47
+ exports.FixAttestationSchema = zod_1.z.object({
48
+ subject: exports.FixAttestationSubjectSchema,
49
+ /** Full 40-character SHA, lowercase — the reviewed head that requested changes */
50
+ respondsToHeadSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/),
51
+ /** The DIDComm fix task this attestation was dispatched for, when applicable */
52
+ taskId: zod_1.z.string().min(1).optional(),
53
+ /** did:<method>:<method-specific-id>, e.g. did:web:knowthat.ai:agents:acme-bot */
54
+ agentDid: agent_deployment_js_1.DidStringSchema,
55
+ /** Detached JWS over `getFixAttestationSigningString(subject, respondsToHeadSha)` */
56
+ proof: signing_spec_js_1.DetachedJwsSchema,
57
+ });
58
+ /**
59
+ * Field order for the fix-attestation signing input, fixed forever: changing
60
+ * it changes every existing signature. `"fix-attestation:v1"` is a version
61
+ * tag, not a subject field — bumping the scheme (e.g. adding a field) must
62
+ * bump this string too, so an old signature can never be replayed against a
63
+ * new canonicalization.
64
+ */
65
+ exports.FIX_ATTESTATION_SIGNING_ORDER = [
66
+ 'version',
67
+ 'repo',
68
+ 'prNumber',
69
+ 'fixedHeadSha',
70
+ 'respondsToHeadSha',
71
+ ];
72
+ /** A single canonicalization token: `JSON.stringify(value)`, matching canonicalize.ts's scheme. */
73
+ function canonicalToken(value) {
74
+ return JSON.stringify(value);
75
+ }
76
+ /**
77
+ * Build the canonical signing string for a fix attestation's detached JWS:
78
+ * newline-joined `"fix-attestation:v1"`, `subject.repo`, `subject.prNumber`
79
+ * (decimal), `subject.fixedHeadSha`, `respondsToHeadSha`, in that fixed
80
+ * order (`FIX_ATTESTATION_SIGNING_ORDER`). Every field is required here (no
81
+ * optional-field ambiguity to resolve, unlike `getVerdictCanonicalSigningString`'s
82
+ * findings tokens), so each token is simply `JSON.stringify(value)`.
83
+ *
84
+ * ### Worked example
85
+ *
86
+ * ```ts
87
+ * const subject: FixAttestationSubject = {
88
+ * repo: 'acme/demo',
89
+ * prNumber: 42,
90
+ * fixedHeadSha: 'a'.repeat(40),
91
+ * };
92
+ * getFixAttestationSigningString(subject, 'b'.repeat(40))
93
+ * // => '"fix-attestation:v1"\n"acme/demo"\n42\n"aaaa...aaaa"\n"bbbb...bbbb"'
94
+ * ```
95
+ */
96
+ function getFixAttestationSigningString(subject, respondsToHeadSha) {
97
+ const values = {
98
+ version: 'fix-attestation:v1',
99
+ repo: subject.repo,
100
+ prNumber: subject.prNumber,
101
+ fixedHeadSha: subject.fixedHeadSha,
102
+ respondsToHeadSha,
103
+ };
104
+ return exports.FIX_ATTESTATION_SIGNING_ORDER.map((field) => canonicalToken(values[field])).join('\n');
105
+ }