witnora 0.9.3 → 0.10.2

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.
Files changed (77) hide show
  1. package/README.md +76 -9
  2. package/dist/assurance-contract.js +312 -0
  3. package/dist/assurance-loop-demo.js +245 -0
  4. package/dist/authorization-state-machine.js +35 -0
  5. package/dist/authorization-v02.js +60 -0
  6. package/dist/bundle.js +22 -0
  7. package/dist/canonical-v02.js +197 -0
  8. package/dist/canonical.js +31 -0
  9. package/dist/cli.js +132 -0
  10. package/dist/command-help.js +81 -0
  11. package/dist/control-plane.js +12 -3
  12. package/dist/credentials.js +1 -1
  13. package/dist/design-partner-pilot.js +402 -0
  14. package/dist/design-partner-v02.js +449 -0
  15. package/dist/evidence-v02.js +118 -0
  16. package/dist/generic-eval.js +160 -0
  17. package/dist/github-design-partner-v02.js +399 -0
  18. package/dist/github-live-v02.js +45 -0
  19. package/dist/guided-setup.js +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/offline-verifier.js +375 -0
  22. package/dist/onboard.js +132 -0
  23. package/dist/onboarding-templates.js +49 -6
  24. package/dist/outcome-evaluator.js +51 -0
  25. package/dist/privacy-manifest.js +273 -0
  26. package/dist/probe-protocol-v02.js +101 -0
  27. package/dist/runtime-context.js +75 -0
  28. package/dist/sandbox.js +1 -1
  29. package/dist/schema-validator.js +141 -3
  30. package/dist/trust-v02.js +111 -0
  31. package/dist/try.js +1 -1
  32. package/dist/vendor/design-partner/failure-exercises.mjs +353 -0
  33. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts +8 -0
  34. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts.map +1 -1
  35. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.js +43 -1
  36. package/dist/vendor/witnora-probe/canonical.d.ts +3 -0
  37. package/dist/vendor/witnora-probe/canonical.js +39 -0
  38. package/dist/vendor/witnora-probe/cli.d.ts +2 -0
  39. package/dist/vendor/witnora-probe/cli.js +36 -0
  40. package/dist/vendor/witnora-probe/config.d.ts +2 -0
  41. package/dist/vendor/witnora-probe/config.js +63 -0
  42. package/dist/vendor/witnora-probe/credential-resolver.d.ts +6 -0
  43. package/dist/vendor/witnora-probe/credential-resolver.js +17 -0
  44. package/dist/vendor/witnora-probe/crypto.d.ts +2 -0
  45. package/dist/vendor/witnora-probe/crypto.js +14 -0
  46. package/dist/vendor/witnora-probe/emulator.d.ts +51 -0
  47. package/dist/vendor/witnora-probe/emulator.js +164 -0
  48. package/dist/vendor/witnora-probe/index.d.ts +11 -0
  49. package/dist/vendor/witnora-probe/index.js +11 -0
  50. package/dist/vendor/witnora-probe/logger.d.ts +3 -0
  51. package/dist/vendor/witnora-probe/logger.js +26 -0
  52. package/dist/vendor/witnora-probe/metrics.d.ts +12 -0
  53. package/dist/vendor/witnora-probe/metrics.js +31 -0
  54. package/dist/vendor/witnora-probe/probe.d.ts +22 -0
  55. package/dist/vendor/witnora-probe/probe.js +208 -0
  56. package/dist/vendor/witnora-probe/request-verifier.d.ts +9 -0
  57. package/dist/vendor/witnora-probe/request-verifier.js +84 -0
  58. package/dist/vendor/witnora-probe/server.d.ts +9 -0
  59. package/dist/vendor/witnora-probe/server.js +85 -0
  60. package/dist/vendor/witnora-probe/storage.d.ts +16 -0
  61. package/dist/vendor/witnora-probe/storage.js +114 -0
  62. package/dist/vendor/witnora-probe/types.d.ts +126 -0
  63. package/dist/vendor/witnora-probe/types.js +2 -0
  64. package/dist/vendor/witnora-verifier-python/README.md +43 -0
  65. package/dist/vendor/witnora-verifier-python/pyproject.toml +23 -0
  66. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/__init__.py +33 -0
  67. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/canonical.py +218 -0
  68. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/cli.py +75 -0
  69. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/conformance.py +124 -0
  70. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/crypto.py +139 -0
  71. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/errors.py +15 -0
  72. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/event_chain.py +80 -0
  73. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/evidence.py +336 -0
  74. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/probe.py +188 -0
  75. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/producer.py +127 -0
  76. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/trust.py +337 -0
  77. package/package.json +5 -5
@@ -23,10 +23,12 @@ export function parseSchemaId(input) {
23
23
  value === "evolution-manifest" ||
24
24
  value === "permission-diff" ||
25
25
  value === "promotion-grant" ||
26
- value === "promotion-receipt") {
26
+ value === "promotion-receipt" ||
27
+ value === "assurance-wallet" ||
28
+ value === "payment-token-reference") {
27
29
  return value;
28
30
  }
29
- throw new Error(`Unsupported schema "${value}". Use evidence-bundle, result, corpus-record, failure-review, classifier-eval, monitor-snapshot, robustness-lab, release-gate, assurance-report, assurance-delivery, assurance-scope, evidence-signature, evidence-strength, action-mandate, trusted-action-record, trusted-run-receipt, agent-mutation, evolution-manifest, permission-diff, promotion-grant, or promotion-receipt.`);
31
+ throw new Error(`Unsupported schema "${value}". Use evidence-bundle, result, corpus-record, failure-review, classifier-eval, monitor-snapshot, robustness-lab, release-gate, assurance-report, assurance-delivery, assurance-scope, evidence-signature, evidence-strength, action-mandate, trusted-action-record, trusted-run-receipt, agent-mutation, evolution-manifest, permission-diff, promotion-grant, promotion-receipt, assurance-wallet, or payment-token-reference.`);
30
32
  }
31
33
  export function validateAgentCertSchema(schema, input) {
32
34
  const errors = [];
@@ -78,9 +80,100 @@ export function validateAgentCertSchema(schema, input) {
78
80
  validatePromotionGrant(value, errors);
79
81
  if (schema === "promotion-receipt")
80
82
  validatePromotionReceipt(value, errors);
83
+ if (schema === "assurance-wallet")
84
+ validateAssuranceWallet(value, errors);
85
+ if (schema === "payment-token-reference")
86
+ validatePaymentTokenReference(value, errors);
81
87
  }
82
88
  return { schema, valid: errors.length === 0, errors };
83
89
  }
90
+ function validateAssuranceWallet(value, errors) {
91
+ requiredConst(value, "schemaVersion", "witnora.assurance_wallet.v0.1", errors);
92
+ for (const field of ["id", "projectId", "name", "ownerPrincipalId", "baseCurrency", "policyDigestSha256", "status", "createdBy", "createdAt", "updatedAt"])
93
+ requiredString(value, field, errors);
94
+ sha256Field(value, "policyDigestSha256", errors);
95
+ requiredEnum(value, "status", ["ACTIVE", "SUSPENDED", "REVOKED"], errors);
96
+ for (const field of ["createdAt", "updatedAt"])
97
+ validateTimestamp(value[field], field, errors);
98
+ const policy = recordValue(value.policy);
99
+ if (!policy) {
100
+ errors.push("policy must be an object.");
101
+ return;
102
+ }
103
+ requiredArray(policy, "allowedProviders", errors);
104
+ requiredArray(policy, "allowedEnvironments", errors);
105
+ requiredArray(policy, "allowedCurrencies", errors);
106
+ stringArray(policy.allowedProviders, "policy.allowedProviders", errors);
107
+ stringArray(policy.allowedEnvironments, "policy.allowedEnvironments", errors);
108
+ stringArray(policy.allowedCurrencies, "policy.allowedCurrencies", errors);
109
+ enumArray(policy.allowedProviders, "policy.allowedProviders", ["STRIPE", "CLOUDFLARE"], errors);
110
+ enumArray(policy.allowedEnvironments, "policy.allowedEnvironments", ["SANDBOX", "TEST"], errors);
111
+ currencyArray(policy.allowedCurrencies, "policy.allowedCurrencies", errors);
112
+ currencyField(value, "baseCurrency", errors);
113
+ if (Array.isArray(policy.allowedCurrencies) &&
114
+ (policy.allowedCurrencies.length !== 1 || policy.allowedCurrencies[0] !== value.baseCurrency)) {
115
+ errors.push("policy.allowedCurrencies must contain only baseCurrency in v0.1.");
116
+ }
117
+ requiredNumber(policy, "maxAmountPerAction", errors);
118
+ requiredNumber(policy, "maxAmountPerPeriod", errors);
119
+ requiredNumber(policy, "periodSeconds", errors);
120
+ positiveNumber(policy, "maxAmountPerAction", errors);
121
+ positiveNumber(policy, "maxAmountPerPeriod", errors);
122
+ positiveInteger(policy, "periodSeconds", errors);
123
+ requiredBoolean(policy, "mandateRequired", errors);
124
+ requiredBoolean(policy, "independentOutcomeRequired", errors);
125
+ if (policy.mandateRequired !== true)
126
+ errors.push("policy.mandateRequired must be true.");
127
+ if (policy.independentOutcomeRequired !== true)
128
+ errors.push("policy.independentOutcomeRequired must be true.");
129
+ requiredEnum(policy, "recurringPayments", ["DENY", "REQUIRE_APPROVAL"], errors);
130
+ }
131
+ function validatePaymentTokenReference(value, errors) {
132
+ requiredConst(value, "schemaVersion", "witnora.payment_token_reference.v0.1", errors);
133
+ for (const field of ["id", "projectId", "walletId", "providerAccountId", "tokenType", "tokenSha256", "audience", "currency", "expiresAt", "status", "createdBy", "createdAt", "updatedAt"])
134
+ requiredString(value, field, errors);
135
+ sha256Field(value, "tokenSha256", errors);
136
+ requiredNumber(value, "maxAmount", errors);
137
+ positiveNumber(value, "maxAmount", errors);
138
+ currencyField(value, "currency", errors);
139
+ requiredEnum(value, "provider", ["STRIPE", "CLOUDFLARE"], errors);
140
+ requiredEnum(value, "environment", ["SANDBOX", "TEST"], errors);
141
+ requiredEnum(value, "status", ["AVAILABLE", "BOUND", "CONSUMED", "EXPIRED", "REVOKED"], errors);
142
+ for (const field of ["expiresAt", "createdAt", "updatedAt"])
143
+ validateTimestamp(value[field], field, errors);
144
+ }
145
+ function enumArray(value, path, allowed, errors) {
146
+ if (!Array.isArray(value))
147
+ return;
148
+ for (const [index, item] of value.entries()) {
149
+ if (typeof item === "string" && !allowed.includes(item)) {
150
+ errors.push(`${path}[${index}] must be one of: ${allowed.join(", ")}.`);
151
+ }
152
+ }
153
+ }
154
+ function currencyArray(value, path, errors) {
155
+ if (!Array.isArray(value))
156
+ return;
157
+ for (const [index, item] of value.entries()) {
158
+ if (typeof item === "string" && !/^[A-Z]{3}$/.test(item)) {
159
+ errors.push(`${path}[${index}] must be a three-letter uppercase currency code.`);
160
+ }
161
+ }
162
+ }
163
+ function currencyField(input, key, errors) {
164
+ if (typeof input[key] === "string" && !/^[A-Z]{3}$/.test(input[key])) {
165
+ errors.push(`${key} must be a three-letter uppercase currency code.`);
166
+ }
167
+ }
168
+ function positiveNumber(input, key, errors) {
169
+ if (typeof input[key] === "number" && input[key] <= 0)
170
+ errors.push(`${key} must be greater than zero.`);
171
+ }
172
+ function positiveInteger(input, key, errors) {
173
+ if (typeof input[key] === "number" && (!Number.isInteger(input[key]) || input[key] <= 0)) {
174
+ errors.push(`${key} must be a positive integer.`);
175
+ }
176
+ }
84
177
  function validateEvidenceBundle(value, errors) {
85
178
  requiredConst(value, "schemaName", "agentcert.evidence_bundle", errors);
86
179
  requiredConst(value, "schemaVersion", AGENTCERT_EVIDENCE_SCHEMA_VERSION, errors);
@@ -135,6 +228,21 @@ function validateEvidenceStrength(value, errors, prefix = "") {
135
228
  requiredArray(value, "limitations", errors);
136
229
  stringArray(value.claims, `${prefix}claims`, errors);
137
230
  stringArray(value.limitations, `${prefix}limitations`, errors);
231
+ const trust = recordValue(value.trustVector);
232
+ if (value.trustVector !== undefined && !trust)
233
+ errors.push(`${prefix}trustVector must be an object.`);
234
+ if (trust)
235
+ validateEvidenceTrustVector(trust, errors, `${prefix}trustVector.`);
236
+ }
237
+ function validateEvidenceTrustVector(value, errors, prefix) {
238
+ requiredConst(value, "schemaVersion", "witnora.evidence_trust_vector.v0.1", errors);
239
+ requiredEnumAt(value, "capture", ["self_reported", "collector_recorded", "boundary_observed"], `${prefix}capture`, errors);
240
+ requiredEnumAt(value, "mediation", ["none", "advisory", "enforced"], `${prefix}mediation`, errors);
241
+ requiredEnumAt(value, "outcome", ["unverified", "verified", "contradicted"], `${prefix}outcome`, errors);
242
+ requiredEnumAt(value, "completeness", ["unknown", "partial", "target_reconciled"], `${prefix}completeness`, errors);
243
+ requiredEnumAt(value, "attestation", ["unsigned", "source_signed", "platform_signed", "externally_witnessed"], `${prefix}attestation`, errors);
244
+ requiredEnumAt(value, "review", ["none", "internal", "independent_external"], `${prefix}review`, errors);
245
+ stringArray(value.limitations, `${prefix}limitations`, errors);
138
246
  }
139
247
  function validateActionMandate(value, errors) {
140
248
  requiredConst(value, "schemaVersion", "agentcert.action_mandate.v0.1", errors);
@@ -363,7 +471,9 @@ function validateAssuranceContinuity(input, errors) {
363
471
  }
364
472
  }
365
473
  function validateAssuranceScope(value, errors) {
366
- requiredConst(value, "schemaVersion", "agentcert.assurance_scope.v0.1", errors);
474
+ if (value.schemaVersion !== "agentcert.assurance_scope.v0.1" && value.schemaVersion !== "agentcert.assurance_scope.v0.2") {
475
+ errors.push("schemaVersion must be agentcert.assurance_scope.v0.1 or agentcert.assurance_scope.v0.2.");
476
+ }
367
477
  for (const key of ["agent", "model", "prompt", "tools", "policy", "scenarioSuite"])
368
478
  requiredObject(value, key, errors);
369
479
  const agent = recordValue(value.agent);
@@ -394,6 +504,34 @@ function validateAssuranceScope(value, errors) {
394
504
  requiredStringAt(suite, "version", "scenarioSuite.version", errors);
395
505
  requiredSha256At(suite, "sha256", "scenarioSuite.sha256", errors);
396
506
  }
507
+ if (value.schemaVersion === "agentcert.assurance_scope.v0.2") {
508
+ for (const key of ["runtimeBoundary", "outcomeProbe", "evidenceTrust"])
509
+ requiredObject(value, key, errors);
510
+ const runtime = recordValue(value.runtimeBoundary);
511
+ const probe = recordValue(value.outcomeProbe);
512
+ const trust = recordValue(value.evidenceTrust);
513
+ if (runtime) {
514
+ requiredSha256At(runtime, "gatewayDigestSha256", "runtimeBoundary.gatewayDigestSha256", errors);
515
+ requiredSha256At(runtime, "adapterDigestSha256", "runtimeBoundary.adapterDigestSha256", errors);
516
+ requiredStringAt(runtime, "credentialBoundary", "runtimeBoundary.credentialBoundary", errors);
517
+ requiredSha256At(runtime, "networkBoundarySha256", "runtimeBoundary.networkBoundarySha256", errors);
518
+ requiredStringAt(runtime, "grantIssuer", "runtimeBoundary.grantIssuer", errors);
519
+ }
520
+ if (probe) {
521
+ requiredStringAt(probe, "profileId", "outcomeProbe.profileId", errors);
522
+ requiredStringAt(probe, "version", "outcomeProbe.version", errors);
523
+ requiredSha256At(probe, "digestSha256", "outcomeProbe.digestSha256", errors);
524
+ requiredStringAt(probe, "authoritativeSource", "outcomeProbe.authoritativeSource", errors);
525
+ requiredStringAt(probe, "readCredentialBoundary", "outcomeProbe.readCredentialBoundary", errors);
526
+ }
527
+ if (trust) {
528
+ requiredSha256At(trust, "collectorDigestSha256", "evidenceTrust.collectorDigestSha256", errors);
529
+ requiredStringAt(trust, "evidenceSchemaVersion", "evidenceTrust.evidenceSchemaVersion", errors);
530
+ requiredStringAt(trust, "signingKeyId", "evidenceTrust.signingKeyId", errors);
531
+ requiredSha256At(trust, "verifierDigestSha256", "evidenceTrust.verifierDigestSha256", errors);
532
+ requiredSha256At(trust, "retentionPolicySha256", "evidenceTrust.retentionPolicySha256", errors);
533
+ }
534
+ }
397
535
  }
398
536
  function requiredSha256At(value, key, path, errors) {
399
537
  if (typeof value[key] !== "string" || !/^[0-9a-f]{64}$/.test(value[key]))
@@ -0,0 +1,111 @@
1
+ import { createHash, createPrivateKey, createPublicKey, sign, verify } from "node:crypto";
2
+ import { canonicalBytesV02, sha256CanonicalV02 } from "./canonical-v02.js";
3
+ export function createTrustRoot(input) {
4
+ const core = { ...input, protocolVersion: "witnora.trust_root.v0.2" };
5
+ return { ...core, rootFingerprint: createHash("sha256").update(createPublicKey(input.publicKeyPem).export({ format: "der", type: "spki" })).digest("hex") };
6
+ }
7
+ export function issueKeyCertificate(input, issuerPrivateKeyPem) {
8
+ const core = { ...input, protocolVersion: "witnora.key_certificate.v0.2" };
9
+ const certificateDigest = sha256CanonicalV02(core);
10
+ return { ...core, certificateDigest, signature: sign(null, canonicalBytesV02({ ...core, certificateDigest }), createPrivateKey(issuerPrivateKeyPem)).toString("base64") };
11
+ }
12
+ export function verifyKeyCertificate(certificate, root, at, expected) {
13
+ if (certificate.protocolVersion !== "witnora.key_certificate.v0.2")
14
+ throw new Error("Unsupported key certificate version.");
15
+ verifyPinnedRootShape(root);
16
+ const eventAt = parseInstant(at, "certificate verification time");
17
+ const rootNotBefore = parseInstant(root.notBefore, "trust root notBefore");
18
+ const rootNotAfter = parseInstant(root.notAfter, "trust root notAfter");
19
+ if (rootNotAfter <= rootNotBefore)
20
+ throw new Error("Pinned trust-root validity interval is invalid.");
21
+ if (eventAt < rootNotBefore || eventAt > rootNotAfter)
22
+ throw new Error("Pinned trust root is outside its validity interval.");
23
+ if (certificate.issuerRootId !== root.rootId)
24
+ throw new Error("Certificate issuer is not the pinned root.");
25
+ if (certificate.role !== expected.role || !root.allowedRoles.includes(certificate.role))
26
+ throw new Error("Certificate role is not authorized by the pinned root.");
27
+ if (certificate.tenantRef !== expected.tenantRef || certificate.projectRef !== expected.projectRef || certificate.environment !== expected.environment)
28
+ throw new Error("Certificate trust scope mismatch.");
29
+ const certificateNotBefore = parseInstant(certificate.notBefore, "certificate notBefore");
30
+ const certificateNotAfter = parseInstant(certificate.notAfter, "certificate notAfter");
31
+ if (certificateNotAfter <= certificateNotBefore)
32
+ throw new Error("Certificate validity interval is invalid.");
33
+ if (eventAt < certificateNotBefore || eventAt > certificateNotAfter)
34
+ throw new Error("Certificate is outside its validity interval.");
35
+ const { signature, certificateDigest, ...core } = certificate;
36
+ if (sha256CanonicalV02(core) !== certificateDigest)
37
+ throw new Error("Certificate digest mismatch.");
38
+ if (!verify(null, canonicalBytesV02({ ...core, certificateDigest }), createPublicKey(root.publicKeyPem), Buffer.from(signature, "base64")))
39
+ throw new Error("Certificate signature is invalid.");
40
+ }
41
+ export function appendRevocation(journal, input, rootPrivateKeyPem) {
42
+ const statements = journal?.statements ?? [];
43
+ const core = {
44
+ sequence: statements.length + 1,
45
+ previousJournalDigest: journal?.checkpointDigest ?? null,
46
+ ...input,
47
+ protocolVersion: "witnora.key_revocation_statement.v0.2",
48
+ };
49
+ const statementDigest = sha256CanonicalV02(core);
50
+ const statement = { ...core, statementDigest, signature: sign(null, canonicalBytesV02({ ...core, statementDigest }), createPrivateKey(rootPrivateKeyPem)).toString("base64") };
51
+ const next = [...statements, statement];
52
+ return { protocolVersion: "witnora.revocation_journal.v0.2", rootId: input.issuerRootId, statements: next, checkpointDigest: sha256CanonicalV02(next) };
53
+ }
54
+ export function verifyRevocationJournal(journal, root) {
55
+ if (journal.protocolVersion !== "witnora.revocation_journal.v0.2")
56
+ throw new Error("Unsupported revocation journal version.");
57
+ verifyPinnedRootShape(root);
58
+ let previous = null;
59
+ for (const [index, statement] of journal.statements.entries()) {
60
+ if (statement.protocolVersion !== "witnora.key_revocation_statement.v0.2")
61
+ throw new Error("Unsupported revocation statement version.");
62
+ if (statement.sequence !== index + 1 || statement.previousJournalDigest !== previous || statement.issuerRootId !== root.rootId)
63
+ throw new Error("Revocation journal continuity is invalid.");
64
+ parseInstant(statement.effectiveAt, "revocation effectiveAt");
65
+ const { signature, statementDigest, ...core } = statement;
66
+ if (sha256CanonicalV02(core) !== statementDigest)
67
+ throw new Error("Revocation statement digest mismatch.");
68
+ if (!verify(null, canonicalBytesV02({ ...core, statementDigest }), createPublicKey(root.publicKeyPem), Buffer.from(signature, "base64")))
69
+ throw new Error("Revocation statement signature is invalid.");
70
+ previous = sha256CanonicalV02(journal.statements.slice(0, index + 1));
71
+ }
72
+ if (journal.rootId !== root.rootId || journal.checkpointDigest !== (previous ?? sha256CanonicalV02([])))
73
+ throw new Error("Revocation journal checkpoint mismatch.");
74
+ }
75
+ export function assertNotRevoked(certificate, journal, eventAt) {
76
+ const eventTime = parseInstant(eventAt, "revocation event time");
77
+ for (const revocation of journal.statements) {
78
+ if (revocation.revokedId !== certificate.certificateId && revocation.revokedId !== certificate.subjectKeyId)
79
+ continue;
80
+ const effectiveAt = parseInstant(revocation.effectiveAt, "revocation effectiveAt");
81
+ if (revocation.retroactive || eventTime >= effectiveAt)
82
+ throw new Error("Certificate was revoked for the event time.");
83
+ }
84
+ }
85
+ export function assertRevocationJournalExtends(packetJournal, latestJournal) {
86
+ if (packetJournal.rootId !== latestJournal.rootId || packetJournal.statements.length > latestJournal.statements.length)
87
+ throw new Error("Revocation rollback detected: packet journal is not a prefix of the latest trusted journal.");
88
+ for (const [index, statement] of packetJournal.statements.entries()) {
89
+ if (statement.statementDigest !== latestJournal.statements[index]?.statementDigest)
90
+ throw new Error("Revocation rollback detected: packet journal diverges from the latest trusted journal.");
91
+ }
92
+ }
93
+ function parseInstant(value, field) {
94
+ if (typeof value === "string" && !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/.test(value))
95
+ throw new Error(`${field} must be an RFC 3339 UTC timestamp.`);
96
+ const parsed = value instanceof Date ? value.getTime() : Date.parse(value);
97
+ if (!Number.isFinite(parsed))
98
+ throw new Error(`${field} must be a valid timestamp.`);
99
+ return parsed;
100
+ }
101
+ function verifyPinnedRootShape(root) {
102
+ if (root.protocolVersion !== "witnora.trust_root.v0.2" || root.algorithm !== "Ed25519")
103
+ throw new Error("Unsupported pinned trust root.");
104
+ const actualFingerprint = createHash("sha256").update(createPublicKey(root.publicKeyPem).export({ format: "der", type: "spki" })).digest("hex");
105
+ if (root.rootFingerprint !== actualFingerprint)
106
+ throw new Error("Pinned trust-root fingerprint mismatch.");
107
+ const notBefore = parseInstant(root.notBefore, "trust root notBefore");
108
+ const notAfter = parseInstant(root.notAfter, "trust root notAfter");
109
+ if (notAfter <= notBefore)
110
+ throw new Error("Pinned trust-root validity interval is invalid.");
111
+ }
package/dist/try.js CHANGED
@@ -92,7 +92,7 @@ export async function writeTryEvidence(options) {
92
92
  kind: "synthetic_onboarding",
93
93
  severity: "info",
94
94
  message: `Deterministic ${options.template} sample passed. Replace it with evidence from the real agent boundary before making a release decision.`,
95
- source: "agentcert try",
95
+ source: "witnora try",
96
96
  artifactPath,
97
97
  metadata: { synthetic: true, template: options.template, purpose: "onboarding_only" },
98
98
  }],