@agentproto/governance 0.1.0-alpha.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.
@@ -0,0 +1,266 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * @agentproto/governance v0.1.0-alpha
5
+ * agentgovernance/v1 — universal contractual approval framework.
6
+ * Vendor-neutral. Filesystem-first. Third-party verifiable.
7
+ */
8
+
9
+ var SIGNER_KIND = [
10
+ "operator",
11
+ "user",
12
+ "counterparty",
13
+ "agent",
14
+ "external"
15
+ ];
16
+ var signerKindSchema = z.enum(SIGNER_KIND);
17
+ var SIGNING_METHOD = [
18
+ "typed_name",
19
+ // human types name + nonce on a tokenized portal page
20
+ "agent_confirm",
21
+ // agent records explicit confirmation with model + reasoning evidence
22
+ "click_through",
23
+ // single-click confirmation from a signed URL
24
+ "esign_external"
25
+ // DocuSeal / HelloSign / etc.; signed PDF archived alongside
26
+ ];
27
+ var signingMethodSchema = z.enum(SIGNING_METHOD);
28
+ var typedNameEvidenceSchema = z.object({
29
+ kind: z.literal("typed_name"),
30
+ signerName: z.string().min(1),
31
+ ipAddress: z.string(),
32
+ userAgent: z.string(),
33
+ nonce: z.string(),
34
+ signedUrlToken: z.string().optional()
35
+ });
36
+ var agentConfirmEvidenceSchema = z.object({
37
+ kind: z.literal("agent_confirm"),
38
+ modelId: z.string(),
39
+ promptContextHash: z.string(),
40
+ reasoningSummary: z.string().optional(),
41
+ conversationTurnId: z.string().optional(),
42
+ // For agent signing under policy: which POLICY.md authorized this signature?
43
+ authorizedByPolicy: z.string().optional()
44
+ });
45
+ var clickThroughEvidenceSchema = z.object({
46
+ kind: z.literal("click_through"),
47
+ ipAddress: z.string(),
48
+ userAgent: z.string(),
49
+ signedUrlToken: z.string()
50
+ });
51
+ var esignExternalEvidenceSchema = z.object({
52
+ kind: z.literal("esign_external"),
53
+ provider: z.string(),
54
+ // e.g., "docuseal", "hellosign"
55
+ externalRef: z.string(),
56
+ // provider envelope/document id
57
+ signedPdfRef: z.string().optional()
58
+ // workspace-relative path to archived PDF
59
+ });
60
+ var evidenceSchema = z.discriminatedUnion("kind", [
61
+ typedNameEvidenceSchema,
62
+ agentConfirmEvidenceSchema,
63
+ clickThroughEvidenceSchema,
64
+ esignExternalEvidenceSchema
65
+ ]);
66
+ var sha256HexSchema = z.string().regex(/^[a-f0-9]{64}$/, {
67
+ message: "Expected lowercase hex SHA-256 (64 chars)"
68
+ });
69
+ var signerIdSchema = z.string().regex(/^(operator|user|counterparty|agent|external):[a-z0-9][a-z0-9-]*$/, {
70
+ message: "Expected '<kind>:<slug>' (slug lowercase, alphanumeric + hyphens)"
71
+ });
72
+ var signatureSchema = z.object({
73
+ schema: z.literal("agentgovernance/v1"),
74
+ doctype: z.literal("signature"),
75
+ /** Canonical "<kind>:<slug>" identifier of the signer. */
76
+ signer: signerIdSchema,
77
+ signerKind: signerKindSchema,
78
+ signerEmail: z.email().optional(),
79
+ /**
80
+ * Workspace-relative path to the artifact being signed (e.g.,
81
+ * `engagements/2026-acme/AGREEMENT.md`). Allows verifiers to locate the
82
+ * artifact without relying on file-system layout heuristics.
83
+ */
84
+ artifactPath: z.string().min(1),
85
+ /** SHA-256 of the artifact bytes at signing time. */
86
+ documentHash: sha256HexSchema,
87
+ method: signingMethodSchema,
88
+ evidence: evidenceSchema,
89
+ signedAt: z.iso.datetime(),
90
+ /** Revocation: append-only field set on a subsequent rewrite. */
91
+ revokedAt: z.iso.datetime().optional(),
92
+ revokedReason: z.string().optional(),
93
+ /** Vendor-specific extensions allowed under metadata.<vendor>.* */
94
+ metadata: z.record(z.string(), z.unknown()).optional()
95
+ }).refine((sig) => sig.method === sig.evidence.kind, {
96
+ message: "evidence.kind must match top-level method"
97
+ });
98
+ function signatureFilename(signer, signedAt) {
99
+ const slug = signer.replace(/:/g, "-");
100
+ const date = signedAt.split("T")[0] ?? signedAt;
101
+ return `${slug}-${date}.signature.json`;
102
+ }
103
+ var ACTOR_KIND = [
104
+ "operator",
105
+ "user",
106
+ "counterparty",
107
+ "agent",
108
+ "system"
109
+ ];
110
+ var actorKindSchema = z.enum(ACTOR_KIND);
111
+ var sha256HexSchema2 = z.string().regex(/^[a-f0-9]{64}$/, {
112
+ message: "Expected lowercase hex SHA-256 (64 chars)"
113
+ });
114
+ var KNOWN_ENTITY_TYPES = [
115
+ // governance-native
116
+ "signature",
117
+ "audit-event",
118
+ "policy",
119
+ "approval",
120
+ // agency entities (when agentagencies/v1 is in use; not normative here)
121
+ "engagement",
122
+ "agreement",
123
+ "deliverable",
124
+ "invoice",
125
+ "service",
126
+ "counterparty",
127
+ "routine",
128
+ "procedure",
129
+ // other extensions
130
+ "task",
131
+ "project",
132
+ "company",
133
+ "agent"
134
+ ];
135
+ var auditEventSchema = z.object({
136
+ schema: z.literal("agentgovernance/v1"),
137
+ doctype: z.literal("audit-event"),
138
+ /** Who performed the action. */
139
+ actorKind: actorKindSchema,
140
+ /** Slug or canonical id; null for actorKind=system. */
141
+ actorId: z.string().nullable(),
142
+ /**
143
+ * Free-form entity type. Implementations SHOULD use a known value from
144
+ * KNOWN_ENTITY_TYPES; SHOULD NOT introduce new types ad-hoc.
145
+ */
146
+ entityType: z.string(),
147
+ /**
148
+ * Workspace-relative path to the entity (preferred) or a governance-internal
149
+ * id when the entity has no file. Examples:
150
+ * engagements/2026-acme-website-redesign/AGREEMENT.md
151
+ * policies/invoice-cap-500eur/POLICY.md
152
+ * gov:approval:<idempotencyKey>
153
+ */
154
+ entityId: z.string().min(1),
155
+ /**
156
+ * Action verb in `<entity>.<verb>` form. Examples:
157
+ * signature.created
158
+ * signature.revoked
159
+ * approval.requested
160
+ * approval.granted
161
+ * engagement.status_changed
162
+ * invoice.issued
163
+ */
164
+ action: z.string().regex(/^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/, {
165
+ message: "Expected '<entity>.<verb>' lowercase"
166
+ }),
167
+ /** Action-specific payload. Vendor extensions allowed under payload.<vendor>.* */
168
+ payload: z.record(z.string(), z.unknown()).optional(),
169
+ /** Hash chain: previous line's `signature` (or workspace genesis seed for first line). */
170
+ prevSignature: sha256HexSchema2,
171
+ /** Hash chain: HMAC-SHA256(secret, prevSignature ‖ canonicalBytes(this row sans `signature`)). */
172
+ signature: sha256HexSchema2,
173
+ /** Optional correlation ids for distributed tracing. */
174
+ requestId: z.string().optional(),
175
+ traceId: z.string().optional(),
176
+ /** Optional human-actor evidence. */
177
+ ipAddress: z.string().optional(),
178
+ userAgent: z.string().optional(),
179
+ /** ISO-8601 timestamp; UTC strongly recommended. */
180
+ createdAt: z.iso.datetime(),
181
+ /** Vendor-specific extensions allowed under metadata.<vendor>.* */
182
+ metadata: z.record(z.string(), z.unknown()).optional()
183
+ });
184
+ function parseAuditLine(line) {
185
+ return auditEventSchema.parse(JSON.parse(line));
186
+ }
187
+ var policyAppliesToSchema = z.object({
188
+ /** Restrict by actor kind (e.g., only operators, only agents). */
189
+ actorKind: actorKindSchema.optional(),
190
+ /** Restrict to a specific actor slug. */
191
+ actorId: z.string().optional(),
192
+ /** Restrict to a team. */
193
+ teamId: z.string().optional(),
194
+ /**
195
+ * Restrict to an action type, e.g., `agency.issue_invoice`,
196
+ * `agency.send_agreement`, `governance.policy_override`.
197
+ */
198
+ actionType: z.string().optional()
199
+ });
200
+ var policyCapSchema = z.object({
201
+ field: z.string(),
202
+ // e.g., "amount"
203
+ max: z.number().optional(),
204
+ min: z.number().optional(),
205
+ currency: z.string().length(3).optional()
206
+ // ISO 4217 (e.g., "EUR")
207
+ });
208
+ var POLICY_THRESHOLD = [
209
+ "auto",
210
+ // tool may proceed without signatures (logged)
211
+ "single",
212
+ // any one of requiredSignatures suffices
213
+ "all_of",
214
+ // every requiredSignatures entry must sign
215
+ "any_of",
216
+ // any one of requiredSignatures suffices (alias of single, kept for clarity)
217
+ "weighted_threshold"
218
+ // sum of weights of collected signatures must reach requiredWeight
219
+ ];
220
+ var policyThresholdSchema = z.enum(POLICY_THRESHOLD);
221
+ var requiredSignerSchema = z.object({
222
+ /** Canonical "<kind>:<slug>"; or "<kind>:*" to mean "any signer of this kind". */
223
+ signer: z.string().regex(
224
+ /^(operator|user|counterparty|agent|external):([a-z0-9][a-z0-9-]*|\*)$/,
225
+ {
226
+ message: "Expected '<kind>:<slug>' or '<kind>:*'"
227
+ }
228
+ ),
229
+ method: signingMethodSchema,
230
+ /** For weighted_threshold; ignored otherwise. */
231
+ weight: z.number().min(0).optional()
232
+ });
233
+ var policyEscalationSchema = z.object({
234
+ /** ISO-8601 duration; how long before deadline to escalate. */
235
+ leadTime: z.string().regex(/^P/, { message: "Expected ISO-8601 duration starting with 'P'" }),
236
+ /** Canonical signer ids who get escalated to. */
237
+ escalateTo: z.array(z.string()).min(1)
238
+ });
239
+ var policyFrontmatterSchema = z.object({
240
+ schema: z.literal("agentgovernance/v1"),
241
+ doctype: z.literal("policy"),
242
+ slug: z.string().regex(/^[a-z0-9][a-z0-9-]*$/, { message: "Expected lowercase slug" }),
243
+ name: z.string().min(1),
244
+ description: z.string().optional(),
245
+ appliesTo: z.array(policyAppliesToSchema).default([]),
246
+ caps: z.array(policyCapSchema).default([]),
247
+ threshold: policyThresholdSchema.default("single"),
248
+ /** Required when threshold === "weighted_threshold"; sum of collected signature weights must >= this. */
249
+ requiredWeight: z.number().min(0).optional(),
250
+ requiredSignatures: z.array(requiredSignerSchema).default([]),
251
+ /** ISO-8601 duration. The whole signature-collection process must complete within this. */
252
+ deadline: z.string().regex(/^P/).optional(),
253
+ escalation: policyEscalationSchema.optional(),
254
+ /** Vendor extensions under metadata.<vendor>.* */
255
+ metadata: z.record(z.string(), z.unknown()).optional()
256
+ }).refine(
257
+ (p) => p.threshold !== "weighted_threshold" || typeof p.requiredWeight === "number",
258
+ { message: "threshold='weighted_threshold' requires requiredWeight" }
259
+ );
260
+ function policyDirname(slug) {
261
+ return `policies/${slug}`;
262
+ }
263
+
264
+ export { ACTOR_KIND, KNOWN_ENTITY_TYPES, POLICY_THRESHOLD, SIGNER_KIND, SIGNING_METHOD, actorKindSchema, auditEventSchema, evidenceSchema, parseAuditLine, policyAppliesToSchema, policyCapSchema, policyDirname, policyEscalationSchema, policyFrontmatterSchema, policyThresholdSchema, requiredSignerSchema, signatureFilename, signatureSchema, signerKindSchema, signingMethodSchema };
265
+ //# sourceMappingURL=chunk-J2DX2WOA.mjs.map
266
+ //# sourceMappingURL=chunk-J2DX2WOA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spec/doctypes/signature.ts","../src/spec/doctypes/audit-event.ts","../src/spec/doctypes/policy.ts"],"names":["z","sha256HexSchema"],"mappings":";;;;;;;;AAcO,IAAM,WAAA,GAAc;AAAA,EACzB,UAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF;AACO,IAAM,gBAAA,GAAmB,CAAA,CAAE,IAAA,CAAK,WAAW;AAG3C,IAAM,cAAA,GAAiB;AAAA,EAC5B,YAAA;AAAA;AAAA,EACA,eAAA;AAAA;AAAA,EACA,eAAA;AAAA;AAAA,EACA;AAAA;AACF;AACO,IAAM,mBAAA,GAAsB,CAAA,CAAE,IAAA,CAAK,cAAc;AAIxD,IAAM,uBAAA,GAA0B,EAAE,MAAA,CAAO;AAAA,EACvC,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,YAAY,CAAA;AAAA,EAC5B,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC5B,SAAA,EAAW,EAAE,MAAA,EAAO;AAAA,EACpB,SAAA,EAAW,EAAE,MAAA,EAAO;AAAA,EACpB,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,EAChB,cAAA,EAAgB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAC7B,CAAC,CAAA;AAED,IAAM,0BAAA,GAA6B,EAAE,MAAA,CAAO;AAAA,EAC1C,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,eAAe,CAAA;AAAA,EAC/B,OAAA,EAAS,EAAE,MAAA,EAAO;AAAA,EAClB,iBAAA,EAAmB,EAAE,MAAA,EAAO;AAAA,EAC5B,gBAAA,EAAkB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACtC,kBAAA,EAAoB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAExC,kBAAA,EAAoB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACjC,CAAC,CAAA;AAED,IAAM,0BAAA,GAA6B,EAAE,MAAA,CAAO;AAAA,EAC1C,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,eAAe,CAAA;AAAA,EAC/B,SAAA,EAAW,EAAE,MAAA,EAAO;AAAA,EACpB,SAAA,EAAW,EAAE,MAAA,EAAO;AAAA,EACpB,cAAA,EAAgB,EAAE,MAAA;AACpB,CAAC,CAAA;AAED,IAAM,2BAAA,GAA8B,EAAE,MAAA,CAAO;AAAA,EAC3C,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,gBAAgB,CAAA;AAAA,EAChC,QAAA,EAAU,EAAE,MAAA,EAAO;AAAA;AAAA,EACnB,WAAA,EAAa,EAAE,MAAA,EAAO;AAAA;AAAA,EACtB,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS;AACpC,CAAC,CAAA;AAEM,IAAM,cAAA,GAAiB,CAAA,CAAE,kBAAA,CAAmB,MAAA,EAAQ;AAAA,EACzD,uBAAA;AAAA,EACA,0BAAA;AAAA,EACA,0BAAA;AAAA,EACA;AACF,CAAC;AAID,IAAM,eAAA,GAAkB,CAAA,CAAE,MAAA,EAAO,CAAE,MAAM,gBAAA,EAAkB;AAAA,EACzD,OAAA,EAAS;AACX,CAAC,CAAA;AAYD,IAAM,cAAA,GAAiB,CAAA,CACpB,MAAA,EAAO,CACP,MAAM,kEAAA,EAAoE;AAAA,EACzE,OAAA,EACE;AACJ,CAAC,CAAA;AAEI,IAAM,eAAA,GAAkB,EAC5B,MAAA,CAAO;AAAA,EACN,MAAA,EAAQ,CAAA,CAAE,OAAA,CAAQ,oBAAoB,CAAA;AAAA,EACtC,OAAA,EAAS,CAAA,CAAE,OAAA,CAAQ,WAAW,CAAA;AAAA;AAAA,EAG9B,MAAA,EAAQ,cAAA;AAAA,EACR,UAAA,EAAY,gBAAA;AAAA,EACZ,WAAA,EAAa,CAAA,CAAE,KAAA,EAAM,CAAE,QAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhC,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA;AAAA,EAG9B,YAAA,EAAc,eAAA;AAAA,EAEd,MAAA,EAAQ,mBAAA;AAAA,EACR,QAAA,EAAU,cAAA;AAAA,EAEV,QAAA,EAAU,CAAA,CAAE,GAAA,CAAI,QAAA,EAAS;AAAA;AAAA,EAGzB,SAAA,EAAW,CAAA,CAAE,GAAA,CAAI,QAAA,GAAW,QAAA,EAAS;AAAA,EACrC,aAAA,EAAe,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAGnC,QAAA,EAAU,CAAA,CAAE,MAAA,CAAO,CAAA,CAAE,MAAA,IAAU,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA;AAC9C,CAAC,EACA,MAAA,CAAO,CAAA,GAAA,KAAO,IAAI,MAAA,KAAW,GAAA,CAAI,SAAS,IAAA,EAAM;AAAA,EAC/C,OAAA,EAAS;AACX,CAAC;AAKI,SAAS,iBAAA,CAAkB,QAAgB,QAAA,EAA0B;AAC1E,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA;AACrC,EAAA,MAAM,OAAO,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,QAAA;AACvC,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,eAAA,CAAA;AACxB;ACzHO,IAAM,UAAA,GAAa;AAAA,EACxB,UAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF;AACO,IAAM,eAAA,GAAkBA,CAAAA,CAAE,IAAA,CAAK,UAAU;AAGhD,IAAMC,gBAAAA,GAAkBD,CAAAA,CAAE,MAAA,EAAO,CAAE,MAAM,gBAAA,EAAkB;AAAA,EACzD,OAAA,EAAS;AACX,CAAC,CAAA;AAGM,IAAM,kBAAA,GAAqB;AAAA;AAAA,EAEhC,WAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA;AAAA,EAEA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA;AAAA,EAEA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF;AAEO,IAAM,gBAAA,GAAmBA,EAAE,MAAA,CAAO;AAAA,EACvC,MAAA,EAAQA,CAAAA,CAAE,OAAA,CAAQ,oBAAoB,CAAA;AAAA,EACtC,OAAA,EAASA,CAAAA,CAAE,OAAA,CAAQ,aAAa,CAAA;AAAA;AAAA,EAGhC,SAAA,EAAW,eAAA;AAAA;AAAA,EAEX,OAAA,EAASA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7B,UAAA,EAAYA,EAAE,MAAA,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrB,QAAA,EAAUA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW1B,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,MAAM,oCAAA,EAAsC;AAAA,IAC7D,OAAA,EAAS;AAAA,GACV,CAAA;AAAA;AAAA,EAGD,OAAA,EAASA,CAAAA,CAAE,MAAA,CAAOA,CAAAA,CAAE,MAAA,IAAUA,CAAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,EAAS;AAAA;AAAA,EAGpD,aAAA,EAAeC,gBAAAA;AAAA;AAAA,EAEf,SAAA,EAAWA,gBAAAA;AAAA;AAAA,EAGX,SAAA,EAAWD,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,OAAA,EAASA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAG7B,SAAA,EAAWA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,SAAA,EAAWA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAG/B,SAAA,EAAWA,CAAAA,CAAE,GAAA,CAAI,QAAA,EAAS;AAAA;AAAA,EAG1B,QAAA,EAAUA,CAAAA,CAAE,MAAA,CAAOA,CAAAA,CAAE,MAAA,IAAUA,CAAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA;AAC9C,CAAC;AAKM,SAAS,eAAe,IAAA,EAA0B;AACvD,EAAA,OAAO,gBAAA,CAAiB,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAA;AAChD;ACjFO,IAAM,qBAAA,GAAwBA,EAAE,MAAA,CAAO;AAAA;AAAA,EAE5C,SAAA,EAAW,gBAAgB,QAAA,EAAS;AAAA;AAAA,EAEpC,OAAA,EAASA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAE7B,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAK5B,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACzB,CAAC;AAGM,IAAM,eAAA,GAAkBA,EAAE,MAAA,CAAO;AAAA,EACtC,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA;AAAA,EAChB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,UAAUA,CAAAA,CAAE,MAAA,GAAS,MAAA,CAAO,CAAC,EAAE,QAAA;AAAS;AAC1C,CAAC;AAIM,IAAM,gBAAA,GAAmB;AAAA,EAC9B,MAAA;AAAA;AAAA,EACA,QAAA;AAAA;AAAA,EACA,QAAA;AAAA;AAAA,EACA,QAAA;AAAA;AAAA,EACA;AAAA;AACF;AACO,IAAM,qBAAA,GAAwBA,CAAAA,CAAE,IAAA,CAAK,gBAAgB;AAGrD,IAAM,oBAAA,GAAuBA,EAAE,MAAA,CAAO;AAAA;AAAA,EAE3C,MAAA,EAAQA,CAAAA,CACL,MAAA,EAAO,CACP,KAAA;AAAA,IACC,uEAAA;AAAA,IACA;AAAA,MACE,OAAA,EAAS;AAAA;AACX,GACF;AAAA,EACF,MAAA,EAAQ,mBAAA;AAAA;AAAA,EAER,QAAQA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA;AAC5B,CAAC;AAGM,IAAM,sBAAA,GAAyBA,EAAE,MAAA,CAAO;AAAA;AAAA,EAE7C,QAAA,EAAUA,EACP,MAAA,EAAO,CACP,MAAM,IAAA,EAAM,EAAE,OAAA,EAAS,8CAAA,EAAgD,CAAA;AAAA;AAAA,EAE1E,UAAA,EAAYA,EAAE,KAAA,CAAMA,CAAAA,CAAE,QAAQ,CAAA,CAAE,IAAI,CAAC;AACvC,CAAC;AAGM,IAAM,uBAAA,GAA0BA,EACpC,MAAA,CAAO;AAAA,EACN,MAAA,EAAQA,CAAAA,CAAE,OAAA,CAAQ,oBAAoB,CAAA;AAAA,EACtC,OAAA,EAASA,CAAAA,CAAE,OAAA,CAAQ,QAAQ,CAAA;AAAA,EAC3B,IAAA,EAAMA,EACH,MAAA,EAAO,CACP,MAAM,sBAAA,EAAwB,EAAE,OAAA,EAAS,yBAAA,EAA2B,CAAA;AAAA,EACvE,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACtB,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAEjC,WAAWA,CAAAA,CAAE,KAAA,CAAM,qBAAqB,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACpD,MAAMA,CAAAA,CAAE,KAAA,CAAM,eAAe,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACzC,SAAA,EAAW,qBAAA,CAAsB,OAAA,CAAQ,QAAQ,CAAA;AAAA;AAAA,EAEjD,gBAAgBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC3C,oBAAoBA,CAAAA,CAAE,KAAA,CAAM,oBAAoB,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA;AAAA,EAG5D,UAAUA,CAAAA,CAAE,MAAA,GAAS,KAAA,CAAM,IAAI,EAAE,QAAA,EAAS;AAAA,EAC1C,UAAA,EAAY,uBAAuB,QAAA,EAAS;AAAA;AAAA,EAG5C,QAAA,EAAUA,CAAAA,CAAE,MAAA,CAAOA,CAAAA,CAAE,MAAA,IAAUA,CAAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA;AAC9C,CAAC,CAAA,CACA,MAAA;AAAA,EACC,OACE,CAAA,CAAE,SAAA,KAAc,oBAAA,IAChB,OAAO,EAAE,cAAA,KAAmB,QAAA;AAAA,EAC9B,EAAE,SAAS,wDAAA;AACb;AAcK,SAAS,cAAc,IAAA,EAAsB;AAClD,EAAA,OAAO,YAAY,IAAI,CAAA,CAAA;AACzB","file":"chunk-J2DX2WOA.mjs","sourcesContent":["import { z } from \"zod\"\n\n/**\n * agentgovernance/v1 — `signature.json` doctype.\n *\n * Universal approval primitive. Every approval — of an agreement, deliverable,\n * invoice, policy override, agent-issued action, etc. — is a signature on an\n * artifact, recorded as a `<artifact-path>/../signatures/<signer>-<isoDate>.signature.json`\n * file alongside the artifact being signed.\n *\n * One file = one signature event. Signatures are append-only; revocation\n * writes a new file (or updates `revokedAt` if same signer re-issues).\n */\n\nexport const SIGNER_KIND = [\n \"operator\",\n \"user\",\n \"counterparty\",\n \"agent\",\n \"external\",\n] as const\nexport const signerKindSchema = z.enum(SIGNER_KIND)\nexport type SignerKind = z.infer<typeof signerKindSchema>\n\nexport const SIGNING_METHOD = [\n \"typed_name\", // human types name + nonce on a tokenized portal page\n \"agent_confirm\", // agent records explicit confirmation with model + reasoning evidence\n \"click_through\", // single-click confirmation from a signed URL\n \"esign_external\", // DocuSeal / HelloSign / etc.; signed PDF archived alongside\n] as const\nexport const signingMethodSchema = z.enum(SIGNING_METHOD)\nexport type SigningMethod = z.infer<typeof signingMethodSchema>\n\n/** Evidence shapes per method. Must be consistent with top-level `method`. */\nconst typedNameEvidenceSchema = z.object({\n kind: z.literal(\"typed_name\"),\n signerName: z.string().min(1),\n ipAddress: z.string(),\n userAgent: z.string(),\n nonce: z.string(),\n signedUrlToken: z.string().optional(),\n})\n\nconst agentConfirmEvidenceSchema = z.object({\n kind: z.literal(\"agent_confirm\"),\n modelId: z.string(),\n promptContextHash: z.string(),\n reasoningSummary: z.string().optional(),\n conversationTurnId: z.string().optional(),\n // For agent signing under policy: which POLICY.md authorized this signature?\n authorizedByPolicy: z.string().optional(),\n})\n\nconst clickThroughEvidenceSchema = z.object({\n kind: z.literal(\"click_through\"),\n ipAddress: z.string(),\n userAgent: z.string(),\n signedUrlToken: z.string(),\n})\n\nconst esignExternalEvidenceSchema = z.object({\n kind: z.literal(\"esign_external\"),\n provider: z.string(), // e.g., \"docuseal\", \"hellosign\"\n externalRef: z.string(), // provider envelope/document id\n signedPdfRef: z.string().optional(), // workspace-relative path to archived PDF\n})\n\nexport const evidenceSchema = z.discriminatedUnion(\"kind\", [\n typedNameEvidenceSchema,\n agentConfirmEvidenceSchema,\n clickThroughEvidenceSchema,\n esignExternalEvidenceSchema,\n])\nexport type SignatureEvidence = z.infer<typeof evidenceSchema>\n\n/** SHA-256 hex string (64 chars). */\nconst sha256HexSchema = z.string().regex(/^[a-f0-9]{64}$/, {\n message: \"Expected lowercase hex SHA-256 (64 chars)\",\n})\n\n/**\n * Signer identifier in canonical form `<kind>:<slug>`.\n *\n * Examples:\n * operator:jeremy\n * counterparty:acme-corp\n * agent:ai-paralegal\n * user:6f9e3a12\n * external:contractor-bob\n */\nconst signerIdSchema = z\n .string()\n .regex(/^(operator|user|counterparty|agent|external):[a-z0-9][a-z0-9-]*$/, {\n message:\n \"Expected '<kind>:<slug>' (slug lowercase, alphanumeric + hyphens)\",\n })\n\nexport const signatureSchema = z\n .object({\n schema: z.literal(\"agentgovernance/v1\"),\n doctype: z.literal(\"signature\"),\n\n /** Canonical \"<kind>:<slug>\" identifier of the signer. */\n signer: signerIdSchema,\n signerKind: signerKindSchema,\n signerEmail: z.email().optional(),\n\n /**\n * Workspace-relative path to the artifact being signed (e.g.,\n * `engagements/2026-acme/AGREEMENT.md`). Allows verifiers to locate the\n * artifact without relying on file-system layout heuristics.\n */\n artifactPath: z.string().min(1),\n\n /** SHA-256 of the artifact bytes at signing time. */\n documentHash: sha256HexSchema,\n\n method: signingMethodSchema,\n evidence: evidenceSchema,\n\n signedAt: z.iso.datetime(),\n\n /** Revocation: append-only field set on a subsequent rewrite. */\n revokedAt: z.iso.datetime().optional(),\n revokedReason: z.string().optional(),\n\n /** Vendor-specific extensions allowed under metadata.<vendor>.* */\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .refine(sig => sig.method === sig.evidence.kind, {\n message: \"evidence.kind must match top-level method\",\n })\n\nexport type Signature = z.infer<typeof signatureSchema>\n\n/** Filename helper: `<signer-kind>-<signer-slug>-<isoDate>.signature.json` */\nexport function signatureFilename(signer: string, signedAt: string): string {\n const slug = signer.replace(/:/g, \"-\")\n const date = signedAt.split(\"T\")[0] ?? signedAt\n return `${slug}-${date}.signature.json`\n}\n","import { z } from \"zod\"\n\n/**\n * agentgovernance/v1 — audit-log.jsonl line doctype.\n *\n * Each line of `<scope>/audit/audit-log.jsonl` is one audit event, encoded as\n * a single JSON object on one line (no embedded newlines).\n *\n * Scope is whatever folder hosts the log: per-engagement\n * (`engagements/<slug>/audit/audit-log.jsonl`) or per-workspace/guild\n * (`audit/audit-log.jsonl` for cross-engagement events).\n *\n * Hash chain protocol:\n * signature_n = HMAC-SHA256(secret, signature_{n-1} ‖ canonical(row_n))\n *\n * The first line's `prevSignature` is the workspace genesis seed (vault-backed).\n * See `../hash-chain/protocol.md` for the canonical-bytes specification.\n */\n\nexport const ACTOR_KIND = [\n \"operator\",\n \"user\",\n \"counterparty\",\n \"agent\",\n \"system\",\n] as const\nexport const actorKindSchema = z.enum(ACTOR_KIND)\nexport type ActorKind = z.infer<typeof actorKindSchema>\n\nconst sha256HexSchema = z.string().regex(/^[a-f0-9]{64}$/, {\n message: \"Expected lowercase hex SHA-256 (64 chars)\",\n})\n\n/** Common entity types. Apps may extend via metadata or contributing entries. */\nexport const KNOWN_ENTITY_TYPES = [\n // governance-native\n \"signature\",\n \"audit-event\",\n \"policy\",\n \"approval\",\n // agency entities (when agentagencies/v1 is in use; not normative here)\n \"engagement\",\n \"agreement\",\n \"deliverable\",\n \"invoice\",\n \"service\",\n \"counterparty\",\n \"routine\",\n \"procedure\",\n // other extensions\n \"task\",\n \"project\",\n \"company\",\n \"agent\",\n] as const\n\nexport const auditEventSchema = z.object({\n schema: z.literal(\"agentgovernance/v1\"),\n doctype: z.literal(\"audit-event\"),\n\n /** Who performed the action. */\n actorKind: actorKindSchema,\n /** Slug or canonical id; null for actorKind=system. */\n actorId: z.string().nullable(),\n\n /**\n * Free-form entity type. Implementations SHOULD use a known value from\n * KNOWN_ENTITY_TYPES; SHOULD NOT introduce new types ad-hoc.\n */\n entityType: z.string(),\n\n /**\n * Workspace-relative path to the entity (preferred) or a governance-internal\n * id when the entity has no file. Examples:\n * engagements/2026-acme-website-redesign/AGREEMENT.md\n * policies/invoice-cap-500eur/POLICY.md\n * gov:approval:<idempotencyKey>\n */\n entityId: z.string().min(1),\n\n /**\n * Action verb in `<entity>.<verb>` form. Examples:\n * signature.created\n * signature.revoked\n * approval.requested\n * approval.granted\n * engagement.status_changed\n * invoice.issued\n */\n action: z.string().regex(/^[a-z][a-z0-9_]*\\.[a-z][a-z0-9_]*$/, {\n message: \"Expected '<entity>.<verb>' lowercase\",\n }),\n\n /** Action-specific payload. Vendor extensions allowed under payload.<vendor>.* */\n payload: z.record(z.string(), z.unknown()).optional(),\n\n /** Hash chain: previous line's `signature` (or workspace genesis seed for first line). */\n prevSignature: sha256HexSchema,\n /** Hash chain: HMAC-SHA256(secret, prevSignature ‖ canonicalBytes(this row sans `signature`)). */\n signature: sha256HexSchema,\n\n /** Optional correlation ids for distributed tracing. */\n requestId: z.string().optional(),\n traceId: z.string().optional(),\n\n /** Optional human-actor evidence. */\n ipAddress: z.string().optional(),\n userAgent: z.string().optional(),\n\n /** ISO-8601 timestamp; UTC strongly recommended. */\n createdAt: z.iso.datetime(),\n\n /** Vendor-specific extensions allowed under metadata.<vendor>.* */\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport type AuditEvent = z.infer<typeof auditEventSchema>\n\n/** Convenience: parse a single JSONL line. Returns parsed event or throws. */\nexport function parseAuditLine(line: string): AuditEvent {\n return auditEventSchema.parse(JSON.parse(line))\n}\n","import { z } from \"zod\"\nimport { signingMethodSchema } from \"./signature.js\"\nimport { actorKindSchema } from \"./audit-event.js\"\n\n/**\n * agentgovernance/v1 — POLICY.md doctype.\n *\n * Declarative autonomy rule. Frontmatter declares scope (who/what the policy\n * applies to), constraints (caps, thresholds), and what's required when those\n * thresholds are exceeded (signatures, escalation). Body is human-readable\n * narrative + edge cases.\n *\n * File location: `<scope>/policies/<slug>/POLICY.md` (e.g.,\n * `policies/invoice-cap-500eur/POLICY.md`).\n *\n * Example frontmatter:\n *\n * ```yaml\n * schema: agentgovernance/v1\n * doctype: policy\n * slug: invoice-cap-500eur\n * name: Invoice cap 500 EUR\n * appliesTo:\n * - actorKind: operator\n * actionType: agency.issue_invoice\n * caps:\n * - field: amount\n * max: 500\n * currency: EUR\n * threshold: single\n * requiredSignatures:\n * - signer: operator:founder\n * method: typed_name\n * deadline: PT24H\n * escalation:\n * leadTime: PT2H\n * escalateTo: [operator:cofounder]\n * ```\n */\n\nexport const policyAppliesToSchema = z.object({\n /** Restrict by actor kind (e.g., only operators, only agents). */\n actorKind: actorKindSchema.optional(),\n /** Restrict to a specific actor slug. */\n actorId: z.string().optional(),\n /** Restrict to a team. */\n teamId: z.string().optional(),\n /**\n * Restrict to an action type, e.g., `agency.issue_invoice`,\n * `agency.send_agreement`, `governance.policy_override`.\n */\n actionType: z.string().optional(),\n})\nexport type PolicyAppliesTo = z.infer<typeof policyAppliesToSchema>\n\nexport const policyCapSchema = z.object({\n field: z.string(), // e.g., \"amount\"\n max: z.number().optional(),\n min: z.number().optional(),\n currency: z.string().length(3).optional(), // ISO 4217 (e.g., \"EUR\")\n})\nexport type PolicyCap = z.infer<typeof policyCapSchema>\n\n/** How collected signatures are evaluated. */\nexport const POLICY_THRESHOLD = [\n \"auto\", // tool may proceed without signatures (logged)\n \"single\", // any one of requiredSignatures suffices\n \"all_of\", // every requiredSignatures entry must sign\n \"any_of\", // any one of requiredSignatures suffices (alias of single, kept for clarity)\n \"weighted_threshold\", // sum of weights of collected signatures must reach requiredWeight\n] as const\nexport const policyThresholdSchema = z.enum(POLICY_THRESHOLD)\nexport type PolicyThreshold = z.infer<typeof policyThresholdSchema>\n\nexport const requiredSignerSchema = z.object({\n /** Canonical \"<kind>:<slug>\"; or \"<kind>:*\" to mean \"any signer of this kind\". */\n signer: z\n .string()\n .regex(\n /^(operator|user|counterparty|agent|external):([a-z0-9][a-z0-9-]*|\\*)$/,\n {\n message: \"Expected '<kind>:<slug>' or '<kind>:*'\",\n }\n ),\n method: signingMethodSchema,\n /** For weighted_threshold; ignored otherwise. */\n weight: z.number().min(0).optional(),\n})\nexport type RequiredSigner = z.infer<typeof requiredSignerSchema>\n\nexport const policyEscalationSchema = z.object({\n /** ISO-8601 duration; how long before deadline to escalate. */\n leadTime: z\n .string()\n .regex(/^P/, { message: \"Expected ISO-8601 duration starting with 'P'\" }),\n /** Canonical signer ids who get escalated to. */\n escalateTo: z.array(z.string()).min(1),\n})\nexport type PolicyEscalation = z.infer<typeof policyEscalationSchema>\n\nexport const policyFrontmatterSchema = z\n .object({\n schema: z.literal(\"agentgovernance/v1\"),\n doctype: z.literal(\"policy\"),\n slug: z\n .string()\n .regex(/^[a-z0-9][a-z0-9-]*$/, { message: \"Expected lowercase slug\" }),\n name: z.string().min(1),\n description: z.string().optional(),\n\n appliesTo: z.array(policyAppliesToSchema).default([]),\n caps: z.array(policyCapSchema).default([]),\n threshold: policyThresholdSchema.default(\"single\"),\n /** Required when threshold === \"weighted_threshold\"; sum of collected signature weights must >= this. */\n requiredWeight: z.number().min(0).optional(),\n requiredSignatures: z.array(requiredSignerSchema).default([]),\n\n /** ISO-8601 duration. The whole signature-collection process must complete within this. */\n deadline: z.string().regex(/^P/).optional(),\n escalation: policyEscalationSchema.optional(),\n\n /** Vendor extensions under metadata.<vendor>.* */\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .refine(\n p =>\n p.threshold !== \"weighted_threshold\" ||\n typeof p.requiredWeight === \"number\",\n { message: \"threshold='weighted_threshold' requires requiredWeight\" }\n )\nexport type PolicyFrontmatter = z.infer<typeof policyFrontmatterSchema>\n\n/**\n * Parsed POLICY.md = frontmatter + markdown body.\n * The body is informational (humans + agents can read it); it is NOT used by\n * the policy engine for decisions.\n */\nexport interface Policy {\n frontmatter: PolicyFrontmatter\n body: string\n}\n\n/** Convenience filename helper. */\nexport function policyDirname(slug: string): string {\n return `policies/${slug}`\n}\n"]}
@@ -0,0 +1,137 @@
1
+ import { verifyChain } from './chunk-VWEBMWO2.mjs';
2
+ import { signatureSchema, auditEventSchema, policyFrontmatterSchema } from './chunk-J2DX2WOA.mjs';
3
+ import matter from 'gray-matter';
4
+
5
+ /**
6
+ * @agentproto/governance v0.1.0-alpha
7
+ * agentgovernance/v1 — universal contractual approval framework.
8
+ * Vendor-neutral. Filesystem-first. Third-party verifiable.
9
+ */
10
+ function fromZodError(err2) {
11
+ return err2.issues.map((issue) => ({
12
+ path: issue.path.map((p) => String(p)),
13
+ message: issue.message,
14
+ code: issue.code
15
+ }));
16
+ }
17
+ function err(message, code, path = []) {
18
+ return [{ path, message, code }];
19
+ }
20
+ function validateSignature(json) {
21
+ let parsed;
22
+ try {
23
+ parsed = JSON.parse(json);
24
+ } catch (e) {
25
+ return {
26
+ ok: false,
27
+ errors: err(`JSON parse error: ${e.message}`, "parse_error"),
28
+ warnings: []
29
+ };
30
+ }
31
+ const result = signatureSchema.safeParse(parsed);
32
+ if (!result.success) {
33
+ return { ok: false, errors: fromZodError(result.error), warnings: [] };
34
+ }
35
+ return { ok: true, value: result.data, warnings: [] };
36
+ }
37
+ function validateAuditEvent(line) {
38
+ const trimmed = line.trim();
39
+ if (trimmed.length === 0) {
40
+ return {
41
+ ok: false,
42
+ errors: err("Empty line", "parse_error"),
43
+ warnings: []
44
+ };
45
+ }
46
+ let parsed;
47
+ try {
48
+ parsed = JSON.parse(trimmed);
49
+ } catch (e) {
50
+ return {
51
+ ok: false,
52
+ errors: err(`JSON parse error: ${e.message}`, "parse_error"),
53
+ warnings: []
54
+ };
55
+ }
56
+ const result = auditEventSchema.safeParse(parsed);
57
+ if (!result.success) {
58
+ return { ok: false, errors: fromZodError(result.error), warnings: [] };
59
+ }
60
+ return { ok: true, value: result.data, warnings: [] };
61
+ }
62
+ function validatePolicy(markdown) {
63
+ let parsed;
64
+ try {
65
+ parsed = matter(markdown);
66
+ } catch (e) {
67
+ return {
68
+ ok: false,
69
+ errors: err(
70
+ `Frontmatter parse error: ${e.message}`,
71
+ "parse_error"
72
+ ),
73
+ warnings: []
74
+ };
75
+ }
76
+ const fmResult = policyFrontmatterSchema.safeParse(parsed.data);
77
+ if (!fmResult.success) {
78
+ return {
79
+ ok: false,
80
+ errors: fromZodError(fmResult.error).map((e) => ({
81
+ ...e,
82
+ path: ["frontmatter", ...e.path]
83
+ })),
84
+ warnings: []
85
+ };
86
+ }
87
+ return {
88
+ ok: true,
89
+ value: { frontmatter: fmResult.data, body: parsed.content },
90
+ warnings: []
91
+ };
92
+ }
93
+ function validateAuditLog(jsonl, opts) {
94
+ const lines = jsonl.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
95
+ const events = [];
96
+ const errors = [];
97
+ for (let i = 0; i < lines.length; i++) {
98
+ const result = validateAuditEvent(lines[i]);
99
+ if (!result.ok) {
100
+ errors.push(
101
+ ...result.errors.map((e) => ({ ...e, path: [`line[${i}]`, ...e.path] }))
102
+ );
103
+ continue;
104
+ }
105
+ events.push(result.value);
106
+ }
107
+ if (errors.length > 0) {
108
+ return { ok: false, errors, warnings: [] };
109
+ }
110
+ const chain = verifyChain(jsonl, opts);
111
+ if (!chain.ok) {
112
+ return {
113
+ ok: false,
114
+ errors: err(chain.message, chain.reason, [`line[${chain.brokenAtLine}]`]),
115
+ warnings: []
116
+ };
117
+ }
118
+ return { ok: true, value: { events, chain }, warnings: [] };
119
+ }
120
+ function validateSignatureAgainstArtifact(signature, artifactBytes, computeSha256Hex) {
121
+ const actual = computeSha256Hex(artifactBytes);
122
+ if (actual !== signature.documentHash) {
123
+ return {
124
+ ok: false,
125
+ errors: err(
126
+ `documentHash mismatch: signature claims ${signature.documentHash}, artifact hashes to ${actual}`,
127
+ "document_hash_mismatch"
128
+ ),
129
+ warnings: []
130
+ };
131
+ }
132
+ return { ok: true, value: true, warnings: [] };
133
+ }
134
+
135
+ export { validateAuditEvent, validateAuditLog, validatePolicy, validateSignature, validateSignatureAgainstArtifact };
136
+ //# sourceMappingURL=chunk-UVBFLWSG.mjs.map
137
+ //# sourceMappingURL=chunk-UVBFLWSG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spec/validators/index.ts"],"names":["err"],"mappings":"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","file":"chunk-UVBFLWSG.mjs","sourcesContent":["/**\n * agentgovernance/v1 validators.\n *\n * Per-doctype validators that take file content (string) and return a typed\n * ValidationResult. Cross-doctype consistency checks live alongside.\n *\n * Validators do NOT touch the filesystem — callers pass file contents in.\n * For FS-aware orchestration, see `../../runtime/`.\n */\n\nimport type { z } from \"zod\"\nimport matter from \"gray-matter\"\n\nimport { signatureSchema, type Signature } from \"../doctypes/signature.js\"\nimport { auditEventSchema, type AuditEvent } from \"../doctypes/audit-event.js\"\nimport { policyFrontmatterSchema, type Policy } from \"../doctypes/policy.js\"\nimport {\n verifyChain,\n type VerifyChainOptions,\n type VerifyChainResult,\n} from \"../hash-chain/verify.js\"\n\nexport type ValidationResult<T = unknown> =\n | { ok: true; value: T; warnings: string[] }\n | { ok: false; errors: ValidationError[]; warnings: string[] }\n\nexport interface ValidationError {\n path: string[]\n message: string\n code?: string\n}\n\n/** Convert a zod error into our flat ValidationError array. */\nfunction fromZodError(err: z.ZodError): ValidationError[] {\n return err.issues.map(issue => ({\n path: issue.path.map(p => String(p)),\n message: issue.message,\n code: issue.code,\n }))\n}\n\nfunction err(\n message: string,\n code: string,\n path: string[] = []\n): ValidationError[] {\n return [{ path, message, code }]\n}\n\n// ─── Per-doctype validators ──────────────────────────────────────────────\n\n/**\n * Validate a `signature.json` file content (raw JSON string).\n */\nexport function validateSignature(json: string): ValidationResult<Signature> {\n let parsed: unknown\n try {\n parsed = JSON.parse(json)\n } catch (e) {\n return {\n ok: false,\n errors: err(`JSON parse error: ${(e as Error).message}`, \"parse_error\"),\n warnings: [],\n }\n }\n const result = signatureSchema.safeParse(parsed)\n if (!result.success) {\n return { ok: false, errors: fromZodError(result.error), warnings: [] }\n }\n return { ok: true, value: result.data, warnings: [] }\n}\n\n/**\n * Validate a single line of an audit-log.jsonl file.\n *\n * Whitespace is trimmed; empty input returns parse_error.\n */\nexport function validateAuditEvent(line: string): ValidationResult<AuditEvent> {\n const trimmed = line.trim()\n if (trimmed.length === 0) {\n return {\n ok: false,\n errors: err(\"Empty line\", \"parse_error\"),\n warnings: [],\n }\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed)\n } catch (e) {\n return {\n ok: false,\n errors: err(`JSON parse error: ${(e as Error).message}`, \"parse_error\"),\n warnings: [],\n }\n }\n const result = auditEventSchema.safeParse(parsed)\n if (!result.success) {\n return { ok: false, errors: fromZodError(result.error), warnings: [] }\n }\n return { ok: true, value: result.data, warnings: [] }\n}\n\n/**\n * Validate a POLICY.md file content (markdown with YAML frontmatter).\n */\nexport function validatePolicy(markdown: string): ValidationResult<Policy> {\n let parsed: ReturnType<typeof matter>\n try {\n parsed = matter(markdown)\n } catch (e) {\n return {\n ok: false,\n errors: err(\n `Frontmatter parse error: ${(e as Error).message}`,\n \"parse_error\"\n ),\n warnings: [],\n }\n }\n\n const fmResult = policyFrontmatterSchema.safeParse(parsed.data)\n if (!fmResult.success) {\n return {\n ok: false,\n errors: fromZodError(fmResult.error).map(e => ({\n ...e,\n path: [\"frontmatter\", ...e.path],\n })),\n warnings: [],\n }\n }\n return {\n ok: true,\n value: { frontmatter: fmResult.data, body: parsed.content },\n warnings: [],\n }\n}\n\n// ─── Cross-doctype validators ────────────────────────────────────────────\n\n/**\n * Validate an entire audit-log.jsonl file: every line parses + every line\n * passes the audit-event schema + the hash chain verifies end-to-end.\n *\n * Returns the parsed events on success; the first mismatch (schema or chain)\n * on failure.\n */\nexport function validateAuditLog(\n jsonl: string,\n opts: VerifyChainOptions\n): ValidationResult<{ events: AuditEvent[]; chain: VerifyChainResult }> {\n const lines = jsonl\n .split(\"\\n\")\n .map(l => l.trim())\n .filter(l => l.length > 0)\n const events: AuditEvent[] = []\n const errors: ValidationError[] = []\n\n for (let i = 0; i < lines.length; i++) {\n const result = validateAuditEvent(lines[i]!)\n if (!result.ok) {\n errors.push(\n ...result.errors.map(e => ({ ...e, path: [`line[${i}]`, ...e.path] }))\n )\n continue\n }\n events.push(result.value)\n }\n\n if (errors.length > 0) {\n return { ok: false, errors, warnings: [] }\n }\n\n const chain = verifyChain(jsonl, opts)\n if (!chain.ok) {\n return {\n ok: false,\n errors: err(chain.message, chain.reason, [`line[${chain.brokenAtLine}]`]),\n warnings: [],\n }\n }\n\n return { ok: true, value: { events, chain }, warnings: [] }\n}\n\n/**\n * Verify that a signature's `documentHash` matches the SHA-256 of the artifact bytes\n * it claims to sign.\n */\nexport function validateSignatureAgainstArtifact(\n signature: Signature,\n artifactBytes: Uint8Array,\n computeSha256Hex: (bytes: Uint8Array) => string\n): ValidationResult<true> {\n const actual = computeSha256Hex(artifactBytes)\n if (actual !== signature.documentHash) {\n return {\n ok: false,\n errors: err(\n `documentHash mismatch: signature claims ${signature.documentHash}, artifact hashes to ${actual}`,\n \"document_hash_mismatch\"\n ),\n warnings: [],\n }\n }\n return { ok: true, value: true, warnings: [] }\n}\n\n// Re-export from doctypes for convenience.\nexport type { Signature, AuditEvent, Policy }\n"]}
@@ -0,0 +1,149 @@
1
+ import { createHmac } from 'crypto';
2
+
3
+ /**
4
+ * @agentproto/governance v0.1.0-alpha
5
+ * agentgovernance/v1 — universal contractual approval framework.
6
+ * Vendor-neutral. Filesystem-first. Third-party verifiable.
7
+ */
8
+
9
+ var TEXT_ENCODER = new TextEncoder();
10
+ function canonicalize(value) {
11
+ return TEXT_ENCODER.encode(canonicalJsonString(value));
12
+ }
13
+ function canonicalJsonString(value) {
14
+ if (value === null) return "null";
15
+ if (value === void 0) {
16
+ throw new Error(
17
+ "canonicalJsonString: top-level undefined is not representable"
18
+ );
19
+ }
20
+ if (typeof value === "boolean") return value ? "true" : "false";
21
+ if (typeof value === "number") {
22
+ if (!Number.isFinite(value)) {
23
+ throw new Error(
24
+ `canonicalJsonString: non-finite number ${value} is not JSON-representable`
25
+ );
26
+ }
27
+ return JSON.stringify(value);
28
+ }
29
+ if (typeof value === "string") return JSON.stringify(value);
30
+ if (Array.isArray(value)) {
31
+ return "[" + value.map(canonicalJsonString).join(",") + "]";
32
+ }
33
+ if (typeof value === "object") {
34
+ const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
35
+ return "{" + entries.map(([k, v]) => JSON.stringify(k) + ":" + canonicalJsonString(v)).join(",") + "}";
36
+ }
37
+ throw new Error(`canonicalJsonString: unsupported value type ${typeof value}`);
38
+ }
39
+ function computeChainSignature(row, prevSignature, secret) {
40
+ if (!isHex64(prevSignature)) {
41
+ throw new Error(
42
+ "computeChainSignature: prevSignature must be 64-char lowercase hex"
43
+ );
44
+ }
45
+ const { signature: _omit, ...rowWithoutSignature } = row;
46
+ const canonical = canonicalize(rowWithoutSignature);
47
+ const hmac = createHmac("sha256", secret);
48
+ hmac.update(prevSignature, "utf8");
49
+ hmac.update(canonical);
50
+ return hmac.digest("hex");
51
+ }
52
+ function chainRow(rowWithoutChainFields, prevSignature, secret) {
53
+ const withPrev = { ...rowWithoutChainFields, prevSignature };
54
+ const signature = computeChainSignature(withPrev, prevSignature, secret);
55
+ return { ...withPrev, signature };
56
+ }
57
+ function isHex64(s) {
58
+ return /^[a-f0-9]{64}$/.test(s);
59
+ }
60
+
61
+ // src/spec/hash-chain/verify.ts
62
+ function verifyChain(jsonl, opts) {
63
+ if (!/^[a-f0-9]{64}$/.test(opts.genesisSeed)) {
64
+ return {
65
+ ok: false,
66
+ brokenAtLine: -1,
67
+ expected: "<64-char hex>",
68
+ actual: opts.genesisSeed,
69
+ message: "genesisSeed must be 64-char lowercase hex",
70
+ reason: "missing_field"
71
+ };
72
+ }
73
+ const lines = jsonl.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
74
+ const start = opts.rangeStart ?? 0;
75
+ const end = opts.rangeEnd ?? lines.length - 1;
76
+ let prevSignature = opts.genesisSeed;
77
+ let verifiedLines = 0;
78
+ let lastSignature = prevSignature;
79
+ for (let i = 0; i < lines.length; i++) {
80
+ if (i < start) {
81
+ const computed2 = stepLineOrError(lines[i], prevSignature, opts.secret, i);
82
+ if (typeof computed2 !== "string") return computed2;
83
+ prevSignature = computed2;
84
+ lastSignature = computed2;
85
+ continue;
86
+ }
87
+ if (i > end) break;
88
+ const computed = stepLineOrError(lines[i], prevSignature, opts.secret, i);
89
+ if (typeof computed !== "string") return computed;
90
+ prevSignature = computed;
91
+ lastSignature = computed;
92
+ verifiedLines++;
93
+ }
94
+ return { ok: true, verifiedLines, lastSignature };
95
+ }
96
+ function stepLineOrError(line, prevSignature, secret, lineIndex) {
97
+ let row;
98
+ try {
99
+ row = JSON.parse(line);
100
+ } catch (e) {
101
+ return {
102
+ ok: false,
103
+ brokenAtLine: lineIndex,
104
+ expected: "<parsable JSON>",
105
+ actual: line.length > 80 ? line.slice(0, 80) + "..." : line,
106
+ message: `Line ${lineIndex}: JSON parse error \u2014 ${e.message}`,
107
+ reason: "parse_error"
108
+ };
109
+ }
110
+ if (typeof row.prevSignature !== "string" || typeof row.signature !== "string") {
111
+ return {
112
+ ok: false,
113
+ brokenAtLine: lineIndex,
114
+ expected: "<row with prevSignature and signature fields>",
115
+ actual: JSON.stringify({
116
+ hasPrevSignature: typeof row.prevSignature,
117
+ hasSignature: typeof row.signature
118
+ }),
119
+ message: `Line ${lineIndex}: missing prevSignature or signature`,
120
+ reason: "missing_field"
121
+ };
122
+ }
123
+ if (row.prevSignature !== prevSignature) {
124
+ return {
125
+ ok: false,
126
+ brokenAtLine: lineIndex,
127
+ expected: prevSignature,
128
+ actual: row.prevSignature,
129
+ message: `Line ${lineIndex}: prevSignature mismatch \u2014 chain forked or row reordered`,
130
+ reason: "prev_signature_mismatch"
131
+ };
132
+ }
133
+ const computed = computeChainSignature(row, prevSignature, secret);
134
+ if (computed !== row.signature) {
135
+ return {
136
+ ok: false,
137
+ brokenAtLine: lineIndex,
138
+ expected: computed,
139
+ actual: row.signature,
140
+ message: `Line ${lineIndex}: signature mismatch \u2014 row content tampered`,
141
+ reason: "signature_mismatch"
142
+ };
143
+ }
144
+ return computed;
145
+ }
146
+
147
+ export { canonicalJsonString, canonicalize, chainRow, computeChainSignature, verifyChain };
148
+ //# sourceMappingURL=chunk-VWEBMWO2.mjs.map
149
+ //# sourceMappingURL=chunk-VWEBMWO2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spec/hash-chain/compute.ts","../src/spec/hash-chain/verify.ts"],"names":["computed"],"mappings":"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","file":"chunk-VWEBMWO2.mjs","sourcesContent":["import { createHmac } from \"node:crypto\"\n\n/**\n * agentgovernance/v1 hash-chain — compute primitives.\n *\n * Canonical-bytes serialization (deterministic JSON):\n * - Object keys sorted lexicographically (codepoint order)\n * - Numbers: JSON.stringify representation (matches ECMAScript ToString for finite numbers)\n * - Strings: JSON.stringify (RFC 8259 string escaping)\n * - Arrays: in-order\n * - `undefined` values removed (treated as absent)\n * - No whitespace, UTF-8\n *\n * This is a strict subset of RFC 8785 (JCS). For alpha compatibility, agents\n * SHOULD avoid number values that round-trip differently in JSON (very large\n * integers above 2^53, NaN, ±Infinity, exponent edge cases). The protocol doc\n * specifies the exact rules; verifiers in other languages can be implemented\n * by following protocol.md.\n *\n * Hash chain:\n * signature_n = HMAC-SHA256(\n * key = secret_bytes,\n * data = prev_signature_hex_utf8 ‖ canonical_bytes(row_n_minus_signature)\n * )\n *\n * The very first line uses the workspace genesis seed as prev_signature.\n */\n\nconst TEXT_ENCODER = new TextEncoder()\n\n/**\n * Canonicalize a row to deterministic UTF-8 bytes.\n *\n * Sorts object keys, drops `undefined` values, and emits whitespace-free JSON.\n */\nexport function canonicalize(value: unknown): Uint8Array {\n return TEXT_ENCODER.encode(canonicalJsonString(value))\n}\n\n/** Internal: canonical JSON string. */\nexport function canonicalJsonString(value: unknown): string {\n if (value === null) return \"null\"\n if (value === undefined) {\n throw new Error(\n \"canonicalJsonString: top-level undefined is not representable\"\n )\n }\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\"\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) {\n throw new Error(\n `canonicalJsonString: non-finite number ${value} is not JSON-representable`\n )\n }\n return JSON.stringify(value)\n }\n if (typeof value === \"string\") return JSON.stringify(value)\n if (Array.isArray(value)) {\n return \"[\" + value.map(canonicalJsonString).join(\",\") + \"]\"\n }\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n return (\n \"{\" +\n entries\n .map(([k, v]) => JSON.stringify(k) + \":\" + canonicalJsonString(v))\n .join(\",\") +\n \"}\"\n )\n }\n throw new Error(`canonicalJsonString: unsupported value type ${typeof value}`)\n}\n\nexport interface ChainComputeOptions {\n /** Workspace genesis seed (hex) — used as prev_signature for the first line. */\n genesisSeed: string\n /** HMAC secret key (utf-8 string or hex). */\n secret: string\n}\n\nexport interface ComputedChainSignature {\n /** Hex-encoded HMAC-SHA256. */\n signature: string\n /** Hex-encoded prevSignature carried into this row. */\n prevSignature: string\n}\n\n/**\n * Compute the chain signature for a row given the previous signature.\n *\n * @param row - The audit-event row (the `signature` field, if present, is excluded from the canonical bytes).\n * @param prevSignature - The previous line's signature (or the workspace genesis seed for the first line). Hex-encoded.\n * @param secret - HMAC secret (passed verbatim as the HMAC key).\n * @returns Hex-encoded SHA-256 HMAC.\n */\nexport function computeChainSignature(\n row: Record<string, unknown>,\n prevSignature: string,\n secret: string\n): string {\n if (!isHex64(prevSignature)) {\n throw new Error(\n \"computeChainSignature: prevSignature must be 64-char lowercase hex\"\n )\n }\n // Strip the `signature` field from the row to break the circularity:\n // we hash everything *except* the signature itself.\n const { signature: _omit, ...rowWithoutSignature } = row\n const canonical = canonicalize(rowWithoutSignature)\n const hmac = createHmac(\"sha256\", secret)\n // Feed prev_signature hex as UTF-8 bytes (per protocol.md), then canonical row bytes.\n hmac.update(prevSignature, \"utf8\")\n hmac.update(canonical)\n return hmac.digest(\"hex\")\n}\n\n/**\n * Compute the signature and produce a ready-to-write row with `prevSignature` and `signature` populated.\n */\nexport function chainRow(\n rowWithoutChainFields: Record<string, unknown>,\n prevSignature: string,\n secret: string\n): Record<string, unknown> & { prevSignature: string; signature: string } {\n const withPrev = { ...rowWithoutChainFields, prevSignature }\n const signature = computeChainSignature(withPrev, prevSignature, secret)\n return { ...withPrev, signature }\n}\n\nfunction isHex64(s: string): boolean {\n return /^[a-f0-9]{64}$/.test(s)\n}\n","import { computeChainSignature } from \"./compute.js\"\n\n/**\n * agentgovernance/v1 hash-chain — verifier.\n *\n * Walks an audit-log.jsonl file, recomputing each line's signature given the\n * previous one, and reports the first mismatch. Reports either:\n * - ok with the count of verified lines + last signature (handy for anchoring)\n * - first-mismatch diagnostic (line index, expected vs actual)\n *\n * The verifier is intentionally simple so third-party implementations in any\n * language can be tested for compatibility. See `protocol.md` for the wire\n * format and reference test vectors.\n */\n\nexport interface VerifyChainOptions {\n /** HMAC secret (must match the one used to compute signatures). */\n secret: string\n /** Workspace genesis seed (hex). Becomes prev_signature for the first line. */\n genesisSeed: string\n /** Optional inclusive starting line index (0-based). Defaults to 0. */\n rangeStart?: number\n /** Optional inclusive ending line index (0-based). Defaults to last line. */\n rangeEnd?: number\n}\n\nexport type VerifyChainResult =\n | {\n ok: true\n /** Number of lines verified (inside the optional range). */\n verifiedLines: number\n /** The last line's signature — anchor candidate. */\n lastSignature: string\n }\n | {\n ok: false\n /** 0-based line index where verification failed. */\n brokenAtLine: number\n /** What the verifier computed (expected). */\n expected: string\n /** What the file claims (actual). */\n actual: string\n /** Human-readable diagnostic. */\n message: string\n /** Detail kind for programmatic handling. */\n reason:\n | \"prev_signature_mismatch\"\n | \"signature_mismatch\"\n | \"missing_field\"\n | \"parse_error\"\n }\n\n/**\n * Verify a JSONL audit log's hash chain.\n *\n * Empty lines are skipped. Whitespace-only lines are skipped. JSON parse errors\n * are reported as `parse_error`.\n */\nexport function verifyChain(\n jsonl: string,\n opts: VerifyChainOptions\n): VerifyChainResult {\n if (!/^[a-f0-9]{64}$/.test(opts.genesisSeed)) {\n return {\n ok: false,\n brokenAtLine: -1,\n expected: \"<64-char hex>\",\n actual: opts.genesisSeed,\n message: \"genesisSeed must be 64-char lowercase hex\",\n reason: \"missing_field\",\n }\n }\n\n const lines = jsonl\n .split(\"\\n\")\n .map(l => l.trim())\n .filter(l => l.length > 0)\n const start = opts.rangeStart ?? 0\n const end = opts.rangeEnd ?? lines.length - 1\n\n let prevSignature = opts.genesisSeed\n let verifiedLines = 0\n let lastSignature = prevSignature\n\n for (let i = 0; i < lines.length; i++) {\n if (i < start) {\n // Walk forward to maintain chain state up to the range start.\n const computed = stepLineOrError(lines[i]!, prevSignature, opts.secret, i)\n if (typeof computed !== \"string\") return computed\n prevSignature = computed\n lastSignature = computed\n continue\n }\n if (i > end) break\n\n const computed = stepLineOrError(lines[i]!, prevSignature, opts.secret, i)\n if (typeof computed !== \"string\") return computed\n prevSignature = computed\n lastSignature = computed\n verifiedLines++\n }\n\n return { ok: true, verifiedLines, lastSignature }\n}\n\n/** Advance the chain by one line. Returns the new signature or a typed error result. */\nfunction stepLineOrError(\n line: string,\n prevSignature: string,\n secret: string,\n lineIndex: number\n): string | Extract<VerifyChainResult, { ok: false }> {\n let row: Record<string, unknown>\n try {\n row = JSON.parse(line) as Record<string, unknown>\n } catch (e) {\n return {\n ok: false,\n brokenAtLine: lineIndex,\n expected: \"<parsable JSON>\",\n actual: line.length > 80 ? line.slice(0, 80) + \"...\" : line,\n message: `Line ${lineIndex}: JSON parse error — ${(e as Error).message}`,\n reason: \"parse_error\",\n }\n }\n\n if (\n typeof row.prevSignature !== \"string\" ||\n typeof row.signature !== \"string\"\n ) {\n return {\n ok: false,\n brokenAtLine: lineIndex,\n expected: \"<row with prevSignature and signature fields>\",\n actual: JSON.stringify({\n hasPrevSignature: typeof row.prevSignature,\n hasSignature: typeof row.signature,\n }),\n message: `Line ${lineIndex}: missing prevSignature or signature`,\n reason: \"missing_field\",\n }\n }\n\n if (row.prevSignature !== prevSignature) {\n return {\n ok: false,\n brokenAtLine: lineIndex,\n expected: prevSignature,\n actual: row.prevSignature,\n message: `Line ${lineIndex}: prevSignature mismatch — chain forked or row reordered`,\n reason: \"prev_signature_mismatch\",\n }\n }\n\n const computed = computeChainSignature(row, prevSignature, secret)\n if (computed !== row.signature) {\n return {\n ok: false,\n brokenAtLine: lineIndex,\n expected: computed,\n actual: row.signature,\n message: `Line ${lineIndex}: signature mismatch — row content tampered`,\n reason: \"signature_mismatch\",\n }\n }\n\n return computed\n}\n"]}