geospec-engine 0.0.0 → 0.1.0-next.19

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 (181) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +99 -0
  3. package/README.md +150 -0
  4. package/dist/bindings/mixed-wasm/geospec_engine_native.mjs +2 -0
  5. package/dist/bindings/mixed-wasm/geospec_engine_native.wasm +0 -0
  6. package/dist/host-types.d.mts +48 -0
  7. package/dist/host-types.mjs +1 -0
  8. package/dist/index.d.mts +3 -0
  9. package/dist/index.mjs +1 -0
  10. package/dist/mixed-wasm-loader.d.mts +16 -0
  11. package/dist/mixed-wasm-loader.mjs +3 -0
  12. package/dist/native/index.js +708 -0
  13. package/dist/node.d.mts +97 -0
  14. package/dist/node.mjs +1 -0
  15. package/dist/wasm.d.mts +93 -0
  16. package/dist/wasm.mjs +1 -0
  17. package/licenses/FreeType-FTL.txt +169 -0
  18. package/licenses/GeoSpec-LICENSE.txt +201 -0
  19. package/licenses/Manifold-Rust-LICENSE.txt +201 -0
  20. package/licenses/NOTICE.txt +99 -0
  21. package/licenses/OCCT-LGPL-2.1.txt +502 -0
  22. package/licenses/OCCT-LGPL-exception.txt +10 -0
  23. package/licenses/RapidJSON-LICENSE.txt +57 -0
  24. package/licenses/SOURCE-RELINK.json +152 -0
  25. package/licenses/SOURCE-RELINK.md +22 -0
  26. package/licenses/THIRD-PARTY-NOTICES.txt +1088 -0
  27. package/licenses/cargo/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f-COPYING +3 -0
  28. package/licenses/cargo/0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720-LICENSE-MIT +25 -0
  29. package/licenses/cargo/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594-LICENSE-APACHE +177 -0
  30. package/licenses/cargo/0e6c282dfcb08a031c37b8f851fe5813fad63612e88a29dbe5121d727d67bbf2-LICENSE-MIT +26 -0
  31. package/licenses/cargo/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f-LICENSE-MIT +21 -0
  32. package/licenses/cargo/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e-LICENSE-MIT +25 -0
  33. package/licenses/cargo/13ce2fb7da9c6c3a5a16e86877a604e80237f076b9258115d8f0444127f6a281-NOTICE.md +41 -0
  34. package/licenses/cargo/20fe7b00e904ed690e3b9fd6073784d3fc428141dbd10b81c01fd143d0797f58-LICENSE-APACHE +176 -0
  35. package/licenses/cargo/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3-LICENSE-MIT +23 -0
  36. package/licenses/cargo/275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427-LICENSE-APACHE +202 -0
  37. package/licenses/cargo/27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac-LICENSE-MIT +25 -0
  38. package/licenses/cargo/30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652-LICENSE-MIT +23 -0
  39. package/licenses/cargo/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897-LICENSE-MIT +25 -0
  40. package/licenses/cargo/36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9-LICENSE-MIT +23 -0
  41. package/licenses/cargo/3708458dee7f359ac6c9c5558023ed481be87e5372c43ebd7f2ca7ad23c12026-LICENSE-APACHE +202 -0
  42. package/licenses/cargo/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397-LICENSE-MIT +25 -0
  43. package/licenses/cargo/3f8a05fc8617c5ce569fa5a4f2301cd847fe00fa011bdaa8f353fd55a2691a54-LICENSE-MIT +21 -0
  44. package/licenses/cargo/42fa16951ce7f24b5a467a40e5b449a1d41e662f97ca779864f053f39e097737-LICENSE-MIT +26 -0
  45. package/licenses/cargo/4455bf75a91154108304cb283e0fea9948c14f13e20d60887cf2552449dea3b1-LICENSE-MIT +21 -0
  46. package/licenses/cargo/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406-LICENSE-APACHE +201 -0
  47. package/licenses/cargo/553fffcd9b1cb158bc3e9edc35da85ca5c3b3d7d2e61c883ebcfa8a65814b583-LICENSE-APACHE +13 -0
  48. package/licenses/cargo/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a-LICENSE-APACHE +176 -0
  49. package/licenses/cargo/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb-LICENSE-MIT +25 -0
  50. package/licenses/cargo/6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd-LICENSE-MIT +26 -0
  51. package/licenses/cargo/7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349-LICENSE-MIT +25 -0
  52. package/licenses/cargo/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0-LICENSE-MIT +25 -0
  53. package/licenses/cargo/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c-UNLICENSE +24 -0
  54. package/licenses/cargo/8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18-LICENSE +25 -0
  55. package/licenses/cargo/95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc-LICENSE-APACHE +176 -0
  56. package/licenses/cargo/98b52ccf20010b67d8fd3bdf151f50ecdfc01f25d6de190e015dd436d9f7ea0b-LICENSE +201 -0
  57. package/licenses/cargo/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba-LICENSE-MIT +25 -0
  58. package/licenses/cargo/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2-LICENSE-APACHE +201 -0
  59. package/licenses/cargo/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f-LICENSE-MIT +21 -0
  60. package/licenses/cargo/a8ad31b1c3f40dca5a84119351b8fa8ddc868edd77fad8a8ebf6d8f2d16fa4ae-LICENSE-APACHE +201 -0
  61. package/licenses/cargo/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5-LICENSE-APACHE +201 -0
  62. package/licenses/cargo/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf-LICENSE-APACHE +201 -0
  63. package/licenses/cargo/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985-LICENSE-MIT +25 -0
  64. package/licenses/cargo/aed7b1758e35afa0cd0fde059d61950747ca11cd0e5e169cb21c11608daed772-LICENSE +21 -0
  65. package/licenses/cargo/b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744-LICENSE +19 -0
  66. package/licenses/cargo/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f-LICENSE +12 -0
  67. package/licenses/cargo/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1-LICENSE-MIT +27 -0
  68. package/licenses/cargo/b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e-LICENSE-MIT +19 -0
  69. package/licenses/cargo/bccaa8b6c09f94e81f06696e179dbe058464bbdfbc823b6d49cada1d71e84ac3-LICENSE-MIT +5 -0
  70. package/licenses/cargo/beb8e42e9d6b4284e03304d05a81a0755200a965fc8d0a5e0aea1e84cf805d6e-LICENSE +23 -0
  71. package/licenses/cargo/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583-LICENSE +21 -0
  72. package/licenses/cargo/c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4-LICENSE +201 -0
  73. package/licenses/cargo/c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566-LICENSE-BOOST +23 -0
  74. package/licenses/cargo/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30-LICENSE-APACHE +202 -0
  75. package/licenses/cargo/d1fc1bc0d155df60b2e7705b6b2ae02a05c96f948e1cec6e2fb86360b09f346b-LICENSE +29 -0
  76. package/licenses/cargo/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef-LICENSE-MIT +25 -0
  77. package/licenses/cargo/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a-LICENSE +1 -0
  78. package/licenses/cargo/e36d55837170195cdf934aa6a48c0ad6efba1bde3f5b4a1b9259c171d5aeb647-LICENSE-APACHE +201 -0
  79. package/licenses/cargo/ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061-LICENSE-MIT +21 -0
  80. package/licenses/cargo/ec353d4fecf7963b4c054384557e5dbc3c7a717997eb4a3815b315721a6aa75a-LICENSE-MIT +18 -0
  81. package/licenses/cargo/f71fd5946d6674af304514dc7b3b4272aa9117052dd347fb3a9dc9679f33d95f-LICENSE-MIT +26 -0
  82. package/licenses/cargo/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1-LICENSE-UNICODE +39 -0
  83. package/licenses/cargo/fe5c9498374de7953275f83f35565b289f377ceab4a28d04c7da87723e02a372-LICENSE +20 -0
  84. package/licenses/cargo/ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2-LICENSE-MIT +25 -0
  85. package/licenses/components.json +5897 -0
  86. package/licenses/fallback/MIT.txt +21 -0
  87. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/backtrace/LICENSE-APACHE +201 -0
  88. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/backtrace/LICENSE-MIT +25 -0
  89. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/compiler-builtins/LICENSE.txt +275 -0
  90. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/compiler-builtins/libm/LICENSE.txt +258 -0
  91. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/portable-simd/LICENSE-APACHE +202 -0
  92. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/portable-simd/LICENSE-MIT +19 -0
  93. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/portable-simd/crates/core_simd/LICENSE-APACHE +202 -0
  94. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/portable-simd/crates/core_simd/LICENSE-MIT +19 -0
  95. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/stdarch/LICENSE-APACHE +201 -0
  96. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/stdarch/LICENSE-MIT +25 -0
  97. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/stdarch/crates/core_arch/LICENSE-APACHE +201 -0
  98. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/stdarch/crates/core_arch/LICENSE-MIT +25 -0
  99. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/stdarch/crates/intrinsic-test/LICENSE-APACHE +201 -0
  100. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/stdarch/crates/intrinsic-test/LICENSE-MIT +25 -0
  101. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/addr2line-0.27.1/LICENSE-APACHE +201 -0
  102. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/addr2line-0.27.1/LICENSE-MIT +25 -0
  103. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/adler2-2.0.1/LICENSE-0BSD +12 -0
  104. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/adler2-2.0.1/LICENSE-APACHE +201 -0
  105. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/adler2-2.0.1/LICENSE-MIT +23 -0
  106. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/cc-1.2.0/LICENSE-APACHE +201 -0
  107. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/cc-1.2.0/LICENSE-MIT +25 -0
  108. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/cfg-if-1.0.4/LICENSE-APACHE +201 -0
  109. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/cfg-if-1.0.4/LICENSE-MIT +25 -0
  110. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/dlmalloc-0.2.14/LICENSE-APACHE +201 -0
  111. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/dlmalloc-0.2.14/LICENSE-MIT +25 -0
  112. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/foldhash-0.2.0/LICENSE +19 -0
  113. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/getopts-0.2.24/LICENSE-APACHE +201 -0
  114. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/getopts-0.2.24/LICENSE-MIT +25 -0
  115. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/gimli-0.34.0/LICENSE-APACHE +201 -0
  116. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/gimli-0.34.0/LICENSE-MIT +25 -0
  117. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/hashbrown-0.17.1/LICENSE-APACHE +201 -0
  118. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/hashbrown-0.17.1/LICENSE-MIT +25 -0
  119. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/hermit-abi-0.5.2/LICENSE-APACHE +201 -0
  120. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/hermit-abi-0.5.2/LICENSE-MIT +23 -0
  121. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/libc-0.2.189/LICENSE-APACHE +176 -0
  122. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/libc-0.2.189/LICENSE-MIT +25 -0
  123. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/memchr-2.8.3/COPYING +3 -0
  124. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/memchr-2.8.3/LICENSE-MIT +21 -0
  125. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/memchr-2.8.3/UNLICENSE +24 -0
  126. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/miniz_oxide-0.9.1/LICENSE +25 -0
  127. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/miniz_oxide-0.9.1/LICENSE-APACHE.md +177 -0
  128. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/miniz_oxide-0.9.1/LICENSE-MIT.md +24 -0
  129. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/miniz_oxide-0.9.1/LICENSE-ZLIB.md +14 -0
  130. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/moto-rt-0.16.3/LICENSE-APACHE +201 -0
  131. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/moto-rt-0.16.3/LICENSE-MIT +25 -0
  132. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/object-0.39.1/LICENSE-APACHE +201 -0
  133. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/object-0.39.1/LICENSE-MIT +25 -0
  134. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/r-efi-5.3.0/AUTHORS +74 -0
  135. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/r-efi-alloc-2.1.0/AUTHORS +62 -0
  136. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand-0.9.5/COPYRIGHT +12 -0
  137. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand-0.9.5/LICENSE-APACHE +176 -0
  138. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand-0.9.5/LICENSE-MIT +26 -0
  139. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand_core-0.9.5/COPYRIGHT +12 -0
  140. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand_core-0.9.5/LICENSE-APACHE +187 -0
  141. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand_core-0.9.5/LICENSE-MIT +26 -0
  142. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand_xorshift-0.4.0/COPYRIGHT +12 -0
  143. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand_xorshift-0.4.0/LICENSE-APACHE +176 -0
  144. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rand_xorshift-0.4.0/LICENSE-MIT +26 -0
  145. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rustc-demangle-0.1.28/LICENSE-APACHE +201 -0
  146. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rustc-demangle-0.1.28/LICENSE-MIT +25 -0
  147. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rustc-literal-escaper-0.0.8/LICENSE-APACHE +176 -0
  148. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/rustc-literal-escaper-0.0.8/LICENSE-MIT +23 -0
  149. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/shlex-1.3.0/LICENSE-APACHE +13 -0
  150. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/shlex-1.3.0/LICENSE-MIT +21 -0
  151. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/unwinding-0.2.10/LICENSE-APACHE +176 -0
  152. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/unwinding-0.2.10/LICENSE-MIT +23 -0
  153. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wasip2-1.0.4+wasi-0.2.12/LICENSE-APACHE +201 -0
  154. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wasip2-1.0.4+wasi-0.2.12/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  155. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wasip2-1.0.4+wasi-0.2.12/LICENSE-MIT +23 -0
  156. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wasip3-0.7.1+wasi-0.3.0/LICENSE-APACHE +201 -0
  157. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wasip3-0.7.1+wasi-0.3.0/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  158. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wasip3-0.7.1+wasi-0.3.0/LICENSE-MIT +23 -0
  159. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wit-bindgen-0.57.1/LICENSE-APACHE +201 -0
  160. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wit-bindgen-0.57.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  161. package/licenses/mixed-tools/rustPrefix/lib/rustlib/src/rust/library/vendor/wit-bindgen-0.57.1/LICENSE-MIT +23 -0
  162. package/licenses/mixed-tools/rustPrefix/share/doc/rust/COPYRIGHT-library.html +29378 -0
  163. package/licenses/mixed-tools/sdkPrefix/emscripten/AUTHORS +607 -0
  164. package/licenses/mixed-tools/sdkPrefix/emscripten/LICENSE +102 -0
  165. package/licenses/mixed-tools/sdkPrefix/emscripten/system/include/SDL/COPYING +24 -0
  166. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/compiler-rt/LICENSE.TXT +311 -0
  167. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/libc/musl/COPYRIGHT +193 -0
  168. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/libcxx/LICENSE.TXT +311 -0
  169. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/libcxxabi/LICENSE.TXT +311 -0
  170. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/libunwind/LICENSE.TXT +311 -0
  171. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/llvm-libc/LICENSE.TXT +278 -0
  172. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/mimalloc/LICENSE +21 -0
  173. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/openmp/LICENSE.TXT +361 -0
  174. package/licenses/mixed-tools/sdkPrefix/emscripten/system/lib/openmp/src/thirdparty/ittnotify/LICENSE.txt +8 -0
  175. package/package.json +83 -4
  176. package/trust/README.md +42 -0
  177. package/trust/canonicalize.mjs +37 -0
  178. package/trust/evaluate-worker.mjs +164 -0
  179. package/trust/index.d.mts +112 -0
  180. package/trust/run.mjs +850 -0
  181. package/trust/verify.py +470 -0
package/trust/run.mjs ADDED
@@ -0,0 +1,850 @@
1
+ /* oxlint-disable @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unnecessary-condition, @typescript-eslint/restrict-plus-operands -- Approved plans, policy, and worker records cross intentionally untyped JSON boundaries. */
2
+ import assert from 'node:assert/strict';
3
+ import { spawnSync } from 'node:child_process';
4
+ import { createHash, createPublicKey, sign as cryptoSign, verify } from 'node:crypto';
5
+ import {
6
+ closeSync,
7
+ copyFileSync,
8
+ existsSync,
9
+ fstatSync,
10
+ mkdirSync,
11
+ mkdtempSync,
12
+ openSync,
13
+ readFileSync,
14
+ readdirSync,
15
+ readSync,
16
+ realpathSync,
17
+ rmSync,
18
+ statSync,
19
+ writeFileSync,
20
+ } from 'node:fs';
21
+ import { tmpdir } from 'node:os';
22
+ import { createRequire } from 'node:module';
23
+ import { dirname, join, resolve } from 'node:path';
24
+ import { fileURLToPath, pathToFileURL } from 'node:url';
25
+
26
+ const TRUST_ROOT = dirname(fileURLToPath(import.meta.url));
27
+ const PAYLOAD_TYPE = 'application/vnd.in-toto+json';
28
+ const PREDICATE_TYPE = 'https://taucad.dev/attestation/geospec-trusted-evaluation/v3';
29
+ const EVALUATOR_MODE = 'signed-local-record';
30
+ const ISOLATION_CLASS = 'none';
31
+ const MAX_ENVELOPE_BYTES = 4_194_304;
32
+ const MAX_ARTIFACT_BYTES = 67_108_864;
33
+ const MAX_CANONICAL_BATCH_BYTES = 3 * MAX_ARTIFACT_BYTES;
34
+ const RUNNER_FILES = ['canonicalize.mjs', 'evaluate-worker.mjs', 'run.mjs'];
35
+ const DARWIN_ARM64_PACKAGE = 'geospec-engine-darwin-arm64';
36
+ const DARWIN_ARM64_BINARY = 'geospec-engine.darwin-arm64.node';
37
+
38
+ const sha256 = (bytes) => createHash('sha256').update(bytes).digest('hex');
39
+ const readBoundedFile = (path, maximumBytes) => {
40
+ assert.ok(Number.isSafeInteger(maximumBytes) && maximumBytes >= 0 && maximumBytes <= MAX_ARTIFACT_BYTES);
41
+ const descriptor = openSync(path, 'r');
42
+ try {
43
+ const metadata = fstatSync(descriptor);
44
+ assert.ok(metadata.isFile(), `${path} must be a regular file`);
45
+ assert.ok(metadata.size <= maximumBytes, `${path} exceeds input limit`);
46
+ const bytes = Buffer.alloc(metadata.size);
47
+ let offset = 0;
48
+ while (offset < bytes.byteLength) {
49
+ const length = readSync(descriptor, bytes, offset, bytes.byteLength - offset, null);
50
+ assert.ok(length > 0, `${path} changed length during read`);
51
+ offset += length;
52
+ }
53
+ assert.equal(readSync(descriptor, Buffer.alloc(1), 0, 1, null), 0, `${path} changed length during read`);
54
+ return bytes;
55
+ } finally {
56
+ closeSync(descriptor);
57
+ }
58
+ };
59
+
60
+ const exactKeys = (value, keys, label) => {
61
+ assert.ok(value && typeof value === 'object' && !Array.isArray(value), `${label} must be an object`);
62
+ assert.deepEqual(Object.keys(value).toSorted(), keys.toSorted(), `${label} fields`);
63
+ };
64
+ const safeName = (value, label) => {
65
+ assert.equal(typeof value, 'string', `${label} must be a string`);
66
+ assert.match(value, /^[\w./-]+$/, `${label} must be bounded ASCII`);
67
+ assert.ok(!value.startsWith('/') && !value.split('/').includes('..'), `${label} must be relative`);
68
+ return value;
69
+ };
70
+ const sourcePath = (value, label) => {
71
+ assert.equal(typeof value, 'string', `${label} must be a string`);
72
+ assert.match(value, /^[\w./-]+$/, `${label} must be bounded ASCII`);
73
+ assert.ok(!value.startsWith('/'), `${label} must be relative`);
74
+ return value;
75
+ };
76
+ const pae = (payloadType, payload) =>
77
+ Buffer.concat([
78
+ Buffer.from(`DSSEv1 ${Buffer.byteLength(payloadType)} ${payloadType} ${payload.byteLength} `),
79
+ payload,
80
+ ]);
81
+
82
+ const controlledEnvironment = (temporaryDirectory) => ({
83
+ LANG: 'C',
84
+ NAPI_RS_ENFORCE_VERSION_CHECK: '1',
85
+ NODE_NO_WARNINGS: '1',
86
+ PATH: dirname(process.execPath),
87
+ TMPDIR: temporaryDirectory,
88
+ });
89
+
90
+ const runCanonicalizer = (productRoot, inputPath, mode) => {
91
+ const arguments_ = [join(TRUST_ROOT, 'canonicalize.mjs'), productRoot, inputPath];
92
+ if (mode) {
93
+ arguments_.push(mode);
94
+ }
95
+ const result = spawnSync(process.execPath, arguments_, {
96
+ encoding: null,
97
+ env: controlledEnvironment(dirname(inputPath)),
98
+ maxBuffer: mode === '--batch' ? MAX_CANONICAL_BATCH_BYTES : MAX_ARTIFACT_BYTES,
99
+ timeout: 10_000,
100
+ });
101
+ assert.ifError(result.error);
102
+ assert.equal(result.signal, null, 'canonicalizer terminated by signal');
103
+ assert.equal(result.status, 0, Buffer.from(result.stderr ?? []).toString('utf8'));
104
+ return Buffer.from(result.stdout);
105
+ };
106
+
107
+ const frameJsonRecords = (records) =>
108
+ Buffer.concat(
109
+ records.flatMap((record) => {
110
+ const header = Buffer.alloc(4);
111
+ header.writeUInt32BE(record.byteLength);
112
+ return [header, record];
113
+ }),
114
+ );
115
+
116
+ const canonicalizeJsonBatch = (productRoot, records) => {
117
+ assert.ok(records.length > 0, 'canonicalization batch must not be empty');
118
+ const directory = mkdtempSync(join(tmpdir(), 'geospec-trust-batch-'));
119
+ const input = join(directory, 'input.bin');
120
+ try {
121
+ writeFileSync(input, frameJsonRecords(records));
122
+ const output = runCanonicalizer(productRoot, input, '--batch');
123
+ const canonical = [];
124
+ let offset = 0;
125
+ while (offset < output.byteLength) {
126
+ assert.ok(offset + 4 <= output.byteLength, 'incomplete canonicalization batch header');
127
+ const byteLength = output.readUInt32BE(offset);
128
+ offset += 4;
129
+ assert.ok(offset + byteLength <= output.byteLength, 'incomplete canonicalization batch value');
130
+ canonical.push(output.subarray(offset, offset + byteLength));
131
+ offset += byteLength;
132
+ }
133
+ assert.equal(canonical.length, records.length, 'canonicalization batch result count');
134
+ return canonical;
135
+ } finally {
136
+ rmSync(directory, { force: true, recursive: true });
137
+ }
138
+ };
139
+
140
+ const canonicalizeBytes = (productRoot, bytes) => {
141
+ const directory = mkdtempSync(join(tmpdir(), 'geospec-trust-'));
142
+ const input = join(directory, 'input.json');
143
+ try {
144
+ writeFileSync(input, bytes);
145
+ return runCanonicalizer(productRoot, input);
146
+ } finally {
147
+ rmSync(directory, { force: true, recursive: true });
148
+ }
149
+ };
150
+
151
+ const canonicalizeValue = (productRoot, value) => canonicalizeBytes(productRoot, Buffer.from(JSON.stringify(value)));
152
+
153
+ const writeCanonical = ({ directory, name, productRoot, value }) => {
154
+ const bytes = canonicalizeValue(productRoot, value);
155
+ const path = join(directory, name);
156
+ writeFileSync(path, bytes);
157
+ return { bytes, path };
158
+ };
159
+
160
+ const validatePlan = (plan) => {
161
+ exactKeys(plan, ['authority', 'claims', 'requirements', 'schema', 'subjects'], 'approved plan');
162
+ assert.equal(plan.schema, 'geospec-approved-evaluation-plan-v2');
163
+ exactKeys(
164
+ plan.authority,
165
+ ['canonicalProfile', 'protocolVersion', 'registryVersion', 'requirementRevision'],
166
+ 'authority',
167
+ );
168
+ exactKeys(
169
+ plan.requirements,
170
+ ['freshChallengeRequired', 'maxClaims', 'maxSubjectBytes', 'maxTotalSubjectBytes', 'workerDeadlineMs'],
171
+ 'requirements',
172
+ );
173
+ assert.equal(plan.authority.canonicalProfile, 'geospec-jcs-v1');
174
+ assert.equal(plan.authority.protocolVersion, 3);
175
+ assert.equal(plan.authority.registryVersion, 5);
176
+ assert.ok(plan.claims.length > 0 && plan.claims.length <= plan.requirements.maxClaims);
177
+ assert.ok(plan.subjects.length > 0 && plan.subjects.length <= 4);
178
+ assert.equal(new Set(plan.claims.map((entry) => entry.claim.claimId)).size, plan.claims.length);
179
+ assert.equal(new Set(plan.subjects.map((entry) => entry.slot)).size, plan.subjects.length);
180
+ let totalBytes = 0;
181
+ for (const entry of plan.claims) {
182
+ exactKeys(entry, ['canonicalClaimSha256', 'claim'], 'approved claim');
183
+ }
184
+ for (const subject of plan.subjects) {
185
+ exactKeys(
186
+ subject,
187
+ [
188
+ 'expectedIdentity',
189
+ 'format',
190
+ 'frame',
191
+ 'identityField',
192
+ 'ingestRequest',
193
+ 'ingestRequestSha256',
194
+ 'primary',
195
+ 'resources',
196
+ 'slot',
197
+ ],
198
+ 'approved subject',
199
+ );
200
+ exactKeys(subject.primary, ['byteLength', 'path', 'sha256'], 'primary descriptor');
201
+ exactKeys(
202
+ subject.ingestRequest,
203
+ [
204
+ 'canonicalProfile',
205
+ 'format',
206
+ 'frame',
207
+ 'ingestOptions',
208
+ 'method',
209
+ 'primaryByteLength',
210
+ 'protocolVersion',
211
+ 'registryVersion',
212
+ 'requestId',
213
+ 'resources',
214
+ ],
215
+ 'ingest request',
216
+ );
217
+ safeName(subject.slot, 'subject slot');
218
+ sourcePath(subject.primary.path, 'primary path');
219
+ assert.equal(subject.ingestRequest.canonicalProfile, plan.authority.canonicalProfile);
220
+ assert.equal(subject.ingestRequest.protocolVersion, plan.authority.protocolVersion);
221
+ assert.equal(subject.ingestRequest.registryVersion, plan.authority.registryVersion);
222
+ assert.equal(subject.ingestRequest.method, 'ingestSubject');
223
+ assert.equal(subject.ingestRequest.format, subject.format);
224
+ assert.deepEqual(subject.ingestRequest.frame, subject.frame);
225
+ assert.equal(subject.ingestRequest.primaryByteLength, subject.primary.byteLength);
226
+ assert.ok(subject.primary.byteLength <= plan.requirements.maxSubjectBytes);
227
+ totalBytes += subject.primary.byteLength;
228
+ for (const resource of subject.resources) {
229
+ exactKeys(resource, ['byteLength', 'name', 'path', 'sha256'], 'resource descriptor');
230
+ safeName(resource.name, 'resource name');
231
+ sourcePath(resource.path, 'resource path');
232
+ assert.ok(resource.byteLength <= plan.requirements.maxSubjectBytes);
233
+ totalBytes += resource.byteLength;
234
+ }
235
+ assert.deepEqual(
236
+ subject.ingestRequest.resources,
237
+ subject.resources.map(({ byteLength, name }) => ({ byteLength, name })),
238
+ 'ingest resource descriptors',
239
+ );
240
+ }
241
+ assert.ok(totalBytes <= plan.requirements.maxTotalSubjectBytes);
242
+ };
243
+
244
+ const copyBoundFile = ({ destinationPath, expected, planRoot, requestedSourcePath }) => {
245
+ const source = resolve(planRoot, sourcePath(requestedSourcePath, 'subject source path'));
246
+ const bytes = readBoundedFile(source, expected.byteLength);
247
+ assert.equal(bytes.byteLength, expected.byteLength, `${requestedSourcePath} byte length`);
248
+ assert.equal(sha256(bytes), expected.sha256, `${requestedSourcePath} digest`);
249
+ mkdirSync(dirname(destinationPath), { recursive: true });
250
+ writeFileSync(destinationPath, bytes);
251
+ return destinationPath;
252
+ };
253
+
254
+ const artifact = (root, name) => {
255
+ safeName(name, 'artifact name');
256
+ const path = join(root, name);
257
+ const metadata = statSync(path);
258
+ assert.ok(metadata.isFile() && !metadata.isSymbolicLink(), `${name} must be a regular file`);
259
+ assert.ok(metadata.size <= MAX_ARTIFACT_BYTES, `${name} exceeds artifact limit`);
260
+ return { byteLength: metadata.size, name, sha256: sha256(readFileSync(path)) };
261
+ };
262
+
263
+ const installedEngineFiles = (productRoot) => {
264
+ assert.equal(process.platform, 'darwin', 'trusted evaluator currently requires Darwin');
265
+ assert.equal(process.arch, 'arm64', 'trusted evaluator currently requires Darwin ARM64');
266
+ const packagePath = join(productRoot, 'node_modules/geospec-engine/package.json');
267
+ const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'));
268
+ assert.equal(packageJson.optionalDependencies?.[DARWIN_ARM64_PACKAGE], packageJson.version);
269
+ const localNativeDirectory = join(productRoot, 'node_modules/geospec-engine/dist/native');
270
+ assert.deepEqual(
271
+ readdirSync(localNativeDirectory).filter((entry) => entry.endsWith('.node')),
272
+ [],
273
+ 'local native loader alternatives must be absent',
274
+ );
275
+ const loaderRequire = createRequire(realpathSync(join(localNativeDirectory, 'index.js')));
276
+ let universalCandidate;
277
+ try {
278
+ universalCandidate = loaderRequire.resolve('geospec-engine-darwin-universal');
279
+ } catch (error) {
280
+ assert.equal(error.code, 'MODULE_NOT_FOUND', 'universal candidate resolution');
281
+ }
282
+ assert.equal(universalCandidate, undefined, 'Darwin universal loader alternative must not resolve');
283
+ const platformDirectory = join(productRoot, 'node_modules', DARWIN_ARM64_PACKAGE);
284
+ assert.equal(
285
+ realpathSync(loaderRequire.resolve(DARWIN_ARM64_PACKAGE)),
286
+ realpathSync(join(platformDirectory, DARWIN_ARM64_BINARY)),
287
+ 'resolved native binary must match the engine manifest',
288
+ );
289
+ assert.equal(
290
+ realpathSync(loaderRequire.resolve(`${DARWIN_ARM64_PACKAGE}/package.json`)),
291
+ realpathSync(join(platformDirectory, 'package.json')),
292
+ 'resolved platform package must match the engine manifest',
293
+ );
294
+ const platformPackageJson = JSON.parse(readFileSync(join(platformDirectory, 'package.json'), 'utf8'));
295
+ assert.equal(platformPackageJson.name, DARWIN_ARM64_PACKAGE);
296
+ assert.equal(platformPackageJson.version, packageJson.version);
297
+ assert.equal(platformPackageJson.main, DARWIN_ARM64_BINARY);
298
+ assert.deepEqual(
299
+ readdirSync(platformDirectory).filter((entry) => entry.endsWith('.node')),
300
+ [DARWIN_ARM64_BINARY],
301
+ 'Darwin ARM64 package must contain exactly the selected binary',
302
+ );
303
+ return {
304
+ files: [
305
+ 'node_modules/geospec-engine/package.json',
306
+ 'node_modules/geospec-engine/dist/host-types.mjs',
307
+ 'node_modules/geospec-engine/dist/node.mjs',
308
+ 'node_modules/geospec-engine/dist/native/index.js',
309
+ `node_modules/${DARWIN_ARM64_PACKAGE}/package.json`,
310
+ `node_modules/${DARWIN_ARM64_PACKAGE}/${DARWIN_ARM64_BINARY}`,
311
+ ],
312
+ packageJson,
313
+ platformPackage: DARWIN_ARM64_PACKAGE,
314
+ };
315
+ };
316
+
317
+ const createEngineManifest = (productRoot) => {
318
+ const { files, packageJson, platformPackage } = installedEngineFiles(productRoot);
319
+ const retainedArtifacts = files.map((sourceName) => {
320
+ const bytes = readFileSync(join(productRoot, sourceName));
321
+ return {
322
+ byteLength: bytes.byteLength,
323
+ name: `engine/${sourceName.replace('node_modules/', '')}`,
324
+ sha256: sha256(bytes),
325
+ sourceName,
326
+ };
327
+ });
328
+ const nodePath = realpathSync(process.execPath);
329
+ return {
330
+ manifest: {
331
+ package: { name: packageJson.name, version: packageJson.version },
332
+ platformPackage,
333
+ retainedArtifacts: retainedArtifacts.map(({ sourceName: _sourceName, ...entry }) => entry),
334
+ runtimeObservation: {
335
+ byteLength: statSync(nodePath).size,
336
+ node: process.version,
337
+ sha256: sha256(readFileSync(nodePath)),
338
+ },
339
+ schema: 'geospec-engine-artifact-manifest-v2',
340
+ },
341
+ retainedArtifacts,
342
+ };
343
+ };
344
+
345
+ const createRunnerManifest = () => ({
346
+ retainedArtifacts: RUNNER_FILES.map((sourceName) => {
347
+ const bytes = readFileSync(join(TRUST_ROOT, sourceName));
348
+ return {
349
+ byteLength: bytes.byteLength,
350
+ name: `runner/${sourceName}`,
351
+ sha256: sha256(bytes),
352
+ sourceName,
353
+ };
354
+ }),
355
+ schema: 'geospec-evaluator-runner-manifest-v1',
356
+ });
357
+
358
+ const loadPlan = (productRoot, planPath) => {
359
+ const approvedSource = readBoundedFile(planPath, 1024 * 1024);
360
+ const planBytes = canonicalizeBytes(productRoot, approvedSource);
361
+ const plan = JSON.parse(planBytes);
362
+ validatePlan(plan);
363
+ const canonicalControls = canonicalizeJsonBatch(productRoot, [
364
+ ...plan.claims.map(({ claim }) => Buffer.from(JSON.stringify(claim))),
365
+ ...plan.subjects.map(({ ingestRequest }) => Buffer.from(JSON.stringify(ingestRequest))),
366
+ ]);
367
+ for (const [index, approved] of plan.claims.entries()) {
368
+ assert.equal(sha256(canonicalControls[index]), approved.canonicalClaimSha256);
369
+ }
370
+ for (const [index, subject] of plan.subjects.entries()) {
371
+ assert.equal(sha256(canonicalControls[plan.claims.length + index]), subject.ingestRequestSha256);
372
+ }
373
+ return { approvedSource, plan, planBytes };
374
+ };
375
+
376
+ /** Derive the immutable identities that an evaluation authority must pin. @public */
377
+ export const describeTrustedInputs = ({ productRoot: requestedProductRoot, planPath: requestedPlanPath }) => {
378
+ const productRoot = resolve(requestedProductRoot);
379
+ const planPath = resolve(requestedPlanPath);
380
+ assert.ok(existsSync(productRoot), 'installed product is missing');
381
+ const { plan, planBytes } = loadPlan(productRoot, planPath);
382
+ const engine = createEngineManifest(productRoot);
383
+ const runner = createRunnerManifest();
384
+ const engineBytes = canonicalizeValue(productRoot, engine.manifest);
385
+ const runnerManifest = {
386
+ retainedArtifacts: runner.retainedArtifacts.map(({ sourceName: _sourceName, ...entry }) => entry),
387
+ schema: runner.schema,
388
+ };
389
+ const runnerBytes = canonicalizeValue(productRoot, runnerManifest);
390
+ return {
391
+ approvedPlanSha256: sha256(planBytes),
392
+ canonicalProfile: plan.authority.canonicalProfile,
393
+ engineManifestSha256: sha256(engineBytes),
394
+ expectedClaimIds: plan.claims.map((entry) => entry.claim.claimId),
395
+ expectedSubjects: plan.subjects
396
+ .flatMap((subject) => [
397
+ { name: `subjects/${subject.slot}/primary.${subject.format}`, sha256: subject.primary.sha256 },
398
+ ...subject.resources.map((resource) => ({
399
+ name: `subjects/${subject.slot}/resources/${resource.name}`,
400
+ sha256: resource.sha256,
401
+ })),
402
+ ])
403
+ .toSorted((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0)),
404
+ protocolVersion: plan.authority.protocolVersion,
405
+ registryVersion: plan.authority.registryVersion,
406
+ requirementRevision: plan.authority.requirementRevision,
407
+ requireFreshChallenge: plan.requirements.freshChallengeRequired,
408
+ runnerManifestSha256: sha256(runnerBytes),
409
+ };
410
+ };
411
+
412
+ const validatePolicy = (policy, described, jobChallenge) => {
413
+ exactKeys(
414
+ policy,
415
+ [
416
+ 'approvedPlanSha256',
417
+ 'cacheMode',
418
+ 'canonicalProfile',
419
+ 'engineManifestSha256',
420
+ 'evaluatorId',
421
+ 'evaluatorMode',
422
+ 'expectedClaimIds',
423
+ 'expectedJobChallenge',
424
+ 'expectedSubjects',
425
+ 'isolationClass',
426
+ 'maxArtifactBytes',
427
+ 'maxEnvelopeBytes',
428
+ 'numericProfile',
429
+ 'payloadType',
430
+ 'predicateType',
431
+ 'protocolVersion',
432
+ 'publicKeyPem',
433
+ 'registryVersion',
434
+ 'requireFreshChallenge',
435
+ 'requirementRevision',
436
+ 'runnerManifestSha256',
437
+ 'schema',
438
+ 'trustedKeyId',
439
+ ],
440
+ 'verification policy',
441
+ );
442
+ assert.equal(policy.schema, 'geospec-trusted-verifier-policy-v3');
443
+ assert.deepEqual(
444
+ {
445
+ approvedPlanSha256: policy.approvedPlanSha256,
446
+ canonicalProfile: policy.canonicalProfile,
447
+ engineManifestSha256: policy.engineManifestSha256,
448
+ expectedClaimIds: policy.expectedClaimIds,
449
+ expectedSubjects: policy.expectedSubjects,
450
+ protocolVersion: policy.protocolVersion,
451
+ registryVersion: policy.registryVersion,
452
+ requirementRevision: policy.requirementRevision,
453
+ requireFreshChallenge: policy.requireFreshChallenge,
454
+ runnerManifestSha256: policy.runnerManifestSha256,
455
+ },
456
+ described,
457
+ 'pinned policy input binding',
458
+ );
459
+ assert.equal(policy.cacheMode, 'disabled');
460
+ assert.equal(policy.payloadType, PAYLOAD_TYPE);
461
+ assert.equal(policy.predicateType, PREDICATE_TYPE);
462
+ assert.equal(policy.maxArtifactBytes, MAX_ARTIFACT_BYTES);
463
+ assert.equal(policy.maxEnvelopeBytes, MAX_ENVELOPE_BYTES);
464
+ assert.equal(policy.expectedJobChallenge, jobChallenge);
465
+ assert.match(policy.evaluatorId, /^[\w.:-]{1,128}$/);
466
+ assert.equal(policy.evaluatorMode, EVALUATOR_MODE);
467
+ assert.equal(policy.isolationClass, ISOLATION_CLASS);
468
+ };
469
+
470
+ const decodeRecordBytes = (entry) => {
471
+ exactKeys(entry, ['base64', 'sha256'], 'canonical byte record');
472
+ const bytes = Buffer.from(entry.base64, 'base64');
473
+ assert.equal(sha256(bytes), entry.sha256);
474
+ return bytes;
475
+ };
476
+
477
+ const validateCompleteRecord = (record, plan, productRoot) => {
478
+ exactKeys(
479
+ record,
480
+ ['cache', 'canonicalPlan', 'canonicalResult', 'complete', 'initialization', 'rows', 'schema', 'subjects'],
481
+ 'raw evaluation',
482
+ );
483
+ assert.equal(record.schema, 'geospec-trusted-native-evaluation-v2');
484
+ assert.equal(record.complete, true);
485
+ assert.deepEqual(record.cache, { mode: 'disabled', persistent: false });
486
+ assert.equal(record.initialization.canonicalProfile, plan.authority.canonicalProfile);
487
+ assert.equal(record.initialization.protocolVersion, plan.authority.protocolVersion);
488
+ assert.equal(record.initialization.registryVersion, plan.authority.registryVersion);
489
+ exactKeys(
490
+ record.initialization,
491
+ ['base64', 'canonicalProfile', 'numericProfile', 'protocolVersion', 'registryVersion', 'sha256'],
492
+ 'initialization record',
493
+ );
494
+ const initializationResponse = JSON.parse(
495
+ decodeRecordBytes({ base64: record.initialization.base64, sha256: record.initialization.sha256 }),
496
+ );
497
+ assert.equal(initializationResponse.requestId, 'trusted-evaluator-initialize');
498
+ assert.equal(initializationResponse.result.canonicalProfile, record.initialization.canonicalProfile);
499
+ assert.equal(initializationResponse.result.numericProfile, record.initialization.numericProfile);
500
+ assert.equal(initializationResponse.result.protocolVersion, record.initialization.protocolVersion);
501
+ assert.equal(initializationResponse.result.registryVersion, record.initialization.registryVersion);
502
+ const canonicalPlanBytes = decodeRecordBytes(record.canonicalPlan);
503
+ const canonicalResultBytes = decodeRecordBytes(record.canonicalResult);
504
+ const canonicalPlan = JSON.parse(canonicalPlanBytes);
505
+ const canonicalResult = JSON.parse(canonicalResultBytes);
506
+ assert.equal(canonicalPlan.canonicalProfile, plan.authority.canonicalProfile);
507
+ assert.equal(canonicalPlan.protocolVersion, plan.authority.protocolVersion);
508
+ assert.equal(canonicalPlan.registryVersion, plan.authority.registryVersion);
509
+ assert.equal(canonicalPlan.numericProfile, record.initialization.numericProfile);
510
+ assert.equal(canonicalResult.numericProfile, record.initialization.numericProfile);
511
+ assert.deepEqual(
512
+ canonicalPlan.plan.subjects,
513
+ plan.subjects.map((subject) => ({
514
+ slot: subject.slot,
515
+ [subject.identityField]: subject.expectedIdentity,
516
+ })),
517
+ );
518
+ assert.deepEqual(
519
+ canonicalPlan.plan.claims,
520
+ plan.claims.map(({ claim }) => claim),
521
+ );
522
+ assert.equal(record.rows.length, plan.claims.length);
523
+ assert.equal(record.subjects.length, plan.subjects.length);
524
+ assert.deepEqual(
525
+ record.rows.map((row) => row.claimId),
526
+ plan.claims.map((entry) => entry.claim.claimId),
527
+ );
528
+ assert.deepEqual(
529
+ record.rows.map((row) => row.canonicalClaimSha256),
530
+ plan.claims.map((entry) => entry.canonicalClaimSha256),
531
+ );
532
+ assert.ok(record.rows.every((row) => ['passed', 'failed', 'refused'].includes(row.status)));
533
+ assert.equal(canonicalResult.results.length, plan.claims.length);
534
+ const rowBytes = record.rows.map((row) => ({
535
+ claim: Buffer.from(row.canonicalClaim, 'base64'),
536
+ result: Buffer.from(row.canonicalResult, 'base64'),
537
+ }));
538
+ const ingestRequestBytes = record.subjects.map(({ ingestRequest }) => decodeRecordBytes(ingestRequest));
539
+ const canonicalized = canonicalizeJsonBatch(productRoot, [
540
+ canonicalPlanBytes,
541
+ canonicalResultBytes,
542
+ ...rowBytes.flatMap(({ claim, result }) => [claim, result]),
543
+ ...ingestRequestBytes,
544
+ ]);
545
+ assert.deepEqual(canonicalPlanBytes, canonicalized[0]);
546
+ assert.deepEqual(canonicalResultBytes, canonicalized[1]);
547
+ for (const [ordinal, approved] of plan.claims.entries()) {
548
+ const row = record.rows[ordinal];
549
+ const claim = canonicalPlan.plan.claims[ordinal];
550
+ const result = canonicalResult.results[ordinal];
551
+ const { claim: claimBytes, result: resultBytes } = rowBytes[ordinal];
552
+ assert.equal(row.ordinal, ordinal);
553
+ assert.equal(row.claimId, approved.claim.claimId);
554
+ assert.equal(row.claimId, claim.claimId);
555
+ assert.equal(row.claimId, result.claimId);
556
+ assert.equal(row.polarity, approved.claim.polarity);
557
+ assert.equal(row.polarity, claim.polarity);
558
+ assert.equal(row.status, result.status);
559
+ assert.ok(['passed', 'failed', 'refused'].includes(result.status));
560
+ assert.equal(sha256(claimBytes), row.canonicalClaimSha256);
561
+ assert.equal(row.canonicalClaimSha256, approved.canonicalClaimSha256);
562
+ assert.equal(sha256(resultBytes), row.canonicalResultSha256);
563
+ assert.deepEqual(JSON.parse(claimBytes), claim);
564
+ assert.deepEqual(JSON.parse(resultBytes), result);
565
+ assert.deepEqual(claimBytes, canonicalized[2 + ordinal * 2]);
566
+ assert.deepEqual(resultBytes, canonicalized[3 + ordinal * 2]);
567
+ }
568
+ for (const [index, subject] of plan.subjects.entries()) {
569
+ const observed = record.subjects[index];
570
+ exactKeys(observed, ['actualIdentity', 'admission', 'identityField', 'ingestRequest', 'slot'], 'subject record');
571
+ assert.equal(observed.slot, subject.slot);
572
+ assert.equal(observed.actualIdentity, subject.expectedIdentity);
573
+ assert.equal(observed.identityField, subject.identityField);
574
+ const observedIngestRequestBytes = ingestRequestBytes[index];
575
+ assert.equal(observed.ingestRequest.sha256, subject.ingestRequestSha256);
576
+ assert.deepEqual(observedIngestRequestBytes, canonicalized[2 + plan.claims.length * 2 + index]);
577
+ const admission = JSON.parse(decodeRecordBytes(observed.admission));
578
+ assert.equal(admission.requestId, subject.ingestRequest.requestId);
579
+ const admitted = admission.result.subject;
580
+ assert.equal(admitted[subject.identityField], subject.expectedIdentity);
581
+ assert.equal(admitted.format, subject.format);
582
+ assert.equal(admitted.descriptor.format, subject.format);
583
+ assert.equal(admitted.descriptor.primary.byteLength, subject.primary.byteLength);
584
+ assert.equal(admitted.descriptor.primary.sha256, subject.primary.sha256);
585
+ assert.deepEqual(
586
+ admitted.descriptor.resources,
587
+ subject.resources.map(({ byteLength, name, sha256: digest }) => ({ byteLength, name, sha256: digest })),
588
+ );
589
+ }
590
+ return { canonicalPlanBytes, canonicalResultBytes, validationCanonicalizerChildren: 1 };
591
+ };
592
+
593
+ /** Evaluate an approved plan and sign its complete joined native result. @public */
594
+ export const evaluateTrustedPlan = async ({
595
+ jobChallenge,
596
+ outputDirectory: requestedOutput,
597
+ planPath: requestedPlanPath,
598
+ productRoot: requestedProductRoot,
599
+ signer,
600
+ verificationPolicy: policy,
601
+ }) => {
602
+ assert.match(jobChallenge, /^[\w.:-]{1,128}$/, 'job challenge must be bounded ASCII');
603
+ assert.ok(signer && typeof signer.sign === 'function', 'signer.sign is required');
604
+ const productRoot = resolve(requestedProductRoot);
605
+ const planPath = resolve(requestedPlanPath);
606
+ const output = resolve(requestedOutput);
607
+ assert.ok(!existsSync(output), 'output directory must not already exist');
608
+ const described = describeTrustedInputs({ planPath, productRoot });
609
+ validatePolicy(policy, described, jobChallenge);
610
+ const publicKey = createPublicKey(policy.publicKeyPem);
611
+ const publicDer = publicKey.export({ format: 'der', type: 'spki' });
612
+ assert.equal(sha256(publicDer), policy.trustedKeyId, 'trusted key ID');
613
+
614
+ const closure = join(output, 'closure');
615
+ mkdirSync(closure, { recursive: true, mode: 0o700 });
616
+ const { approvedSource, plan, planBytes } = loadPlan(productRoot, planPath);
617
+ assert.equal(sha256(planBytes), policy.approvedPlanSha256, 'second approved plan load');
618
+ writeFileSync(join(closure, 'plan.json'), planBytes);
619
+ const planRoot = dirname(planPath);
620
+ const workerSubjects = [];
621
+ const subjectArtifactNames = [];
622
+ for (const subject of plan.subjects) {
623
+ const primaryName = `subjects/${subject.slot}/primary.${subject.format}`;
624
+ const primaryPath = copyBoundFile({
625
+ destinationPath: join(closure, primaryName),
626
+ expected: subject.primary,
627
+ planRoot,
628
+ requestedSourcePath: subject.primary.path,
629
+ });
630
+ const resourcePaths = subject.resources.map((resource) => {
631
+ const name = `subjects/${subject.slot}/resources/${safeName(resource.name, 'resource name')}`;
632
+ subjectArtifactNames.push(name);
633
+ return {
634
+ name: resource.name,
635
+ path: copyBoundFile({
636
+ destinationPath: join(closure, name),
637
+ expected: resource,
638
+ planRoot,
639
+ requestedSourcePath: resource.path,
640
+ }),
641
+ };
642
+ });
643
+ subjectArtifactNames.push(primaryName);
644
+ workerSubjects.push({ primaryPath, resourcePaths, slot: subject.slot });
645
+ }
646
+
647
+ const engine = createEngineManifest(productRoot);
648
+ for (const entry of engine.retainedArtifacts) {
649
+ const destination = join(closure, entry.name);
650
+ mkdirSync(dirname(destination), { recursive: true });
651
+ copyFileSync(join(productRoot, entry.sourceName), destination);
652
+ }
653
+ const { bytes: engineBytes } = writeCanonical({
654
+ directory: closure,
655
+ name: 'engine.json',
656
+ productRoot,
657
+ value: engine.manifest,
658
+ });
659
+
660
+ const runner = createRunnerManifest();
661
+ for (const entry of runner.retainedArtifacts) {
662
+ const destination = join(closure, entry.name);
663
+ mkdirSync(dirname(destination), { recursive: true });
664
+ copyFileSync(join(TRUST_ROOT, entry.sourceName), destination);
665
+ }
666
+ const runnerManifest = {
667
+ retainedArtifacts: runner.retainedArtifacts.map(({ sourceName: _sourceName, ...entry }) => entry),
668
+ schema: runner.schema,
669
+ };
670
+ const { bytes: runnerBytes } = writeCanonical({
671
+ directory: closure,
672
+ name: 'runner.json',
673
+ productRoot,
674
+ value: runnerManifest,
675
+ });
676
+ assert.equal(sha256(engineBytes), policy.engineManifestSha256, 'pinned engine manifest');
677
+ assert.equal(sha256(runnerBytes), policy.runnerManifestSha256, 'pinned runner manifest');
678
+
679
+ const workerConfigPath = join(output, 'worker-config.json');
680
+ writeFileSync(
681
+ workerConfigPath,
682
+ `${JSON.stringify({ planPath: join(closure, 'plan.json'), productRoot, subjects: workerSubjects }, null, 2)}\n`,
683
+ );
684
+ const worker = spawnSync(process.execPath, [join(TRUST_ROOT, 'evaluate-worker.mjs'), workerConfigPath], {
685
+ cwd: output,
686
+ encoding: null,
687
+ env: controlledEnvironment(output),
688
+ maxBuffer: MAX_ARTIFACT_BYTES,
689
+ timeout: plan.requirements.workerDeadlineMs,
690
+ });
691
+ writeFileSync(join(output, 'worker.stderr'), worker.stderr ?? Buffer.alloc(0));
692
+ assert.ifError(worker.error);
693
+ assert.equal(worker.signal, null, 'evaluator terminated by signal');
694
+ assert.equal(worker.status, 0, Buffer.from(worker.stderr ?? []).toString('utf8'));
695
+ assert.ok(worker.stdout && worker.stdout.byteLength > 0, 'worker produced no record');
696
+ writeFileSync(join(closure, 'raw-evaluation.json'), worker.stdout);
697
+ assert.deepEqual(runCanonicalizer(productRoot, join(closure, 'raw-evaluation.json')), Buffer.from(worker.stdout));
698
+ const record = JSON.parse(worker.stdout);
699
+ const { canonicalPlanBytes, canonicalResultBytes, validationCanonicalizerChildren } = validateCompleteRecord(
700
+ record,
701
+ plan,
702
+ productRoot,
703
+ );
704
+ assert.equal(validationCanonicalizerChildren, 1);
705
+ assert.equal(record.initialization.numericProfile, policy.numericProfile, 'pinned numeric profile');
706
+
707
+ writeFileSync(join(closure, 'canonical-plan.json'), canonicalPlanBytes);
708
+ writeFileSync(join(closure, 'canonical-result.json'), canonicalResultBytes);
709
+
710
+ const runnerNames = runnerManifest.retainedArtifacts.map(({ name }) => name);
711
+ const engineNames = engine.manifest.retainedArtifacts.map(({ name }) => name);
712
+ const closureNames = [
713
+ 'plan.json',
714
+ ...subjectArtifactNames.toSorted(),
715
+ ...engineNames,
716
+ 'engine.json',
717
+ ...runnerNames,
718
+ 'runner.json',
719
+ 'canonical-plan.json',
720
+ 'canonical-result.json',
721
+ 'raw-evaluation.json',
722
+ ];
723
+ const artifacts = closureNames.map((name) => artifact(closure, name));
724
+ const subjectRecords = subjectArtifactNames.toSorted().map((name) => artifact(closure, name));
725
+ const expectedClaimIds = plan.claims.map((entry) => entry.claim.claimId);
726
+ const inventory = record.rows.map((row) => ({
727
+ canonicalClaimSha256: row.canonicalClaimSha256,
728
+ canonicalResultSha256: row.canonicalResultSha256,
729
+ claimId: row.claimId,
730
+ ordinal: row.ordinal,
731
+ polarity: row.polarity,
732
+ status: row.status,
733
+ }));
734
+ const statement = {
735
+ _type: 'https://in-toto.io/Statement/v1',
736
+ predicate: {
737
+ artifacts,
738
+ assurance: {
739
+ geometryTruth: 'trusted-evaluator-assertion',
740
+ heldSecurityEvaluation: 'open-s10',
741
+ scope: 'authenticated-complete-record-not-independent-geometry-proof',
742
+ },
743
+ cache: { mode: 'disabled', persistent: false },
744
+ claims: { count: expectedClaimIds.length, expectedClaimIds, inventory },
745
+ complete: true,
746
+ engine: {
747
+ manifestSha256: sha256(engineBytes),
748
+ packageName: engine.manifest.package.name,
749
+ packageVersion: engine.manifest.package.version,
750
+ },
751
+ evaluator: { id: policy.evaluatorId, isolationClass: ISOLATION_CLASS, mode: EVALUATOR_MODE },
752
+ profiles: {
753
+ canonical: plan.authority.canonicalProfile,
754
+ numeric: record.initialization.numericProfile,
755
+ protocolVersion: record.initialization.protocolVersion,
756
+ registryVersion: record.initialization.registryVersion,
757
+ },
758
+ requirements: {
759
+ approvedPlanSha256: sha256(planBytes),
760
+ approvedPlanSourceSha256: sha256(approvedSource),
761
+ requirementRevision: plan.authority.requirementRevision,
762
+ },
763
+ run: { freshChallengeRequired: plan.requirements.freshChallengeRequired, jobChallenge },
764
+ runner: { manifestSha256: sha256(runnerBytes) },
765
+ schema: 'geospec-trusted-evaluation-predicate-v3',
766
+ subjects: plan.subjects.map((subject) => ({
767
+ expectedIdentity: subject.expectedIdentity,
768
+ format: subject.format,
769
+ frame: subject.frame,
770
+ identityField: subject.identityField,
771
+ primarySha256: subject.primary.sha256,
772
+ resourceSha256: subject.resources.map((resource) => resource.sha256),
773
+ slot: subject.slot,
774
+ })),
775
+ },
776
+ predicateType: PREDICATE_TYPE,
777
+ subject: subjectRecords.map(({ name, sha256: digest }) => ({ digest: { sha256: digest }, name })),
778
+ };
779
+ const statementRecord = writeCanonical({
780
+ directory: output,
781
+ name: 'statement.json',
782
+ productRoot,
783
+ value: statement,
784
+ });
785
+ const signedBytes = pae(PAYLOAD_TYPE, statementRecord.bytes);
786
+ const signature = Buffer.from(await signer.sign(signedBytes));
787
+ assert.ok(verify(null, signedBytes, publicKey, signature), 'signer does not match pinned public key');
788
+ const envelope = {
789
+ payload: statementRecord.bytes.toString('base64'),
790
+ payloadType: PAYLOAD_TYPE,
791
+ signatures: [{ keyid: policy.trustedKeyId, sig: signature.toString('base64') }],
792
+ };
793
+ const envelopeRecord = writeCanonical({
794
+ directory: output,
795
+ name: 'envelope.json',
796
+ productRoot,
797
+ value: envelope,
798
+ });
799
+ assert.ok(envelopeRecord.bytes.byteLength <= MAX_ENVELOPE_BYTES);
800
+ writeFileSync(join(output, 'policy.json'), canonicalizeValue(productRoot, policy));
801
+ const summary = {
802
+ artifacts: artifacts.length,
803
+ cacheMode: 'disabled',
804
+ claims: inventory,
805
+ envelopeSha256: sha256(envelopeRecord.bytes),
806
+ scope: 'authenticated-complete-record-not-independent-geometry-proof',
807
+ statementSha256: sha256(statementRecord.bytes),
808
+ };
809
+ writeFileSync(join(output, 'summary.json'), `${JSON.stringify(summary, null, 2)}\n`);
810
+ return { output, ...summary };
811
+ };
812
+
813
+ const runCli = async () => {
814
+ const requestPath = process.argv[2];
815
+ assert.ok(requestPath, 'Usage: node run.mjs <evaluation-request.json>');
816
+ const absoluteRequestPath = resolve(requestPath);
817
+ const requestRoot = dirname(absoluteRequestPath);
818
+ const request = JSON.parse(readFileSync(absoluteRequestPath, 'utf8'));
819
+ exactKeys(
820
+ request,
821
+ [
822
+ 'jobChallenge',
823
+ 'outputDirectory',
824
+ 'planPath',
825
+ 'privateKeyPath',
826
+ 'productRoot',
827
+ 'schema',
828
+ 'verificationPolicyPath',
829
+ ],
830
+ 'evaluation request',
831
+ );
832
+ assert.equal(request.schema, 'geospec-trusted-evaluation-request-v1');
833
+ const resolveRequestPath = (value) => resolve(requestRoot, value);
834
+ const verificationPolicy = JSON.parse(readFileSync(resolveRequestPath(request.verificationPolicyPath), 'utf8'));
835
+ const result = await evaluateTrustedPlan({
836
+ jobChallenge: request.jobChallenge,
837
+ outputDirectory: resolveRequestPath(request.outputDirectory),
838
+ planPath: resolveRequestPath(request.planPath),
839
+ productRoot: resolveRequestPath(request.productRoot),
840
+ signer: {
841
+ sign: (bytes) => cryptoSign(null, bytes, readFileSync(resolveRequestPath(request.privateKeyPath))),
842
+ },
843
+ verificationPolicy,
844
+ });
845
+ process.stdout.write(`${JSON.stringify(result)}\n`);
846
+ };
847
+
848
+ if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) {
849
+ await runCli();
850
+ }