failproofai 1.0.7 → 1.0.8

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 (268) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +4 -4
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +8 -7
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  33. package/.next/standalone/.next/server/app/audit/page.js +9 -7
  34. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/index.html +1 -1
  37. package/.next/standalone/.next/server/app/index.rsc +15 -15
  38. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  40. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js +6 -6
  43. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +11 -10
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page.js +8 -7
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -6
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +7 -6
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +52 -8
  63. package/.next/standalone/.next/server/app/settings/page.js +12 -7
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/{[externals]__1msfs-h._.js → [externals]__19_pzeq._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__1_bftcl._.js → [externals]__20kzpkf._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +22 -0
  70. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
  71. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
  74. package/.next/standalone/.next/server/chunks/{_1c3k-8x._.js → _1q5i8mb._.js} +2 -2
  75. package/.next/standalone/.next/server/chunks/lib_16xa545._.js +3 -0
  76. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/src_hooks_1aveq0u._.js +5 -0
  78. package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +4 -2
  80. package/.next/standalone/.next/server/chunks/ssr/[externals]__0ohnuzs._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +4 -0
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02npjtd._.js → [root-of-the-server]__056wjo4._.js} +3 -3
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06pflha._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +22 -0
  87. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0p-5p8u._.js → [root-of-the-server]__0n0xg95._.js} +3 -3
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__013jr2b._.js → [root-of-the-server]__0rwtwpm._.js} +3 -3
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0da85px._.js → [root-of-the-server]__11mayhe._.js} +3 -3
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12e7nhs._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13t1zkw._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19evfi8._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +4 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0cxe_2_._.js → [root-of-the-server]__1mf3zp6._.js} +3 -3
  100. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ftmoxc._.js → [root-of-the-server]__1pprgri._.js} +3 -3
  101. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__1q4p5b8._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/ssr/{_166t73i._.js → _0-vcssj._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/ssr/_13kfn90._.js +23 -0
  109. package/.next/standalone/.next/server/chunks/ssr/{_1es2j7i._.js → _1gb0ifp._.js} +5 -5
  110. package/.next/standalone/.next/server/chunks/ssr/{_1_qswah._.js → _1q46vxx._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +13 -13
  113. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  117. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0drixxt._.js → node_modules_next_dist_0w6mzq5._.js} +4 -4
  119. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_18_d8l1._.js +151 -0
  120. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0-q0umm._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9d._.js +12 -0
  122. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0g194sy._.js +3 -0
  123. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +4 -2
  124. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1kx9e0d._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +5 -0
  126. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  127. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +3 -0
  130. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  131. package/.next/standalone/.next/server/pages/404.html +1 -1
  132. package/.next/standalone/.next/server/pages/500.html +1 -1
  133. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  134. package/.next/standalone/.next/server/server-reference-manifest.json +67 -23
  135. package/.next/standalone/.next/static/chunks/06dnzbolj00mc.js +6 -0
  136. package/.next/standalone/.next/static/chunks/0bhidk90e-07f.css +2 -0
  137. package/.next/standalone/.next/static/chunks/{2mdh397ghgnvv.js → 0m-9d6yn9hx4j.js} +1 -1
  138. package/.next/standalone/.next/static/chunks/{0__8a7m868fvf.js → 0wbjy0zo-m7is.js} +1 -1
  139. package/.next/standalone/.next/static/chunks/16f3fa-lx38hk.js +1 -0
  140. package/.next/standalone/.next/static/chunks/{0o6qlkgubtoex.js → 21uv-uusw329x.js} +1 -1
  141. package/.next/standalone/.next/static/chunks/2g2tki08kdhie.js +1 -0
  142. package/.next/standalone/.next/static/chunks/2qdpj67x6ifk_.js +69 -0
  143. package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +1 -0
  144. package/.next/standalone/.next/static/chunks/3-nbtkhg9y-1j.js +1 -0
  145. package/.next/standalone/.next/static/chunks/355km0ihuqo1p.js +1 -0
  146. package/.next/standalone/.next/static/chunks/{13i7-9is-vhys.js → 3c3qbmosdjl6w.js} +1 -1
  147. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  148. package/.next/standalone/app/actions/get-jev-config.ts +604 -0
  149. package/.next/standalone/app/actions/pack-actions.ts +12 -0
  150. package/.next/standalone/app/actions/update-jev-config.ts +569 -0
  151. package/.next/standalone/app/components/jev-notices.tsx +96 -0
  152. package/.next/standalone/app/policies/hooks-client.tsx +14 -3
  153. package/.next/standalone/app/settings/jev-panel.tsx +630 -0
  154. package/.next/standalone/app/settings/page.tsx +20 -1
  155. package/.next/standalone/app/settings/settings-client.tsx +27 -1
  156. package/.next/standalone/app/settings/settings.css +79 -0
  157. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +22 -4
  158. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +14 -1
  159. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +17 -3
  160. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +3 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +22 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +169 -0
  163. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +1 -1
  164. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +65 -0
  165. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +61 -0
  166. package/.next/standalone/package.json +10 -10
  167. package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
  168. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  169. package/.next/standalone/sdk/typescript/CHANGELOG.md +18 -1
  170. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +0 -274
  171. package/.next/standalone/sdk/typescript/scripts/release.mjs +30 -0
  172. package/.next/standalone/server.js +1 -1
  173. package/README.md +3 -2
  174. package/bin/failproofai.mjs +148 -4
  175. package/dist/cli.mjs +18599 -9478
  176. package/dist/index.js +19 -1
  177. package/dist/worker.mjs +10500 -3773
  178. package/package.json +10 -10
  179. package/pi-extension/index.ts +11 -0
  180. package/scripts/build-policy-pack.mjs +53 -2
  181. package/src/audit/features.ts +3 -2
  182. package/src/hooks/builtin-policies.ts +195 -8
  183. package/src/hooks/cloud-connection.ts +190 -1
  184. package/src/hooks/cloud-enrollment-cli.ts +57 -8
  185. package/src/hooks/cloud-introspect.ts +6 -0
  186. package/src/hooks/cloud-managed-policies.ts +22 -0
  187. package/src/hooks/configure-wizard.ts +26 -6
  188. package/src/hooks/custom-hooks-loader.ts +98 -10
  189. package/src/hooks/custom-hooks-registry.ts +45 -1
  190. package/src/hooks/effective-reviewers.ts +243 -0
  191. package/src/hooks/first-run-gate.ts +5 -0
  192. package/src/hooks/flush-cli.ts +35 -8
  193. package/src/hooks/fp-config.ts +266 -1
  194. package/src/hooks/fp-home.ts +23 -0
  195. package/src/hooks/fp-reset.ts +22 -4
  196. package/src/hooks/handler.ts +303 -7
  197. package/src/hooks/hook-activity-store.ts +118 -6
  198. package/src/hooks/hook-telemetry.ts +41 -0
  199. package/src/hooks/jev-activity.ts +385 -0
  200. package/src/hooks/jev-cli.ts +2172 -0
  201. package/src/hooks/jev-cloud-connection.ts +392 -0
  202. package/src/hooks/loader-utils.ts +6 -0
  203. package/src/hooks/manager.ts +45 -7
  204. package/src/hooks/pack-cli.ts +568 -37
  205. package/src/hooks/pack-failclosed.ts +3 -0
  206. package/src/hooks/pack-manifest.ts +489 -7
  207. package/src/hooks/pack-store.ts +194 -11
  208. package/src/hooks/policy-authority.ts +386 -0
  209. package/src/hooks/policy-catalog.ts +206 -0
  210. package/src/hooks/policy-evaluator.ts +963 -796
  211. package/src/hooks/policy-registry.ts +27 -1
  212. package/src/hooks/policy-reviewability.ts +258 -0
  213. package/src/hooks/policy-types.ts +128 -0
  214. package/src/hooks/semantic/combine.ts +581 -0
  215. package/src/hooks/semantic/compile.ts +176 -0
  216. package/src/hooks/semantic/decide.ts +513 -0
  217. package/src/hooks/semantic/envelope.ts +1255 -0
  218. package/src/hooks/semantic/evaluator.ts +556 -0
  219. package/src/hooks/semantic/facts.ts +387 -0
  220. package/src/hooks/semantic/intent.ts +1190 -0
  221. package/src/hooks/semantic/jev-client.ts +1155 -0
  222. package/src/hooks/semantic/jev-config.ts +1142 -0
  223. package/src/hooks/semantic/jev-review.ts +389 -0
  224. package/src/hooks/semantic/jev-stats.ts +289 -0
  225. package/src/hooks/semantic/jev-throttle.ts +427 -0
  226. package/src/hooks/semantic/pack-policies.ts +294 -0
  227. package/src/hooks/semantic/policies.ts +597 -0
  228. package/src/hooks/semantic/precondition-names.ts +60 -0
  229. package/src/hooks/semantic/preconditions.ts +58 -0
  230. package/src/hooks/semantic/redact.ts +2937 -0
  231. package/src/hooks/semantic/session-root.ts +116 -0
  232. package/src/hooks/semantic/types.ts +162 -0
  233. package/src/hooks/semver-precedence.ts +128 -0
  234. package/src/hooks/tui.ts +4 -0
  235. package/src/hooks/types.ts +1 -1
  236. package/src/hooks/worker-server.ts +121 -27
  237. package/src/index.ts +6 -0
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +0 -3
  239. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_r2rbg._.js +0 -24
  240. package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +0 -3
  241. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +0 -4
  242. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +0 -4
  243. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bd3mje._.js +0 -3
  244. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +0 -5
  245. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +0 -3
  246. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +0 -22
  247. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +0 -3
  248. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +0 -5
  249. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +0 -3
  250. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +0 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +0 -3
  252. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +0 -5
  253. package/.next/standalone/.next/server/chunks/ssr/_0h_douw._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/ssr/_1-i_gzc._.js +0 -23
  255. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +0 -3
  258. package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +0 -1
  259. package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +0 -6
  260. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +0 -1
  261. package/.next/standalone/.next/static/chunks/2klitrtzpaoe0.js +0 -1
  262. package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +0 -2
  263. package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +0 -1
  264. package/.next/standalone/.next/static/chunks/3rh5o7e16irrm.js +0 -69
  265. package/.next/standalone/.next/static/chunks/43ufqrz8qo3h-.js +0 -1
  266. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_buildManifest.js +0 -0
  267. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_clientMiddlewareManifest.js +0 -0
  268. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_ssgManifest.js +0 -0
@@ -22,7 +22,19 @@
22
22
  * someone opens when something is wrong. That guidance now lives in
23
23
  * `failproofai config --status` and the docs, which is a worse place for it.
24
24
  */
25
- import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
25
+ import {
26
+ chmodSync,
27
+ closeSync,
28
+ constants as fsConstants,
29
+ existsSync,
30
+ fstatSync,
31
+ mkdirSync,
32
+ openSync,
33
+ readFileSync,
34
+ readSync,
35
+ statSync,
36
+ writeFileSync,
37
+ } from "node:fs";
26
38
  import { dirname } from "node:path";
27
39
  import { version as cliVersion } from "../../package.json";
28
40
  import {
@@ -753,6 +765,26 @@ export interface FpCredentials {
753
765
  org?: { id?: string; slug?: string; name?: string };
754
766
  ingest?: { url: string; key: string };
755
767
  auth?: { baseUrl?: string; sessionToken?: string; expiresAt?: number; email?: string };
768
+ /**
769
+ * The key Jev's FailproofAI Cloud route sends, and the Cloud ORIGIN it was
770
+ * verified against. Written by connect only when introspect reports
771
+ * `jev:evaluate`; cleared by disconnect. See {@link readJevCloudCredential}.
772
+ *
773
+ * A slot of its own, not a reuse of `[cloud]` or `[ingest]`, although it holds
774
+ * the same key today: those two are written under their own permission checks
775
+ * and can hold DIFFERENT keys (see `cloud-connection.ts`), and "which of the
776
+ * two backs Jev" is a question nobody reading the file should have to answer.
777
+ * One slot per capability keeps revoking one from ever silently re-routing
778
+ * another.
779
+ */
780
+ jev?: JevCloudCredential;
781
+ }
782
+
783
+ /** The `jev` slot of `credentials.json`. */
784
+ export interface JevCloudCredential {
785
+ /** The Cloud origin the key was verified against, e.g. `https://app.befailproof.ai`. */
786
+ url: string;
787
+ key: string;
756
788
  }
757
789
 
758
790
  /**
@@ -775,6 +807,8 @@ const OWNED_CREDENTIAL_KEYS: readonly (readonly string[])[] = [
775
807
  ["org", "name"],
776
808
  ["ingest", "url"],
777
809
  ["ingest", "key"],
810
+ ["jev", "url"],
811
+ ["jev", "key"],
778
812
  ["auth", "base_url"],
779
813
  ["auth", "session_token"],
780
814
  ["auth", "expires_at"],
@@ -843,6 +877,8 @@ export function projectCredentials(parsed: Record<string, unknown>): FpCredentia
843
877
  if (ingest && typeof ingest.url === "string" && typeof ingest.key === "string" && ingest.url && ingest.key) {
844
878
  out.ingest = { url: ingest.url, key: ingest.key };
845
879
  }
880
+ const jev = projectJevSlot(parsed.jev);
881
+ if (jev) out.jev = jev;
846
882
  if (auth) {
847
883
  out.auth = {
848
884
  baseUrl: typeof auth.base_url === "string" ? auth.base_url : undefined,
@@ -876,6 +912,9 @@ export function writeCredentials(creds: FpCredentials, raw?: Record<string, unkn
876
912
  if (creds.ingest) {
877
913
  out.ingest = { url: creds.ingest.url, key: creds.ingest.key };
878
914
  }
915
+ if (creds.jev) {
916
+ out.jev = { url: creds.jev.url, key: creds.jev.key };
917
+ }
879
918
  if (creds.org && (creds.org.id || creds.org.slug || creds.org.name)) {
880
919
  out.org = {
881
920
  ...(creds.org.id ? { id: creds.org.id } : {}),
@@ -920,6 +959,232 @@ export function hasCloudCredentials(): boolean {
920
959
  return Boolean(c.cloud || c.ingest);
921
960
  }
922
961
 
962
+ // ── The Jev slot ─────────────────────────────────────────────────────────────
963
+ //
964
+ // The one credential in this file that a HOOK reads. Everything else here is
965
+ // read by the daemon or a CLI command; this is read by `inspectJevConfig` on
966
+ // every gated tool call of a machine whose `jev.json` names the FailproofAI
967
+ // Cloud provider — and the key it yields is what lets Jev's answers clear a
968
+ // deny. So it is read the way `jev.json` itself is (`semantic/jev-config.ts`),
969
+ // not the way `readCredentials` reads: a file or directory other users could
970
+ // have written is REFUSED rather than read, because a routing credential for a
971
+ // tier that can clear denies must not be one somebody else chose.
972
+ //
973
+ // And only from `credentialsFile()`, never from `FAILPROOFAI_CLOUD_CREDENTIALS`.
974
+ // That override relocates the policy credential for the daemon and CI; honoured
975
+ // here it would be an environment variable choosing the key Jev spends, which a
976
+ // repository's `.claude/settings.json` can set for a session. `FAILPROOFAI_HOME`
977
+ // is not an exception to that rule for the reason `jev-config.ts` gives: it
978
+ // moves the whole layout, `jev.json` included.
979
+ //
980
+ // # A slot counts only while the connection it came with is still there
981
+ //
982
+ // The slot is written by `config --token` and cleared by `config --disconnect`
983
+ // — by THIS build. An older one (1.0.7-beta.2 and before) knows nothing about
984
+ // it: its disconnect clears `[cloud]` and `[ingest]` and carries the `jev`
985
+ // table over as a key it does not own. So downgrade, disconnect, upgrade, and
986
+ // a machine its owner disconnected would find a Cloud key and a Cloud
987
+ // `jev.json` both still in place, and Jev would start spending on an org the
988
+ // machine had left. So the slot is read as usable only when a FailproofAI Cloud
989
+ // connection on the SAME origin — a policy (`[cloud]`) or reporting
990
+ // (`[ingest]`) credential — is in the same file. A key carrying `jev:evaluate`
991
+ // always carries `events:add` and `policies:pull` too (the server refuses it
992
+ // otherwise), so a live Jev connection always has one of them.
993
+ //
994
+ // And that connection must hold the SAME KEY. The origin alone does not say
995
+ // whose connection it is: on hosted FailproofAI Cloud every organisation shares
996
+ // one origin. An older build's `config --token` with another org's key
997
+ // rewrites `[cloud]` and `[ingest]` to that key and carries the `jev` table
998
+ // over untouched, so the origin still matches while the machine now reports
999
+ // into the other org — and Jev would go on spending the first org's budget.
1000
+ // This build's connect writes one key to all three (a partial connect may
1001
+ // leave one of `[cloud]`/`[ingest]` holding an earlier key, never both), so a
1002
+ // live slot always has a same-origin credential holding its key.
1003
+ //
1004
+ // Only from this file, for the reason above: under `FAILPROOFAI_CLOUD_CREDENTIALS`
1005
+ // the policy credential lives elsewhere, and an environment variable must not
1006
+ // be able to re-arm a slot either. The reporting credential is always here,
1007
+ // and connecting a Jev key writes it.
1008
+
1009
+ /** Same bound `jev.json` gets; no legitimate `credentials.json` is near it. */
1010
+ const MAX_CREDENTIALS_BYTES = 64 * 1024;
1011
+ /**
1012
+ * Non-blocking, so a FIFO in the file's place cannot hang a hook in `open()`.
1013
+ * A function, not a module-level constant: this module is imported everywhere,
1014
+ * and reading `fs.constants` at import time would make every importer depend on
1015
+ * it — including test doubles of `node:fs` that never needed it before.
1016
+ */
1017
+ const credentialsOpenFlags = (): number => fsConstants.O_RDONLY | (fsConstants.O_NONBLOCK ?? 0);
1018
+ /** Group- or world-WRITE bits on the directory: whoever has them can replace the file. */
1019
+ const DIR_WRITABLE_BY_OTHERS = 0o022;
1020
+
1021
+ export type JevCloudCredentialRead =
1022
+ | { status: "ok"; path: string; credential: JevCloudCredential }
1023
+ /**
1024
+ * No usable Jev credential: no file, no `jev` slot, or a slot no live
1025
+ * connection backs (see "A slot counts only while…" above).
1026
+ */
1027
+ | {
1028
+ status: "absent";
1029
+ path: string;
1030
+ /**
1031
+ * This machine IS connected to FailproofAI Cloud — a policy or reporting
1032
+ * credential is stored — just not with a Jev key. Tells "connected, but
1033
+ * the key does not carry Jev" apart from "not connected at all".
1034
+ */
1035
+ connected: boolean;
1036
+ /** A `jev` slot is there, but no connection on its origin holding its key is: it is ignored. */
1037
+ orphaned?: true;
1038
+ }
1039
+ | {
1040
+ status: "refused";
1041
+ path: string;
1042
+ /** The file's permission bits, when they are the reason. */
1043
+ mode: number | null;
1044
+ reason: "too-open" | "unreadable" | "too-large" | "not-json";
1045
+ problem: string;
1046
+ /** The command that fixes it, when one does. */
1047
+ fix?: string;
1048
+ };
1049
+
1050
+ /** A `jev` table with two non-empty strings, or null. Shape only; `jev-config.ts` validates the values. */
1051
+ function projectJevSlot(raw: unknown): JevCloudCredential | null {
1052
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
1053
+ const { url, key } = raw as Record<string, unknown>;
1054
+ return typeof url === "string" && url && typeof key === "string" && key ? { url, key } : null;
1055
+ }
1056
+
1057
+ /**
1058
+ * The `jev` slot, read owner-only.
1059
+ *
1060
+ * The file is opened once and every check runs against that descriptor, so the
1061
+ * permissions checked are the permissions of the bytes read — the same shape
1062
+ * as `inspectJevConfig`, for the same reason. Never throws.
1063
+ */
1064
+ export function readJevCloudCredential(): JevCloudCredentialRead {
1065
+ const path = credentialsFile();
1066
+ let fd: number;
1067
+ try {
1068
+ fd = openSync(path, credentialsOpenFlags());
1069
+ } catch (err) {
1070
+ const code = (err as NodeJS.ErrnoException).code;
1071
+ if (code === "ENOENT" || code === "ENOTDIR") return { status: "absent", path, connected: false };
1072
+ return { status: "refused", path, mode: null, reason: "unreadable", problem: `cannot open ${path} (${code ?? "error"})` };
1073
+ }
1074
+ let text: string;
1075
+ try {
1076
+ const st = fstatSync(fd);
1077
+ if (!st.isFile()) return { status: "refused", path, mode: null, reason: "unreadable", problem: `${path} is not a regular file` };
1078
+ // On Windows `mode` is synthesized and would refuse every file while
1079
+ // protecting nothing; Jev setup is refused there anyway.
1080
+ const meaningful = process.platform !== "win32";
1081
+ const mode = st.mode & 0o777;
1082
+ if (meaningful && (mode & 0o077) !== 0) {
1083
+ return {
1084
+ status: "refused",
1085
+ path,
1086
+ mode,
1087
+ reason: "too-open",
1088
+ problem:
1089
+ `${path} is ${mode.toString(8).padStart(4, "0")}; it holds the key Jev sends to FailproofAI Cloud, ` +
1090
+ `so it must be owner-only (chmod 600 ${path})`,
1091
+ fix: `chmod 600 ${path}`,
1092
+ };
1093
+ }
1094
+ if (meaningful) {
1095
+ let dirMode: number | null = null;
1096
+ try {
1097
+ const m = statSync(dirname(path)).mode & 0o777;
1098
+ if ((m & DIR_WRITABLE_BY_OTHERS) !== 0) dirMode = m;
1099
+ } catch {
1100
+ // No permission to stat it: the read below reports what it can.
1101
+ }
1102
+ if (dirMode !== null) {
1103
+ return {
1104
+ status: "refused",
1105
+ path,
1106
+ mode,
1107
+ reason: "too-open",
1108
+ problem:
1109
+ `its directory ${dirname(path)} is ${dirMode.toString(8).padStart(4, "0")} — other users can write there, ` +
1110
+ `so they can put their own credentials in its place; it must be owner-only (chmod 700 ${dirname(path)})`,
1111
+ fix: `chmod 700 ${dirname(path)}`,
1112
+ };
1113
+ }
1114
+ }
1115
+ if (st.size > MAX_CREDENTIALS_BYTES) {
1116
+ return { status: "refused", path, mode, reason: "too-large", problem: `${path} is larger than ${MAX_CREDENTIALS_BYTES} bytes` };
1117
+ }
1118
+ const buf = Buffer.alloc(st.size);
1119
+ let off = 0;
1120
+ while (off < buf.length) {
1121
+ const n = readSync(fd, buf, off, buf.length - off, off);
1122
+ if (n === 0) break;
1123
+ off += n;
1124
+ }
1125
+ text = buf.subarray(0, off).toString("utf8");
1126
+ } catch (err) {
1127
+ return { status: "refused", path, mode: null, reason: "unreadable", problem: `cannot read ${path} (${(err as NodeJS.ErrnoException).code ?? "error"})` };
1128
+ } finally {
1129
+ try {
1130
+ closeSync(fd);
1131
+ } catch {
1132
+ // Nothing useful to do.
1133
+ }
1134
+ }
1135
+ let parsed: unknown;
1136
+ try {
1137
+ parsed = JSON.parse(text);
1138
+ } catch {
1139
+ return { status: "refused", path, mode: null, reason: "not-json", problem: `${path} is not valid JSON` };
1140
+ }
1141
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1142
+ return { status: "refused", path, mode: null, reason: "not-json", problem: `${path} does not hold a JSON object` };
1143
+ }
1144
+ const fields = parsed as Record<string, unknown>;
1145
+ // The same projection `readCredentials` uses, so "a cloud block without a
1146
+ // token is not a cloud block" means the same thing here as everywhere else.
1147
+ const others = projectCredentials(fields);
1148
+ const connections = [
1149
+ others.cloud ? { origin: originOrNull(others.cloud.url), key: others.cloud.token } : null,
1150
+ others.ingest ? { origin: originOrNull(others.ingest.url), key: others.ingest.key } : null,
1151
+ ].filter((c): c is { origin: string; key: string } => c !== null && c.origin !== null);
1152
+ const connected = connections.length > 0;
1153
+ const credential = projectJevSlot(fields.jev);
1154
+ if (!credential) return { status: "absent", path, connected };
1155
+ const slotOrigin = originOrNull(credential.url);
1156
+ // The same origin AND the same key: see "A slot counts only while…" above.
1157
+ const backed = slotOrigin !== null && connections.some((c) => c.origin === slotOrigin && c.key === credential.key);
1158
+ if (!backed) return { status: "absent", path, connected, orphaned: true };
1159
+ return { status: "ok", path, credential };
1160
+ }
1161
+
1162
+ /** A URL's origin, or null for a missing or unparseable one. */
1163
+ function originOrNull(url: string | undefined): string | null {
1164
+ if (!url) return null;
1165
+ try {
1166
+ const origin = new URL(url).origin;
1167
+ return origin === "null" ? null : origin;
1168
+ } catch {
1169
+ return null;
1170
+ }
1171
+ }
1172
+
1173
+ /** Store the `jev` slot (0600, owner-only home), keeping every other credential. */
1174
+ export function writeJevCloudCredential(credential: JevCloudCredential): string {
1175
+ writeCredentials({ ...readCredentials(), jev: { url: credential.url, key: credential.key } });
1176
+ return credentialsFile();
1177
+ }
1178
+
1179
+ /** Remove the `jev` slot. True if there was one. Every other credential stays. */
1180
+ export function clearJevCloudCredential(): boolean {
1181
+ const current = readCredentials();
1182
+ if (!current.jev) return false;
1183
+ const { jev: _dropped, ...rest } = current;
1184
+ writeCredentials(rest);
1185
+ return true;
1186
+ }
1187
+
923
1188
  function writeFileAt(path: string, contents: string): void {
924
1189
  mkdirSync(dirname(path), { recursive: true });
925
1190
  writeFileSync(path, contents, "utf8");
@@ -51,6 +51,7 @@
51
51
  * VERSION layout / cli / daemon versions
52
52
  * config.json 0644 non-secret: mode, daemon, collector prefs
53
53
  * credentials.json 0600 every token
54
+ * jev.json 0600 the customer's own Jev endpoint + key (BYOK opt-in)
54
55
  * policies-config.json the builtin enable/disable set + params
55
56
  * bin/ downloaded daemon binaries, one per version
56
57
  * policies/ every policy: the user's *.mjs sit directly here
@@ -148,6 +149,14 @@ export const configFile = (home?: string) => atHome(home, "config.json");
148
149
  */
149
150
  export const credentialsFile = (home?: string) => atHome(home, "credentials.json");
150
151
 
152
+ /**
153
+ * The customer's own Jev endpoint and key (BYOK), owner-only. Its presence is
154
+ * the whole opt-in to the two-tier evaluator: absent, hooks run the regex
155
+ * engine exactly as before. GLOBAL only — a repository can never set it. See
156
+ * `src/hooks/semantic/jev-config.ts`.
157
+ */
158
+ export const jevConfigFile = (home?: string) => atHome(home, "jev.json");
159
+
151
160
  // ── Daemon binaries ──────────────────────────────────────────────────────────
152
161
 
153
162
  export const binDir = (home?: string) => atHome(home, "bin");
@@ -389,6 +398,12 @@ export const failedDir = (home?: string) => resolve(stateDir(home), "failed");
389
398
  export const collectorHealthFile = (home?: string) => resolve(stateDir(home), "collector-health.json");
390
399
  /** Per-session enforcement pauses, keyed by a hash of the session id. */
391
400
  export const sessionPauseDir = () => resolve(stateDir(), "sessions");
401
+ /**
402
+ * The semantic (Jev) evaluator's local state: `sessions/<id>.json` holds the
403
+ * human prompts recorded at `UserPromptSubmit`, and `verdicts.jsonl` one row
404
+ * per semantic evaluation. Written only when a Jev config (BYOK) is present.
405
+ */
406
+ export const semanticDir = () => resolve(stateDir(), "semantic");
392
407
  /**
393
408
  * When the scheduled audit last ran, and when the next one is due.
394
409
  *
@@ -554,6 +569,9 @@ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: Da
554
569
  // policy silently — it keeps enforcing whatever it last had, reports healthy,
555
570
  // and never reconciles again. Nothing re-derives a token.
556
571
  { path: credentialsFile, class: "user-typed" },
572
+ // The Jev BYOK config. A person typed the key; nothing regenerates it, and
573
+ // losing it silently turns the two-tier evaluator off.
574
+ { path: jevConfigFile, class: "user-typed" },
557
575
  // Holds `daemon.configured` (the flag that makes the machine fail closed),
558
576
  // the collector preferences, `[audit] auto`, the telemetry opt-out, and
559
577
  // `collector.sources.*.extra_paths` — the entire output of `harness add-path`.
@@ -642,6 +660,11 @@ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: Da
642
660
  { path: codexSessionPathsFile, class: "derived" },
643
661
  { path: shimsDir, class: "derived" },
644
662
  { path: sessionPauseDir, class: "derived" },
663
+ // Recorded prompts (a six-hour window that only ever lets Jev clear a
664
+ // reviewable policy) and a local diagnostic log of semantic verdicts that is
665
+ // never shipped. Losing either costs a clear and some history, never
666
+ // enforcement.
667
+ { path: semanticDir, class: "derived" },
645
668
  { path: logsDir, class: "derived" },
646
669
  { path: lastVersionFile, class: "derived" },
647
670
  { path: launcherMarker, class: "derived" },
@@ -97,6 +97,7 @@ import {
97
97
  daemonVersionSkew,
98
98
  isDaemonSupportedPlatform,
99
99
  probeDaemonEndToEnd,
100
+ type DaemonServiceStatus,
100
101
  } from "./daemon-service";
101
102
 
102
103
  export interface ResetOutcome {
@@ -1094,7 +1095,24 @@ async function drainSpoolAfterMigrating(): Promise<number> {
1094
1095
  }
1095
1096
  }
1096
1097
 
1097
- export async function checkLayoutForCli(): Promise<LayoutCheck> {
1098
+ /**
1099
+ * Injectable for tests, matching `refreshDaemonToCliVersion`'s shape in
1100
+ * `daemon-service.ts`.
1101
+ *
1102
+ * `healDaemonFlag` asks systemd whether the unit is installed, and on a machine
1103
+ * with no unit that call blocks for seconds before answering. Two tests here
1104
+ * set `daemon.configured` and so reach it, and they were timing out at vitest's
1105
+ * 5 s default against the real service manager — a check about what this command
1106
+ * PRINTS, failing on how long the host takes to say "not-installed". A
1107
+ * `vi.spyOn` cannot intercept it either: this module calls its own local
1108
+ * binding, so without a seam a stub is ignored and the test passes or fails for
1109
+ * the wrong reason.
1110
+ */
1111
+ export interface LayoutCheckDeps {
1112
+ daemonStatus?: () => DaemonServiceStatus;
1113
+ }
1114
+
1115
+ export async function checkLayoutForCli(deps: LayoutCheckDeps = {}): Promise<LayoutCheck> {
1098
1116
  const state = detectLayout();
1099
1117
 
1100
1118
  if (state.kind === "future") {
@@ -1220,7 +1238,7 @@ export async function checkLayoutForCli(): Promise<LayoutCheck> {
1220
1238
  state,
1221
1239
  fatal: false,
1222
1240
  didReset: false,
1223
- lines: [...(await healDaemonFlag()), ...staleDaemonHint()],
1241
+ lines: [...(await healDaemonFlag(deps)), ...staleDaemonHint()],
1224
1242
  };
1225
1243
  }
1226
1244
 
@@ -1239,13 +1257,13 @@ export async function checkLayoutForCli(): Promise<LayoutCheck> {
1239
1257
  * downgrade a healthy machine to the in-process path — trading a loud, correct
1240
1258
  * failure for a quiet, wrong one.
1241
1259
  */
1242
- async function healDaemonFlag(): Promise<string[]> {
1260
+ async function healDaemonFlag(deps: LayoutCheckDeps = {}): Promise<string[]> {
1243
1261
  try {
1244
1262
  const cfg = readConfig();
1245
1263
  if (!cfg.daemon.configured) return [];
1246
1264
  if (!isDaemonSupportedPlatform()) return [];
1247
1265
 
1248
- const status = daemonServiceStatus();
1266
+ const status = (deps.daemonStatus ?? daemonServiceStatus)();
1249
1267
  if (status === "not-installed") {
1250
1268
  updateConfig({ daemon: { configured: false } });
1251
1269
  return [