@oxdeai/conformance 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -0
- package/LICENSE +213 -0
- package/README.md +217 -5
- package/dist/evidence-metadata.json +3489 -0
- package/dist/scripts/build-evidence-metadata.d.mts +1 -0
- package/dist/scripts/build-evidence-metadata.mjs +7 -0
- package/dist/scripts/build-evidence-metadata.mjs.map +1 -0
- package/dist/scripts/extract-vectors.js +228 -22
- package/dist/scripts/extract-vectors.js.map +1 -1
- package/dist/src/evidenceScope.d.mts +68 -0
- package/dist/src/evidenceScope.mjs +127 -0
- package/dist/src/evidenceScope.mjs.map +1 -0
- package/dist/src/fixtures/conformance-engine-secret.fixture.d.ts +5 -0
- package/dist/src/fixtures/conformance-engine-secret.fixture.js +7 -0
- package/dist/src/fixtures/conformance-engine-secret.fixture.js.map +1 -0
- package/dist/src/fixtures/ed25519.test-only.fixture.d.ts +1 -1
- package/dist/src/fixtures/ed25519.test-only.fixture.js +2 -1
- package/dist/src/fixtures/ed25519.test-only.fixture.js.map +1 -1
- package/dist/src/fixtures/krl-ed25519.test-only.fixture.d.ts +13 -0
- package/dist/src/fixtures/krl-ed25519.test-only.fixture.js +19 -0
- package/dist/src/fixtures/krl-ed25519.test-only.fixture.js.map +1 -0
- package/dist/src/trustedTimeConformance.d.ts +32 -0
- package/dist/src/trustedTimeConformance.js +484 -0
- package/dist/src/trustedTimeConformance.js.map +1 -0
- package/dist/src/validate-trusted-time.d.ts +1 -0
- package/dist/src/validate-trusted-time.js +14 -0
- package/dist/src/validate-trusted-time.js.map +1 -0
- package/dist/src/validate.d.ts +1 -0
- package/dist/src/validate.js +723 -31
- package/dist/src/validate.js.map +1 -1
- package/package.json +37 -12
- package/vectors/audit-chain.json +2 -2
- package/vectors/authorization-payload.json +46 -34
- package/vectors/authorization-signature-verification.json +39 -1
- package/vectors/authorization-verification.json +54 -1
- package/vectors/clock-semantics-verification.json +136 -0
- package/vectors/delegation-chain-verification.json +366 -0
- package/vectors/delegation-parent-hash.json +54 -0
- package/vectors/delegation-signature-verification.json +317 -0
- package/vectors/delegation-verification.json +252 -0
- package/vectors/envelope-verification.json +3 -3
- package/vectors/key-lifecycle-verification.json +131 -0
- package/vectors/profile-c-state-verification.json +217 -0
- package/vectors/signed-krl-verification.json +103 -0
- package/vectors/trusted-time.json +50 -0
- package/dist/extract-vectors.js +0 -416
- package/scripts/extract-vectors.ts +0 -466
- package/src/fixtures/README.md +0 -11
- package/src/fixtures/ed25519.test-only.fixture.ts +0 -14
- package/src/validate.ts +0 -828
- package/tsconfig.json +0 -14
package/src/validate.ts
DELETED
|
@@ -1,828 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import {
|
|
5
|
-
encodeCanonicalState,
|
|
6
|
-
encodeEnvelope,
|
|
7
|
-
PolicyEngine,
|
|
8
|
-
sha256HexFromJson,
|
|
9
|
-
signAuthorizationEd25519,
|
|
10
|
-
signEnvelopeEd25519,
|
|
11
|
-
verifyAuthorization,
|
|
12
|
-
verifyAuditEvents,
|
|
13
|
-
verifyEnvelope,
|
|
14
|
-
verifySnapshot
|
|
15
|
-
} from "@oxdeai/core";
|
|
16
|
-
import type { AuthorizationV1, Intent, KeySet, State, VerificationResult } from "@oxdeai/core";
|
|
17
|
-
import {
|
|
18
|
-
TEST_ONLY_ED25519_PRIVATE_KEY_PEM_DO_NOT_USE_IN_PRODUCTION,
|
|
19
|
-
TEST_ONLY_ED25519_PUBLIC_KEY_PEM_DO_NOT_USE_IN_PRODUCTION,
|
|
20
|
-
} from "./fixtures/ed25519.test-only.fixture.js";
|
|
21
|
-
|
|
22
|
-
type JsonRecord = Record<string, unknown>;
|
|
23
|
-
|
|
24
|
-
type AuthorizationLike = {
|
|
25
|
-
auth_id: string;
|
|
26
|
-
issuer: string;
|
|
27
|
-
audience: string;
|
|
28
|
-
intent_hash: string;
|
|
29
|
-
state_hash: string;
|
|
30
|
-
policy_id: string;
|
|
31
|
-
decision: "ALLOW" | "DENY";
|
|
32
|
-
issued_at: number;
|
|
33
|
-
expiry: number;
|
|
34
|
-
alg: "Ed25519" | "HMAC-SHA256";
|
|
35
|
-
kid: string;
|
|
36
|
-
signature: string;
|
|
37
|
-
state_snapshot_hash: string;
|
|
38
|
-
expires_at: number;
|
|
39
|
-
engine_signature: string;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
type EnvelopeEvent = Parameters<typeof encodeEnvelope>[0]["events"][number];
|
|
43
|
-
|
|
44
|
-
type ConformanceAdapter = {
|
|
45
|
-
name: string;
|
|
46
|
-
canonicalJson(value: unknown): string;
|
|
47
|
-
intentHash(intent: Intent): string;
|
|
48
|
-
evaluateAuthorization(intent: Intent): { authorization: AuthorizationLike; policyId: string };
|
|
49
|
-
encodeSnapshot(state: State): { bytes: Uint8Array; policyId: string };
|
|
50
|
-
verifySnapshot(bytes: Uint8Array, expectedPolicyId?: string): VerificationResult;
|
|
51
|
-
verifyAuditEvents(
|
|
52
|
-
events: unknown[],
|
|
53
|
-
opts?: { expectedPolicyId?: string; mode?: "strict" | "best-effort"; requireStateAnchors?: boolean }
|
|
54
|
-
): VerificationResult;
|
|
55
|
-
verifyEnvelope(bytes: Uint8Array, opts?: {
|
|
56
|
-
expectedPolicyId?: string;
|
|
57
|
-
mode?: "strict" | "best-effort";
|
|
58
|
-
expectedIssuer?: string;
|
|
59
|
-
trustedKeySets?: KeySet | readonly KeySet[];
|
|
60
|
-
requireSignatureVerification?: boolean;
|
|
61
|
-
now?: number;
|
|
62
|
-
}): VerificationResult;
|
|
63
|
-
verifyAuthorization(auth: AuthorizationV1, opts?: {
|
|
64
|
-
now?: number;
|
|
65
|
-
expectedIssuer?: string;
|
|
66
|
-
expectedAudience?: string;
|
|
67
|
-
expectedPolicyId?: string;
|
|
68
|
-
consumedAuthIds?: readonly string[];
|
|
69
|
-
trustedKeySets?: KeySet | readonly KeySet[];
|
|
70
|
-
requireSignatureVerification?: boolean;
|
|
71
|
-
legacyHmacSecret?: string;
|
|
72
|
-
}): VerificationResult;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const TEST_KEYSET: KeySet = {
|
|
76
|
-
issuer: "oxdeai.policy-engine",
|
|
77
|
-
version: "1",
|
|
78
|
-
keys: [
|
|
79
|
-
{
|
|
80
|
-
kid: "2026-01",
|
|
81
|
-
alg: "Ed25519",
|
|
82
|
-
public_key: TEST_ONLY_ED25519_PUBLIC_KEY_PEM_DO_NOT_USE_IN_PRODUCTION
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const CORE_ENGINE_SECRET = "test-secret";
|
|
88
|
-
const CORE_POLICY_ID = "a".repeat(64);
|
|
89
|
-
const INTENT_BINDING_FIELDS = [
|
|
90
|
-
"intent_id",
|
|
91
|
-
"agent_id",
|
|
92
|
-
"action_type",
|
|
93
|
-
"depth",
|
|
94
|
-
"amount",
|
|
95
|
-
"asset",
|
|
96
|
-
"target",
|
|
97
|
-
"timestamp",
|
|
98
|
-
"metadata_hash",
|
|
99
|
-
"nonce",
|
|
100
|
-
"type",
|
|
101
|
-
"authorization_id",
|
|
102
|
-
"tool",
|
|
103
|
-
"tool_call"
|
|
104
|
-
] as const;
|
|
105
|
-
|
|
106
|
-
function makeEngine(): PolicyEngine {
|
|
107
|
-
return new PolicyEngine({
|
|
108
|
-
policy_version: "v1.0.0",
|
|
109
|
-
engine_secret: CORE_ENGINE_SECRET,
|
|
110
|
-
authorization_ttl_seconds: 60,
|
|
111
|
-
policyId: CORE_POLICY_ID
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function makeBaseState(): State {
|
|
116
|
-
return {
|
|
117
|
-
policy_version: "v1.0.0",
|
|
118
|
-
period_id: "period-1",
|
|
119
|
-
kill_switch: { global: false, agents: {} },
|
|
120
|
-
allowlists: {},
|
|
121
|
-
budget: {
|
|
122
|
-
budget_limit: { "agent-1": 5_000_000n },
|
|
123
|
-
spent_in_period: { "agent-1": 0n }
|
|
124
|
-
},
|
|
125
|
-
max_amount_per_action: { "agent-1": 2_000_000n },
|
|
126
|
-
velocity: {
|
|
127
|
-
config: { window_seconds: 60, max_actions: 10 },
|
|
128
|
-
counters: {}
|
|
129
|
-
},
|
|
130
|
-
replay: {
|
|
131
|
-
window_seconds: 300,
|
|
132
|
-
max_nonces_per_agent: 256,
|
|
133
|
-
nonces: {}
|
|
134
|
-
},
|
|
135
|
-
concurrency: {
|
|
136
|
-
max_concurrent: { "agent-1": 3 },
|
|
137
|
-
active: {},
|
|
138
|
-
active_auths: {}
|
|
139
|
-
},
|
|
140
|
-
recursion: {
|
|
141
|
-
max_depth: { "agent-1": 5 }
|
|
142
|
-
},
|
|
143
|
-
tool_limits: {
|
|
144
|
-
window_seconds: 60,
|
|
145
|
-
max_calls: { "agent-1": 50 },
|
|
146
|
-
calls: {}
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function asRecord(value: unknown): JsonRecord {
|
|
152
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
153
|
-
throw new Error("expected object");
|
|
154
|
-
}
|
|
155
|
-
return value as JsonRecord;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function parseIntent(input: unknown): Intent {
|
|
159
|
-
const r = asRecord(input);
|
|
160
|
-
const maybeType = r.type;
|
|
161
|
-
const type = maybeType === "RELEASE" ? "RELEASE" : "EXECUTE";
|
|
162
|
-
|
|
163
|
-
const base = {
|
|
164
|
-
intent_id: String(r.intent_id),
|
|
165
|
-
agent_id: String(r.agent_id),
|
|
166
|
-
action_type: String(r.action_type) as Intent["action_type"],
|
|
167
|
-
amount: BigInt(String(r.amount)),
|
|
168
|
-
asset: r.asset === undefined ? undefined : String(r.asset),
|
|
169
|
-
target: String(r.target),
|
|
170
|
-
timestamp: Number(r.timestamp),
|
|
171
|
-
metadata_hash: String(r.metadata_hash),
|
|
172
|
-
nonce: BigInt(String(r.nonce)),
|
|
173
|
-
signature: String(r.signature),
|
|
174
|
-
depth: r.depth === undefined ? undefined : Number(r.depth),
|
|
175
|
-
tool: r.tool === undefined ? undefined : String(r.tool),
|
|
176
|
-
tool_call: r.tool_call === undefined ? undefined : Boolean(r.tool_call)
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
if (type === "RELEASE") {
|
|
180
|
-
return {
|
|
181
|
-
...base,
|
|
182
|
-
type: "RELEASE",
|
|
183
|
-
authorization_id: String(r.authorization_id)
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
...base,
|
|
189
|
-
type: "EXECUTE",
|
|
190
|
-
authorization_id: r.authorization_id === undefined ? undefined : String(r.authorization_id)
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function parseState(input: unknown): State {
|
|
195
|
-
const r = asRecord(input);
|
|
196
|
-
const budget = asRecord(r.budget);
|
|
197
|
-
const budget_limit = asRecord(budget.budget_limit);
|
|
198
|
-
const spent_in_period = asRecord(budget.spent_in_period);
|
|
199
|
-
|
|
200
|
-
const max_amount_per_action = asRecord(r.max_amount_per_action);
|
|
201
|
-
|
|
202
|
-
const toBigintRecord = (rec: JsonRecord): Record<string, bigint> => {
|
|
203
|
-
const out: Record<string, bigint> = {};
|
|
204
|
-
for (const [k, v] of Object.entries(rec)) out[k] = BigInt(String(v));
|
|
205
|
-
return out;
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const state = makeBaseState();
|
|
209
|
-
state.policy_version = String(r.policy_version);
|
|
210
|
-
state.period_id = String(r.period_id);
|
|
211
|
-
|
|
212
|
-
state.kill_switch = {
|
|
213
|
-
global: Boolean(asRecord(r.kill_switch).global),
|
|
214
|
-
agents: asRecord(asRecord(r.kill_switch).agents) as Record<string, boolean>
|
|
215
|
-
};
|
|
216
|
-
state.allowlists = asRecord(r.allowlists) as State["allowlists"];
|
|
217
|
-
state.budget = {
|
|
218
|
-
budget_limit: toBigintRecord(budget_limit),
|
|
219
|
-
spent_in_period: toBigintRecord(spent_in_period)
|
|
220
|
-
};
|
|
221
|
-
state.max_amount_per_action = toBigintRecord(max_amount_per_action);
|
|
222
|
-
state.velocity = asRecord(r.velocity) as State["velocity"];
|
|
223
|
-
state.replay = asRecord(r.replay) as State["replay"];
|
|
224
|
-
state.concurrency = asRecord(r.concurrency) as State["concurrency"];
|
|
225
|
-
state.recursion = asRecord(r.recursion) as State["recursion"];
|
|
226
|
-
state.tool_limits = asRecord(r.tool_limits) as State["tool_limits"];
|
|
227
|
-
|
|
228
|
-
return state;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function b64ToBytes(value: string): Uint8Array {
|
|
232
|
-
return Uint8Array.from(Buffer.from(value, "base64"));
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function hexSha256Utf8(value: string): string {
|
|
236
|
-
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
240
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function canonicalize(value: unknown): unknown {
|
|
244
|
-
if (value === undefined) return null;
|
|
245
|
-
if (typeof value === "bigint") return value.toString();
|
|
246
|
-
if (Array.isArray(value)) return value.map(canonicalize);
|
|
247
|
-
if (isPlainObject(value)) {
|
|
248
|
-
const out: Record<string, unknown> = {};
|
|
249
|
-
for (const k of Object.keys(value).sort()) out[k] = canonicalize(value[k]);
|
|
250
|
-
return out;
|
|
251
|
-
}
|
|
252
|
-
return value;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function canonicalJson(value: unknown): string {
|
|
256
|
-
return JSON.stringify(canonicalize(value));
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const coreAdapter: ConformanceAdapter = {
|
|
260
|
-
name: "@oxdeai/core",
|
|
261
|
-
canonicalJson,
|
|
262
|
-
intentHash(intent: Intent): string {
|
|
263
|
-
const src = intent as unknown as Record<string, unknown>;
|
|
264
|
-
const binding: Record<string, unknown> = {};
|
|
265
|
-
for (const key of INTENT_BINDING_FIELDS) {
|
|
266
|
-
const value = src[key];
|
|
267
|
-
if (value !== undefined) binding[key] = value;
|
|
268
|
-
}
|
|
269
|
-
return sha256HexFromJson(binding);
|
|
270
|
-
},
|
|
271
|
-
evaluateAuthorization(intent: Intent) {
|
|
272
|
-
const engine = makeEngine();
|
|
273
|
-
const out = engine.evaluatePure(intent, makeBaseState());
|
|
274
|
-
if (out.decision !== "ALLOW") {
|
|
275
|
-
throw new Error(`expected ALLOW, got DENY: ${out.reasons.join(",")}`);
|
|
276
|
-
}
|
|
277
|
-
return { authorization: out.authorization, policyId: engine.computePolicyId() };
|
|
278
|
-
},
|
|
279
|
-
encodeSnapshot(state: State) {
|
|
280
|
-
const engine = makeEngine();
|
|
281
|
-
const snapshot = engine.exportState(state);
|
|
282
|
-
return { bytes: encodeCanonicalState(snapshot), policyId: engine.computePolicyId() };
|
|
283
|
-
},
|
|
284
|
-
verifySnapshot(bytes: Uint8Array, expectedPolicyId?: string): VerificationResult {
|
|
285
|
-
return verifySnapshot(bytes, expectedPolicyId ? { expectedPolicyId } : undefined);
|
|
286
|
-
},
|
|
287
|
-
verifyAuditEvents(events, opts) {
|
|
288
|
-
return verifyAuditEvents(events as any, opts);
|
|
289
|
-
},
|
|
290
|
-
verifyEnvelope,
|
|
291
|
-
verifyAuthorization
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
function loadJson<T>(name: string): T {
|
|
295
|
-
const p = resolve(process.cwd(), "vectors", name);
|
|
296
|
-
return JSON.parse(readFileSync(p, "utf8")) as T;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
type VectorFile = { version: string; vectors: Array<JsonRecord> };
|
|
300
|
-
|
|
301
|
-
type CheckCtx = {
|
|
302
|
-
failures: string[];
|
|
303
|
-
passed: number;
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
function pass(ctx: CheckCtx, msg: string): void {
|
|
307
|
-
ctx.passed += 1;
|
|
308
|
-
console.log(`PASS ${msg}`);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function fail(ctx: CheckCtx, msg: string): void {
|
|
312
|
-
ctx.failures.push(msg);
|
|
313
|
-
console.error(`FAIL ${msg}`);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function eq(ctx: CheckCtx, label: string, actual: unknown, expected: unknown): void {
|
|
317
|
-
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
318
|
-
fail(ctx, `${label}: expected=${JSON.stringify(expected)} actual=${JSON.stringify(actual)}`);
|
|
319
|
-
} else {
|
|
320
|
-
pass(ctx, label);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function validateIntentHashVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
325
|
-
const file = loadJson<VectorFile>("intent-hash.json");
|
|
326
|
-
const vectors = file.vectors;
|
|
327
|
-
const hashes: Record<string, string> = {};
|
|
328
|
-
|
|
329
|
-
for (const v of vectors) {
|
|
330
|
-
const id = String(v.id);
|
|
331
|
-
const intent = parseIntent(v.input);
|
|
332
|
-
const got = adapter.intentHash(intent);
|
|
333
|
-
const want = String(asRecord(v.expected).hash);
|
|
334
|
-
hashes[id] = got;
|
|
335
|
-
eq(ctx, `${id} hash`, got, want);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
eq(ctx, "intent-hash-002 invariant", hashes["intent-hash-002"], hashes["intent-hash-001"]);
|
|
339
|
-
eq(ctx, "intent-hash-003 invariant", hashes["intent-hash-003"], hashes["intent-hash-001"]);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function validateAuthorizationVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
343
|
-
const file = loadJson<VectorFile>("authorization-payload.json");
|
|
344
|
-
|
|
345
|
-
for (const v of file.vectors) {
|
|
346
|
-
const id = String(v.id);
|
|
347
|
-
const intent = parseIntent(v.input);
|
|
348
|
-
const { authorization, policyId } = adapter.evaluateAuthorization(intent);
|
|
349
|
-
const expected = asRecord(v.expected);
|
|
350
|
-
|
|
351
|
-
eq(ctx, `${id} intent_hash`, authorization.intent_hash, String(expected.intent_hash));
|
|
352
|
-
if (expected.state_hash !== undefined) {
|
|
353
|
-
eq(ctx, `${id} state_hash`, authorization.state_snapshot_hash, String(expected.state_hash));
|
|
354
|
-
}
|
|
355
|
-
eq(ctx, `${id} expires_at`, authorization.expires_at, Number(expected.expires_at));
|
|
356
|
-
|
|
357
|
-
const payload = adapter.canonicalJson({
|
|
358
|
-
expires_at: authorization.expires_at,
|
|
359
|
-
intent_hash: authorization.intent_hash,
|
|
360
|
-
policy_id: policyId,
|
|
361
|
-
state_hash: authorization.state_snapshot_hash
|
|
362
|
-
});
|
|
363
|
-
eq(ctx, `${id} canonical_signing_payload`, payload, String(expected.canonical_signing_payload));
|
|
364
|
-
eq(ctx, `${id} signature`, authorization.engine_signature, String(expected.signature));
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function validateAuthorizationVerificationVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
369
|
-
const file = loadJson<VectorFile>("authorization-verification.json");
|
|
370
|
-
|
|
371
|
-
for (const v of file.vectors) {
|
|
372
|
-
const id = String(v.id);
|
|
373
|
-
const input = asRecord(v.input);
|
|
374
|
-
const auth = {
|
|
375
|
-
alg: "HMAC-SHA256",
|
|
376
|
-
kid: "legacy",
|
|
377
|
-
signature: "legacy-placeholder",
|
|
378
|
-
...(asRecord(input.auth) as Record<string, unknown>)
|
|
379
|
-
} as AuthorizationV1;
|
|
380
|
-
const opts = (input.opts ? asRecord(input.opts) : {}) as {
|
|
381
|
-
now?: number;
|
|
382
|
-
expectedIssuer?: string;
|
|
383
|
-
expectedAudience?: string;
|
|
384
|
-
expectedPolicyId?: string;
|
|
385
|
-
consumedAuthIds?: readonly string[];
|
|
386
|
-
};
|
|
387
|
-
const expected = asRecord(v.expected);
|
|
388
|
-
const got = adapter.verifyAuthorization(auth, opts);
|
|
389
|
-
|
|
390
|
-
eq(ctx, `${id} status`, got.status, String(expected.status));
|
|
391
|
-
eq(ctx, `${id} violations`, got.violations, expected.violations ?? []);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function makeSignedAuthorizationBase(now = 1730000000): AuthorizationV1 {
|
|
396
|
-
return signAuthorizationEd25519(
|
|
397
|
-
{
|
|
398
|
-
auth_id: "f".repeat(64),
|
|
399
|
-
issuer: "oxdeai.policy-engine",
|
|
400
|
-
audience: "merchant-gateway",
|
|
401
|
-
intent_hash: "a".repeat(64),
|
|
402
|
-
state_hash: "b".repeat(64),
|
|
403
|
-
policy_id: "c".repeat(64),
|
|
404
|
-
decision: "ALLOW",
|
|
405
|
-
issued_at: now,
|
|
406
|
-
expiry: now + 60,
|
|
407
|
-
kid: "2026-01"
|
|
408
|
-
},
|
|
409
|
-
TEST_ONLY_ED25519_PRIVATE_KEY_PEM_DO_NOT_USE_IN_PRODUCTION
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function validateAuthorizationSignatureVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
414
|
-
const file = loadJson<VectorFile>("authorization-signature-verification.json");
|
|
415
|
-
|
|
416
|
-
for (const v of file.vectors) {
|
|
417
|
-
const id = String(v.id);
|
|
418
|
-
const mode = String(v.mode);
|
|
419
|
-
const expected = asRecord(v.expected);
|
|
420
|
-
let auth = makeSignedAuthorizationBase();
|
|
421
|
-
const opts: Parameters<ConformanceAdapter["verifyAuthorization"]>[1] = {
|
|
422
|
-
now: 1730000010,
|
|
423
|
-
expectedIssuer: "oxdeai.policy-engine",
|
|
424
|
-
expectedAudience: "merchant-gateway",
|
|
425
|
-
expectedPolicyId: "c".repeat(64),
|
|
426
|
-
trustedKeySets: TEST_KEYSET,
|
|
427
|
-
requireSignatureVerification: true,
|
|
428
|
-
consumedAuthIds: []
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
if (mode === "invalid-signature") {
|
|
432
|
-
auth = { ...auth, signature: `${auth.signature.slice(0, -2)}aa` };
|
|
433
|
-
} else if (mode === "wrong-kid") {
|
|
434
|
-
auth = { ...auth, kid: "unknown-kid" };
|
|
435
|
-
} else if (mode === "wrong-issuer") {
|
|
436
|
-
auth = { ...auth, issuer: "other-issuer" };
|
|
437
|
-
} else if (mode === "wrong-audience") {
|
|
438
|
-
const { signature: _sig, alg: _alg, ...unsigned } = auth;
|
|
439
|
-
auth = signAuthorizationEd25519(
|
|
440
|
-
{
|
|
441
|
-
...unsigned,
|
|
442
|
-
audience: "other-audience"
|
|
443
|
-
},
|
|
444
|
-
TEST_ONLY_ED25519_PRIVATE_KEY_PEM_DO_NOT_USE_IN_PRODUCTION
|
|
445
|
-
);
|
|
446
|
-
opts.expectedAudience = "merchant-gateway";
|
|
447
|
-
} else if (mode === "tampered-field") {
|
|
448
|
-
auth = { ...auth, state_hash: "d".repeat(64) };
|
|
449
|
-
} else if (mode === "expired") {
|
|
450
|
-
const { signature: _sig, alg: _alg, ...unsigned } = auth;
|
|
451
|
-
auth = signAuthorizationEd25519(
|
|
452
|
-
{
|
|
453
|
-
...unsigned,
|
|
454
|
-
issued_at: 100,
|
|
455
|
-
expiry: 110
|
|
456
|
-
},
|
|
457
|
-
TEST_ONLY_ED25519_PRIVATE_KEY_PEM_DO_NOT_USE_IN_PRODUCTION
|
|
458
|
-
);
|
|
459
|
-
opts.now = 120;
|
|
460
|
-
} else if (mode === "replay") {
|
|
461
|
-
opts.consumedAuthIds = [auth.auth_id];
|
|
462
|
-
} else if (mode === "unknown-alg") {
|
|
463
|
-
auth = { ...auth, alg: "Unknown" as any };
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const got = adapter.verifyAuthorization(auth, opts);
|
|
467
|
-
eq(ctx, `${id} status`, got.status, String(expected.status));
|
|
468
|
-
eq(ctx, `${id} violations`, got.violations, expected.violations ?? []);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
function validateSnapshotVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
473
|
-
const file = loadJson<VectorFile>("snapshot-hash.json");
|
|
474
|
-
|
|
475
|
-
for (const v of file.vectors) {
|
|
476
|
-
const id = String(v.id);
|
|
477
|
-
const expected = asRecord(v.expected);
|
|
478
|
-
|
|
479
|
-
if (v.input_state !== undefined) {
|
|
480
|
-
const state = parseState(v.input_state);
|
|
481
|
-
const { bytes, policyId } = adapter.encodeSnapshot(state);
|
|
482
|
-
const out = adapter.verifySnapshot(bytes, policyId);
|
|
483
|
-
if (out.status !== "ok" || !out.stateHash) {
|
|
484
|
-
fail(ctx, `${id} verifySnapshot expected ok`);
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
eq(ctx, `${id} snapshot_base64`, Buffer.from(bytes).toString("base64"), String(expected.snapshot_base64));
|
|
488
|
-
eq(ctx, `${id} state_hash`, out.stateHash, String(expected.state_hash));
|
|
489
|
-
} else {
|
|
490
|
-
const bytes = b64ToBytes(String(v.input_snapshot_base64));
|
|
491
|
-
const out = adapter.verifySnapshot(bytes, CORE_POLICY_ID);
|
|
492
|
-
if (out.status !== "ok" || !out.stateHash) {
|
|
493
|
-
fail(ctx, `${id} verifySnapshot expected ok`);
|
|
494
|
-
continue;
|
|
495
|
-
}
|
|
496
|
-
eq(ctx, `${id} state_hash`, out.stateHash, String(expected.state_hash));
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
function validateAuditChainVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
502
|
-
const file = loadJson<VectorFile>("audit-chain.json");
|
|
503
|
-
const [v1, v2, v3, v4] = file.vectors;
|
|
504
|
-
|
|
505
|
-
const genesis = hexSha256Utf8(String(v1.input));
|
|
506
|
-
eq(ctx, "audit-chain-001 genesis", genesis, String(asRecord(v1.expected).genesis_hex));
|
|
507
|
-
|
|
508
|
-
const i2 = asRecord(v2.input);
|
|
509
|
-
const e0 = i2.event_0;
|
|
510
|
-
const head1 = hexSha256Utf8(`${String(i2.head_0)}\n${adapter.canonicalJson(e0)}`);
|
|
511
|
-
eq(ctx, "audit-chain-002 head_1", head1, String(asRecord(v2.expected).head_1));
|
|
512
|
-
|
|
513
|
-
const i3 = asRecord(v3.input);
|
|
514
|
-
const events = (i3.events as unknown[]) ?? [];
|
|
515
|
-
let head = String(i3.genesis);
|
|
516
|
-
const heads: string[] = [];
|
|
517
|
-
for (const ev of events) {
|
|
518
|
-
head = hexSha256Utf8(`${head}\n${adapter.canonicalJson(ev)}`);
|
|
519
|
-
heads.push(head);
|
|
520
|
-
}
|
|
521
|
-
const e3 = asRecord(v3.expected);
|
|
522
|
-
eq(ctx, "audit-chain-003 head_1", heads[0], String(e3.head_1));
|
|
523
|
-
eq(ctx, "audit-chain-003 head_2", heads[1], String(e3.head_2));
|
|
524
|
-
eq(ctx, "audit-chain-003 head_3", heads[2], String(e3.head_3));
|
|
525
|
-
|
|
526
|
-
const i4 = asRecord(v4.input);
|
|
527
|
-
const mut = i4.mutated_event_0;
|
|
528
|
-
const mutHead1 = hexSha256Utf8(`${String(i4.head_0)}\n${adapter.canonicalJson(mut)}`);
|
|
529
|
-
const e4 = asRecord(v4.expected);
|
|
530
|
-
eq(ctx, "audit-chain-004 original_head_1", String(e4.original_head_1), String(e4.original_head_1));
|
|
531
|
-
eq(ctx, "audit-chain-004 mutated_head_1", mutHead1, String(e4.mutated_head_1));
|
|
532
|
-
eq(ctx, "audit-chain-004 must differ", mutHead1 !== String(e4.original_head_1), true);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
function buildEnvelopeCases(adapter: ConformanceAdapter): Array<{ status: string; violations: unknown[]; policyId?: string; stateHash?: string; auditHeadHash?: string }> {
|
|
536
|
-
const engine = makeEngine();
|
|
537
|
-
const state = makeBaseState();
|
|
538
|
-
const intent = parseIntent({
|
|
539
|
-
intent_id: "intent-300",
|
|
540
|
-
agent_id: "agent-1",
|
|
541
|
-
action_type: "PAYMENT",
|
|
542
|
-
amount: "1000000",
|
|
543
|
-
target: "merchant-1",
|
|
544
|
-
timestamp: 1730000000,
|
|
545
|
-
metadata_hash: "0".repeat(64),
|
|
546
|
-
nonce: "300",
|
|
547
|
-
signature: "sig-placeholder",
|
|
548
|
-
depth: 0,
|
|
549
|
-
tool: "openai.responses",
|
|
550
|
-
tool_call: true,
|
|
551
|
-
type: "EXECUTE"
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
const out = engine.evaluatePure(intent, state);
|
|
555
|
-
if (out.decision !== "ALLOW") throw new Error("expected ALLOW for envelope cases");
|
|
556
|
-
|
|
557
|
-
const events = engine.audit.snapshot();
|
|
558
|
-
const snapshotBytes = encodeCanonicalState(engine.exportState(state));
|
|
559
|
-
const snap = adapter.verifySnapshot(snapshotBytes, engine.computePolicyId());
|
|
560
|
-
if (snap.status !== "ok" || !snap.stateHash) throw new Error("failed to build envelope cases");
|
|
561
|
-
|
|
562
|
-
const valid = encodeEnvelope({ formatVersion: 1, snapshot: snapshotBytes, events });
|
|
563
|
-
const withCheckpointEvents: EnvelopeEvent[] = [
|
|
564
|
-
...events,
|
|
565
|
-
{
|
|
566
|
-
type: "STATE_CHECKPOINT" as const,
|
|
567
|
-
stateHash: snap.stateHash,
|
|
568
|
-
timestamp: intent.timestamp,
|
|
569
|
-
policyId: engine.computePolicyId()
|
|
570
|
-
}
|
|
571
|
-
];
|
|
572
|
-
const withCheckpoint = encodeEnvelope({
|
|
573
|
-
formatVersion: 1,
|
|
574
|
-
snapshot: snapshotBytes,
|
|
575
|
-
events: withCheckpointEvents
|
|
576
|
-
});
|
|
577
|
-
const mismatchedEvents: EnvelopeEvent[] = events.map((e) => ({
|
|
578
|
-
...e,
|
|
579
|
-
policyId: "c".repeat(64)
|
|
580
|
-
}));
|
|
581
|
-
const mismatched = encodeEnvelope({
|
|
582
|
-
formatVersion: 1,
|
|
583
|
-
snapshot: snapshotBytes,
|
|
584
|
-
events: mismatchedEvents
|
|
585
|
-
});
|
|
586
|
-
const corrupt = new Uint8Array([1, 2, 3, 4, 5]);
|
|
587
|
-
|
|
588
|
-
return [
|
|
589
|
-
adapter.verifyEnvelope(withCheckpoint, { expectedPolicyId: engine.computePolicyId(), mode: "strict" }),
|
|
590
|
-
adapter.verifyEnvelope(valid, { expectedPolicyId: engine.computePolicyId(), mode: "best-effort" }),
|
|
591
|
-
adapter.verifyEnvelope(mismatched, { expectedPolicyId: engine.computePolicyId(), mode: "best-effort" }),
|
|
592
|
-
adapter.verifyEnvelope(corrupt, { expectedPolicyId: engine.computePolicyId(), mode: "best-effort" }),
|
|
593
|
-
adapter.verifyEnvelope(valid, { expectedPolicyId: engine.computePolicyId(), mode: "strict" })
|
|
594
|
-
];
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
function validateEnvelopeVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
598
|
-
const file = loadJson<VectorFile>("envelope-verification.json");
|
|
599
|
-
const actual = buildEnvelopeCases(adapter);
|
|
600
|
-
|
|
601
|
-
for (let i = 0; i < file.vectors.length; i++) {
|
|
602
|
-
const id = String(file.vectors[i].id);
|
|
603
|
-
const expected = asRecord(file.vectors[i].expected);
|
|
604
|
-
const got = actual[i];
|
|
605
|
-
|
|
606
|
-
eq(ctx, `${id} status`, got.status, String(expected.status));
|
|
607
|
-
if (expected.policyId !== undefined) eq(ctx, `${id} policyId`, got.policyId, String(expected.policyId));
|
|
608
|
-
if (expected.stateHash !== undefined) eq(ctx, `${id} stateHash`, got.stateHash, String(expected.stateHash));
|
|
609
|
-
if (expected.auditHeadHash !== undefined) eq(ctx, `${id} auditHeadHash`, got.auditHeadHash, String(expected.auditHeadHash));
|
|
610
|
-
eq(ctx, `${id} violations`, got.violations, expected.violations ?? []);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
function validateEnvelopeSignatureVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
615
|
-
const file = loadJson<VectorFile>("envelope-signature-verification.json");
|
|
616
|
-
const engine = makeEngine();
|
|
617
|
-
const state = makeBaseState();
|
|
618
|
-
const bytes = encodeCanonicalState(engine.exportState(state));
|
|
619
|
-
const policyId = engine.computePolicyId();
|
|
620
|
-
const events = [
|
|
621
|
-
{
|
|
622
|
-
type: "INTENT_RECEIVED" as const,
|
|
623
|
-
intent_hash: "11".repeat(32),
|
|
624
|
-
agent_id: "agent-1",
|
|
625
|
-
timestamp: 100,
|
|
626
|
-
policyId
|
|
627
|
-
},
|
|
628
|
-
{
|
|
629
|
-
type: "STATE_CHECKPOINT" as const,
|
|
630
|
-
stateHash: verifySnapshot(bytes, { expectedPolicyId: policyId }).stateHash!,
|
|
631
|
-
timestamp: 101,
|
|
632
|
-
policyId
|
|
633
|
-
}
|
|
634
|
-
];
|
|
635
|
-
const signed = signEnvelopeEd25519(
|
|
636
|
-
{
|
|
637
|
-
formatVersion: 1,
|
|
638
|
-
snapshot: bytes,
|
|
639
|
-
events
|
|
640
|
-
},
|
|
641
|
-
{ issuer: "oxdeai.policy-engine", kid: "2026-01", privateKeyPem: TEST_ONLY_ED25519_PRIVATE_KEY_PEM_DO_NOT_USE_IN_PRODUCTION }
|
|
642
|
-
);
|
|
643
|
-
|
|
644
|
-
for (const v of file.vectors) {
|
|
645
|
-
const id = String(v.id);
|
|
646
|
-
const mode = String(v.mode);
|
|
647
|
-
const expected = asRecord(v.expected);
|
|
648
|
-
let env = structuredClone(signed);
|
|
649
|
-
const opts: Parameters<ConformanceAdapter["verifyEnvelope"]>[1] & {
|
|
650
|
-
trustedKeySets?: KeySet;
|
|
651
|
-
expectedIssuer?: string;
|
|
652
|
-
requireSignatureVerification?: boolean;
|
|
653
|
-
now?: number;
|
|
654
|
-
} = {
|
|
655
|
-
mode: "strict",
|
|
656
|
-
expectedPolicyId: policyId,
|
|
657
|
-
expectedIssuer: "oxdeai.policy-engine",
|
|
658
|
-
trustedKeySets: TEST_KEYSET,
|
|
659
|
-
requireSignatureVerification: true,
|
|
660
|
-
now: 1730000010
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
if (mode === "tampered-envelope") {
|
|
664
|
-
env = { ...env, events: [...env.events, { type: "DECISION", intent_hash: "11".repeat(32), decision: "ALLOW", reasons: [], policy_version: "v1", timestamp: 102, policyId }] as any };
|
|
665
|
-
} else if (mode === "unknown-alg") {
|
|
666
|
-
env = { ...env, alg: "Unknown" as any };
|
|
667
|
-
} else if (mode === "unknown-kid") {
|
|
668
|
-
env = { ...env, kid: "missing-kid" };
|
|
669
|
-
} else if (mode === "malformed-signature") {
|
|
670
|
-
env = { ...env, signature: "!!!not-base64!!!" };
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
const wire = encodeEnvelope(env as any);
|
|
674
|
-
const got = adapter.verifyEnvelope(wire, opts as any);
|
|
675
|
-
eq(ctx, `${id} status`, got.status, String(expected.status));
|
|
676
|
-
eq(ctx, `${id} violations`, got.violations, expected.violations ?? []);
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
function buildAuditVerificationCases(
|
|
681
|
-
adapter: ConformanceAdapter
|
|
682
|
-
): Array<{ status: string; violations: unknown[] }> {
|
|
683
|
-
const expectedPolicyId = "a".repeat(64);
|
|
684
|
-
const mismatchPolicyId = "b".repeat(64);
|
|
685
|
-
const altPolicyId = "c".repeat(64);
|
|
686
|
-
|
|
687
|
-
const policyMismatch = adapter.verifyAuditEvents(
|
|
688
|
-
[
|
|
689
|
-
{
|
|
690
|
-
type: "INTENT_RECEIVED",
|
|
691
|
-
intent_hash: "11".repeat(32),
|
|
692
|
-
agent_id: "agent-1",
|
|
693
|
-
timestamp: 100,
|
|
694
|
-
policyId: mismatchPolicyId
|
|
695
|
-
}
|
|
696
|
-
],
|
|
697
|
-
{ expectedPolicyId, mode: "best-effort" }
|
|
698
|
-
);
|
|
699
|
-
|
|
700
|
-
const nonMonotonic = adapter.verifyAuditEvents(
|
|
701
|
-
[
|
|
702
|
-
{
|
|
703
|
-
type: "INTENT_RECEIVED",
|
|
704
|
-
intent_hash: "22".repeat(32),
|
|
705
|
-
agent_id: "agent-1",
|
|
706
|
-
timestamp: 200,
|
|
707
|
-
policyId: expectedPolicyId
|
|
708
|
-
},
|
|
709
|
-
{
|
|
710
|
-
type: "DECISION",
|
|
711
|
-
intent_hash: "22".repeat(32),
|
|
712
|
-
decision: "ALLOW",
|
|
713
|
-
reasons: [],
|
|
714
|
-
policy_version: "v1",
|
|
715
|
-
timestamp: 100,
|
|
716
|
-
policyId: expectedPolicyId
|
|
717
|
-
}
|
|
718
|
-
],
|
|
719
|
-
{ mode: "best-effort" }
|
|
720
|
-
);
|
|
721
|
-
|
|
722
|
-
const mixedPolicy = adapter.verifyAuditEvents(
|
|
723
|
-
[
|
|
724
|
-
{
|
|
725
|
-
type: "INTENT_RECEIVED",
|
|
726
|
-
intent_hash: "33".repeat(32),
|
|
727
|
-
agent_id: "agent-1",
|
|
728
|
-
timestamp: 100,
|
|
729
|
-
policyId: expectedPolicyId
|
|
730
|
-
},
|
|
731
|
-
{
|
|
732
|
-
type: "DECISION",
|
|
733
|
-
intent_hash: "33".repeat(32),
|
|
734
|
-
decision: "ALLOW",
|
|
735
|
-
reasons: [],
|
|
736
|
-
policy_version: "v1",
|
|
737
|
-
timestamp: 100,
|
|
738
|
-
policyId: mismatchPolicyId
|
|
739
|
-
}
|
|
740
|
-
],
|
|
741
|
-
{ mode: "best-effort" }
|
|
742
|
-
);
|
|
743
|
-
|
|
744
|
-
const strictMissingAnchor = adapter.verifyAuditEvents(
|
|
745
|
-
[
|
|
746
|
-
{
|
|
747
|
-
type: "INTENT_RECEIVED",
|
|
748
|
-
intent_hash: "44".repeat(32),
|
|
749
|
-
agent_id: "agent-1",
|
|
750
|
-
timestamp: 100,
|
|
751
|
-
policyId: expectedPolicyId
|
|
752
|
-
},
|
|
753
|
-
{
|
|
754
|
-
type: "DECISION",
|
|
755
|
-
intent_hash: "44".repeat(32),
|
|
756
|
-
decision: "ALLOW",
|
|
757
|
-
reasons: [],
|
|
758
|
-
policy_version: "v1",
|
|
759
|
-
timestamp: 100,
|
|
760
|
-
policyId: expectedPolicyId
|
|
761
|
-
}
|
|
762
|
-
],
|
|
763
|
-
{ mode: "strict" }
|
|
764
|
-
);
|
|
765
|
-
|
|
766
|
-
const orderingCase = adapter.verifyAuditEvents(
|
|
767
|
-
[
|
|
768
|
-
{
|
|
769
|
-
type: "INTENT_RECEIVED",
|
|
770
|
-
intent_hash: "55".repeat(32),
|
|
771
|
-
agent_id: "agent-1",
|
|
772
|
-
timestamp: 300,
|
|
773
|
-
policyId: altPolicyId
|
|
774
|
-
},
|
|
775
|
-
{
|
|
776
|
-
type: "DECISION",
|
|
777
|
-
intent_hash: "55".repeat(32),
|
|
778
|
-
decision: "ALLOW",
|
|
779
|
-
reasons: [],
|
|
780
|
-
policy_version: "v1",
|
|
781
|
-
timestamp: 100,
|
|
782
|
-
policyId: mismatchPolicyId
|
|
783
|
-
}
|
|
784
|
-
],
|
|
785
|
-
{ expectedPolicyId, mode: "strict" }
|
|
786
|
-
);
|
|
787
|
-
|
|
788
|
-
return [policyMismatch, nonMonotonic, mixedPolicy, strictMissingAnchor, orderingCase];
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
function validateAuditVerificationVectors(ctx: CheckCtx, adapter: ConformanceAdapter): void {
|
|
792
|
-
const file = loadJson<VectorFile>("audit-verification.json");
|
|
793
|
-
const actual = buildAuditVerificationCases(adapter);
|
|
794
|
-
|
|
795
|
-
for (let i = 0; i < file.vectors.length; i++) {
|
|
796
|
-
const id = String(file.vectors[i].id);
|
|
797
|
-
const expected = asRecord(file.vectors[i].expected);
|
|
798
|
-
const got = actual[i];
|
|
799
|
-
eq(ctx, `${id} status`, got.status, String(expected.status));
|
|
800
|
-
eq(ctx, `${id} violations`, got.violations, expected.violations ?? []);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
function main(): void {
|
|
805
|
-
const ctx: CheckCtx = { failures: [], passed: 0 };
|
|
806
|
-
const adapter = coreAdapter;
|
|
807
|
-
|
|
808
|
-
console.log(`Running conformance validation with ${adapter.name}`);
|
|
809
|
-
|
|
810
|
-
validateIntentHashVectors(ctx, adapter);
|
|
811
|
-
validateAuthorizationVectors(ctx, adapter);
|
|
812
|
-
validateAuthorizationVerificationVectors(ctx, adapter);
|
|
813
|
-
validateAuthorizationSignatureVectors(ctx, adapter);
|
|
814
|
-
validateSnapshotVectors(ctx, adapter);
|
|
815
|
-
validateAuditChainVectors(ctx, adapter);
|
|
816
|
-
validateAuditVerificationVectors(ctx, adapter);
|
|
817
|
-
validateEnvelopeVectors(ctx, adapter);
|
|
818
|
-
validateEnvelopeSignatureVectors(ctx, adapter);
|
|
819
|
-
|
|
820
|
-
if (ctx.failures.length > 0) {
|
|
821
|
-
console.error(`\nConformance failed: ${ctx.failures.length} assertion(s)`);
|
|
822
|
-
process.exit(1);
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
console.log(`\nConformance passed: ${ctx.passed} assertions`);
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
main();
|