failproofai 1.0.11 → 1.0.12-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +23 -23
- package/.next/standalone/.next/prerender-manifest.json +4 -4
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +3 -3
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +5 -6
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +24 -24
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js +2 -2
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +4 -5
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +6 -7
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +6 -7
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +5 -6
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +2 -2
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +4 -4
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +7 -7
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +7 -7
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +8 -8
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +3 -3
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js +10 -10
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0qkp92tjfvw8r._.js → [externals]__0vt9i6fqinjne._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1x24dzcbbq6-g._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02vous7mpi2xm._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__03i5o4a840guz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__a_je8fsn65._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_hsnj_a2mvl_._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1izwqj_ij_9x_._.js → [root-of-the-server]__0f_4g-vazrvxv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-oi4gdtmlo5._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0swiyzbmvja2d._.js → [root-of-the-server]__0t9ufnv5hi2hq._.js} +5 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wg9dk8x8bnau._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12kq3x-h7t7i1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a5zkndjwlc13._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1r7kbfkiw2xmu._.js → [root-of-the-server]__1aaw59g-5uty7._.js} +12 -12
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hqpg6vgmfexv._.js +3 -0
- package/.next/standalone/.next/server/chunks/_09dz7xva4ce_2._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0hf5q4xzyg40j._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
- package/.next/standalone/.next/server/chunks/_19011-u44143j._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1vslkoe35wok6._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_1ixl-kxq_ctsa._.js → _1y590mjzpkbos._.js} +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0_em82s16zfym._.js +5 -0
- package/.next/standalone/.next/server/chunks/src_hooks_builtin-policies_ts_1yq5ybgx1v98e._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3h94wnn._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_daemon-client_ts_0il_yu1zc0291._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn_4twyh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01j58mdcdw0vn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0588st-tpiuia._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_a8z2ldp2v3n._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0vcyntk4snf0f._.js → [root-of-the-server]__0b78b0j8iyv6l._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ffu2-38y03ic._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8b0kyorya-t._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1_xbg2kx30wp-._.js → [root-of-the-server]__0naevg4bcoh54._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__075uro8t92s0_._.js → [root-of-the-server]__0pwj2h2efe5f-._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zn1d4blhd3bu._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17r4zrwanhp6r._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1lnfv02ucky7m._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mc9-zlnh656_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1s2-ck3k3rsoo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1l1qgu5mfapkh._.js → [root-of-the-server]__1vx7o8ukefudh._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_128ebxr83nk6g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgifqv1ssi._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1gb0ifpkowwub._.js → _1a3tubds7s7ow._.js} +10 -9
- package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1f_ymmaonkksc.js → node_modules_html-to-image_es_index_1i8oid1gc7s1f.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9ddabn3_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4l1tzrm._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_daemon-client_ts_0k41_i7jg6ndv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me658zqmh_._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +23 -23
- package/.next/standalone/.next/server/middleware.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/preview-props.json +3 -3
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
- package/.next/standalone/.next/static/chunks/{0frxv4_m-m2u5.js → 063al_q720fkj.js} +1 -1
- package/.next/standalone/.next/static/chunks/0_zfad4co-t2z.js +1 -0
- package/.next/standalone/.next/static/chunks/0jutamwqz8pg5.js +1 -0
- package/.next/standalone/.next/static/chunks/114hbolvrv94e.js +1 -0
- package/.next/standalone/.next/static/chunks/{37stoe-_yd852.js → 18433qz-8njv3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1kwj8uqxuv85t.js → 1b32-afqacaen.js} +1 -1
- package/.next/standalone/.next/static/chunks/{44a7k2_62qc-9.js → 1p-hsi58i-6h0.js} +2 -2
- package/.next/standalone/.next/static/chunks/{302llgh97ce6w.js → 2-tf6_7u623kd.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1_c0dc7zqj1n7.js → 24w3x2da9sk49.js} +1 -1
- package/.next/standalone/.next/static/chunks/2tjfp9dirxnku.js +1 -0
- package/.next/standalone/.next/static/chunks/{16z6_d7sp61jm.js → 3-pku9qwv1yfu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{15rm15u5a6dua.js → 42e8zab314654.js} +1 -1
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +41 -0
- package/.next/standalone/fp-cloud-cli/README.md +42 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +117 -12
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +285 -19
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +84 -18
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +170 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/models.py +89 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +259 -21
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +8 -5
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +2 -2
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +17 -9
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +692 -0
- package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +46 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +23 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +6 -6
- package/.next/standalone/hermes-plugin/README.md +6 -4
- package/.next/standalone/hermes-plugin/__init__.py +16 -0
- package/.next/standalone/hermes-plugin/client.py +5 -1
- package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/context.js +72 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/diag.js +84 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/metrics.js +50 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/propagation.js +80 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/trace.js +70 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/context-helpers.js +52 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/baggage-impl.js +44 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/symbol.js +12 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/utils.js +41 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/NoopContextManager.js +27 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/context.js +52 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/context-api.js +16 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/ComponentLogger.js +47 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/consoleLogger.js +73 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/internal/logLevelLogger.js +34 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/types.js +33 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag-api.js +20 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/index.js +71 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/global-utils.js +60 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/semver.js +111 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/Metric.js +18 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeter.js +118 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeterProvider.js +20 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics-api.js +17 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/NoopTextMapPropagator.js +23 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/TextMapPropagator.js +36 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation-api.js +17 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NonRecordingSpan.js +58 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracer.js +68 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracerProvider.js +21 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracer.js +46 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracerProvider.js +46 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/SamplingResult.js +33 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/context-utils.js +71 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-impl.js +94 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-validators.js +35 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/utils.js +16 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/invalid-span-constants.js +25 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/span_kind.js +38 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/spancontext-utils.js +66 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/status.js +29 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/trace_flags.js +18 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace-api.js +17 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/version.js +10 -0
- package/.next/standalone/node_modules/@opentelemetry/api/package.json +96 -0
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/app-render/async-local-storage.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/generate-agent-files.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/trace/tracer.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/typescript/rules/config.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +11 -11
- package/.next/standalone/package.json +11 -11
- package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
- package/.next/standalone/sdk/python/pyproject.toml +19 -0
- package/.next/standalone/sdk/python/uv.lock +520 -301
- package/.next/standalone/sdk/typescript/CHANGELOG.md +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +4 -13
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +2 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4 -13
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +3 -0
- package/.next/standalone/sdk/typescript/package-lock.json +178 -162
- package/.next/standalone/sdk/typescript/package.json +1 -1
- package/.next/standalone/sdk/typescript/src/version.ts +1 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +17 -1
- package/dist/cli.mjs +2866 -1124
- package/dist/worker.mjs +1450 -145
- package/hermes-plugin/README.md +6 -4
- package/hermes-plugin/__init__.py +16 -0
- package/hermes-plugin/client.py +5 -1
- package/hermes-plugin/plugin.yaml +1 -1
- package/package.json +11 -11
- package/src/hooks/agent-roster.ts +172 -0
- package/src/hooks/agent-targets.ts +60 -0
- package/src/hooks/cloud-connection.ts +97 -27
- package/src/hooks/cloud-enrollment-cli.ts +7 -4
- package/src/hooks/cloud-managed-policies.ts +380 -20
- package/src/hooks/cloud-policy-errors.ts +481 -0
- package/src/hooks/config-status.ts +1 -1
- package/src/hooks/custom-hooks-loader.ts +26 -3
- package/src/hooks/daemon-client.ts +9 -4
- package/src/hooks/daemon-service.ts +2 -1
- package/src/hooks/effective-reviewers.ts +22 -1
- package/src/hooks/fp-home.ts +6 -0
- package/src/hooks/handler.ts +235 -18
- package/src/hooks/health-probe.ts +15 -0
- package/src/hooks/integrations.ts +18 -11
- package/src/hooks/jev-cli.ts +197 -0
- package/src/hooks/jev-cloud-connection.ts +92 -0
- package/src/hooks/manager.ts +122 -16
- package/src/hooks/pack-failclosed.ts +2 -0
- package/src/hooks/pack-manifest.ts +8 -1
- package/src/hooks/policy-evaluator.ts +5 -1
- package/src/hooks/policy-registry.ts +3 -2
- package/src/hooks/policy-reviewability.ts +21 -5
- package/src/hooks/semantic/cloud-jev-health.ts +227 -0
- package/src/hooks/semantic/cloud-jev.ts +677 -0
- package/src/hooks/semantic/jev-client.ts +18 -1
- package/src/hooks/semantic/jev-config.ts +173 -3
- package/src/hooks/semantic/jev-review.ts +129 -10
- package/src/hooks/semantic/pack-policies.ts +2 -1
- package/src/hooks/semantic/types.ts +8 -0
- package/src/hooks/session-pause-cli.ts +1 -1
- package/src/hooks/worker-server.ts +5 -1
- package/.next/standalone/.next/server/chunks/[externals]__0hjaw70fchx66._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07l68zv0hqdiu._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0car70pylmvor._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0u3i025_setk_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10a2f6s636yc7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qt5u58xrcuk6._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_077n_4ip5__fu._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mqvvxcn6v0op._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0pb7ds5g0vzgn._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1gasm5xkeqmm3._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1q1heqmkhh8l4._.js +0 -3
- package/.next/standalone/.next/server/chunks/src_hooks_1aveq0uhs2t1b._.js +0 -5
- package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7cyqlb2._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0888k4s6spfmh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_bflu046ep5j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_lbstb5x2t15._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0fdwgktjfhedo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s4deza787asx._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__18qe-hu0gwqm4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_p_9xe520fex._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fmhm8_s9i4re._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1g76awtnmimd1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pczevlpk5lxh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0dc-of_bn0cim._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo55j16x._.js +0 -5
- package/.next/standalone/.next/static/chunks/0m-tv1y6ghhtk.js +0 -1
- package/.next/standalone/.next/static/chunks/0ol2gj4ntfn56.js +0 -1
- package/.next/standalone/.next/static/chunks/3hj5_7i3nw4zj.js +0 -1
- package/.next/standalone/.next/static/chunks/3iyoapeoq_hup.js +0 -1
- /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_ssgManifest.js +0 -0
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* before import so the worker never knowingly executes modified bytes.
|
|
6
6
|
*/
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
|
-
import { existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
|
8
|
+
import { existsSync, readFileSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
9
9
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
10
|
-
import { cloudPoliciesDir } from "./fp-home";
|
|
10
|
+
import { cloudPoliciesDir, configFile } from "./fp-home";
|
|
11
|
+
import { agentTargetsMatch, parseAgentTargets, type AgentIdentity, type AgentTarget } from "./agent-targets";
|
|
11
12
|
import { authorityFieldsOf } from "./policy-authority";
|
|
12
13
|
import type { PolicyAuthority } from "./policy-types";
|
|
13
14
|
|
|
@@ -22,10 +23,10 @@ import type { PolicyAuthority } from "./policy-types";
|
|
|
22
23
|
* enforced while every other signal says the machine is healthy. Reproduced
|
|
23
24
|
* exactly that way while syncing this with AgentEye#559.
|
|
24
25
|
*
|
|
25
|
-
* 1 is accepted for files a pre-rename beta daemon left behind; 2 is
|
|
26
|
-
*
|
|
26
|
+
* 1 is accepted for files a pre-rename beta daemon left behind; 2 is
|
|
27
|
+
* unscoped and 3 is targeted. An old hook must reject 3.
|
|
27
28
|
*/
|
|
28
|
-
const ACCEPTED_ACTIVE_SCHEMA_VERSIONS: readonly number[] = [1, 2];
|
|
29
|
+
const ACCEPTED_ACTIVE_SCHEMA_VERSIONS: readonly number[] = [1, 2, 3];
|
|
29
30
|
const SHA256_RE = /^[a-f0-9]{64}$/;
|
|
30
31
|
const POLICY_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
|
|
31
32
|
|
|
@@ -59,6 +60,7 @@ export interface CloudManagedPolicyArtifact {
|
|
|
59
60
|
authority?: PolicyAuthority;
|
|
60
61
|
/** The semantic policies that must all be asked and none answer `deny`; see `authority`. */
|
|
61
62
|
reviewedBy?: string[];
|
|
63
|
+
agentTargets?: AgentTarget[];
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
interface ActiveManifest {
|
|
@@ -72,6 +74,7 @@ interface ActiveManifest {
|
|
|
72
74
|
path: string;
|
|
73
75
|
authority?: unknown;
|
|
74
76
|
reviewedBy?: unknown;
|
|
77
|
+
agentTargets?: unknown;
|
|
75
78
|
}>;
|
|
76
79
|
}
|
|
77
80
|
|
|
@@ -82,6 +85,24 @@ export function cloudManagedPolicyRoot(): string {
|
|
|
82
85
|
);
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
/**
|
|
89
|
+
* An explicit disconnect vetoes an old deployment even when an operator's
|
|
90
|
+
* overridden policy directory is shared and therefore cannot be cleaned up.
|
|
91
|
+
* Missing or unreadable config does not veto older enrolled machines; this
|
|
92
|
+
* mirrors the daemon's `disconnected_by_config` rule.
|
|
93
|
+
*/
|
|
94
|
+
function disconnectedByConfig(): boolean {
|
|
95
|
+
try {
|
|
96
|
+
const raw: unknown = JSON.parse(readFileSync(configFile(), "utf8"));
|
|
97
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
98
|
+
const mode = (raw as { mode?: unknown }).mode;
|
|
99
|
+
return !!mode && typeof mode === "object" && !Array.isArray(mode) &&
|
|
100
|
+
(mode as { kind?: unknown }).kind === "oss";
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
85
106
|
/**
|
|
86
107
|
* A version-1 manifest, in the spelling a pre-rename daemon actually wrote.
|
|
87
108
|
*
|
|
@@ -148,11 +169,18 @@ export function resolveManagedPath(root: string, candidate: string): string {
|
|
|
148
169
|
/**
|
|
149
170
|
* Stop enforcing cloud-managed policies on this machine.
|
|
150
171
|
*
|
|
151
|
-
* Removes `
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
172
|
+
* Removes `desired-state.json` FIRST, then `active.json` — the manifest that
|
|
173
|
+
* says which deployment is live — both error reports and the Jev budget record.
|
|
174
|
+
* The content-addressed artifacts are left alone: they are large, hash-verified
|
|
175
|
+
* on use, and inert once nothing points at them, so keeping them makes a
|
|
176
|
+
* reconnect cheap.
|
|
177
|
+
*
|
|
178
|
+
* The snapshot has to go, and before the pointer. It is what the daemon's
|
|
179
|
+
* maintenance lane rebuilds a lost `active.json` from, and it used to be left
|
|
180
|
+
* behind: within one interval of `--disconnect` the old org's JS policies and
|
|
181
|
+
* Jev mode were back, on a machine whose owner had left (the daemon
|
|
182
|
+
* also refuses to rebuild on a machine that is not enrolled now, so neither
|
|
183
|
+
* half alone decides it).
|
|
156
184
|
*
|
|
157
185
|
* Called by `--disconnect`, which without it did not disconnect. Clearing the
|
|
158
186
|
* credential stops the daemon REFRESHING policy; every artifact already on disk
|
|
@@ -164,36 +192,365 @@ export function resolveManagedPath(root: string, candidate: string): string {
|
|
|
164
192
|
* Returns true when a manifest was actually removed.
|
|
165
193
|
*/
|
|
166
194
|
export function clearActiveCloudManagedPolicies(): boolean {
|
|
195
|
+
// An override can point to a shared directory with unrelated files named
|
|
196
|
+
// active.json or errors.json. Never delete from a path the CLI does not own.
|
|
197
|
+
// `mode: oss` independently stops the hook from reading retained artifacts.
|
|
198
|
+
if (process.env.FAILPROOFAI_CLOUD_POLICY_DIR !== undefined) return false;
|
|
199
|
+
const root = cloudManagedPolicyRoot();
|
|
200
|
+
// The snapshot first, so nothing can rebuild the pointer from it in between.
|
|
201
|
+
// The error reports go too: they describe a deployment this machine no
|
|
202
|
+
// longer has, and a reconnect (possibly to another organisation) must not
|
|
203
|
+
// open by reporting the old one's problems. The Cloud Jev mode lives IN
|
|
204
|
+
// active.json, so removing it clears that too.
|
|
205
|
+
// Either manifest counts as a removed deployment: a stopped daemon would
|
|
206
|
+
// rebuild `active.json` from the snapshot alone.
|
|
167
207
|
let removed = false;
|
|
168
|
-
for (const name of ["
|
|
169
|
-
const path = resolve(
|
|
208
|
+
for (const name of [DESIRED_STATE_FILE, CLOUD_POLICY_ERRORS_FILE, DAEMON_POLICY_ERRORS_FILE, JEV_BUDGET_FILE, "load-checked.json", "active.json"]) {
|
|
209
|
+
const path = resolve(root, name);
|
|
170
210
|
if (!existsSync(path)) continue;
|
|
171
211
|
try {
|
|
172
212
|
rmSync(path, { force: true });
|
|
173
|
-
removed = true;
|
|
213
|
+
if (name === DESIRED_STATE_FILE || name === "active.json") removed = true;
|
|
174
214
|
} catch {
|
|
175
|
-
//
|
|
176
|
-
//
|
|
215
|
+
// Best-effort and independent: a failure removing one file must not leave
|
|
216
|
+
// the others in place. `--disconnect` still clears the credentials, and
|
|
217
|
+
// reporting one failed removal would obscure that the rest succeeded.
|
|
177
218
|
}
|
|
178
219
|
}
|
|
220
|
+
// The org's policy source goes too (B15): the content-addressed artifacts
|
|
221
|
+
// are the departed organisation's code, and nothing on a disconnected
|
|
222
|
+
// machine may use them; a reconnect downloads what its deployment names.
|
|
223
|
+
// Only here, in the directory the CLI owns (an override returned above).
|
|
224
|
+
try {
|
|
225
|
+
rmSync(resolve(root, "artifacts"), { recursive: true, force: true });
|
|
226
|
+
} catch {
|
|
227
|
+
// Best-effort, like the files above.
|
|
228
|
+
}
|
|
179
229
|
return removed;
|
|
180
230
|
}
|
|
181
231
|
|
|
182
|
-
|
|
232
|
+
/** The daemon's snapshot of the last desired state (`PolicyStore::desired_state_path`). */
|
|
233
|
+
export const DESIRED_STATE_FILE = "desired-state.json";
|
|
234
|
+
/** The CLI's error report, beside `active.json`. See `cloud-policy-errors.ts`. */
|
|
235
|
+
export const CLOUD_POLICY_ERRORS_FILE = "errors.json";
|
|
236
|
+
/** The daemon's own reconcile error state (`PolicyStore::daemon_errors_path`). */
|
|
237
|
+
export const DAEMON_POLICY_ERRORS_FILE = "daemon-errors.json";
|
|
238
|
+
/**
|
|
239
|
+
* Installed packs' Jev checks FailproofAI Cloud dropped from a request for the
|
|
240
|
+
* question budget, kept for the deployment they happened under so the report
|
|
241
|
+
* does not flap with each tool call's selection. See `cloud-policy-errors.ts`.
|
|
242
|
+
*/
|
|
243
|
+
export const JEV_BUDGET_FILE = "jev-budget.json";
|
|
244
|
+
|
|
245
|
+
// ── FailproofAI Cloud Jev (CONTRACT C10) ─────────────────────────────────────
|
|
246
|
+
//
|
|
247
|
+
// Jev policies, and the Jev half of `both` policies, live ONLY on FailproofAI
|
|
248
|
+
// Cloud: nothing but the MODE reaches this machine. `active.json` carries
|
|
249
|
+
// `jevMode` (`off | observe | enforce`, or absent), and a `both` policy's JS
|
|
250
|
+
// half carries `authority: "reviewable"` with `reviewedBy` = the names of its
|
|
251
|
+
// own Cloud checks. With `observe`/`enforce` the hook path sends every gated
|
|
252
|
+
// tool call to FailproofAI Cloud, which asks the checks deployed to this
|
|
253
|
+
// machine and returns their verdict (`semantic/cloud-jev.ts`).
|
|
254
|
+
|
|
255
|
+
/** The Jev modes Cloud may set. `local` never reaches a machine (stored NULL). */
|
|
256
|
+
export type CloudJevMode = "off" | "observe" | "enforce";
|
|
257
|
+
|
|
258
|
+
/** What `errors.json` reports, one entry per problem (CONTRACT C4/C6). */
|
|
259
|
+
export type CloudPolicyErrorKind = "regex" | "jev" | "both" | "daemon";
|
|
260
|
+
export interface CloudPolicyError {
|
|
261
|
+
id: string;
|
|
262
|
+
version: number | null;
|
|
263
|
+
kind: CloudPolicyErrorKind;
|
|
264
|
+
message: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** What this machine knows about FailproofAI Cloud's Jev: the mode, and nothing else. */
|
|
268
|
+
export interface CloudJevState {
|
|
269
|
+
/** Cloud's Jev mode, or null when Cloud does not set one (or there is no deployment). */
|
|
270
|
+
jevMode: CloudJevMode | null;
|
|
271
|
+
/** The deployment `active.json` names, or null without one. */
|
|
272
|
+
deployment: number | null;
|
|
273
|
+
/** A `jevMode` this build cannot read, reported rather than guessed at. */
|
|
274
|
+
errors: CloudPolicyError[];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const noCloudJev = (): CloudJevState => ({ jevMode: null, deployment: null, errors: [] });
|
|
278
|
+
|
|
279
|
+
function parseCloudJevMode(raw: unknown): CloudJevMode | null {
|
|
280
|
+
return raw === "off" || raw === "observe" || raw === "enforce" ? raw : null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Whether Cloud's mode sends this machine's gated tool calls to FailproofAI Cloud Jev. */
|
|
284
|
+
export function cloudJevAsks(mode: CloudJevMode | null): mode is "observe" | "enforce" {
|
|
285
|
+
return mode === "observe" || mode === "enforce";
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ── Read once per change ─────────────────────────────────────────────────────
|
|
289
|
+
//
|
|
290
|
+
// The hook path asks about this deployment several times per event — the JS
|
|
291
|
+
// reader, the reviewer set, the Jev mode — and the warm worker does that on
|
|
292
|
+
// every tool call of every session. So `active.json` is parsed once per CHANGE
|
|
293
|
+
// of the file, keyed on its identity and version: device, inode, mode, size,
|
|
294
|
+
// and modification and change times to the nanosecond.
|
|
295
|
+
//
|
|
296
|
+
// Sound for this file in particular. The daemon writes it by rename, so a new
|
|
297
|
+
// deployment is a new inode, and an edit in place moves the change time, which
|
|
298
|
+
// nothing short of the system clock can set back.
|
|
299
|
+
|
|
300
|
+
/** A file's identity and version, or null when it does not exist. Throws on anything else. */
|
|
301
|
+
function fileVersion(path: string): string | null {
|
|
302
|
+
try {
|
|
303
|
+
const s = statSync(path, { bigint: true });
|
|
304
|
+
return `${s.dev}:${s.ino}:${s.mode}:${s.size}:${s.mtimeNs}:${s.ctimeNs}`;
|
|
305
|
+
} catch (err) {
|
|
306
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
307
|
+
if (code === "ENOENT" || code === "ENOTDIR") return null;
|
|
308
|
+
throw err;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
let activeJsonCache: { path: string; version: string; value: unknown } | null = null;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* `active.json` parsed, once per change of the file — or `undefined` when
|
|
316
|
+
* there is none (a file holding `null` is a bad manifest, not an absent one).
|
|
317
|
+
* Throws on a file that cannot be read or is not JSON (not cached: the next
|
|
318
|
+
* call tries again). Callers must not mutate what it returns.
|
|
319
|
+
*/
|
|
320
|
+
function readActiveJson(): unknown {
|
|
321
|
+
if (disconnectedByConfig()) {
|
|
322
|
+
activeJsonCache = null;
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
const path = resolve(cloudManagedPolicyRoot(), "active.json");
|
|
326
|
+
const version = fileVersion(path);
|
|
327
|
+
if (version === null) {
|
|
328
|
+
activeJsonCache = null;
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
if (activeJsonCache && activeJsonCache.path === path && activeJsonCache.version === version) return activeJsonCache.value;
|
|
332
|
+
const value: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
333
|
+
activeJsonCache = { path, version, value };
|
|
334
|
+
return value;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Forget every cached read. Tests only: a test that rewrites a file in place can beat the clock's granularity. */
|
|
338
|
+
export function _resetCloudManagedCachesForTest(): void {
|
|
339
|
+
activeJsonCache = null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** `active.json` as untyped JSON, schema-checked, or null when there is none. Throws on a bad one. */
|
|
343
|
+
function readActiveRaw(): Record<string, unknown> | null {
|
|
344
|
+
const raw = readActiveJson();
|
|
345
|
+
if (raw === undefined) return null;
|
|
346
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error("active manifest is not an object");
|
|
347
|
+
const record = raw as Record<string, unknown>;
|
|
348
|
+
if (!ACCEPTED_ACTIVE_SCHEMA_VERSIONS.includes(record.schemaVersion as number)) {
|
|
349
|
+
throw new Error(`unsupported active manifest schema ${String(record.schemaVersion)}`);
|
|
350
|
+
}
|
|
351
|
+
return record;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** Schema 3 means at least one machine assignment is targeted, including a
|
|
355
|
+
* Jev-only one whose JS policies array is empty. Never reads any artifact. */
|
|
356
|
+
export function readCloudAgentScopeRequired(): boolean {
|
|
357
|
+
try {
|
|
358
|
+
return readActiveRaw()?.schemaVersion === 3;
|
|
359
|
+
} catch {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Cloud's Jev mode from `active.json`, or null — no deployment, no mode, or a
|
|
366
|
+
* file that cannot be read (which is then simply not a mode: the local
|
|
367
|
+
* `jev.json` decides, as it does on a machine Cloud never touched). Cheap and
|
|
368
|
+
* never throws: the hook path asks on every gate event.
|
|
369
|
+
*/
|
|
370
|
+
export function readCloudJevMode(): CloudJevMode | null {
|
|
371
|
+
try {
|
|
372
|
+
return parseCloudJevMode(readActiveRaw()?.jevMode);
|
|
373
|
+
} catch {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* The Cloud Jev state `active.json` carries: the mode, the deployment it came
|
|
380
|
+
* with, and a report of a mode this build cannot read. Never throws; an
|
|
381
|
+
* unreadable manifest is reported by the JS reader (and the handler files it),
|
|
382
|
+
* so it is not reported twice here.
|
|
383
|
+
*/
|
|
384
|
+
export function readCloudJevState(): CloudJevState {
|
|
385
|
+
let active: Record<string, unknown> | null;
|
|
386
|
+
try {
|
|
387
|
+
active = readActiveRaw();
|
|
388
|
+
} catch {
|
|
389
|
+
return noCloudJev();
|
|
390
|
+
}
|
|
391
|
+
if (!active) return noCloudJev();
|
|
392
|
+
const rawMode = active.jevMode;
|
|
393
|
+
const jevMode = parseCloudJevMode(rawMode);
|
|
394
|
+
const errors: CloudPolicyError[] = [];
|
|
395
|
+
if (rawMode !== undefined && rawMode !== null && jevMode === null) {
|
|
396
|
+
// The daemon refuses such a state, so this is a hand-edited or foreign file.
|
|
397
|
+
errors.push({ id: "jevMode", version: null, kind: "daemon", message: `unknown Jev mode ${JSON.stringify(rawMode)} ignored` });
|
|
398
|
+
}
|
|
399
|
+
const deployment = Number.isSafeInteger(active.deployment) ? (active.deployment as number) : null;
|
|
400
|
+
return { jevMode, deployment, errors };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ── `both` policies: reviewed by their OWN Cloud checks ─────────────────────
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* The reviewer name a FailproofAI Cloud policy's `reviewedBy` entry stands for
|
|
407
|
+
* on this machine: `cloud:<policyId>/<name>`. Pack check names cannot contain
|
|
408
|
+
* `:` or `/`, so this can never be a pack's check — and the Cloud review files
|
|
409
|
+
* a Cloud check's outcome under the same key (`toReview`, `jev-review.ts`),
|
|
410
|
+
* built from the outcome's own `origin.cloudPolicyId`. So a `both` policy's
|
|
411
|
+
* verdict can be cleared by exactly that policy's Cloud checks and nothing
|
|
412
|
+
* else: never by an installed pack's check of the same name (CONTRACT C10.5,
|
|
413
|
+
* C9.4), never by another Cloud policy's.
|
|
414
|
+
*/
|
|
415
|
+
export function cloudReviewerName(policyId: string, name: string): string {
|
|
416
|
+
return `cloud:${policyId}/${name}`;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** The authority fields of one Cloud JS assignment, as `active.json` carries them. */
|
|
420
|
+
export interface CloudAuthorityInput {
|
|
421
|
+
id: string;
|
|
422
|
+
effect?: PolicyEffect;
|
|
423
|
+
authority?: PolicyAuthority;
|
|
424
|
+
reviewedBy?: string[];
|
|
425
|
+
agentTargets?: AgentTarget[];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** A name {@link cloudReviewerName} already made (a Jev check name can contain neither `:` nor `/`). */
|
|
429
|
+
const CLOUD_REVIEWER_RE = /^cloud:[^/]+\/./;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* The authority a Cloud JS policy registers with on this machine:
|
|
433
|
+
*
|
|
434
|
+
* - declared `hard` (or nothing): as declared;
|
|
435
|
+
* - an `observe` assignment: `hard`, silently. FailproofAI Cloud does not ask
|
|
436
|
+
* an observe `both` policy's Jev half (C9.3), and an observe policy blocks
|
|
437
|
+
* nothing anyway;
|
|
438
|
+
* - Cloud's Jev mode is not `observe`/`enforce`: `hard`, silently. Nothing on
|
|
439
|
+
* this machine can ask a Cloud check, and that is the org's own choice, so
|
|
440
|
+
* it is not a warning;
|
|
441
|
+
* - otherwise `reviewable`, by its `reviewedBy` names as {@link cloudReviewerName}s
|
|
442
|
+
* (a name already translated is kept, so applying this twice is harmless).
|
|
443
|
+
*
|
|
444
|
+
* Pure. The handler applies it to every assignment BEFORE the loader merges
|
|
445
|
+
* two assignments that share one artifact — so each name keeps the policy it
|
|
446
|
+
* came from — and the reviewer set (`effective-reviewers.ts`) and the
|
|
447
|
+
* reviewability survey use it too, so none of them can disagree.
|
|
448
|
+
*/
|
|
449
|
+
export function cloudAuthorityDeclaration(
|
|
450
|
+
policy: CloudAuthorityInput,
|
|
451
|
+
mode: CloudJevMode | null,
|
|
452
|
+
): { authority?: PolicyAuthority; reviewedBy?: string[] } {
|
|
453
|
+
if (policy.authority !== "reviewable") return policy.authority ? { authority: policy.authority } : {};
|
|
454
|
+
if (policy.effect === "observe" || !cloudJevAsks(mode)) return { authority: "hard" };
|
|
455
|
+
return {
|
|
456
|
+
authority: "reviewable",
|
|
457
|
+
reviewedBy: (policy.reviewedBy ?? []).map((n) => (CLOUD_REVIEWER_RE.test(n) ? n : cloudReviewerName(policy.id, n))),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* A Cloud JS assignment as this machine registers it: its `authority` and
|
|
463
|
+
* `reviewedBy` replaced by {@link cloudAuthorityDeclaration}'s. Pure.
|
|
464
|
+
*/
|
|
465
|
+
export function withCloudAuthority<T extends CloudAuthorityInput>(policy: T, mode: CloudJevMode | null): T {
|
|
466
|
+
const { authority: _authority, reviewedBy: _reviewedBy, ...rest } = policy;
|
|
467
|
+
void _authority;
|
|
468
|
+
void _reviewedBy;
|
|
469
|
+
return { ...rest, ...cloudAuthorityDeclaration(policy, mode) } as T;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Every reviewer name the deployment's `both` policies may be cleared by on
|
|
474
|
+
* this machine — empty unless Cloud's Jev mode asks. Pure.
|
|
475
|
+
*/
|
|
476
|
+
export function cloudReviewerNames(policies: ReadonlyArray<CloudAuthorityInput>, mode: CloudJevMode | null): string[] {
|
|
477
|
+
const out: string[] = [];
|
|
478
|
+
for (const policy of policies) {
|
|
479
|
+
const declared = cloudAuthorityDeclaration(policy, mode);
|
|
480
|
+
if (declared.authority === "reviewable") out.push(...(declared.reviewedBy ?? []));
|
|
481
|
+
}
|
|
482
|
+
return out;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* The Cloud JS assignments' authority fields, read off the cached `active.json`
|
|
487
|
+
* parse — no artifact is read or hashed, so this is cheap enough for the
|
|
488
|
+
* reviewer set, which is rebuilt on every event. Never throws: an unreadable
|
|
489
|
+
* manifest has no assignments here (the JS reader reports it).
|
|
490
|
+
*/
|
|
491
|
+
export function readCloudAuthorityInputs(agent: AgentIdentity | null = null): CloudAuthorityInput[] {
|
|
492
|
+
try {
|
|
493
|
+
const raw = readActiveJson();
|
|
494
|
+
if (raw === undefined) return [];
|
|
495
|
+
const manifest = parseManifest(raw);
|
|
496
|
+
return manifest.policies.flatMap((policy) => {
|
|
497
|
+
if (typeof policy.id !== "string") return [];
|
|
498
|
+
const targets = parseAgentTargets(policy.agentTargets, manifest.schemaVersion);
|
|
499
|
+
if (!agentTargetsMatch(targets, agent)) return [];
|
|
500
|
+
return [{
|
|
501
|
+
id: policy.id,
|
|
502
|
+
effect: policy.effect === "observe" ? "observe" : "enforce",
|
|
503
|
+
...(targets ? { agentTargets: targets } : {}),
|
|
504
|
+
...authorityFieldsOf(policy as unknown as Record<string, unknown>),
|
|
505
|
+
} satisfies CloudAuthorityInput];
|
|
506
|
+
});
|
|
507
|
+
} catch {
|
|
508
|
+
// A malformed selector invalidates the entire active manifest for the JS
|
|
509
|
+
// loader too. Do not keep reviewers from a partial set of that manifest:
|
|
510
|
+
// Cloud's JS has not loaded, and a subset would claim otherwise.
|
|
511
|
+
return [];
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Every Cloud JS assignment in the deployment, whatever agent it targets — for
|
|
517
|
+
* LISTING only (`failproofai policies`), never for import: the hook path scopes
|
|
518
|
+
* with {@link readActiveCloudManagedPolicies} before any artifact is read.
|
|
519
|
+
* A listing that applied a hook's scope with no agent hid every agent-scoped
|
|
520
|
+
* policy (B4). Each artifact is still digest-checked, so a row is never shown
|
|
521
|
+
* for bytes that would be refused.
|
|
522
|
+
*/
|
|
523
|
+
export function listActiveCloudManagedPolicies(): CloudManagedPolicyArtifact[] {
|
|
524
|
+
return readActiveCloudManagedPoliciesFor(() => true);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export function readActiveCloudManagedPolicies(agent: AgentIdentity | null = null): CloudManagedPolicyArtifact[] {
|
|
528
|
+
return readActiveCloudManagedPoliciesFor((targets) => agentTargetsMatch(targets, agent));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function readActiveCloudManagedPoliciesFor(
|
|
532
|
+
applies: (targets: ReturnType<typeof parseAgentTargets>) => boolean,
|
|
533
|
+
): CloudManagedPolicyArtifact[] {
|
|
183
534
|
const root = cloudManagedPolicyRoot();
|
|
184
|
-
const activePath = resolve(root, "active.json");
|
|
185
|
-
if (!existsSync(activePath)) return [];
|
|
186
535
|
|
|
536
|
+
// Parsed once per change of the file (`readActiveJson`). Each JS artifact is
|
|
537
|
+
// still read and hashed HERE, on every call: the loader imports what this
|
|
538
|
+
// returns, and the digest check is kept immediately before that import.
|
|
187
539
|
let raw: unknown;
|
|
188
540
|
try {
|
|
189
|
-
raw =
|
|
541
|
+
raw = readActiveJson();
|
|
190
542
|
} catch (err) {
|
|
191
543
|
throw new Error(`failed to read cloud-managed active manifest: ${err instanceof Error ? err.message : String(err)}`);
|
|
192
544
|
}
|
|
545
|
+
if (raw === undefined) return [];
|
|
193
546
|
const manifest = parseManifest(raw);
|
|
547
|
+
// Scope before reading or importing any artifact: a foreign agent must not
|
|
548
|
+
// execute policy code even to discover that it does not apply.
|
|
549
|
+
const applicable = manifest.policies.filter((policy) =>
|
|
550
|
+
applies(parseAgentTargets(policy.agentTargets, manifest.schemaVersion)));
|
|
194
551
|
const seen = new Set<string>();
|
|
195
552
|
|
|
196
|
-
return
|
|
553
|
+
return applicable.map((policy) => {
|
|
197
554
|
if (!POLICY_ID_RE.test(policy.id) || policy.id === "." || policy.id === "..") {
|
|
198
555
|
throw new Error(`unsafe cloud-managed policy id ${JSON.stringify(policy.id)}`);
|
|
199
556
|
}
|
|
@@ -227,6 +584,9 @@ export function readActiveCloudManagedPolicies(): CloudManagedPolicyArtifact[] {
|
|
|
227
584
|
sha256: policy.sha256,
|
|
228
585
|
path,
|
|
229
586
|
deployment: manifest.deployment,
|
|
587
|
+
...(parseAgentTargets(policy.agentTargets, manifest.schemaVersion)
|
|
588
|
+
? { agentTargets: parseAgentTargets(policy.agentTargets, manifest.schemaVersion) }
|
|
589
|
+
: {}),
|
|
230
590
|
// Unlike `effect`, a malformed authority is dropped rather than refused:
|
|
231
591
|
// dropping it makes this policy `hard`, the default that keeps enforcing,
|
|
232
592
|
// while refusing would take the whole deployment down over an optional
|