@algovoi/audit-verifier 0.1.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/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/canonicalize.d.ts +5 -0
- package/dist/canonicalize.d.ts.map +1 -0
- package/dist/canonicalize.js +26 -0
- package/dist/canonicalize.js.map +1 -0
- package/dist/check-report.d.ts +18 -0
- package/dist/check-report.d.ts.map +1 -0
- package/dist/check-report.js +48 -0
- package/dist/check-report.js.map +1 -0
- package/dist/checks.d.ts +9 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +337 -0
- package/dist/checks.js.map +1 -0
- package/dist/demo.d.ts +17 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +186 -0
- package/dist/demo.js.map +1 -0
- package/dist/extractors.d.ts +13 -0
- package/dist/extractors.d.ts.map +1 -0
- package/dist/extractors.js +72 -0
- package/dist/extractors.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/verify.d.ts +10 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +44 -0
- package/dist/verify.js.map +1 -0
- package/package.json +64 -0
- package/src/canonicalize.ts +29 -0
- package/src/check-report.ts +58 -0
- package/src/checks.ts +435 -0
- package/src/demo.ts +214 -0
- package/src/extractors.ts +87 -0
- package/src/index.ts +44 -0
- package/src/types.ts +70 -0
- package/src/verify.ts +66 -0
package/dist/demo.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demo bundle generator -- builds a small synthetic signed AlgoVoi audit
|
|
3
|
+
* bundle for testing the verifier.
|
|
4
|
+
*
|
|
5
|
+
* Byte-for-byte equivalent to the Python sibling demo_audit_bundle.py
|
|
6
|
+
* when called with bundle_emitted_at fixed (the Python default uses
|
|
7
|
+
* datetime.now() so timestamps will differ; passing a fixed emittedAt
|
|
8
|
+
* makes the two implementations produce identical bytes for the same
|
|
9
|
+
* row_count + chain_name + signing_key + key_id).
|
|
10
|
+
*/
|
|
11
|
+
import { createHash, createHmac } from 'node:crypto';
|
|
12
|
+
import { canonicaliseToBytes } from './canonicalize.js';
|
|
13
|
+
export const GENESIS_PREV_HASH = '0'.repeat(64);
|
|
14
|
+
export const DEFAULT_KEY = 'demo-key-not-for-production-use';
|
|
15
|
+
function pad(n, width) {
|
|
16
|
+
return String(n).padStart(width, '0');
|
|
17
|
+
}
|
|
18
|
+
function sha256OfJcs(obj) {
|
|
19
|
+
return createHash('sha256').update(canonicaliseToBytes(obj)).digest('hex');
|
|
20
|
+
}
|
|
21
|
+
function auditLogRow(chainPosition, prevHash) {
|
|
22
|
+
const canonical = {
|
|
23
|
+
trace_id: `00000000-0000-0000-0000-${pad(chainPosition, 12)}`,
|
|
24
|
+
actor: 'demo-admin@example.com',
|
|
25
|
+
action: 'tenant.create',
|
|
26
|
+
target_type: 'tenant',
|
|
27
|
+
target_id: `tnt-${chainPosition}`,
|
|
28
|
+
tenant_id: null,
|
|
29
|
+
before_state: null,
|
|
30
|
+
after_state: { created: true, seq: chainPosition },
|
|
31
|
+
ip_address: '203.0.113.7',
|
|
32
|
+
user_agent: 'demo-agent/1.0',
|
|
33
|
+
created_at: `2026-05-06T20:00:${pad(chainPosition, 2)}+00:00`,
|
|
34
|
+
chain_position: chainPosition,
|
|
35
|
+
prev_hash: prevHash,
|
|
36
|
+
};
|
|
37
|
+
const contentHash = sha256OfJcs(canonical);
|
|
38
|
+
return { id: chainPosition * 100, content_hash: contentHash, ...canonical };
|
|
39
|
+
}
|
|
40
|
+
function screeningHitRow(chainPosition, prevHash) {
|
|
41
|
+
const canonical = {
|
|
42
|
+
screened_at: `2026-05-06T20:00:${pad(chainPosition, 2)}+00:00`,
|
|
43
|
+
subject_type: 'payer',
|
|
44
|
+
wallet_address: `0xdemo${String(chainPosition).padStart(36, '0')}`,
|
|
45
|
+
tenant_id: null,
|
|
46
|
+
payment_ledger_id: null,
|
|
47
|
+
sanctions_entry_id: chainPosition,
|
|
48
|
+
action_taken: 'flagged',
|
|
49
|
+
screening_context: 'realtime',
|
|
50
|
+
chain_position: chainPosition,
|
|
51
|
+
prev_hash: prevHash,
|
|
52
|
+
};
|
|
53
|
+
const contentHash = sha256OfJcs(canonical);
|
|
54
|
+
return { id: chainPosition * 100, content_hash: contentHash, ...canonical };
|
|
55
|
+
}
|
|
56
|
+
function complianceEventRow(chainPosition, prevHash) {
|
|
57
|
+
const fixedUuid = `11111111-1111-1111-1111-${pad(chainPosition, 12)}`;
|
|
58
|
+
const tenantUuid = `22222222-2222-2222-2222-${pad(chainPosition, 12)}`;
|
|
59
|
+
const ruleUuid = `33333333-3333-3333-3333-${pad(chainPosition, 12)}`;
|
|
60
|
+
const canonical = {
|
|
61
|
+
id: fixedUuid,
|
|
62
|
+
tenant_id: tenantUuid,
|
|
63
|
+
rule_id: ruleUuid,
|
|
64
|
+
payment_ledger_id: null,
|
|
65
|
+
payer_address_snapshot: null,
|
|
66
|
+
review_of_event_id: null,
|
|
67
|
+
event_type: 'alert',
|
|
68
|
+
metric_value: '100.0000',
|
|
69
|
+
threshold_value: '50.0000',
|
|
70
|
+
created_at: `2026-05-06T20:00:${pad(chainPosition, 2)}+00:00`,
|
|
71
|
+
chain_position: chainPosition,
|
|
72
|
+
prev_hash: prevHash,
|
|
73
|
+
};
|
|
74
|
+
const contentHash = sha256OfJcs(canonical);
|
|
75
|
+
return { ...canonical, content_hash: contentHash };
|
|
76
|
+
}
|
|
77
|
+
function negotiationTraceRow(chainPosition, prevHash) {
|
|
78
|
+
const canonical = {
|
|
79
|
+
trace_id: '44444444-4444-4444-4444-444444444444',
|
|
80
|
+
session_id: null,
|
|
81
|
+
tenant_id: null,
|
|
82
|
+
counterparty_a: 'did:example:demo_agent_a',
|
|
83
|
+
counterparty_b: 'did:example:demo_agent_b',
|
|
84
|
+
protocol: 'x402',
|
|
85
|
+
message_seq: chainPosition,
|
|
86
|
+
message_role: chainPosition === 1 ? 'offer' : 'counter',
|
|
87
|
+
message_payload: { step: chainPosition, amount: '10000', asset: 'USDC' },
|
|
88
|
+
payment_ledger_id: null,
|
|
89
|
+
created_at: `2026-05-06T20:00:${pad(chainPosition, 2)}+00:00`,
|
|
90
|
+
chain_position: chainPosition,
|
|
91
|
+
prev_hash: prevHash,
|
|
92
|
+
};
|
|
93
|
+
const contentHash = sha256OfJcs(canonical);
|
|
94
|
+
const fixedUuid = `55555555-5555-5555-5555-${pad(chainPosition, 12)}`;
|
|
95
|
+
return { id: fixedUuid, content_hash: contentHash, ...canonical };
|
|
96
|
+
}
|
|
97
|
+
const CHAIN_BUILDERS = {
|
|
98
|
+
audit_log: auditLogRow,
|
|
99
|
+
screening_hits: screeningHitRow,
|
|
100
|
+
compliance_events: complianceEventRow,
|
|
101
|
+
negotiation_trace_events: negotiationTraceRow,
|
|
102
|
+
};
|
|
103
|
+
const CHAIN_EMPTY_CRITERIA = {
|
|
104
|
+
audit_log: {
|
|
105
|
+
actor: null, action: null, target_type: null,
|
|
106
|
+
tenant_id: null, trace_id: null, since: null, until: null,
|
|
107
|
+
},
|
|
108
|
+
screening_hits: {
|
|
109
|
+
subject_type: null, action_taken: null, screening_context: null,
|
|
110
|
+
tenant_id: null, wallet_address: null,
|
|
111
|
+
since: null, until: null,
|
|
112
|
+
},
|
|
113
|
+
compliance_events: {
|
|
114
|
+
tenant_id: null, rule_id: null, event_type: null,
|
|
115
|
+
payment_ledger_id: null, since: null, until: null,
|
|
116
|
+
},
|
|
117
|
+
negotiation_trace_events: {
|
|
118
|
+
trace_id: null, tenant_id: null, protocol: null,
|
|
119
|
+
counterparty: null, message_role: null,
|
|
120
|
+
payment_ledger_id: null, since: null, until: null,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
export function buildDemoBundle(options = {}) {
|
|
124
|
+
const chainName = options.chainName ?? 'audit_log';
|
|
125
|
+
const rowCount = options.rowCount ?? 3;
|
|
126
|
+
const signingKey = options.signingKey ?? DEFAULT_KEY;
|
|
127
|
+
const keyId = options.keyId ?? 'demo-v1';
|
|
128
|
+
if (rowCount < 1)
|
|
129
|
+
throw new Error('row_count must be >= 1');
|
|
130
|
+
const builder = CHAIN_BUILDERS[chainName];
|
|
131
|
+
if (!builder) {
|
|
132
|
+
const known = Object.keys(CHAIN_BUILDERS).sort();
|
|
133
|
+
throw new Error(`chain_name '${chainName}' is not recognised. Expected one of: ${JSON.stringify(known)}`);
|
|
134
|
+
}
|
|
135
|
+
const rows = [];
|
|
136
|
+
let prev = GENESIS_PREV_HASH;
|
|
137
|
+
for (let pos = 1; pos <= rowCount; pos++) {
|
|
138
|
+
const row = builder(pos, prev);
|
|
139
|
+
rows.push(row);
|
|
140
|
+
prev = row['content_hash'];
|
|
141
|
+
}
|
|
142
|
+
const head = rows[rows.length - 1];
|
|
143
|
+
const bundle = {
|
|
144
|
+
chain_format_version: 1,
|
|
145
|
+
chain_name: chainName,
|
|
146
|
+
bundle_emitted_at: options.bundleEmittedAt ?? new Date().toISOString(),
|
|
147
|
+
selection_criteria: CHAIN_EMPTY_CRITERIA[chainName],
|
|
148
|
+
selection: {
|
|
149
|
+
row_count: rows.length,
|
|
150
|
+
min_chain_position: rows[0]['chain_position'],
|
|
151
|
+
max_chain_position: head['chain_position'],
|
|
152
|
+
truncated: false,
|
|
153
|
+
max_rows_cap: 10000,
|
|
154
|
+
},
|
|
155
|
+
rows: rows,
|
|
156
|
+
bridging_rows: [],
|
|
157
|
+
bridging: { included: true, row_count: 0, truncated: false },
|
|
158
|
+
chain_anchor: {
|
|
159
|
+
chain_name: chainName,
|
|
160
|
+
genesis_chain_position: 1,
|
|
161
|
+
genesis_prev_hash: GENESIS_PREV_HASH,
|
|
162
|
+
current_head: {
|
|
163
|
+
chain_position: head['chain_position'],
|
|
164
|
+
content_hash: head['content_hash'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
off_vm_anchor: null,
|
|
168
|
+
verification_instructions: `Demo bundle for chain '${chainName}'. Run the AlgoVoi audit ` +
|
|
169
|
+
`verifier against this file with --signing-key '${signingKey}' to verify.`,
|
|
170
|
+
};
|
|
171
|
+
// Sign: HMAC-SHA256 over JCS canonical of bundle minus signature.
|
|
172
|
+
const inner = {};
|
|
173
|
+
for (const [k, v] of Object.entries(bundle)) {
|
|
174
|
+
if (k !== 'bundle_signature')
|
|
175
|
+
inner[k] = v;
|
|
176
|
+
}
|
|
177
|
+
const digest = createHmac('sha256', signingKey).update(canonicaliseToBytes(inner)).digest('hex');
|
|
178
|
+
bundle.bundle_signature = {
|
|
179
|
+
algorithm: 'HMAC-SHA256',
|
|
180
|
+
canonicalisation: 'RFC 8785',
|
|
181
|
+
key_id: keyId,
|
|
182
|
+
hex: digest,
|
|
183
|
+
};
|
|
184
|
+
return bundle;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=demo.js.map
|
package/dist/demo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-chain canonical-field extractors.
|
|
3
|
+
*
|
|
4
|
+
* Each chain (audit_log / screening_hits / compliance_events /
|
|
5
|
+
* negotiation_trace_events) commits a different set of fields to its
|
|
6
|
+
* content_hash. These functions MUST byte-for-byte match the Python
|
|
7
|
+
* sibling (verify_audit_bundle.py) and the emitter side, otherwise every
|
|
8
|
+
* row will fail verification on the auditor side.
|
|
9
|
+
*/
|
|
10
|
+
import type { FieldExtractor } from './types.js';
|
|
11
|
+
export declare const FIELD_EXTRACTORS: Record<string, FieldExtractor>;
|
|
12
|
+
export declare const KNOWN_CHAIN_NAMES: string[];
|
|
13
|
+
//# sourceMappingURL=extractors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractors.d.ts","sourceRoot":"","sources":["../src/extractors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,YAAY,CAAC;AAsE3D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAK3D,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAuC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
function auditLogCanonicalFields(row) {
|
|
2
|
+
return {
|
|
3
|
+
trace_id: row.trace_id ?? null,
|
|
4
|
+
actor: row.actor ?? null,
|
|
5
|
+
action: row.action ?? null,
|
|
6
|
+
target_type: row.target_type ?? null,
|
|
7
|
+
target_id: row.target_id ?? null,
|
|
8
|
+
tenant_id: row.tenant_id ?? null,
|
|
9
|
+
before_state: row.before_state ?? null,
|
|
10
|
+
after_state: row.after_state ?? null,
|
|
11
|
+
ip_address: row.ip_address ?? null,
|
|
12
|
+
user_agent: row.user_agent ?? null,
|
|
13
|
+
created_at: row.created_at ?? null,
|
|
14
|
+
chain_position: row.chain_position ?? null,
|
|
15
|
+
prev_hash: row.prev_hash ?? null,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function screeningHitCanonicalFields(row) {
|
|
19
|
+
return {
|
|
20
|
+
screened_at: row.screened_at ?? null,
|
|
21
|
+
subject_type: row.subject_type ?? null,
|
|
22
|
+
wallet_address: row.wallet_address ?? null,
|
|
23
|
+
tenant_id: row.tenant_id ?? null,
|
|
24
|
+
payment_ledger_id: row.payment_ledger_id ?? null,
|
|
25
|
+
sanctions_entry_id: row.sanctions_entry_id ?? null,
|
|
26
|
+
action_taken: row.action_taken ?? null,
|
|
27
|
+
screening_context: row.screening_context ?? null,
|
|
28
|
+
chain_position: row.chain_position ?? null,
|
|
29
|
+
prev_hash: row.prev_hash ?? null,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function complianceEventCanonicalFields(row) {
|
|
33
|
+
return {
|
|
34
|
+
id: row.id ?? null,
|
|
35
|
+
tenant_id: row.tenant_id ?? null,
|
|
36
|
+
rule_id: row.rule_id ?? null,
|
|
37
|
+
payment_ledger_id: row.payment_ledger_id ?? null,
|
|
38
|
+
payer_address_snapshot: row.payer_address_snapshot ?? null,
|
|
39
|
+
review_of_event_id: row.review_of_event_id ?? null,
|
|
40
|
+
event_type: row.event_type ?? null,
|
|
41
|
+
metric_value: row.metric_value ?? null,
|
|
42
|
+
threshold_value: row.threshold_value ?? null,
|
|
43
|
+
created_at: row.created_at ?? null,
|
|
44
|
+
chain_position: row.chain_position ?? null,
|
|
45
|
+
prev_hash: row.prev_hash ?? null,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function negotiationTraceCanonicalFields(row) {
|
|
49
|
+
return {
|
|
50
|
+
trace_id: row.trace_id ?? null,
|
|
51
|
+
session_id: row.session_id ?? null,
|
|
52
|
+
tenant_id: row.tenant_id ?? null,
|
|
53
|
+
counterparty_a: row.counterparty_a ?? null,
|
|
54
|
+
counterparty_b: row.counterparty_b ?? null,
|
|
55
|
+
protocol: row.protocol ?? null,
|
|
56
|
+
message_seq: row.message_seq ?? null,
|
|
57
|
+
message_role: row.message_role ?? null,
|
|
58
|
+
message_payload: row.message_payload ?? null,
|
|
59
|
+
payment_ledger_id: row.payment_ledger_id ?? null,
|
|
60
|
+
created_at: row.created_at ?? null,
|
|
61
|
+
chain_position: row.chain_position ?? null,
|
|
62
|
+
prev_hash: row.prev_hash ?? null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export const FIELD_EXTRACTORS = {
|
|
66
|
+
audit_log: auditLogCanonicalFields,
|
|
67
|
+
screening_hits: screeningHitCanonicalFields,
|
|
68
|
+
compliance_events: complianceEventCanonicalFields,
|
|
69
|
+
negotiation_trace_events: negotiationTraceCanonicalFields,
|
|
70
|
+
};
|
|
71
|
+
export const KNOWN_CHAIN_NAMES = Object.keys(FIELD_EXTRACTORS).sort();
|
|
72
|
+
//# sourceMappingURL=extractors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractors.js","sourceRoot":"","sources":["../src/extractors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @algovoi/audit-verifier
|
|
3
|
+
*
|
|
4
|
+
* TypeScript reference verifier for AlgoVoi selective-disclosure audit
|
|
5
|
+
* bundles. Byte-for-byte parity with the Python sibling
|
|
6
|
+
* algovoi-audit-verifier (PyPI).
|
|
7
|
+
*
|
|
8
|
+
* The hosted version is at https://verify.algovoi.co.uk; the offline /
|
|
9
|
+
* embedded version is this package.
|
|
10
|
+
*/
|
|
11
|
+
export { canonicalize, canonicaliseToBytes, sha256Hex, sha256JcsHex, } from './canonicalize.js';
|
|
12
|
+
export { FIELD_EXTRACTORS, KNOWN_CHAIN_NAMES } from './extractors.js';
|
|
13
|
+
export { CheckReport } from './check-report.js';
|
|
14
|
+
export { checkPerRowContentHash, checkContinuity, checkBundleSignature, checkSelectionCriteriaMatch, checkOffVmAnchor, parseObjectKeyShaPrefix, } from './checks.js';
|
|
15
|
+
export { verifyBundle, SUPPORTED_CHAIN_FORMAT_VERSIONS } from './verify.js';
|
|
16
|
+
export { buildDemoBundle } from './demo.js';
|
|
17
|
+
export type { AuditBundle, AuditRow, BundleSignature, ChainAnchor, CheckEntry, CheckReportJSON, CheckResult, FieldExtractor, OffVmAnchor, SelectionCriteria, VerifyBundleOptions, } from './types.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,YAAY,EACV,WAAW,EACX,QAAQ,EACR,eAAe,EACf,WAAW,EACX,UAAU,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @algovoi/audit-verifier
|
|
3
|
+
*
|
|
4
|
+
* TypeScript reference verifier for AlgoVoi selective-disclosure audit
|
|
5
|
+
* bundles. Byte-for-byte parity with the Python sibling
|
|
6
|
+
* algovoi-audit-verifier (PyPI).
|
|
7
|
+
*
|
|
8
|
+
* The hosted version is at https://verify.algovoi.co.uk; the offline /
|
|
9
|
+
* embedded version is this package.
|
|
10
|
+
*/
|
|
11
|
+
export { canonicalize, canonicaliseToBytes, sha256Hex, sha256JcsHex, } from './canonicalize.js';
|
|
12
|
+
export { FIELD_EXTRACTORS, KNOWN_CHAIN_NAMES } from './extractors.js';
|
|
13
|
+
export { CheckReport } from './check-report.js';
|
|
14
|
+
export { checkPerRowContentHash, checkContinuity, checkBundleSignature, checkSelectionCriteriaMatch, checkOffVmAnchor, parseObjectKeyShaPrefix, } from './checks.js';
|
|
15
|
+
export { verifyBundle, SUPPORTED_CHAIN_FORMAT_VERSIONS } from './verify.js';
|
|
16
|
+
export { buildDemoBundle } from './demo.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public type surface for the audit-verifier.
|
|
3
|
+
*/
|
|
4
|
+
export type AuditRow = Record<string, unknown>;
|
|
5
|
+
export type FieldExtractor = (row: AuditRow) => Record<string, unknown>;
|
|
6
|
+
export interface BundleSignature {
|
|
7
|
+
hex: string;
|
|
8
|
+
algorithm?: string;
|
|
9
|
+
canonicalisation?: string;
|
|
10
|
+
key_id?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface OffVmAnchor {
|
|
13
|
+
bucket_name?: string;
|
|
14
|
+
object_key?: string;
|
|
15
|
+
region?: string;
|
|
16
|
+
object_lock_until?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ChainAnchor {
|
|
19
|
+
current_head?: {
|
|
20
|
+
chain_position?: number;
|
|
21
|
+
content_hash?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface SelectionCriteria {
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
since?: string;
|
|
27
|
+
until?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface BridgingMeta {
|
|
30
|
+
included?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface AuditBundle {
|
|
33
|
+
chain_format_version?: number;
|
|
34
|
+
chain_name?: string;
|
|
35
|
+
rows?: AuditRow[];
|
|
36
|
+
bridging_rows?: AuditRow[];
|
|
37
|
+
bridging?: BridgingMeta;
|
|
38
|
+
bundle_signature?: BundleSignature | null;
|
|
39
|
+
off_vm_anchor?: OffVmAnchor;
|
|
40
|
+
chain_anchor?: ChainAnchor;
|
|
41
|
+
selection_criteria?: SelectionCriteria;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
44
|
+
export type CheckResult = 'ok' | 'fail' | 'skip';
|
|
45
|
+
export interface CheckEntry {
|
|
46
|
+
name: string;
|
|
47
|
+
passed: boolean | null;
|
|
48
|
+
detail: string;
|
|
49
|
+
}
|
|
50
|
+
export interface VerifyBundleOptions {
|
|
51
|
+
signingKey?: string | null;
|
|
52
|
+
manifestDir?: string | null;
|
|
53
|
+
}
|
|
54
|
+
export interface CheckReportJSON {
|
|
55
|
+
all_passed: boolean;
|
|
56
|
+
fatal: string[];
|
|
57
|
+
checks: CheckEntry[];
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAExE,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE;QACb,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAClB,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,gBAAgB,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,kBAAkB,CAAC,EAAE,iBAAiB,CAAC;IACvC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifyBundle -- run all checks against a parsed bundle, return CheckReport.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour byte-for-byte parity with the Python sibling verify_bundle().
|
|
5
|
+
*/
|
|
6
|
+
import { CheckReport } from './check-report.js';
|
|
7
|
+
import type { AuditBundle, VerifyBundleOptions } from './types.js';
|
|
8
|
+
export declare const SUPPORTED_CHAIN_FORMAT_VERSIONS: Set<number>;
|
|
9
|
+
export declare function verifyBundle(bundle: AuditBundle, options?: VerifyBundleOptions): Promise<CheckReport>;
|
|
10
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAShD,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEnE,eAAO,MAAM,+BAA+B,aAAuB,CAAC;AAEpE,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,WAAW,CAAC,CA4CtB"}
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifyBundle -- run all checks against a parsed bundle, return CheckReport.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour byte-for-byte parity with the Python sibling verify_bundle().
|
|
5
|
+
*/
|
|
6
|
+
import { CheckReport } from './check-report.js';
|
|
7
|
+
import { checkPerRowContentHash, checkContinuity, checkBundleSignature, checkSelectionCriteriaMatch, checkOffVmAnchor, } from './checks.js';
|
|
8
|
+
import { KNOWN_CHAIN_NAMES } from './extractors.js';
|
|
9
|
+
export const SUPPORTED_CHAIN_FORMAT_VERSIONS = new Set([1]);
|
|
10
|
+
export async function verifyBundle(bundle, options = {}) {
|
|
11
|
+
const report = new CheckReport();
|
|
12
|
+
// Version check first.
|
|
13
|
+
const version = bundle.chain_format_version;
|
|
14
|
+
if (version === undefined || version === null) {
|
|
15
|
+
report.addFatal("bundle is missing required field 'chain_format_version' " +
|
|
16
|
+
'-- bundle is malformed or was not emitted by AlgoVoi');
|
|
17
|
+
return report;
|
|
18
|
+
}
|
|
19
|
+
if (!SUPPORTED_CHAIN_FORMAT_VERSIONS.has(version)) {
|
|
20
|
+
const supported = Array.from(SUPPORTED_CHAIN_FORMAT_VERSIONS).sort();
|
|
21
|
+
report.addFatal(`bundle.chain_format_version=${JSON.stringify(version)} is not supported by ` +
|
|
22
|
+
`this verifier (supported: ${JSON.stringify(supported)}). ` +
|
|
23
|
+
'Pull a fresh verifier from https://github.com/chopmob-cloud/algovoi-audit-verifier ' +
|
|
24
|
+
'-- running an older verifier against a newer bundle risks a false PASS.');
|
|
25
|
+
return report;
|
|
26
|
+
}
|
|
27
|
+
const chainName = bundle.chain_name;
|
|
28
|
+
if (!chainName || !KNOWN_CHAIN_NAMES.includes(chainName)) {
|
|
29
|
+
report.addFatal(`bundle.chain_name='${chainName}' is not recognised ` +
|
|
30
|
+
`(expected one of: ${JSON.stringify(KNOWN_CHAIN_NAMES)})`);
|
|
31
|
+
return report;
|
|
32
|
+
}
|
|
33
|
+
if (!('rows' in bundle)) {
|
|
34
|
+
report.addFatal("bundle is missing required field 'rows'");
|
|
35
|
+
return report;
|
|
36
|
+
}
|
|
37
|
+
checkPerRowContentHash(bundle, report);
|
|
38
|
+
checkContinuity(bundle, report);
|
|
39
|
+
checkSelectionCriteriaMatch(bundle, report);
|
|
40
|
+
checkBundleSignature(bundle, options.signingKey ?? null, report);
|
|
41
|
+
await checkOffVmAnchor(bundle, options.manifestDir ?? null, report);
|
|
42
|
+
return report;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAmB,EACnB,UAA+B,EAAE;IAEjC,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;IAEjC,uBAAuB;IACvB,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAC5C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC9C,MAAM,CAAC,QAAQ,CACb,0DAA0D;YAC1D,sDAAsD,CACvD,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,+BAA+B,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAClD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,IAAI,EAAE,CAAC;QACrE,MAAM,CAAC,QAAQ,CACb,+BAA+B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB;YAC7E,6BAA6B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK;YAC3D,qFAAqF;YACrF,yEAAyE,CAC1E,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC;IACpC,IAAI,CAAC,SAAS,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzD,MAAM,CAAC,QAAQ,CACb,sBAAsB,SAAS,sBAAsB;YACrD,qBAAqB,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,GAAG,CAC1D,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,QAAQ,CAAC,yCAAyC,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,2BAA2B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;IACjE,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;IAEpE,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@algovoi/audit-verifier",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Standalone reference verifier for AlgoVoi selective-disclosure audit bundles. TypeScript port; byte-for-byte parity with the Python algovoi-audit-verifier.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"algovoi",
|
|
7
|
+
"audit",
|
|
8
|
+
"verifier",
|
|
9
|
+
"jcs",
|
|
10
|
+
"rfc8785",
|
|
11
|
+
"hash-chain",
|
|
12
|
+
"compliance",
|
|
13
|
+
"agentic-payments"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://verify.algovoi.co.uk",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/chopmob-cloud/algovoi-audit-verifier.git",
|
|
19
|
+
"directory": "typescript"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/chopmob-cloud/algovoi-audit-verifier/issues"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "AlgoVoi <chopmob@gmail.com>",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"types": "./dist/index.d.ts"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/**/*",
|
|
38
|
+
"src/**/*",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"clean": "rimraf dist",
|
|
47
|
+
"prepublishOnly": "npm run clean && npm run build && npm test"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"canonicalize": "^3.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^20.0.0",
|
|
57
|
+
"rimraf": "^5.0.0",
|
|
58
|
+
"typescript": "^5.4.0",
|
|
59
|
+
"vitest": "^1.6.0"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalisation wrapper for the audit verifier.
|
|
3
|
+
*
|
|
4
|
+
* Uses RFC 8785 JCS via the `canonicalize` npm package, byte-for-byte
|
|
5
|
+
* equivalent to the Python `rfc8785` package used by the sibling
|
|
6
|
+
* algovoi-audit-verifier (Python).
|
|
7
|
+
*/
|
|
8
|
+
import canonicalizeLib from 'canonicalize';
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
|
|
11
|
+
export function canonicalize(obj: unknown): string {
|
|
12
|
+
const out = canonicalizeLib(obj);
|
|
13
|
+
if (out === undefined) {
|
|
14
|
+
throw new Error('canonicalize returned undefined (input not JCS-canonicalisable)');
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function canonicaliseToBytes(obj: unknown): Buffer {
|
|
20
|
+
return Buffer.from(canonicalize(obj), 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function sha256Hex(bytes: Buffer | string): string {
|
|
24
|
+
return createHash('sha256').update(bytes).digest('hex');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function sha256JcsHex(obj: unknown): string {
|
|
28
|
+
return sha256Hex(canonicaliseToBytes(obj));
|
|
29
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CheckReport — aggregates individual check results into a single
|
|
3
|
+
* PASS / FAIL summary. Byte-for-byte equivalent to the Python sibling's
|
|
4
|
+
* CheckReport class.
|
|
5
|
+
*/
|
|
6
|
+
import type { CheckEntry, CheckReportJSON } from './types.js';
|
|
7
|
+
|
|
8
|
+
export class CheckReport {
|
|
9
|
+
readonly checks: CheckEntry[] = [];
|
|
10
|
+
readonly fatal: string[] = [];
|
|
11
|
+
|
|
12
|
+
add(name: string, passed: boolean, detail = ''): void {
|
|
13
|
+
this.checks.push({ name, passed, detail });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addSkip(name: string, reason: string): void {
|
|
17
|
+
this.checks.push({ name, passed: null, detail: `skipped: ${reason}` });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
addFatal(msg: string): void {
|
|
21
|
+
this.fatal.push(msg);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get allPassed(): boolean {
|
|
25
|
+
if (this.fatal.length > 0) return false;
|
|
26
|
+
return this.checks.every((c) => c.passed !== false);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get hasFatal(): boolean {
|
|
30
|
+
return this.fatal.length > 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toJSON(): CheckReportJSON {
|
|
34
|
+
return {
|
|
35
|
+
all_passed: this.allPassed,
|
|
36
|
+
fatal: this.fatal.slice(),
|
|
37
|
+
checks: this.checks.map((c) => ({ ...c })),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
render(): string {
|
|
42
|
+
const lines: string[] = [];
|
|
43
|
+
if (this.fatal.length > 0) {
|
|
44
|
+
lines.push('FATAL:');
|
|
45
|
+
for (const f of this.fatal) lines.push(` ! ${f}`);
|
|
46
|
+
return lines.join('\n');
|
|
47
|
+
}
|
|
48
|
+
for (const c of this.checks) {
|
|
49
|
+
const mark = c.passed === true ? ' ok' : c.passed === false ? 'FAIL' : 'skip';
|
|
50
|
+
let line = ` [${mark}] ${c.name}`;
|
|
51
|
+
if (c.detail) line += ` -- ${c.detail}`;
|
|
52
|
+
lines.push(line);
|
|
53
|
+
}
|
|
54
|
+
const verdict = this.allPassed ? 'PASS' : 'FAIL';
|
|
55
|
+
lines.push(`\nVerdict: ${verdict}`);
|
|
56
|
+
return lines.join('\n');
|
|
57
|
+
}
|
|
58
|
+
}
|