@mikeargento/bitgraph 1.9.1 → 1.10.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.
Files changed (248) hide show
  1. package/README.md +21 -21
  2. package/dist/fuse-cli.js +2 -2
  3. package/dist/fuse-cli.js.map +1 -1
  4. package/dist/fuse.d.ts +15 -1
  5. package/dist/fuse.d.ts.map +1 -1
  6. package/dist/fuse.js +29 -12
  7. package/dist/fuse.js.map +1 -1
  8. package/package.json +12 -8
  9. package/src/fuse-cli.ts +2 -2
  10. package/src/fuse.ts +46 -13
  11. package/dist/__tests__/audit-anchors.test.d.ts +0 -2
  12. package/dist/__tests__/audit-anchors.test.d.ts.map +0 -1
  13. package/dist/__tests__/audit-anchors.test.js +0 -152
  14. package/dist/__tests__/audit-anchors.test.js.map +0 -1
  15. package/dist/__tests__/audit-anomalies.test.d.ts +0 -2
  16. package/dist/__tests__/audit-anomalies.test.d.ts.map +0 -1
  17. package/dist/__tests__/audit-anomalies.test.js +0 -663
  18. package/dist/__tests__/audit-anomalies.test.js.map +0 -1
  19. package/dist/__tests__/audit-attestation.test.d.ts +0 -2
  20. package/dist/__tests__/audit-attestation.test.d.ts.map +0 -1
  21. package/dist/__tests__/audit-attestation.test.js +0 -403
  22. package/dist/__tests__/audit-attestation.test.js.map +0 -1
  23. package/dist/__tests__/audit-bench-smoke.test.d.ts +0 -2
  24. package/dist/__tests__/audit-bench-smoke.test.d.ts.map +0 -1
  25. package/dist/__tests__/audit-bench-smoke.test.js +0 -87
  26. package/dist/__tests__/audit-bench-smoke.test.js.map +0 -1
  27. package/dist/__tests__/audit-boundary.test.d.ts +0 -20
  28. package/dist/__tests__/audit-boundary.test.d.ts.map +0 -1
  29. package/dist/__tests__/audit-boundary.test.js +0 -84
  30. package/dist/__tests__/audit-boundary.test.js.map +0 -1
  31. package/dist/__tests__/audit-cli.test.d.ts +0 -2
  32. package/dist/__tests__/audit-cli.test.d.ts.map +0 -1
  33. package/dist/__tests__/audit-cli.test.js +0 -239
  34. package/dist/__tests__/audit-cli.test.js.map +0 -1
  35. package/dist/__tests__/audit-dependencies.test.d.ts +0 -2
  36. package/dist/__tests__/audit-dependencies.test.d.ts.map +0 -1
  37. package/dist/__tests__/audit-dependencies.test.js +0 -116
  38. package/dist/__tests__/audit-dependencies.test.js.map +0 -1
  39. package/dist/__tests__/audit-fixtures.d.ts +0 -265
  40. package/dist/__tests__/audit-fixtures.d.ts.map +0 -1
  41. package/dist/__tests__/audit-fixtures.js +0 -511
  42. package/dist/__tests__/audit-fixtures.js.map +0 -1
  43. package/dist/__tests__/audit-ingest.test.d.ts +0 -2
  44. package/dist/__tests__/audit-ingest.test.d.ts.map +0 -1
  45. package/dist/__tests__/audit-ingest.test.js +0 -473
  46. package/dist/__tests__/audit-ingest.test.js.map +0 -1
  47. package/dist/__tests__/audit-memory-ingest.test.d.ts +0 -12
  48. package/dist/__tests__/audit-memory-ingest.test.d.ts.map +0 -1
  49. package/dist/__tests__/audit-memory-ingest.test.js +0 -135
  50. package/dist/__tests__/audit-memory-ingest.test.js.map +0 -1
  51. package/dist/__tests__/audit-property.test.d.ts +0 -2
  52. package/dist/__tests__/audit-property.test.d.ts.map +0 -1
  53. package/dist/__tests__/audit-property.test.js +0 -771
  54. package/dist/__tests__/audit-property.test.js.map +0 -1
  55. package/dist/__tests__/audit-real-fixtures.test.d.ts +0 -2
  56. package/dist/__tests__/audit-real-fixtures.test.d.ts.map +0 -1
  57. package/dist/__tests__/audit-real-fixtures.test.js +0 -132
  58. package/dist/__tests__/audit-real-fixtures.test.js.map +0 -1
  59. package/dist/__tests__/audit-real-live.test.d.ts +0 -2
  60. package/dist/__tests__/audit-real-live.test.d.ts.map +0 -1
  61. package/dist/__tests__/audit-real-live.test.js +0 -107
  62. package/dist/__tests__/audit-real-live.test.js.map +0 -1
  63. package/dist/__tests__/audit-reconstruct.test.d.ts +0 -2
  64. package/dist/__tests__/audit-reconstruct.test.d.ts.map +0 -1
  65. package/dist/__tests__/audit-reconstruct.test.js +0 -287
  66. package/dist/__tests__/audit-reconstruct.test.js.map +0 -1
  67. package/dist/__tests__/audit-report.test.d.ts +0 -2
  68. package/dist/__tests__/audit-report.test.d.ts.map +0 -1
  69. package/dist/__tests__/audit-report.test.js +0 -186
  70. package/dist/__tests__/audit-report.test.js.map +0 -1
  71. package/dist/__tests__/audit-roundtrip.test.d.ts +0 -2
  72. package/dist/__tests__/audit-roundtrip.test.d.ts.map +0 -1
  73. package/dist/__tests__/audit-roundtrip.test.js +0 -368
  74. package/dist/__tests__/audit-roundtrip.test.js.map +0 -1
  75. package/dist/__tests__/audit-temporal.test.d.ts +0 -2
  76. package/dist/__tests__/audit-temporal.test.d.ts.map +0 -1
  77. package/dist/__tests__/audit-temporal.test.js +0 -364
  78. package/dist/__tests__/audit-temporal.test.js.map +0 -1
  79. package/dist/__tests__/audit-tiers.test.d.ts +0 -2
  80. package/dist/__tests__/audit-tiers.test.d.ts.map +0 -1
  81. package/dist/__tests__/audit-tiers.test.js +0 -282
  82. package/dist/__tests__/audit-tiers.test.js.map +0 -1
  83. package/dist/__tests__/audit-witness-real.test.d.ts +0 -19
  84. package/dist/__tests__/audit-witness-real.test.d.ts.map +0 -1
  85. package/dist/__tests__/audit-witness-real.test.js +0 -82
  86. package/dist/__tests__/audit-witness-real.test.js.map +0 -1
  87. package/dist/__tests__/audit-witness.test.d.ts +0 -2
  88. package/dist/__tests__/audit-witness.test.d.ts.map +0 -1
  89. package/dist/__tests__/audit-witness.test.js +0 -308
  90. package/dist/__tests__/audit-witness.test.js.map +0 -1
  91. package/dist/__tests__/canonical.test.d.ts +0 -2
  92. package/dist/__tests__/canonical.test.d.ts.map +0 -1
  93. package/dist/__tests__/canonical.test.js +0 -162
  94. package/dist/__tests__/canonical.test.js.map +0 -1
  95. package/dist/__tests__/chain-hash-anchor.test.d.ts +0 -22
  96. package/dist/__tests__/chain-hash-anchor.test.d.ts.map +0 -1
  97. package/dist/__tests__/chain-hash-anchor.test.js +0 -55
  98. package/dist/__tests__/chain-hash-anchor.test.js.map +0 -1
  99. package/dist/__tests__/commit-service.integration.test.d.ts +0 -2
  100. package/dist/__tests__/commit-service.integration.test.d.ts.map +0 -1
  101. package/dist/__tests__/commit-service.integration.test.js +0 -95
  102. package/dist/__tests__/commit-service.integration.test.js.map +0 -1
  103. package/dist/__tests__/constructor.test.d.ts +0 -2
  104. package/dist/__tests__/constructor.test.d.ts.map +0 -1
  105. package/dist/__tests__/constructor.test.js +0 -267
  106. package/dist/__tests__/constructor.test.js.map +0 -1
  107. package/dist/__tests__/declared-proof-fixture.d.ts +0 -66
  108. package/dist/__tests__/declared-proof-fixture.d.ts.map +0 -1
  109. package/dist/__tests__/declared-proof-fixture.js +0 -66
  110. package/dist/__tests__/declared-proof-fixture.js.map +0 -1
  111. package/dist/__tests__/fuse-inline.test.d.ts +0 -2
  112. package/dist/__tests__/fuse-inline.test.d.ts.map +0 -1
  113. package/dist/__tests__/fuse-inline.test.js +0 -181
  114. package/dist/__tests__/fuse-inline.test.js.map +0 -1
  115. package/dist/__tests__/fuse-placement.test.d.ts +0 -2
  116. package/dist/__tests__/fuse-placement.test.d.ts.map +0 -1
  117. package/dist/__tests__/fuse-placement.test.js +0 -31
  118. package/dist/__tests__/fuse-placement.test.js.map +0 -1
  119. package/dist/__tests__/fuse-roundtrip.test.d.ts +0 -2
  120. package/dist/__tests__/fuse-roundtrip.test.d.ts.map +0 -1
  121. package/dist/__tests__/fuse-roundtrip.test.js +0 -241
  122. package/dist/__tests__/fuse-roundtrip.test.js.map +0 -1
  123. package/dist/__tests__/fuse-sdk.test.d.ts +0 -2
  124. package/dist/__tests__/fuse-sdk.test.d.ts.map +0 -1
  125. package/dist/__tests__/fuse-sdk.test.js +0 -117
  126. package/dist/__tests__/fuse-sdk.test.js.map +0 -1
  127. package/dist/__tests__/fuse-set-sdk.test.d.ts +0 -2
  128. package/dist/__tests__/fuse-set-sdk.test.d.ts.map +0 -1
  129. package/dist/__tests__/fuse-set-sdk.test.js +0 -721
  130. package/dist/__tests__/fuse-set-sdk.test.js.map +0 -1
  131. package/dist/__tests__/fuse-set.test.d.ts +0 -2
  132. package/dist/__tests__/fuse-set.test.d.ts.map +0 -1
  133. package/dist/__tests__/fuse-set.test.js +0 -889
  134. package/dist/__tests__/fuse-set.test.js.map +0 -1
  135. package/dist/__tests__/fuse-set2.test.d.ts +0 -2
  136. package/dist/__tests__/fuse-set2.test.d.ts.map +0 -1
  137. package/dist/__tests__/fuse-set2.test.js +0 -294
  138. package/dist/__tests__/fuse-set2.test.js.map +0 -1
  139. package/dist/__tests__/fuse-vectors.test.d.ts +0 -2
  140. package/dist/__tests__/fuse-vectors.test.d.ts.map +0 -1
  141. package/dist/__tests__/fuse-vectors.test.js +0 -175
  142. package/dist/__tests__/fuse-vectors.test.js.map +0 -1
  143. package/dist/__tests__/fuse-verify.test.d.ts +0 -2
  144. package/dist/__tests__/fuse-verify.test.d.ts.map +0 -1
  145. package/dist/__tests__/fuse-verify.test.js +0 -250
  146. package/dist/__tests__/fuse-verify.test.js.map +0 -1
  147. package/dist/__tests__/hello-world.test.d.ts +0 -2
  148. package/dist/__tests__/hello-world.test.d.ts.map +0 -1
  149. package/dist/__tests__/hello-world.test.js +0 -9
  150. package/dist/__tests__/hello-world.test.js.map +0 -1
  151. package/dist/__tests__/mock-proof-fixture.d.ts +0 -15
  152. package/dist/__tests__/mock-proof-fixture.d.ts.map +0 -1
  153. package/dist/__tests__/mock-proof-fixture.js +0 -34
  154. package/dist/__tests__/mock-proof-fixture.js.map +0 -1
  155. package/dist/__tests__/policy-enforcement.test.d.ts +0 -2
  156. package/dist/__tests__/policy-enforcement.test.d.ts.map +0 -1
  157. package/dist/__tests__/policy-enforcement.test.js +0 -188
  158. package/dist/__tests__/policy-enforcement.test.js.map +0 -1
  159. package/dist/__tests__/proof-hash-regression.test.d.ts +0 -2
  160. package/dist/__tests__/proof-hash-regression.test.d.ts.map +0 -1
  161. package/dist/__tests__/proof-hash-regression.test.js +0 -95
  162. package/dist/__tests__/proof-hash-regression.test.js.map +0 -1
  163. package/dist/__tests__/proof-hash.test.d.ts +0 -2
  164. package/dist/__tests__/proof-hash.test.d.ts.map +0 -1
  165. package/dist/__tests__/proof-hash.test.js +0 -116
  166. package/dist/__tests__/proof-hash.test.js.map +0 -1
  167. package/dist/__tests__/proof-integrity.test.d.ts +0 -2
  168. package/dist/__tests__/proof-integrity.test.d.ts.map +0 -1
  169. package/dist/__tests__/proof-integrity.test.js +0 -454
  170. package/dist/__tests__/proof-integrity.test.js.map +0 -1
  171. package/dist/__tests__/realistic-proof-fixture.d.ts +0 -56
  172. package/dist/__tests__/realistic-proof-fixture.d.ts.map +0 -1
  173. package/dist/__tests__/realistic-proof-fixture.js +0 -57
  174. package/dist/__tests__/realistic-proof-fixture.js.map +0 -1
  175. package/dist/__tests__/run.test.d.ts +0 -2
  176. package/dist/__tests__/run.test.d.ts.map +0 -1
  177. package/dist/__tests__/run.test.js +0 -178
  178. package/dist/__tests__/run.test.js.map +0 -1
  179. package/dist/__tests__/verifier.test.d.ts +0 -2
  180. package/dist/__tests__/verifier.test.d.ts.map +0 -1
  181. package/dist/__tests__/verifier.test.js +0 -531
  182. package/dist/__tests__/verifier.test.js.map +0 -1
  183. package/dist/canonical.d.ts +0 -54
  184. package/dist/canonical.d.ts.map +0 -1
  185. package/dist/canonical.js +0 -119
  186. package/dist/canonical.js.map +0 -1
  187. package/dist/proof-hash.d.ts +0 -9
  188. package/dist/proof-hash.d.ts.map +0 -1
  189. package/dist/proof-hash.js +0 -75
  190. package/dist/proof-hash.js.map +0 -1
  191. package/dist/types.d.ts +0 -705
  192. package/dist/types.d.ts.map +0 -1
  193. package/dist/types.js +0 -3
  194. package/dist/types.js.map +0 -1
  195. package/dist/verifier.d.ts +0 -27
  196. package/dist/verifier.d.ts.map +0 -1
  197. package/dist/verifier.js +0 -844
  198. package/dist/verifier.js.map +0 -1
  199. package/src/__tests__/audit-anchors.test.ts +0 -188
  200. package/src/__tests__/audit-anomalies.test.ts +0 -815
  201. package/src/__tests__/audit-attestation.test.ts +0 -529
  202. package/src/__tests__/audit-bench-smoke.test.ts +0 -108
  203. package/src/__tests__/audit-boundary.test.ts +0 -96
  204. package/src/__tests__/audit-cli.test.ts +0 -288
  205. package/src/__tests__/audit-dependencies.test.ts +0 -141
  206. package/src/__tests__/audit-fixtures.ts +0 -736
  207. package/src/__tests__/audit-ingest.test.ts +0 -575
  208. package/src/__tests__/audit-memory-ingest.test.ts +0 -156
  209. package/src/__tests__/audit-property.test.ts +0 -892
  210. package/src/__tests__/audit-real-fixtures.test.ts +0 -153
  211. package/src/__tests__/audit-real-live.test.ts +0 -128
  212. package/src/__tests__/audit-reconstruct.test.ts +0 -353
  213. package/src/__tests__/audit-report.test.ts +0 -222
  214. package/src/__tests__/audit-roundtrip.test.ts +0 -464
  215. package/src/__tests__/audit-temporal.test.ts +0 -446
  216. package/src/__tests__/audit-tiers.test.ts +0 -343
  217. package/src/__tests__/audit-witness-real.test.ts +0 -92
  218. package/src/__tests__/audit-witness.test.ts +0 -345
  219. package/src/__tests__/canonical.test.ts +0 -253
  220. package/src/__tests__/chain-hash-anchor.test.ts +0 -67
  221. package/src/__tests__/commit-service.integration.test.ts +0 -117
  222. package/src/__tests__/constructor.test.ts +0 -340
  223. package/src/__tests__/declared-proof-fixture.ts +0 -65
  224. package/src/__tests__/fuse-inline.test.ts +0 -211
  225. package/src/__tests__/fuse-placement.test.ts +0 -32
  226. package/src/__tests__/fuse-roundtrip.test.ts +0 -243
  227. package/src/__tests__/fuse-sdk.test.ts +0 -142
  228. package/src/__tests__/fuse-set-sdk.test.ts +0 -852
  229. package/src/__tests__/fuse-set.test.ts +0 -1027
  230. package/src/__tests__/fuse-set2.test.ts +0 -343
  231. package/src/__tests__/fuse-vectors.test.ts +0 -218
  232. package/src/__tests__/fuse-verify.test.ts +0 -278
  233. package/src/__tests__/hello-world.test.ts +0 -10
  234. package/src/__tests__/mock-proof-fixture.ts +0 -36
  235. package/src/__tests__/policy-enforcement.test.ts +0 -226
  236. package/src/__tests__/proof-hash-regression.test.ts +0 -107
  237. package/src/__tests__/proof-hash.test.ts +0 -129
  238. package/src/__tests__/proof-integrity.test.ts +0 -576
  239. package/src/__tests__/real-fixtures/anchor-after-112762.json +0 -47
  240. package/src/__tests__/real-fixtures/anchor-with-ethereum-112758.json +0 -47
  241. package/src/__tests__/real-fixtures/live-proof-0.json +0 -42
  242. package/src/__tests__/real-fixtures/live-proof-1.json +0 -43
  243. package/src/__tests__/real-fixtures/live-proof-2.json +0 -43
  244. package/src/__tests__/real-fixtures/successor-112760.json +0 -38
  245. package/src/__tests__/real-fixtures/witness-25525146.json +0 -6
  246. package/src/__tests__/real-fixtures/witness-25525147.json +0 -6
  247. package/src/__tests__/realistic-proof-fixture.ts +0 -57
  248. package/src/__tests__/verifier.test.ts +0 -624
@@ -1,153 +0,0 @@
1
- // Copyright (c) Argento Computing Inc. All rights reserved. See LICENSE.
2
-
3
- /**
4
- * Real-fixture audit test (Phase 4e, G8 honesty).
5
- *
6
- * Builds a bundle from the repo's real embedded fixtures and asserts the
7
- * audit reports them honestly:
8
- *
9
- * - REALISTIC_PROOF mirrors what the TEE actually produces: a
10
- * real-shaped Ethereum anchor proof with a TRUNCATED attestation blob
11
- * and a placeholder signature. It must be observed, identified as an
12
- * Ethereum anchor by its SIGNED attribution, fail verification with
13
- * the verifier's precise NON-version reason (the placeholder
14
- * signature), and its attestation must report document-present-but-
15
- * invalid (the truncated blob), never a pass and never a version
16
- * failure.
17
- *
18
- * - MOCK_PROOF is placeholder values throughout; it fails on the first
19
- * canonical check its placeholders trip (the non-base64 digest), also
20
- * a non-version reason.
21
- *
22
- * The fixtures are used verbatim from their shared modules and are never
23
- * edited.
24
- */
25
-
26
- import { describe, it, before, after } from "node:test";
27
- import * as assert from "node:assert/strict";
28
- import { rm } from "node:fs/promises";
29
- import { computeProofHash } from "@mikeargento/bitgraph-verify";
30
- import { buildJsonReport, runAudit } from "@mikeargento/bitgraph-audit";
31
- import type { AuditResult } from "@mikeargento/bitgraph-audit";
32
- import { makeTempDir, writeBundleDir } from "./audit-fixtures.js";
33
- import { REALISTIC_PROOF } from "./realistic-proof-fixture.js";
34
- import { MOCK_PROOF } from "./mock-proof-fixture.js";
35
-
36
- describe("audit over the repo's real embedded fixtures", () => {
37
- let dir: string;
38
- let result: AuditResult;
39
- const realisticHash = computeProofHash(REALISTIC_PROOF as unknown as Record<string, unknown>);
40
- const mockHash = computeProofHash(MOCK_PROOF as unknown as Record<string, unknown>);
41
-
42
- before(async () => {
43
- dir = await makeTempDir("bitgraph-audit-real-fixtures-");
44
- await writeBundleDir(dir, {
45
- "proofs/realistic.json": JSON.stringify(REALISTIC_PROOF),
46
- "proofs/mock.json": JSON.stringify(MOCK_PROOF),
47
- });
48
- result = await runAudit(dir);
49
- });
50
-
51
- after(async () => {
52
- await rm(dir, { recursive: true, force: true });
53
- });
54
-
55
- it("observes both fixtures; neither is a version reject", () => {
56
- assert.equal(result.ingest.counts.observed, 2);
57
- assert.equal(result.ingest.counts.unsupportedVersion, 0);
58
- const hashes = result.ingest.proofs.map((p) => p.proofHash).sort();
59
- assert.deepEqual(hashes, [realisticHash, mockHash].sort());
60
- });
61
-
62
- it("REALISTIC_PROOF fails verification with the precise non-version signature reason", () => {
63
- const proof = result.ingest.proofs.find((p) => p.proofHash === realisticHash);
64
- assert.equal(proof?.verification?.tier, "integrity");
65
- assert.equal(proof?.verification?.status, "failed");
66
- assert.equal(
67
- proof?.verification?.reason,
68
- "signature verification failed: signature does not match"
69
- );
70
- assert.ok(!(proof?.verification?.reason as string).includes("version"));
71
- });
72
-
73
- it("MOCK_PROOF fails verification with a precise non-version placeholder reason", () => {
74
- const proof = result.ingest.proofs.find((p) => p.proofHash === mockHash);
75
- assert.equal(proof?.verification?.status, "failed");
76
- assert.equal(proof?.verification?.reason, "artifact.digestB64 is not valid base64");
77
- assert.ok(!(proof?.verification?.reason as string).includes("version"));
78
- });
79
-
80
- it("nothing passes: no proof is ever reported verified or artifact-unavailable", () => {
81
- assert.equal(result.verification.verified, 0);
82
- assert.equal(result.verification.artifactUnavailable, 0);
83
- assert.equal(result.verification.failed, 2);
84
- });
85
-
86
- it("REALISTIC_PROOF is identified as an Ethereum anchor by its signed attribution", () => {
87
- assert.equal(result.anchors.anchors.length, 1);
88
- const anchor = result.anchors.anchors[0]!;
89
- assert.equal(anchor.proofHash, realisticHash);
90
- assert.equal(anchor.blockNumber, "24800448");
91
- assert.equal(
92
- anchor.blockHash,
93
- "0x28ed3639cd705fb8cb2b915c1991e9f808b40e775bc8eb540702942729fec2c0"
94
- );
95
- // No unsigned metadata on the fixture: absent corroboration, not disagreement.
96
- assert.equal(anchor.metadataCorroboration, "absent");
97
- // The verification failure rides along unmodified.
98
- assert.equal(anchor.verificationStatus, "failed");
99
- // MOCK_PROOF's attribution ("test") never identifies an anchor.
100
- assert.ok(!result.anchors.anchors.some((a) => a.proofHash === mockHash));
101
- // No witness in the bundle: causal identification only, no wall-clock evidence.
102
- assert.deepEqual(result.temporal.verifiedAnchorProofHashes, []);
103
- assert.deepEqual(result.temporal.unverifiedAnchorProofHashes, [realisticHash]);
104
- });
105
-
106
- it("REALISTIC_PROOF attestation reports document-present-but-invalid, never a pass", () => {
107
- const record = result.attestations.records.find((r) => r.proofHash === realisticHash);
108
- assert.ok(record !== undefined);
109
- assert.equal(record.declaredMeasurementPresent, true);
110
- assert.equal(
111
- record.declaredMeasurement,
112
- "638d655ad6091bed5c358628b7780de0cdbe138a37fe09d52bf8021a720680a2b3c730fee9f6bef79c1dbe68ef3cdd94"
113
- );
114
- assert.equal(record.attestationFormat, "aws-nitro");
115
- assert.equal(record.documentPresent, true);
116
- assert.equal(record.documentValidated, false);
117
- // The truncated blob fails with a precise reason, never silently.
118
- assert.equal(typeof record.validationFailure, "string");
119
- assert.ok((record.validationFailure as string).length > 0);
120
- // Facts derived from an unvalidated document are never asserted.
121
- assert.equal(record.pcr0MatchesDeclared, undefined);
122
- assert.equal(record.userDataBoundToProof, undefined);
123
- // Aggregates: documents present on both fixtures, zero validated.
124
- assert.equal(result.attestations.counts.proofsWithDocument, 2);
125
- assert.equal(result.attestations.counts.documentsValidated, 0);
126
- assert.equal(result.attestations.counts.documentsFailed, 2);
127
- assert.equal(result.attestations.counts.pcr0Matches, 0);
128
- assert.equal(result.attestations.counts.userDataBound, 0);
129
- });
130
-
131
- it("the exact anomaly code multiset is honest: crypto and topology findings, no version failure", () => {
132
- const report = buildJsonReport(result);
133
- const codes = report.anomalies.map((a) => a.code).sort();
134
- assert.deepEqual(codes, [
135
- "attestation-invalid", // MOCK_PROOF's placeholder attestation blob
136
- "attestation-invalid", // REALISTIC_PROOF's truncated attestation blob
137
- "chain-break-malformed", // MOCK_PROOF's placeholder prevB64 ("prev==")
138
- ]);
139
- // REALISTIC_PROOF's real-shaped prevB64 into unobserved history is the
140
- // frontier of its (single-proof) partition, so it is an expected bundle
141
- // boundary, not a chain-integrity anomaly.
142
- assert.equal(report.boundaryEntryPoints.length, 1);
143
- assert.ok(!codes.includes("unsupported-version"));
144
- assert.equal(report.summary.fullyVerified, 0);
145
- // Still exit 3: attestation-invalid trips verification, chain-break-malformed
146
- // trips chain anomalies. The boundary alone would never set an exit bit.
147
- assert.deepEqual(report.summary.exit, {
148
- verificationFailures: true,
149
- chainAnomaliesOrDivergences: true,
150
- code: 3,
151
- });
152
- });
153
- });
@@ -1,128 +0,0 @@
1
- // Copyright (c) Argento Computing Inc. All rights reserved. See LICENSE.
2
-
3
- /**
4
- * Real-ledger regression test for the audit pipeline.
5
- *
6
- * These three proofs (real-fixtures/live-proof-0.json .. live-proof-2.json)
7
- * were captured from the live BitGraph ledger: a contiguous single-epoch
8
- * chain (genesis commit counter 2, then 4, then 6, each linked to its
9
- * predecessor by commit.prevB64). They are stored-form, carrying the
10
- * ledger-added proofHash field.
11
- *
12
- * This test exists specifically because the synthetic fixtures shared the
13
- * audit tool's ORIGINAL wrong assumptions and so masked two real bugs:
14
- *
15
- * Bug A: real slot allocations carry NO time field (the enclave builds
16
- * slot bodies without a clock). The verifier used to require it, so real
17
- * slots failed verification. If this test's proofs verify at the
18
- * integrity tier (0 failed), Bug A is fixed.
19
- *
20
- * Bug B: commit.prevB64 references computeChainHash(predecessor) (SHA-256
21
- * over the whole canonical proof minus the ledger proofHash), NOT
22
- * computeProofHash (the signed-body subset). The synthetic fixtures built
23
- * their prevB64 from computeProofHash, the same wrong value the tool
24
- * assumed, so they linked "by accident". Real proofs use the true chain
25
- * hash. If this real chain reconstructs as ONE intact component with ZERO
26
- * anomalies, Bug B is fixed.
27
- *
28
- * No synthetic construction: the assertions ride entirely on real bytes.
29
- */
30
-
31
- import { describe, it, before, after } from "node:test";
32
- import * as assert from "node:assert/strict";
33
- import { mkdtemp, mkdir, writeFile, rm, readFile } from "node:fs/promises";
34
- import { tmpdir } from "node:os";
35
- import { join } from "node:path";
36
- import { fileURLToPath } from "node:url";
37
- import {
38
- runAudit,
39
- buildJsonReport,
40
- computeExitFlags,
41
- type AuditResult,
42
- } from "@mikeargento/bitgraph-audit";
43
- import { computeProofHash, type BitGraphProof } from "@mikeargento/bitgraph-verify";
44
-
45
- /** Filesystem-safe token from a base64/arbitrary string. */
46
- function safe(value: string): string {
47
- return value.replace(/[^A-Za-z0-9]/g, "_");
48
- }
49
-
50
- describe("audit: real live-ledger chain (Bug A + Bug B regression)", () => {
51
- let dir: string;
52
- let result: AuditResult;
53
- let proofs: Array<BitGraphProof & { proofHash?: string }>;
54
-
55
- before(async () => {
56
- // Load the three captured real proofs from src/__tests__/real-fixtures.
57
- // The test runs from dist/__tests__, so reach back into src.
58
- proofs = [];
59
- for (const i of [0, 1, 2]) {
60
- const url = new URL(
61
- `../../src/__tests__/real-fixtures/live-proof-${i}.json`,
62
- import.meta.url
63
- );
64
- const raw = await readFile(fileURLToPath(url), "utf8");
65
- proofs.push(JSON.parse(raw) as BitGraphProof & { proofHash?: string });
66
- }
67
-
68
- // Write a valid directory bundle: proofs/<epoch>/<counter>-<hash>.json.
69
- // Bytes are the exact captured stored-form JSON; no re-serialization of
70
- // the signed content, so nothing about the real proof is altered.
71
- dir = await mkdtemp(join(tmpdir(), "bitgraph-audit-real-live-"));
72
- for (const proof of proofs) {
73
- const epochDir = join(dir, "proofs", safe(proof.commit.epochId as string));
74
- await mkdir(epochDir, { recursive: true });
75
- const name = `${proof.commit.counter}-${safe(computeProofHash(proof))}.json`;
76
- await writeFile(join(epochDir, name), JSON.stringify(proof));
77
- }
78
-
79
- result = await runAudit(dir);
80
- });
81
-
82
- after(async () => {
83
- if (dir !== undefined) await rm(dir, { recursive: true, force: true });
84
- });
85
-
86
- it("verifies every real proof at the integrity tier (Bug A: clockless slots verify)", () => {
87
- // All three are observed, none rejected as an unsupported version.
88
- assert.equal(result.ingest.counts.observed, 3);
89
- assert.equal(result.ingest.counts.unsupportedVersion, 0);
90
-
91
- // Bug A proof: real slot allocations carry no time field. If the
92
- // verifier still required it, these would be "failed", not
93
- // "artifact-unavailable". No artifact bytes are in the bundle, so the
94
- // integrity tier is the ceiling and every proof must pass it.
95
- assert.equal(result.verification.failed, 0);
96
- assert.equal(result.verification.verified, 0);
97
- assert.equal(result.verification.artifactUnavailable, 3);
98
- });
99
-
100
- it("reconstructs the real chain as one intact component (Bug B: prevB64 is the chain hash)", () => {
101
- const report = buildJsonReport(result);
102
-
103
- // One signer, one epoch, one chain -> exactly one partition.
104
- assert.equal(result.reconstruction.partitions.length, 1);
105
- const partition = result.reconstruction.partitions[0]!;
106
-
107
- // The three proofs link into a SINGLE connected component of all three
108
- // members. This only holds if commit.prevB64 resolves against
109
- // computeChainHash(predecessor); against computeProofHash it would
110
- // fragment into three genesis components with chain breaks.
111
- assert.equal(partition.components.length, 1);
112
- assert.equal(partition.components[0]!.memberProofHashes.length, 3);
113
-
114
- // No anomalies of any kind, no divergences, chain intact.
115
- assert.equal(result.anomalies.anomalies.length, 0);
116
- assert.equal(result.anomalies.divergences.length, 0);
117
- assert.equal(report.summary.chainIntact, true);
118
- assert.equal(report.summary.partitionsIntact, 1);
119
- });
120
-
121
- it("exits clean (code 0) over the real bundle", () => {
122
- assert.deepEqual(computeExitFlags(result), {
123
- verificationFailures: false,
124
- chainAnomaliesOrDivergences: false,
125
- code: 0,
126
- });
127
- });
128
- });
@@ -1,353 +0,0 @@
1
- // Copyright (c) Argento Computing Inc. All rights reserved. See LICENSE.
2
-
3
- /**
4
- * Tests for @mikeargento/bitgraph-audit causal reconstruction:
5
- * partitioning per (signer key, epochId, chainId), chain components from
6
- * prevB64 hash links, genesis and terminal identification, counter
7
- * evidence, and epoch relationships (epochLink lineage edges, hard-edge
8
- * ordering, observed-but-unordered epochs).
9
- */
10
-
11
- import { describe, test, after } from "node:test";
12
- import * as assert from "node:assert/strict";
13
- import { rm } from "node:fs/promises";
14
- import {
15
- classifyAnomalies,
16
- ingestBundle,
17
- reconstructChains,
18
- verifyObservedProofs,
19
- } from "@mikeargento/bitgraph-audit";
20
- import type { IngestResult, ReconstructionResult, AnomalyReport } from "@mikeargento/bitgraph-audit";
21
- import { sha256 } from "@noble/hashes/sha256";
22
- import {
23
- b64,
24
- healthyPairs,
25
- makeConstructorProof,
26
- makeCounterChain,
27
- makeEpochLinkProof,
28
- makeKey,
29
- makeTempDir,
30
- proofJson,
31
- utf8,
32
- writeBundleDir,
33
- } from "./audit-fixtures.js";
34
-
35
- const tempDirs: string[] = [];
36
-
37
- after(async () => {
38
- for (const dir of tempDirs) {
39
- await rm(dir, { recursive: true, force: true });
40
- }
41
- });
42
-
43
- async function auditBundle(files: Record<string, Uint8Array | string>): Promise<{
44
- ingest: IngestResult;
45
- reconstruction: ReconstructionResult;
46
- report: AnomalyReport;
47
- }> {
48
- const dir = await makeTempDir("bitgraph-audit-reconstruct-");
49
- tempDirs.push(dir);
50
- await writeBundleDir(dir, files);
51
- const ingest = await ingestBundle(dir);
52
- await verifyObservedProofs(ingest);
53
- const reconstruction = await reconstructChains(ingest);
54
- const report = await classifyAnomalies(ingest, reconstruction);
55
- return { ingest, reconstruction, report };
56
- }
57
-
58
- // ---------------------------------------------------------------------------
59
- // The critical regression: a healthy chain is clean
60
- // ---------------------------------------------------------------------------
61
-
62
- describe("reconstruct: healthy slot/commit chain", () => {
63
- test("one partition, one component, zero anomalies, zero unexplained positions", async () => {
64
- const chain = await makeCounterChain({
65
- epochId: "epoch-healthy",
66
- chainId: "bitgraph:main",
67
- pairs: healthyPairs(4), // slot 1/commit 2 ... slot 7/commit 8
68
- });
69
- const { ingest, reconstruction, report } = await auditBundle({
70
- "proofs/p0.json": proofJson(chain.proofs[0]!.proof),
71
- "proofs/p1.json": proofJson(chain.proofs[1]!.proof),
72
- "proofs/p2.json": proofJson(chain.proofs[2]!.proof),
73
- "proofs/p3.json": proofJson(chain.proofs[3]!.proof),
74
- });
75
-
76
- assert.equal(ingest.proofs.length, 4);
77
- assert.equal(reconstruction.partitions.length, 1);
78
- const partition = reconstruction.partitions[0]!;
79
- assert.deepEqual(partition.key, {
80
- publicKeyB64: chain.key.publicKeyB64,
81
- epochId: "epoch-healthy",
82
- chainId: "bitgraph:main",
83
- });
84
-
85
- assert.equal(partition.components.length, 1);
86
- const component = partition.components[0]!;
87
- assert.deepEqual(
88
- component.memberProofHashes,
89
- chain.proofs.map((p) => p.proofHash),
90
- "link order must follow the hash chain from genesis to terminal"
91
- );
92
- assert.deepEqual(component.genesisProofHashes, [chain.proofs[0]!.proofHash]);
93
- assert.deepEqual(component.terminalProofHashes, [chain.proofs[3]!.proofHash]);
94
- assert.deepEqual(component.brokenLinkProofHashes, []);
95
- assert.equal(component.hasCounterEvidence, true);
96
- assert.deepEqual(component.positionRange, { min: "1", max: "8" });
97
-
98
- // THE critical regression: a healthy slot/commit chain produces NO
99
- // unexplained positions and no anomalies of any kind.
100
- assert.deepEqual(report.anomalies, []);
101
- assert.deepEqual(report.divergences, []);
102
- });
103
-
104
- test("reconstruction is link-driven: file order and counters are not the mechanism", async () => {
105
- const chain = await makeCounterChain({
106
- epochId: "epoch-shuffled",
107
- pairs: healthyPairs(3),
108
- });
109
- // Write files in an order that reverses the causal order.
110
- const { reconstruction } = await auditBundle({
111
- "a-last.json": proofJson(chain.proofs[2]!.proof),
112
- "b-middle.json": proofJson(chain.proofs[1]!.proof),
113
- "c-first.json": proofJson(chain.proofs[0]!.proof),
114
- });
115
- const component = reconstruction.partitions[0]!.components[0]!;
116
- assert.deepEqual(
117
- component.memberProofHashes,
118
- chain.proofs.map((p) => p.proofHash)
119
- );
120
- });
121
-
122
- test("a counterless link chain still reconstructs as one component", async () => {
123
- const chain = await makeCounterChain({
124
- epochId: "epoch-no-counters",
125
- pairs: [{}, {}, {}], // epochId only: hash links are the only evidence
126
- });
127
- const { reconstruction, report } = await auditBundle({
128
- "p0.json": proofJson(chain.proofs[0]!.proof),
129
- "p1.json": proofJson(chain.proofs[1]!.proof),
130
- "p2.json": proofJson(chain.proofs[2]!.proof),
131
- });
132
- const partition = reconstruction.partitions[0]!;
133
- assert.equal(partition.components.length, 1);
134
- const component = partition.components[0]!;
135
- assert.deepEqual(
136
- component.memberProofHashes,
137
- chain.proofs.map((p) => p.proofHash)
138
- );
139
- assert.equal(component.hasCounterEvidence, false);
140
- assert.equal(component.positionRange, undefined);
141
- assert.deepEqual(report.anomalies, []);
142
- });
143
- });
144
-
145
- // ---------------------------------------------------------------------------
146
- // Partitioning
147
- // ---------------------------------------------------------------------------
148
-
149
- describe("reconstruct: partitioning", () => {
150
- test("two independent lineages are never merged", async () => {
151
- const chainA = await makeCounterChain({ epochId: "epoch-A", pairs: healthyPairs(2) });
152
- const chainB = await makeCounterChain({ epochId: "epoch-B", pairs: healthyPairs(2) });
153
- const { reconstruction, report } = await auditBundle({
154
- "a0.json": proofJson(chainA.proofs[0]!.proof),
155
- "a1.json": proofJson(chainA.proofs[1]!.proof),
156
- "b0.json": proofJson(chainB.proofs[0]!.proof),
157
- "b1.json": proofJson(chainB.proofs[1]!.proof),
158
- });
159
-
160
- assert.equal(reconstruction.partitions.length, 2);
161
- const keys = reconstruction.partitions.map((p) => p.key.publicKeyB64).sort();
162
- assert.deepEqual(keys, [chainA.key.publicKeyB64, chainB.key.publicKeyB64].sort());
163
- // Same counters on both chains, yet no collisions: counters are
164
- // partition-local.
165
- assert.deepEqual(report.anomalies, []);
166
- assert.deepEqual(report.divergences, []);
167
- });
168
-
169
- test("same signer and epoch on different chainIds are separate partitions (G6)", async () => {
170
- const key = await makeKey();
171
- const main = await makeCounterChain({
172
- key,
173
- epochId: "epoch-multichain",
174
- chainId: "bitgraph:main",
175
- pairs: healthyPairs(2),
176
- payloadPrefix: "main",
177
- });
178
- const globalChain = await makeCounterChain({
179
- key,
180
- epochId: "epoch-multichain",
181
- pairs: healthyPairs(2), // no chainId: normalized "global"
182
- payloadPrefix: "global",
183
- });
184
- const { reconstruction, report } = await auditBundle({
185
- "m0.json": proofJson(main.proofs[0]!.proof),
186
- "m1.json": proofJson(main.proofs[1]!.proof),
187
- "g0.json": proofJson(globalChain.proofs[0]!.proof),
188
- "g1.json": proofJson(globalChain.proofs[1]!.proof),
189
- });
190
-
191
- assert.equal(reconstruction.partitions.length, 2);
192
- assert.deepEqual(
193
- reconstruction.partitions.map((p) => p.key.chainId).sort(),
194
- ["bitgraph:main", "global"]
195
- );
196
- assert.deepEqual(report.anomalies, []);
197
- });
198
-
199
- test("chainless proofs stay outside partitions as observed-but-unchained", async () => {
200
- const chain = await makeCounterChain({ epochId: "epoch-with-stray", pairs: healthyPairs(2) });
201
- const chainless = await makeConstructorProof(); // no counter, no epochId
202
- const { ingest, reconstruction, report } = await auditBundle({
203
- "p0.json": proofJson(chain.proofs[0]!.proof),
204
- "p1.json": proofJson(chain.proofs[1]!.proof),
205
- "stray.json": proofJson(chainless.proof),
206
- });
207
-
208
- assert.equal(ingest.proofs.length, 3);
209
- assert.equal(reconstruction.partitions.length, 1);
210
- assert.equal(reconstruction.partitions[0]!.memberProofHashes.length, 2);
211
- const strayHash = ingest.proofs.find((p) => p.chainless)!.proofHash;
212
- assert.deepEqual(reconstruction.unchainedProofHashes, [strayHash]);
213
- // Observed-but-unchained is not an anomaly.
214
- assert.deepEqual(report.anomalies, []);
215
- });
216
-
217
- test("a proof with chain fields but no signer key is unpartitioned", async () => {
218
- const broken = JSON.stringify({
219
- version: "bitgraph/1",
220
- artifact: { hashAlg: "sha256", digestB64: b64(sha256(utf8("broken-payload"))) },
221
- commit: { nonceB64: "AAAA", counter: "2", epochId: "epoch-broken" },
222
- signer: { publicKeyB64: 42, signatureB64: "AAAA" },
223
- });
224
- const { ingest, reconstruction } = await auditBundle({ "broken.json": broken });
225
- assert.equal(ingest.proofs.length, 1);
226
- assert.equal(reconstruction.partitions.length, 0);
227
- assert.deepEqual(reconstruction.unpartitionedProofHashes, [ingest.proofs[0]!.proofHash]);
228
- // The verification dimension reports the structural failure.
229
- assert.equal(ingest.proofs[0]!.verification!.status, "failed");
230
- });
231
- });
232
-
233
- // ---------------------------------------------------------------------------
234
- // Missing proofs split components
235
- // ---------------------------------------------------------------------------
236
-
237
- describe("reconstruct: missing middle proof", () => {
238
- test("splits the partition into two components with the break identified", async () => {
239
- const chain = await makeCounterChain({ epochId: "epoch-gap", pairs: healthyPairs(3) });
240
- // Omit the middle proof (slot 3 / commit 4).
241
- const { reconstruction } = await auditBundle({
242
- "p0.json": proofJson(chain.proofs[0]!.proof),
243
- "p2.json": proofJson(chain.proofs[2]!.proof),
244
- });
245
-
246
- const partition = reconstruction.partitions[0]!;
247
- assert.equal(partition.components.length, 2);
248
- const [first, second] = partition.components;
249
- assert.deepEqual(first!.memberProofHashes, [chain.proofs[0]!.proofHash]);
250
- assert.deepEqual(first!.genesisProofHashes, [chain.proofs[0]!.proofHash]);
251
- assert.deepEqual(first!.terminalProofHashes, [chain.proofs[0]!.proofHash]);
252
- assert.deepEqual(second!.memberProofHashes, [chain.proofs[2]!.proofHash]);
253
- assert.deepEqual(second!.genesisProofHashes, []);
254
- assert.deepEqual(second!.brokenLinkProofHashes, [chain.proofs[2]!.proofHash]);
255
- });
256
- });
257
-
258
- // ---------------------------------------------------------------------------
259
- // Epoch relationships
260
- // ---------------------------------------------------------------------------
261
-
262
- describe("reconstruct: epoch relationships", () => {
263
- test("a valid epochLink produces a hard lineage edge and linked ordering", async () => {
264
- const chainA = await makeCounterChain({ epochId: "epoch-lineage-A", pairs: healthyPairs(2) });
265
- const terminalA = chainA.proofs[1]!;
266
- const genesisB = await makeEpochLinkProof({
267
- prevEpochId: "epoch-lineage-A",
268
- prevCounter: terminalA.proof.commit.counter as string,
269
- prevProofHashB64: terminalA.chainHash,
270
- prevPublicKeyB64: chainA.key.publicKeyB64,
271
- toEpochId: "epoch-lineage-B",
272
- counter: "2",
273
- slotCounter: "1",
274
- });
275
-
276
- const { reconstruction, report } = await auditBundle({
277
- "a0.json": proofJson(chainA.proofs[0]!.proof),
278
- "a1.json": proofJson(terminalA.proof),
279
- "b-genesis.json": proofJson(genesisB.proof),
280
- });
281
-
282
- const { edges, epochs, orderedPairs } = reconstruction.epochRelationships;
283
- assert.equal(edges.length, 1);
284
- const edge = edges[0]!;
285
- assert.equal(edge.resolution, "matched");
286
- assert.equal(edge.fromEpochId, "epoch-lineage-A");
287
- assert.equal(edge.toEpochId, "epoch-lineage-B");
288
- assert.equal(edge.predecessorProofHash, terminalA.proofHash);
289
- assert.equal(edge.metadataConsistent, true);
290
- assert.equal(edge.referencedProofIsTerminal, true);
291
- assert.equal(edge.viaProofValid, true);
292
- assert.equal(edge.predecessorValid, true);
293
- assert.equal(edge.hardEdge, true);
294
-
295
- assert.deepEqual(orderedPairs, [
296
- { beforeEpochId: "epoch-lineage-A", afterEpochId: "epoch-lineage-B" },
297
- ]);
298
- const epochA = epochs.find((e) => e.epochId === "epoch-lineage-A")!;
299
- const epochB = epochs.find((e) => e.epochId === "epoch-lineage-B")!;
300
- assert.equal(epochA.ordering, "linked");
301
- assert.equal(epochB.ordering, "linked");
302
- assert.deepEqual(epochA.linkedSuccessorEpochIds, ["epoch-lineage-B"]);
303
- assert.deepEqual(epochB.linkedPredecessorEpochIds, ["epoch-lineage-A"]);
304
- // The extension point stays untouched by reconstruction.
305
- assert.equal(epochA.anchorBounds, undefined);
306
-
307
- // Valid lineage is not an anomaly.
308
- assert.deepEqual(report.anomalies, []);
309
- assert.deepEqual(report.divergences, []);
310
- });
311
-
312
- test("a dangling epochLink yields no hard edge and no ordering", async () => {
313
- const genesis = await makeEpochLinkProof({
314
- prevEpochId: "epoch-never-observed",
315
- prevCounter: "10",
316
- prevProofHashB64: b64(sha256(utf8("terminal-never-observed"))),
317
- toEpochId: "epoch-dangling-B",
318
- counter: "2",
319
- slotCounter: "1",
320
- });
321
- const { reconstruction } = await auditBundle({
322
- "b-genesis.json": proofJson(genesis.proof),
323
- });
324
-
325
- const { edges, epochs, orderedPairs } = reconstruction.epochRelationships;
326
- assert.equal(edges.length, 1);
327
- assert.equal(edges[0]!.resolution, "dangling");
328
- assert.equal(edges[0]!.hardEdge, false);
329
- assert.deepEqual(orderedPairs, []);
330
- assert.equal(epochs.find((e) => e.epochId === "epoch-dangling-B")!.ordering, "observed-but-unordered");
331
- });
332
-
333
- test("epochs with no lineage evidence are observed-but-unordered, never divergence", async () => {
334
- const chainA = await makeCounterChain({ epochId: "epoch-solo-A", pairs: healthyPairs(2) });
335
- const chainB = await makeCounterChain({ epochId: "epoch-solo-B", pairs: healthyPairs(2) });
336
- const { reconstruction, report } = await auditBundle({
337
- "a0.json": proofJson(chainA.proofs[0]!.proof),
338
- "a1.json": proofJson(chainA.proofs[1]!.proof),
339
- "b0.json": proofJson(chainB.proofs[0]!.proof),
340
- "b1.json": proofJson(chainB.proofs[1]!.proof),
341
- });
342
-
343
- const { epochs, edges, orderedPairs } = reconstruction.epochRelationships;
344
- assert.equal(edges.length, 0);
345
- assert.deepEqual(orderedPairs, []);
346
- for (const epoch of epochs) {
347
- assert.equal(epoch.ordering, "observed-but-unordered");
348
- }
349
- // Concurrent-or-unordered is never divergence.
350
- assert.deepEqual(report.divergences, []);
351
- assert.deepEqual(report.anomalies, []);
352
- });
353
- });