failproofai 1.0.7 → 1.0.8-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +4 -4
- 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 +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- 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 +4 -4
- 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 +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- 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 +8 -7
- 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.nft.json +1 -1
- 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.nft.json +1 -1
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +9 -7
- 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 +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +6 -6
- 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/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +11 -10
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +8 -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/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 +6 -6
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +7 -6
- 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/server-reference-manifest.json +52 -8
- package/.next/standalone/.next/server/app/settings/page.js +12 -7
- 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]__1msfs-h._.js → [externals]__19_pzeq._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1_bftcl._.js → [externals]__20kzpkf._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +22 -0
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
- package/.next/standalone/.next/server/chunks/{_1c3k-8x._.js → _1q5i8mb._.js} +2 -2
- package/.next/standalone/.next/server/chunks/lib_16xa545._.js +3 -0
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_1aveq0u._.js +5 -0
- package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +4 -2
- package/.next/standalone/.next/server/chunks/ssr/[externals]__0ohnuzs._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06pflha._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +22 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12e7nhs._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bd3mje._.js → [root-of-the-server]__14o3ek1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19evfi8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0cxe_2_._.js → [root-of-the-server]__1mf3zp6._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_166t73i._.js → _0o4xkpl._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_1-i_gzc._.js → _1-7sqrb._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1es2j7i._.js → _1gb0ifp._.js} +5 -5
- package/.next/standalone/.next/server/chunks/ssr/{_1_qswah._.js → _1q46vxx._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +13 -13
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0aiy-os._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0drixxt._.js → node_modules_next_dist_0w6mzq5._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_18_d8l1._.js +151 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0-q0umm._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9d._.js +12 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0g194sy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +4 -2
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1kx9e0d._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +3 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- 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/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +67 -23
- package/.next/standalone/.next/static/chunks/078gnymqoh3r4.js +1 -0
- package/.next/standalone/.next/static/chunks/{2mdh397ghgnvv.js → 0ahfwmbkpgfw4.js} +1 -1
- package/.next/standalone/.next/static/chunks/0bhidk90e-07f.css +2 -0
- package/.next/standalone/.next/static/chunks/1bu2-nv59ed6i.js +1 -0
- package/.next/standalone/.next/static/chunks/{0o6qlkgubtoex.js → 1v_tp3hm8wyhe.js} +1 -1
- package/.next/standalone/.next/static/chunks/2a405_e1o26ol.js +1 -0
- package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +1 -0
- package/.next/standalone/.next/static/chunks/2vo7qbdbvnc0o.js +69 -0
- package/.next/standalone/.next/static/chunks/{13i7-9is-vhys.js → 2z7i-yg59w4pn.js} +1 -1
- package/.next/standalone/.next/static/chunks/36uhh9el_oz8e.js +1 -0
- package/.next/standalone/.next/static/chunks/{0__8a7m868fvf.js → 3bgot5v6f6s3c.js} +1 -1
- package/.next/standalone/.next/static/chunks/3o3f1ibfci0p7.js +6 -0
- package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
- package/.next/standalone/app/actions/get-jev-config.ts +604 -0
- package/.next/standalone/app/actions/pack-actions.ts +12 -0
- package/.next/standalone/app/actions/update-jev-config.ts +569 -0
- package/.next/standalone/app/components/jev-notices.tsx +96 -0
- package/.next/standalone/app/policies/hooks-client.tsx +14 -3
- package/.next/standalone/app/settings/jev-panel.tsx +630 -0
- package/.next/standalone/app/settings/page.tsx +20 -1
- package/.next/standalone/app/settings/settings-client.tsx +27 -1
- package/.next/standalone/app/settings/settings.css +79 -0
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +22 -4
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +14 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +17 -3
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +3 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +22 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +169 -0
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +1 -1
- package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +65 -0
- package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +61 -0
- package/.next/standalone/package.json +10 -10
- package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
- package/.next/standalone/sdk/typescript/scripts/release.mjs +30 -0
- package/.next/standalone/server.js +1 -1
- package/README.md +3 -2
- package/bin/failproofai.mjs +148 -4
- package/dist/cli.mjs +18537 -9492
- package/dist/index.js +19 -1
- package/dist/worker.mjs +10421 -3770
- package/package.json +10 -10
- package/pi-extension/index.ts +11 -0
- package/scripts/build-policy-pack.mjs +53 -2
- package/src/audit/features.ts +3 -2
- package/src/hooks/builtin-policies.ts +195 -8
- package/src/hooks/cloud-connection.ts +190 -1
- package/src/hooks/cloud-enrollment-cli.ts +57 -8
- package/src/hooks/cloud-introspect.ts +6 -0
- package/src/hooks/cloud-managed-policies.ts +22 -0
- package/src/hooks/configure-wizard.ts +26 -6
- package/src/hooks/custom-hooks-loader.ts +98 -10
- package/src/hooks/custom-hooks-registry.ts +45 -1
- package/src/hooks/effective-reviewers.ts +243 -0
- package/src/hooks/first-run-gate.ts +5 -0
- package/src/hooks/flush-cli.ts +35 -8
- package/src/hooks/fp-config.ts +266 -1
- package/src/hooks/fp-home.ts +23 -0
- package/src/hooks/fp-reset.ts +22 -4
- package/src/hooks/handler.ts +303 -7
- package/src/hooks/hook-activity-store.ts +118 -6
- package/src/hooks/hook-telemetry.ts +41 -0
- package/src/hooks/jev-activity.ts +385 -0
- package/src/hooks/jev-cli.ts +2172 -0
- package/src/hooks/jev-cloud-connection.ts +392 -0
- package/src/hooks/loader-utils.ts +6 -0
- package/src/hooks/manager.ts +45 -7
- package/src/hooks/pack-cli.ts +568 -37
- package/src/hooks/pack-failclosed.ts +3 -0
- package/src/hooks/pack-manifest.ts +489 -7
- package/src/hooks/pack-store.ts +194 -11
- package/src/hooks/policy-authority.ts +386 -0
- package/src/hooks/policy-catalog.ts +206 -0
- package/src/hooks/policy-evaluator.ts +963 -796
- package/src/hooks/policy-registry.ts +27 -1
- package/src/hooks/policy-reviewability.ts +258 -0
- package/src/hooks/policy-types.ts +128 -0
- package/src/hooks/semantic/combine.ts +581 -0
- package/src/hooks/semantic/compile.ts +176 -0
- package/src/hooks/semantic/decide.ts +408 -0
- package/src/hooks/semantic/envelope.ts +1255 -0
- package/src/hooks/semantic/evaluator.ts +556 -0
- package/src/hooks/semantic/facts.ts +298 -0
- package/src/hooks/semantic/intent.ts +1190 -0
- package/src/hooks/semantic/jev-client.ts +1155 -0
- package/src/hooks/semantic/jev-config.ts +1142 -0
- package/src/hooks/semantic/jev-review.ts +389 -0
- package/src/hooks/semantic/jev-stats.ts +289 -0
- package/src/hooks/semantic/jev-throttle.ts +427 -0
- package/src/hooks/semantic/pack-policies.ts +294 -0
- package/src/hooks/semantic/policies.ts +597 -0
- package/src/hooks/semantic/precondition-names.ts +60 -0
- package/src/hooks/semantic/preconditions.ts +58 -0
- package/src/hooks/semantic/redact.ts +2937 -0
- package/src/hooks/semantic/session-root.ts +116 -0
- package/src/hooks/semantic/types.ts +156 -0
- package/src/hooks/semver-precedence.ts +128 -0
- package/src/hooks/tui.ts +4 -0
- package/src/hooks/types.ts +1 -1
- package/src/hooks/worker-server.ts +121 -27
- package/src/index.ts +6 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_r2rbg._.js +0 -24
- package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +0 -22
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/_0h_douw._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +0 -3
- package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +0 -1
- package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +0 -6
- package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +0 -1
- package/.next/standalone/.next/static/chunks/2klitrtzpaoe0.js +0 -1
- package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +0 -2
- package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +0 -1
- package/.next/standalone/.next/static/chunks/3rh5o7e16irrm.js +0 -69
- package/.next/standalone/.next/static/chunks/43ufqrz8qo3h-.js +0 -1
- /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → O_b5R1axf5cb4NxIXq2kS}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → O_b5R1axf5cb4NxIXq2kS}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → O_b5R1axf5cb4NxIXq2kS}/_ssgManifest.js +0 -0
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { HookEventType } from "./types";
|
|
9
9
|
import type { PolicyFunction, PolicyMatcher, PolicyParamsSchema, RegisteredPolicy } from "./policy-types";
|
|
10
|
+
import { effectiveReviewerNames, forgetEffectiveReviewerNames } from "./effective-reviewers";
|
|
11
|
+
import { resolvePolicyAuthority, type AuthorityDeclaration } from "./policy-authority";
|
|
10
12
|
|
|
11
13
|
const REGISTRY_KEY = "__FAILPROOFAI_POLICY_REGISTRY__";
|
|
12
14
|
const INDEX_CACHE_KEY = "__FAILPROOFAI_POLICY_INDEX_CACHE__";
|
|
@@ -58,15 +60,34 @@ export function registerPolicy(
|
|
|
58
60
|
match: PolicyMatcher,
|
|
59
61
|
priority: number = 0,
|
|
60
62
|
params?: PolicyParamsSchema,
|
|
63
|
+
/**
|
|
64
|
+
* The policy's authority declaration, as its source wrote it. Judged HERE,
|
|
65
|
+
* so the registry only ever holds an effective value: `reviewable` with a
|
|
66
|
+
* clean `reviewedBy`, or `hard`. See `resolvePolicyAuthority`.
|
|
67
|
+
*
|
|
68
|
+
* Absent means the caller declared nothing, and the entry then carries no
|
|
69
|
+
* authority field at all — which `effectiveAuthority` reads as hard.
|
|
70
|
+
*/
|
|
71
|
+
meta?: AuthorityDeclaration,
|
|
61
72
|
): void {
|
|
62
73
|
const canonical = normalizePolicyName(name);
|
|
63
74
|
const registry = getRegistry();
|
|
64
75
|
const idx = registry.findIndex((p) => p.name === canonical);
|
|
76
|
+
// Judged against the reviewers this MACHINE can ask, not against the ones this
|
|
77
|
+
// build compiled in. A pack that ships its own `semantic` set replaces the
|
|
78
|
+
// compiled one, so its policies name checks that exist here and nowhere in
|
|
79
|
+
// `SEMANTIC_POLICY_NAMES` — and judging them by the builtin list would
|
|
80
|
+
// downgrade the whole rewritten set to `hard` while reporting nothing but a
|
|
81
|
+
// warning. `effectiveReviewerNames` reads the manifest — already where a
|
|
82
|
+
// pack's `reviewedBy` itself comes from — once per registration pass.
|
|
83
|
+
const authority = meta ? resolvePolicyAuthority(meta, effectiveReviewerNames()) : undefined;
|
|
65
84
|
const entry: RegisteredPolicy = {
|
|
66
85
|
name: canonical, description, fn, match, priority,
|
|
67
86
|
// Absent stays absent: `evaluatePolicies` distinguishes "declares a schema"
|
|
68
87
|
// from "declares none", and a spread `params: undefined` is neither.
|
|
69
88
|
...(params ? { params } : {}),
|
|
89
|
+
...(authority ? { authority: authority.authority } : {}),
|
|
90
|
+
...(authority?.reviewedBy ? { reviewedBy: authority.reviewedBy } : {}),
|
|
70
91
|
};
|
|
71
92
|
if (idx >= 0) {
|
|
72
93
|
registry[idx] = entry;
|
|
@@ -106,10 +127,15 @@ export function getPoliciesForEvent(
|
|
|
106
127
|
return result;
|
|
107
128
|
}
|
|
108
129
|
|
|
109
|
-
|
|
130
|
+
/** `cli`: the agent this pass registers for, which scopes the Jev reviewer set. */
|
|
131
|
+
export function clearPolicies(cli?: string): void {
|
|
110
132
|
const g = globalThis as GlobalWithRegistry;
|
|
111
133
|
g[REGISTRY_KEY] = [];
|
|
112
134
|
setIndexCache(null);
|
|
135
|
+
// The reviewer set describes the policies that are about to be registered, so
|
|
136
|
+
// it is rebuilt with them. Dropping it here is also what keeps one read per
|
|
137
|
+
// evaluation instead of one per policy.
|
|
138
|
+
forgetEffectiveReviewerNames(cli);
|
|
113
139
|
}
|
|
114
140
|
|
|
115
141
|
/**
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much of what this machine enforces Jev is allowed to CLEAR — the
|
|
3
|
+
* diagnostic half of `policy-authority.ts`, and nothing else.
|
|
4
|
+
*
|
|
5
|
+
* ## The silence this exists to break
|
|
6
|
+
*
|
|
7
|
+
* Authority decides one thing: whether Jev may clear a regex policy's deny or
|
|
8
|
+
* instruct (`combine.ts`, which returns early unless the authority is
|
|
9
|
+
* `reviewable`). Absent means `hard`, and that default is right — it is what
|
|
10
|
+
* keeps an unknown pack, cloud or custom policy from being weakened by a
|
|
11
|
+
* classifier nobody asked about it.
|
|
12
|
+
*
|
|
13
|
+
* It is also completely silent. `authority` and `reviewedBy` reach a pack
|
|
14
|
+
* through its manifest, and the only thing that writes them there is
|
|
15
|
+
* `scripts/build-policy-pack.mjs`, which ships WITH this release. So a pack
|
|
16
|
+
* published before it declares none, every policy in it resolves to `hard`
|
|
17
|
+
* with nothing downgraded, and `warnAuthority` — which only speaks when a
|
|
18
|
+
* `reviewable` declaration was not honored — has nothing to say. The result a
|
|
19
|
+
* customer gets is the deny half of the two-tier evaluator working exactly as
|
|
20
|
+
* documented, the clear half unable to fire once, and no diagnostic anywhere:
|
|
21
|
+
* `jev status` says `on`, the fallback rate says the calls are being answered,
|
|
22
|
+
* and `cleared` says `nothing` forever.
|
|
23
|
+
*
|
|
24
|
+
* This module counts. It changes no policy's authority and no verdict, it is
|
|
25
|
+
* never imported from the hook path, and a machine with no `jev.json` never
|
|
26
|
+
* reaches a caller of it.
|
|
27
|
+
*
|
|
28
|
+
* ## What "enabled" means here
|
|
29
|
+
*
|
|
30
|
+
* The same thing it means in `handler.ts`, read from the same files, without
|
|
31
|
+
* loading or executing a policy:
|
|
32
|
+
*
|
|
33
|
+
* - **Installed packs** — each pack's manifest entries, narrowed by its
|
|
34
|
+
* `enabled` selection (absent means the whole pack). A pack's `clis`
|
|
35
|
+
* narrowing is NOT applied: there is no agent CLI in a status command, and
|
|
36
|
+
* the honest answer to "what could Jev clear on this machine" spans all of
|
|
37
|
+
* them.
|
|
38
|
+
* - **Builtins** — this build's catalog, under the same migration shim the
|
|
39
|
+
* handler applies: they enforce only while no pack is installed. The
|
|
40
|
+
* `alwaysOn` guard is counted always, because it registers always (and is
|
|
41
|
+
* hard always, so it can only ever lower the ratio).
|
|
42
|
+
* - **Cloud assignments** — the active deployment's records, whose authority is
|
|
43
|
+
* declared by whoever deployed them. One record per assignment; an artifact
|
|
44
|
+
* that registers several hooks is still one central decision.
|
|
45
|
+
*
|
|
46
|
+
* Two things are deliberately NOT counted, and `customFiles` is what says so
|
|
47
|
+
* out loud when it matters:
|
|
48
|
+
*
|
|
49
|
+
* - **Policies from the user's own files.** A custom hook declares its
|
|
50
|
+
* authority inside the module, so counting one means importing and running
|
|
51
|
+
* somebody's JavaScript — from a settings page, on every read. The count of
|
|
52
|
+
* custom policy FILES the hook loads (configured paths and the project and
|
|
53
|
+
* user convention files) is reported instead, the summary says in words that
|
|
54
|
+
* those policies were not counted, and no "never" is diagnosed beside them.
|
|
55
|
+
* - **A session pause.** It suspends local policy for minutes, and a warning
|
|
56
|
+
* about a policy set that is coming back shortly would be noise.
|
|
57
|
+
*/
|
|
58
|
+
import { readActiveCloudManagedPolicies } from "./cloud-managed-policies";
|
|
59
|
+
import { jevPacks } from "./effective-reviewers";
|
|
60
|
+
import { resolve } from "node:path";
|
|
61
|
+
import { discoverPolicyFiles } from "./custom-hooks-loader";
|
|
62
|
+
import { customPoliciesDir } from "./fp-home";
|
|
63
|
+
import { configuredCustomPolicyPaths, findProjectConfigDir, readMergedHooksConfig } from "./hooks-config";
|
|
64
|
+
import { hasInstalledPacks, readInstalledPacks } from "./pack-manifest";
|
|
65
|
+
import { resolvePolicyAuthority, SEMANTIC_REVIEWER_NAMES } from "./policy-authority";
|
|
66
|
+
import { POLICY_CATALOG } from "./policy-catalog";
|
|
67
|
+
import { normalizePolicyName } from "./policy-registry";
|
|
68
|
+
import type { HooksConfig } from "./policy-types";
|
|
69
|
+
// A CLI and dashboard module, never on the hook path, so it may ask the
|
|
70
|
+
// resolver itself (`pack-cli.ts` does the same).
|
|
71
|
+
import { semanticPoliciesFromPacks } from "./semantic/pack-policies";
|
|
72
|
+
|
|
73
|
+
/** Anything that carries an authority declaration: a catalog entry, a pack entry, a cloud record. */
|
|
74
|
+
export interface AuthorityRecord {
|
|
75
|
+
authority?: unknown;
|
|
76
|
+
reviewedBy?: unknown;
|
|
77
|
+
alwaysOn?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ReviewableCoverage {
|
|
81
|
+
/** Enabled policies whose authority could be read without running code. */
|
|
82
|
+
enabled: number;
|
|
83
|
+
/** Of those, the ones Jev may clear a deny or an instruct from. */
|
|
84
|
+
reviewable: number;
|
|
85
|
+
/**
|
|
86
|
+
* Custom policy files the hook loads — configured paths and the project and
|
|
87
|
+
* user convention files — whose policies are not in the counts above.
|
|
88
|
+
*/
|
|
89
|
+
customFiles: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The command that replaces a pack with one built by this release. */
|
|
93
|
+
export const RETAKE_PACK_COMMAND = "failproofai policies add FailproofAI/policies";
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Count a policy set by the authority it would REGISTER with —
|
|
97
|
+
* `resolvePolicyAuthority`, the rule `registerPolicy` applies — so this cannot
|
|
98
|
+
* report a clear that would not happen or hide one that would.
|
|
99
|
+
*
|
|
100
|
+
* Deliberately not `effectiveAuthority`, the looser §7 contract `jev-review.ts`
|
|
101
|
+
* asks at evaluation time. That one needs a single non-empty name and is right
|
|
102
|
+
* where it is asked, because by then the registry holds a `reviewedBy` that
|
|
103
|
+
* registration already cleaned, and on cleaned records the two rules agree.
|
|
104
|
+
* Nothing counted HERE has been through registration: these records are read
|
|
105
|
+
* straight off a pack manifest, this build's catalog and the cloud deployment.
|
|
106
|
+
* So a declaration naming a check this build does not have — `reviewedBy:
|
|
107
|
+
* ["future-check"]`, which is what a pack built against a NEWER semantic set
|
|
108
|
+
* looks like here — is reviewable to the loose rule and hard in the registry,
|
|
109
|
+
* and counting it would report a clear that can never happen while
|
|
110
|
+
* `reviewableProblem` stayed silent about the machine it exists to warn.
|
|
111
|
+
*/
|
|
112
|
+
export function countReviewable(
|
|
113
|
+
policies: Iterable<AuthorityRecord>,
|
|
114
|
+
/**
|
|
115
|
+
* The semantic checks that can be asked on this machine. Defaults to the
|
|
116
|
+
* compiled-in set; `surveyReviewableCoverage` passes the pack's when one
|
|
117
|
+
* declares its own, because otherwise this diagnostic reports "0 of 11
|
|
118
|
+
* reviewable" on exactly the machines the feature was built for — the ones
|
|
119
|
+
* running a pack that carries both tiers.
|
|
120
|
+
*/
|
|
121
|
+
knownReviewers?: ReadonlySet<string>,
|
|
122
|
+
): {
|
|
123
|
+
enabled: number;
|
|
124
|
+
reviewable: number;
|
|
125
|
+
} {
|
|
126
|
+
let enabled = 0;
|
|
127
|
+
let reviewable = 0;
|
|
128
|
+
for (const p of policies) {
|
|
129
|
+
enabled += 1;
|
|
130
|
+
if (resolvePolicyAuthority(p, knownReviewers).authority === "reviewable") reviewable += 1;
|
|
131
|
+
}
|
|
132
|
+
return { enabled, reviewable };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* What this machine's enabled policy set looks like to Jev. Reads three files
|
|
137
|
+
* and no policy: see the header for what is in the counts and what is not.
|
|
138
|
+
*
|
|
139
|
+
* Every source is wrapped, and an unreadable one contributes nothing rather
|
|
140
|
+
* than throwing — the same fail-open posture `handler.ts` takes for packs and
|
|
141
|
+
* cloud policies, for the same reason: this is a diagnostic, and one corrupt
|
|
142
|
+
* byte must not replace a settings page with an error boundary.
|
|
143
|
+
*/
|
|
144
|
+
export function surveyReviewableCoverage(cwd?: string): ReviewableCoverage {
|
|
145
|
+
const records: AuthorityRecord[] = [];
|
|
146
|
+
|
|
147
|
+
let packsInstalled = false;
|
|
148
|
+
/**
|
|
149
|
+
* The reviewers a pack brought with it. Collected from the SAME read as the
|
|
150
|
+
* policies rather than through `effectiveReviewerNames()`, which would re-read
|
|
151
|
+
* and re-verify every artifact for an answer already in hand — and would, for
|
|
152
|
+
* one read of a manifest being rewritten underneath, be able to disagree with
|
|
153
|
+
* the records counted here.
|
|
154
|
+
*
|
|
155
|
+
* A pack's `enabled` selection is deliberately not applied: it narrows which
|
|
156
|
+
* of its REGEX policies register, and its semantic set is not selectable.
|
|
157
|
+
*/
|
|
158
|
+
let reviewers: ReadonlySet<string> | undefined;
|
|
159
|
+
try {
|
|
160
|
+
packsInstalled = hasInstalledPacks();
|
|
161
|
+
const packs = readInstalledPacks().packs;
|
|
162
|
+
for (const pack of packs) {
|
|
163
|
+
const selected = pack.enabled;
|
|
164
|
+
records.push(...(selected ? pack.policies.filter((p) => selected.includes(p.name)) : pack.policies));
|
|
165
|
+
}
|
|
166
|
+
// The names of the questions a request will actually carry: only the packs
|
|
167
|
+
// whose checks take part (an observe pack's do not), minus a reserved or
|
|
168
|
+
// contested name AND minus a check the question budget drops — which the
|
|
169
|
+
// hook path's manifest-only `reviewerNamesFor` cannot see. Anything else and
|
|
170
|
+
// the panel and `jev status` promise a clear that cannot happen.
|
|
171
|
+
const asked = semanticPoliciesFromPacks(jevPacks(packs));
|
|
172
|
+
reviewers = asked.fromPack ? new Set(asked.policies.map((p) => p.name)) : SEMANTIC_REVIEWER_NAMES;
|
|
173
|
+
} catch {
|
|
174
|
+
// An unreadable manifest enforces nothing; `readInstalledPacks` already
|
|
175
|
+
// reports that to the hook log on the path that cares.
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let config: HooksConfig;
|
|
179
|
+
try {
|
|
180
|
+
config = readMergedHooksConfig(cwd);
|
|
181
|
+
} catch {
|
|
182
|
+
config = { enabledPolicies: [] };
|
|
183
|
+
}
|
|
184
|
+
// The migration shim, exactly as `handler.ts` applies it: this build's
|
|
185
|
+
// builtins enforce only until a pack is installed.
|
|
186
|
+
const legacyEnabled = new Set(packsInstalled ? [] : config.enabledPolicies.map(normalizePolicyName));
|
|
187
|
+
for (const policy of POLICY_CATALOG) {
|
|
188
|
+
if (policy.alwaysOn || legacyEnabled.has(normalizePolicyName(policy.name))) records.push(policy);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
for (const assignment of readActiveCloudManagedPolicies()) {
|
|
193
|
+
records.push({ authority: assignment.authority, reviewedBy: assignment.reviewedBy });
|
|
194
|
+
}
|
|
195
|
+
} catch {
|
|
196
|
+
// Same fail-open as the handler's own read of this file.
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Every file `loadAllCustomHooks` would load, by resolved path so a file
|
|
200
|
+
// both named and discovered (or a project root that IS home) counts once.
|
|
201
|
+
let customFiles = 0;
|
|
202
|
+
try {
|
|
203
|
+
// Relative paths against the project root, as the loader resolves them.
|
|
204
|
+
const projectRoot = findProjectConfigDir(cwd ?? process.cwd());
|
|
205
|
+
const files = new Set(configuredCustomPolicyPaths(config).map((p) => resolve(projectRoot, p)));
|
|
206
|
+
if (config.customPoliciesEnabled !== false) {
|
|
207
|
+
const projectDir = resolve(projectRoot, ".failproofai", "policies");
|
|
208
|
+
for (const dir of [projectDir, customPoliciesDir()]) for (const f of discoverPolicyFiles(dir)) files.add(f);
|
|
209
|
+
}
|
|
210
|
+
customFiles = files.size;
|
|
211
|
+
} catch {
|
|
212
|
+
customFiles = 0;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return { ...countReviewable(records, reviewers), customFiles };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* The one line both surfaces show: the count, in the words `jev status` and the
|
|
220
|
+
* dashboard panel must agree on. A non-zero count is worth saying too — it is
|
|
221
|
+
* how someone learns how much of their policy set Jev can act on at all.
|
|
222
|
+
*/
|
|
223
|
+
export function reviewableSummary(coverage: ReviewableCoverage): string {
|
|
224
|
+
const { enabled, reviewable } = coverage;
|
|
225
|
+
// Said out loud rather than folded into the number, because a custom policy
|
|
226
|
+
// CAN be reviewable and this count would not know: reading that declaration
|
|
227
|
+
// means importing and running the file it lives in.
|
|
228
|
+
const tail = coverage.customFiles > 0 ? " (policies from your own files are not counted)" : "";
|
|
229
|
+
if (enabled === 0) return `No policies are enabled here, so there is nothing for Jev to clear${tail}.`;
|
|
230
|
+
const noun = enabled === 1 ? "1 enabled policy is" : `${enabled} enabled policies are`;
|
|
231
|
+
if (reviewable === 0) return `0 of ${noun} reviewable${tail}.`;
|
|
232
|
+
return `${reviewable} of ${noun} reviewable: Jev may clear a deny or an instruction from those, and from no others${tail}.`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Why Jev can never clear anything here, and what fixes it — or null when it
|
|
237
|
+
* can clear something, which needs no explanation.
|
|
238
|
+
*
|
|
239
|
+
* It states the observation before naming the usual cause, because the cause is
|
|
240
|
+
* the usual one and not the only one: a machine can also reach zero by enabling
|
|
241
|
+
* only hard policies, or by having nothing but the self-protection guard. The
|
|
242
|
+
* remedy is the same in each case, and it is one command.
|
|
243
|
+
*
|
|
244
|
+
* Nothing is diagnosed for an empty policy set: there is no clear to lose, and
|
|
245
|
+
* an authority warning to someone who enforces nothing answers a question they
|
|
246
|
+
* did not ask.
|
|
247
|
+
*/
|
|
248
|
+
export function reviewableProblem(coverage: ReviewableCoverage): string | null {
|
|
249
|
+
// Policies from the user's own files were not counted and may be reviewable,
|
|
250
|
+
// so "never" cannot be said honestly; the summary already says what was skipped.
|
|
251
|
+
if (coverage.enabled === 0 || coverage.reviewable > 0 || coverage.customFiles > 0) return null;
|
|
252
|
+
return (
|
|
253
|
+
"Jev can add a deny or an instruction on this machine, but it can never clear one. " +
|
|
254
|
+
"No enabled policy is marked reviewable — a policy pack published before this release carries no such marks — " +
|
|
255
|
+
`so re-take the pack (\`${RETAKE_PACK_COMMAND}\`) to get a marked copy, ` +
|
|
256
|
+
"or enforce this build's builtin policies, which carry them."
|
|
257
|
+
);
|
|
258
|
+
}
|
|
@@ -43,6 +43,54 @@ export interface RegisteredPolicy {
|
|
|
43
43
|
* the user's OWN configured `policyParams` for it, not merely the defaults.
|
|
44
44
|
*/
|
|
45
45
|
params?: PolicyParamsSchema;
|
|
46
|
+
/** Whether Jev may clear this policy's deny/instruct; see {@link effectiveAuthority}. */
|
|
47
|
+
authority?: PolicyAuthority;
|
|
48
|
+
/**
|
|
49
|
+
* The semantic policies (`src/hooks/semantic/policies.ts`) that must all be
|
|
50
|
+
* asked, and each clear (see {@link PolicyAuthority}), before Jev clears this
|
|
51
|
+
* policy.
|
|
52
|
+
*/
|
|
53
|
+
reviewedBy?: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Who has the last word on a policy's deny or instruct when Jev is configured.
|
|
58
|
+
*
|
|
59
|
+
* - `hard`: final. Jev can never clear it.
|
|
60
|
+
* - `reviewable`: Jev may clear it, but only through the semantic policies
|
|
61
|
+
* named in `reviewedBy`, and only when every one of them was actually asked
|
|
62
|
+
* and each answered `none`, `overridden`, or a deny the human's task
|
|
63
|
+
* softened to a warning (`combine.ts`, "A check that fired without consent
|
|
64
|
+
* keeps the floor").
|
|
65
|
+
* A named check that was NOT asked always keeps the verdict standing.
|
|
66
|
+
*/
|
|
67
|
+
export type PolicyAuthority = "hard" | "reviewable";
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The authority a policy actually has. `reviewable` only when it is declared
|
|
71
|
+
* `reviewable`, names at least one semantic policy in `reviewedBy`, and is not
|
|
72
|
+
* `alwaysOn`. Anything else — absent, invalid, an empty `reviewedBy`, the
|
|
73
|
+
* self-protection guard — is `hard`, so an unknown custom, cloud or third-party
|
|
74
|
+
* policy can never be weakened by Jev.
|
|
75
|
+
*
|
|
76
|
+
* This is the §7 contract every task builds against, and it is deliberately
|
|
77
|
+
* the looser of two rules: one usable name is enough here. REGISTRATION is
|
|
78
|
+
* stricter — `resolvePolicyAuthority` in `policy-authority.ts` makes the whole
|
|
79
|
+
* declaration hard if any entry is malformed or is not a semantic policy this
|
|
80
|
+
* build has, and that is what `registerPolicy` stores. So a registered policy's
|
|
81
|
+
* `reviewedBy` is already clean, and the two rules agree on everything that
|
|
82
|
+
* reaches the registry.
|
|
83
|
+
*/
|
|
84
|
+
export function effectiveAuthority(p: {
|
|
85
|
+
authority?: unknown;
|
|
86
|
+
reviewedBy?: unknown;
|
|
87
|
+
alwaysOn?: boolean;
|
|
88
|
+
}): PolicyAuthority {
|
|
89
|
+
if (p.alwaysOn === true) return "hard";
|
|
90
|
+
if (p.authority !== "reviewable") return "hard";
|
|
91
|
+
if (!Array.isArray(p.reviewedBy)) return "hard";
|
|
92
|
+
const named = p.reviewedBy.filter((n) => typeof n === "string" && n.length > 0);
|
|
93
|
+
return named.length > 0 ? "reviewable" : "hard";
|
|
46
94
|
}
|
|
47
95
|
|
|
48
96
|
export interface PolicyParamsSchema {
|
|
@@ -89,6 +137,10 @@ export interface BuiltinPolicyDefinition {
|
|
|
89
137
|
* secondary line in the audit report. e.g. "Could leak code from neighboring
|
|
90
138
|
* repos to the model." */
|
|
91
139
|
impact?: string;
|
|
140
|
+
/** See {@link PolicyAuthority}. Absent means `hard`. */
|
|
141
|
+
authority?: PolicyAuthority;
|
|
142
|
+
/** See {@link RegisteredPolicy.reviewedBy}. */
|
|
143
|
+
reviewedBy?: string[];
|
|
92
144
|
}
|
|
93
145
|
|
|
94
146
|
export interface CustomHook {
|
|
@@ -98,6 +150,82 @@ export interface CustomHook {
|
|
|
98
150
|
events?: HookEventType[];
|
|
99
151
|
};
|
|
100
152
|
fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
|
|
153
|
+
/**
|
|
154
|
+
* See {@link PolicyAuthority}. Absent means `hard`.
|
|
155
|
+
*
|
|
156
|
+
* Honored for the user's own local policy files (explicit paths and
|
|
157
|
+
* `.failproofai/policies/`). For a pack policy the pack's MANIFEST decides,
|
|
158
|
+
* and for a cloud-managed one the cloud ARTIFACT record does — the same split
|
|
159
|
+
* as `params`, so the declaration a user reviewed in a listing is the one
|
|
160
|
+
* that takes effect.
|
|
161
|
+
*/
|
|
162
|
+
authority?: PolicyAuthority;
|
|
163
|
+
/** See {@link RegisteredPolicy.reviewedBy}. */
|
|
164
|
+
reviewedBy?: string[];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The tool classes a semantic policy may be asked about.
|
|
169
|
+
*
|
|
170
|
+
* A structural copy of `ToolClass` in `src/hooks/semantic/types.ts`, and
|
|
171
|
+
* deliberately not an import of it. This module is the public API's type
|
|
172
|
+
* surface — every custom policy file and every pack entry imports it — and the
|
|
173
|
+
* semantic modules must stay off the import graph of a machine with no
|
|
174
|
+
* `jev.json` (see `precondition-names.ts` for what that costs when it slips).
|
|
175
|
+
* A type import would be erased, but the two lists still have to agree, so
|
|
176
|
+
* `__tests__/hooks/semantic/pack-semantic-registry.test.ts` pins them.
|
|
177
|
+
*/
|
|
178
|
+
export type SemanticToolClass = "shell" | "write" | "read" | "network" | "other";
|
|
179
|
+
|
|
180
|
+
/** One yes/no question in a semantic policy, as a pack declares it. */
|
|
181
|
+
export interface SemanticProbeDeclaration {
|
|
182
|
+
/** Lowercase slug, unique within the policy. The answer map is keyed `<policy>.<id>`. */
|
|
183
|
+
id: string;
|
|
184
|
+
instructions: string;
|
|
185
|
+
criteria?: { true: string; false: string };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* A semantic (Jev) policy as its author DECLARES it — a question set, not code.
|
|
190
|
+
*
|
|
191
|
+
* The compiled-in equivalent is `SemanticPolicy` in `semantic/types.ts`, and
|
|
192
|
+
* the one difference is the whole reason both exist: there, `precondition` is a
|
|
193
|
+
* function over the computed facts; here it is the NAME of one, because a
|
|
194
|
+
* declaration has to survive a trip through a JSON manifest and because a
|
|
195
|
+
* downloaded artifact must not hand this process an expression to evaluate on
|
|
196
|
+
* every tool call. `semantic/preconditions.ts` binds the name to its predicate.
|
|
197
|
+
*
|
|
198
|
+
* There is no `fn` and no `match`: a semantic policy never executes locally and
|
|
199
|
+
* is never selected by event or tool name — `appliesTo` and `precondition`
|
|
200
|
+
* decide what it is asked about, and Jev answers it. That is also why it is
|
|
201
|
+
* registered through `semanticPolicies`, its own namespace, rather than as a
|
|
202
|
+
* variant of `customPolicies.add`.
|
|
203
|
+
*/
|
|
204
|
+
export interface SemanticPolicyDeclaration {
|
|
205
|
+
/** Short slug. Reported as `semantic/<name>`, and what a `reviewedBy` names. */
|
|
206
|
+
name: string;
|
|
207
|
+
/** Past-tense phrase for what was caught, e.g. "Deleted something irreplaceable". */
|
|
208
|
+
title: string;
|
|
209
|
+
appliesTo: SemanticToolClass[];
|
|
210
|
+
/** `deny` blocks on strong evidence and warns on moderate; `instruct` only ever warns. */
|
|
211
|
+
mode: "deny" | "instruct";
|
|
212
|
+
/**
|
|
213
|
+
* Whether the human's own explicit request may clear this policy.
|
|
214
|
+
*
|
|
215
|
+
* Required, with no default anywhere in the stack. It is the field that
|
|
216
|
+
* decides whether a prompt injection can talk its way past the policy, and a
|
|
217
|
+
* default for it would be a security decision made by absence — the author
|
|
218
|
+
* would never learn which way it went.
|
|
219
|
+
*/
|
|
220
|
+
userCanOverride: boolean;
|
|
221
|
+
/** A name from `PACK_PRECONDITION_NAMES`. Absent, or `"always"`, means no precondition. */
|
|
222
|
+
precondition?: string;
|
|
223
|
+
/** Every probe must hold for the policy to fire (conjunction). 1–6 of them. */
|
|
224
|
+
probes: SemanticProbeDeclaration[];
|
|
225
|
+
/** If this holds, the policy does not fire — the documented exceptions. */
|
|
226
|
+
exempt?: SemanticProbeDeclaration;
|
|
227
|
+
/** Shown to the agent when the policy fires. */
|
|
228
|
+
guidance: string;
|
|
101
229
|
}
|
|
102
230
|
|
|
103
231
|
export interface LlmConfig {
|