failproofai 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- 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]__02npjtd._.js → [root-of-the-server]__056wjo4._.js} +3 -3
- 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]__0p-5p8u._.js → [root-of-the-server]__0n0xg95._.js} +3 -3
- 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]__013jr2b._.js → [root-of-the-server]__0rwtwpm._.js} +3 -3
- 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]__0da85px._.js → [root-of-the-server]__11mayhe._.js} +3 -3
- 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]__13t1zkw._.js +3 -0
- 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]__0ftmoxc._.js → [root-of-the-server]__1pprgri._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__1q4p5b8._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_166t73i._.js → _0-vcssj._.js} +1 -1
- 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/_0uyu3jf._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_13kfn90._.js +23 -0
- 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_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/06dnzbolj00mc.js +6 -0
- package/.next/standalone/.next/static/chunks/0bhidk90e-07f.css +2 -0
- package/.next/standalone/.next/static/chunks/{2mdh397ghgnvv.js → 0m-9d6yn9hx4j.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0__8a7m868fvf.js → 0wbjy0zo-m7is.js} +1 -1
- package/.next/standalone/.next/static/chunks/16f3fa-lx38hk.js +1 -0
- package/.next/standalone/.next/static/chunks/{0o6qlkgubtoex.js → 21uv-uusw329x.js} +1 -1
- package/.next/standalone/.next/static/chunks/2g2tki08kdhie.js +1 -0
- package/.next/standalone/.next/static/chunks/2qdpj67x6ifk_.js +69 -0
- package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +1 -0
- package/.next/standalone/.next/static/chunks/3-nbtkhg9y-1j.js +1 -0
- package/.next/standalone/.next/static/chunks/355km0ihuqo1p.js +1 -0
- package/.next/standalone/.next/static/chunks/{13i7-9is-vhys.js → 3c3qbmosdjl6w.js} +1 -1
- 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/CHANGELOG.md +18 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +0 -274
- 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 +18599 -9478
- package/dist/index.js +19 -1
- package/dist/worker.mjs +10500 -3773
- 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 +513 -0
- package/src/hooks/semantic/envelope.ts +1255 -0
- package/src/hooks/semantic/evaluator.ts +556 -0
- package/src/hooks/semantic/facts.ts +387 -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 +162 -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]__01wy8d-._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bd3mje._.js +0 -3
- 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]__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]__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/_1-i_gzc._.js +0 -23
- 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 → 5yKM8NoTOpUI0MoQl8eo5}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy authority: who has the last word on a policy's deny or instruct once
|
|
3
|
+
* Jev is configured. See {@link PolicyAuthority} for the two values and
|
|
4
|
+
* `docs/policies/authority.mdx` for the builtin table.
|
|
5
|
+
*
|
|
6
|
+
* Every route a policy arrives by — a builtin, the user's own policy file, an
|
|
7
|
+
* installed pack, a cloud assignment — declares its authority somewhere
|
|
8
|
+
* different. This module is the one place those declarations are read and
|
|
9
|
+
* judged, so the rule cannot drift between them:
|
|
10
|
+
*
|
|
11
|
+
* - `hard` is the default and the answer to anything unclear. Absent, a value
|
|
12
|
+
* that is not one of the two, a `reviewedBy` that is empty or malformed or
|
|
13
|
+
* names a check this build does not have, or an `alwaysOn` policy: all hard.
|
|
14
|
+
* - `reviewable` means Jev may clear the policy's verdict — and only through the
|
|
15
|
+
* semantic policies it names, every one of which must have been asked.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here decides anything at evaluation time. It resolves a declaration
|
|
18
|
+
* once, at registration, and `registerPolicy` stores the result, so what sits in
|
|
19
|
+
* the registry is already the effective authority.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import { jevConfigFile } from "./fp-home";
|
|
23
|
+
import { hookLogWarn } from "./hook-logger";
|
|
24
|
+
import { effectiveAuthority } from "./policy-types";
|
|
25
|
+
import type { CustomHook, PolicyAuthority, PolicyCatalogEntry } from "./policy-types";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A declaration as it arrives, before anything has vouched for it. Fields are
|
|
29
|
+
* `unknown` because three of the four sources are files on disk written by
|
|
30
|
+
* somebody else.
|
|
31
|
+
*/
|
|
32
|
+
export interface AuthorityDeclaration {
|
|
33
|
+
authority?: unknown;
|
|
34
|
+
reviewedBy?: unknown;
|
|
35
|
+
/** The self-protection guard. Always hard, whatever else it says. */
|
|
36
|
+
alwaysOn?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The shape-valid authority fields a parsed record (a pack entry, a cloud assignment) carries. */
|
|
40
|
+
export interface AuthorityFields {
|
|
41
|
+
authority?: PolicyAuthority;
|
|
42
|
+
reviewedBy?: string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** What a registered policy carries: already judged, and honest to its type. */
|
|
46
|
+
export interface ResolvedAuthority {
|
|
47
|
+
authority: PolicyAuthority;
|
|
48
|
+
/** Present exactly when `authority` is `reviewable`. Deduplicated, in declared order. */
|
|
49
|
+
reviewedBy?: string[];
|
|
50
|
+
/**
|
|
51
|
+
* Why a `reviewable` declaration was not honored, for a warning. Absent when
|
|
52
|
+
* nothing asked for `reviewable` — a policy that is simply hard is not news.
|
|
53
|
+
*/
|
|
54
|
+
downgraded?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The names `reviewedBy` may use: the semantic policies in
|
|
59
|
+
* `src/hooks/semantic/policies.ts`. Not the probes (`INJECTION_PROBE`,
|
|
60
|
+
* `SCOPE_PROBE`, the task probes) — those are inputs to Jev's decision, not
|
|
61
|
+
* checks a regex verdict can be cleared by.
|
|
62
|
+
*
|
|
63
|
+
* Written out rather than read off `SEMANTIC_POLICIES`, and pinned to it by
|
|
64
|
+
* `policy-authority.test.ts`. The registry imports this module, so a runtime
|
|
65
|
+
* import of the semantic policies would load all sixteen of Jev's prompts on
|
|
66
|
+
* every hook event of a machine that never configured Jev, and bundle them into
|
|
67
|
+
* every pack artifact that registers a policy.
|
|
68
|
+
*/
|
|
69
|
+
export const SEMANTIC_POLICY_NAMES = [
|
|
70
|
+
"destructive-deletion",
|
|
71
|
+
"production-infra-change",
|
|
72
|
+
"git-history-rewrite",
|
|
73
|
+
"push-to-protected-branch",
|
|
74
|
+
"commit-on-protected-branch",
|
|
75
|
+
"secret-exposure",
|
|
76
|
+
"credential-exfiltration",
|
|
77
|
+
"remote-code-execution",
|
|
78
|
+
"privilege-escalation",
|
|
79
|
+
"database-destruction",
|
|
80
|
+
"read-outside-workspace",
|
|
81
|
+
"agent-config-tampering",
|
|
82
|
+
"system-modification",
|
|
83
|
+
"env-secrets-dump",
|
|
84
|
+
"external-destructive-action",
|
|
85
|
+
"external-data-egress",
|
|
86
|
+
] as const;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The compiled-in reviewer set, and the DEFAULT rather than the only one.
|
|
90
|
+
*
|
|
91
|
+
* A pack that declares its own `semantic` entries replaces
|
|
92
|
+
* `SEMANTIC_POLICIES` wholesale on the machine that installed it, so the names
|
|
93
|
+
* a `reviewedBy` may use there are the pack's. Callers that know which set is
|
|
94
|
+
* live pass it (`effectiveReviewerNames()` in `effective-reviewers.ts`, which reads
|
|
95
|
+
* the manifest and imports nothing from `semantic/`); everyone else gets this
|
|
96
|
+
* one, which is what a machine with no pack runs.
|
|
97
|
+
*/
|
|
98
|
+
export const SEMANTIC_REVIEWER_NAMES: ReadonlySet<string> = new Set(SEMANTIC_POLICY_NAMES);
|
|
99
|
+
|
|
100
|
+
const isName = (n: unknown): n is string => typeof n === "string" && n.length > 0;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Judge one declaration.
|
|
104
|
+
*
|
|
105
|
+
* Stricter than `effectiveAuthority`, which is the §7 contract and needs only
|
|
106
|
+
* one usable name: here EVERY entry must be a semantic policy this build has,
|
|
107
|
+
* and anything else makes the whole declaration hard rather than being dropped.
|
|
108
|
+
* `reviewedBy` is a conjunction, so dropping a name the author wrote — a typo, a
|
|
109
|
+
* stray `7` — would let Jev clear the policy on fewer checks than they asked
|
|
110
|
+
* for. It is also the safe direction for version skew: a pack built against a
|
|
111
|
+
* newer semantic set, installed on an older build, enforces as hard rather than
|
|
112
|
+
* as reviewable-by-less.
|
|
113
|
+
*
|
|
114
|
+
* What this returns is what `registerPolicy` stores, so a registered policy's
|
|
115
|
+
* `reviewedBy` is always clean and the two functions agree on it.
|
|
116
|
+
*
|
|
117
|
+
* @param knownReviewers - the semantic policies that CAN be asked on this
|
|
118
|
+
* machine. Defaults to the compiled-in set, which is what runs until a pack
|
|
119
|
+
* ships its own; see {@link SEMANTIC_REVIEWER_NAMES}. It is a parameter rather
|
|
120
|
+
* than a lookup because this module is imported by the registry, and reading
|
|
121
|
+
* which set is live means reading a file — a cost registration is willing to
|
|
122
|
+
* pay once and this judgement must not pay per call.
|
|
123
|
+
*/
|
|
124
|
+
export function resolvePolicyAuthority(
|
|
125
|
+
decl: AuthorityDeclaration | undefined,
|
|
126
|
+
knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
|
|
127
|
+
/** Names left out of `knownReviewers` because packs declare them differently, with those packs. */
|
|
128
|
+
contested?: ReadonlyMap<string, string[]>,
|
|
129
|
+
): ResolvedAuthority {
|
|
130
|
+
const declaredReviewable = decl?.authority === "reviewable";
|
|
131
|
+
if (!decl || effectiveAuthority(decl) === "hard") {
|
|
132
|
+
if (!declaredReviewable) return { authority: "hard" };
|
|
133
|
+
return { authority: "hard", downgraded: whyHard(decl!) };
|
|
134
|
+
}
|
|
135
|
+
const names = decl.reviewedBy as unknown[];
|
|
136
|
+
if (!names.every(isName)) {
|
|
137
|
+
return { authority: "hard", downgraded: "reviewedBy is not a list of semantic policy names" };
|
|
138
|
+
}
|
|
139
|
+
const unknown = names.filter((n) => !knownReviewers.has(n));
|
|
140
|
+
if (unknown.length > 0) {
|
|
141
|
+
return { authority: "hard", downgraded: `reviewedBy names ${unknown.map((n) => whyUnknown(n, knownReviewers, contested)).join("; ")}` };
|
|
142
|
+
}
|
|
143
|
+
return { authority: "reviewable", reviewedBy: [...new Set(names)] };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The rule that kept one name out. "Not in this build" is only true of the
|
|
148
|
+
* compiled-in set: a pack's own checks, or a name two packs disagree on, is a
|
|
149
|
+
* different reason, and the author reading it has a different fix.
|
|
150
|
+
*/
|
|
151
|
+
function whyUnknown(name: string, known: ReadonlySet<string>, contested?: ReadonlyMap<string, string[]>): string {
|
|
152
|
+
// Quoted with JSON.stringify: a pack's name reaches the hook's stderr, so a
|
|
153
|
+
// control character in it must not reach the terminal raw.
|
|
154
|
+
const quoted = JSON.stringify(name);
|
|
155
|
+
const claimants = contested?.get(name);
|
|
156
|
+
if (claimants) return `${quoted}, which packs ${claimants.join(" and ")} declare differently, so it is asked for neither`;
|
|
157
|
+
if (known === SEMANTIC_REVIEWER_NAMES) return `${quoted}, which is not a semantic policy in this build`;
|
|
158
|
+
const sorted = [...known].sort();
|
|
159
|
+
const listed = sorted.length > 6 ? `${sorted.slice(0, 6).join(", ")} and ${sorted.length - 6} more` : sorted.join(", ");
|
|
160
|
+
return `${quoted}, which is not among the Jev checks it is judged against (${listed})`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function whyHard(decl: AuthorityDeclaration): string {
|
|
164
|
+
if (decl.alwaysOn === true) return "it is alwaysOn, and the self-protection guard is never reviewable";
|
|
165
|
+
if (!Array.isArray(decl.reviewedBy) || decl.reviewedBy.length === 0) {
|
|
166
|
+
return "reviewedBy does not name any semantic policy";
|
|
167
|
+
}
|
|
168
|
+
return "reviewedBy is not a list of semantic policy names";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The shape-valid authority fields of a serialized policy entry, for parsers.
|
|
173
|
+
*
|
|
174
|
+
* Invalid fields are DROPPED, never thrown on. A pack or cloud deployment that
|
|
175
|
+
* is refused over a typo in an optional field fails closed and denies every
|
|
176
|
+
* tool call its policies cover; dropping the field makes that one policy hard,
|
|
177
|
+
* which is the default the typo would have produced at registration anyway.
|
|
178
|
+
* Names are not checked against the semantic set here — that is a property of
|
|
179
|
+
* the build reading the entry, not of the entry, and is judged at registration.
|
|
180
|
+
*/
|
|
181
|
+
export function authorityFieldsOf(raw: Record<string, unknown>): AuthorityFields {
|
|
182
|
+
const out: AuthorityFields = {};
|
|
183
|
+
if (raw.authority === "hard" || raw.authority === "reviewable") out.authority = raw.authority;
|
|
184
|
+
const list = raw.reviewedBy;
|
|
185
|
+
if (Array.isArray(list) && list.length > 0 && list.every(isName)) {
|
|
186
|
+
out.reviewedBy = [...(list as string[])];
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Why a declaration cannot be PUBLISHED as written, or `undefined` when it can.
|
|
193
|
+
*
|
|
194
|
+
* For build steps — `scripts/build-policy-pack.mjs` and `failproofai publish`.
|
|
195
|
+
* The loaders drop a malformed field and registration downgrades a refused
|
|
196
|
+
* `reviewable`, both toward hard and both only as a warning, because by then the
|
|
197
|
+
* pack is installed and refusing it would fail it closed. At build time nothing
|
|
198
|
+
* is installed yet, so refusing costs nobody anything, while shipping the
|
|
199
|
+
* declaration would make the policy silently hard on every machine that
|
|
200
|
+
* installs it — a decision its author made, quietly not taking effect.
|
|
201
|
+
*
|
|
202
|
+
* An empty `reviewedBy` on a hard policy is not a problem: it says nothing.
|
|
203
|
+
*/
|
|
204
|
+
export function authorityProblem(
|
|
205
|
+
decl: AuthorityDeclaration,
|
|
206
|
+
/**
|
|
207
|
+
* The reviewers the pack being built will SHIP WITH — its own `semantic`
|
|
208
|
+
* entries when it declares any, this build's set otherwise. A pack that
|
|
209
|
+
* carries both halves of the two-tier set names its own checks, and refusing
|
|
210
|
+
* that would make the feature unpublishable by the tool that implements it.
|
|
211
|
+
*/
|
|
212
|
+
knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
|
|
213
|
+
): string | undefined {
|
|
214
|
+
if (decl.authority !== undefined && decl.authority !== "hard" && decl.authority !== "reviewable") {
|
|
215
|
+
const t = typeof decl.authority;
|
|
216
|
+
return `authority must be "hard" or "reviewable", and is ${t === "string" ? JSON.stringify(decl.authority) : `${/^[aeiou]/.test(t) ? "an" : "a"} ${t}`}`;
|
|
217
|
+
}
|
|
218
|
+
if (decl.reviewedBy !== undefined && !(Array.isArray(decl.reviewedBy) && decl.reviewedBy.every(isName))) {
|
|
219
|
+
return "reviewedBy must be a list of semantic policy names";
|
|
220
|
+
}
|
|
221
|
+
const { downgraded } = resolvePolicyAuthority(decl, knownReviewers);
|
|
222
|
+
return downgraded ? `authority "reviewable" was refused — ${downgraded}` : undefined;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The authority fields a pack MANIFEST should carry for one entry: resolved, as
|
|
227
|
+
* the registry will store them, so the manifest says exactly what takes effect.
|
|
228
|
+
* Throws, naming the entry, on anything {@link authorityProblem} refuses.
|
|
229
|
+
*/
|
|
230
|
+
export function manifestAuthority(
|
|
231
|
+
entry: AuthorityDeclaration & { name: string },
|
|
232
|
+
knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
|
|
233
|
+
): {
|
|
234
|
+
authority: PolicyAuthority;
|
|
235
|
+
reviewedBy?: string[];
|
|
236
|
+
} {
|
|
237
|
+
const problem = authorityProblem(entry, knownReviewers);
|
|
238
|
+
if (problem) throw new Error(`${entry.name}: ${problem}`);
|
|
239
|
+
const { authority, reviewedBy } = resolvePolicyAuthority(entry, knownReviewers);
|
|
240
|
+
return reviewedBy ? { authority, reviewedBy } : { authority };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* One authority for several declarations that land on ONE registration.
|
|
245
|
+
*
|
|
246
|
+
* Artifacts are content-addressed, so two cloud assignments or two packs whose
|
|
247
|
+
* code is byte-identical load as one policy (the collapse in
|
|
248
|
+
* `custom-hooks-loader.ts`). Keeping one of their declarations would let the
|
|
249
|
+
* order of `active.json` or `installed.json` decide — and let one pack's
|
|
250
|
+
* manifest, or one team's assignment, make another's policy reviewable.
|
|
251
|
+
*
|
|
252
|
+
* So it resolves toward HARD, the way the collapse resolves the effect toward
|
|
253
|
+
* enforce: reviewable only when EVERY declaration resolves to reviewable, and
|
|
254
|
+
* then through the UNION of their checks (more checks that must all come back
|
|
255
|
+
* clear is stricter, never weaker).
|
|
256
|
+
*
|
|
257
|
+
* ## What the merged record may carry, and why it is the RESOLUTION
|
|
258
|
+
*
|
|
259
|
+
* Nothing here copies a declaration through. It used to keep the first one that
|
|
260
|
+
* was not reviewable, so that a refused `reviewable` would be reported again at
|
|
261
|
+
* registration — and that was the hole: a declaration is only ever resolved
|
|
262
|
+
* against the reviewer set of whoever is looking, so a `reviewable` naming a
|
|
263
|
+
* PACK's own check resolved to hard here, against the builtin set, and was
|
|
264
|
+
* copied forward verbatim. `registerPolicy` then resolved that same raw
|
|
265
|
+
* declaration against `effectiveReviewerNames()`, which does have the pack's
|
|
266
|
+
* check — and the policy registered reviewable, with a hard peer behind the same
|
|
267
|
+
* artifact overruled by nothing more than which pack was listed first.
|
|
268
|
+
*
|
|
269
|
+
* Two changes close it. The reviewer set is now a PARAMETER, so the merge judges
|
|
270
|
+
* by the same names registration will; and a non-reviewable merge emits
|
|
271
|
+
* `{ authority: "hard" }` — the resolved value — rather than the fields it was
|
|
272
|
+
* asked for. Either alone would have been enough for the case above; both,
|
|
273
|
+
* because the first is an agreement between two callers and the second holds
|
|
274
|
+
* whether or not they agree.
|
|
275
|
+
*
|
|
276
|
+
* The reason a refused declaration carried is not lost: it comes back as
|
|
277
|
+
* `refused`, for the caller to say through {@link refusedAuthorityWarning} at
|
|
278
|
+
* the point where it knows which artifact and which packs are involved.
|
|
279
|
+
*
|
|
280
|
+
* Returns `record` itself when its own fields already say that, and a copy with
|
|
281
|
+
* only the two authority fields replaced otherwise. `overruled` is true when
|
|
282
|
+
* some declaration asked for reviewable, validly, and did not get it.
|
|
283
|
+
*
|
|
284
|
+
* @param knownReviewers - the checks that can be asked on this machine. Callers
|
|
285
|
+
* that merge what will be REGISTERED must pass `effectiveReviewerNames()`;
|
|
286
|
+
* the default is this build's compiled-in set, which is what a machine with no
|
|
287
|
+
* pack runs.
|
|
288
|
+
*/
|
|
289
|
+
export function withMergedAuthority<T extends AuthorityFields>(
|
|
290
|
+
record: T,
|
|
291
|
+
declarations: ReadonlyArray<AuthorityFields>,
|
|
292
|
+
knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
|
|
293
|
+
): { merged: T; overruled: boolean; refused?: string } {
|
|
294
|
+
const resolved = declarations.map((d) => resolvePolicyAuthority(d, knownReviewers));
|
|
295
|
+
const allReviewable = resolved.length > 0 && resolved.every((r) => r.authority === "reviewable");
|
|
296
|
+
// The declaration that decided it is hard. Its own fields are not carried —
|
|
297
|
+
// only whether it said anything at all, because a record that declared
|
|
298
|
+
// nothing is already hard and rewriting it to say so would touch a record the
|
|
299
|
+
// collapse has no business touching.
|
|
300
|
+
const decided = declarations[resolved.findIndex((r) => r.authority !== "reviewable")] ?? {};
|
|
301
|
+
const fields: AuthorityFields = allReviewable
|
|
302
|
+
? { authority: "reviewable", reviewedBy: [...new Set(resolved.flatMap((r) => r.reviewedBy ?? []))] }
|
|
303
|
+
: decided.authority === undefined
|
|
304
|
+
? {}
|
|
305
|
+
: { authority: "hard" };
|
|
306
|
+
const overruled = !allReviewable && resolved.some((r) => r.authority === "reviewable");
|
|
307
|
+
const refused = resolved.find((r) => r.downgraded !== undefined)?.downgraded;
|
|
308
|
+
const extra = refused === undefined ? {} : { refused };
|
|
309
|
+
const same =
|
|
310
|
+
record.authority === fields.authority &&
|
|
311
|
+
JSON.stringify(record.reviewedBy) === JSON.stringify(fields.reviewedBy);
|
|
312
|
+
if (same) return { merged: record, overruled, ...extra };
|
|
313
|
+
const { authority: _a, reviewedBy: _r, ...rest } = record;
|
|
314
|
+
return { merged: { ...rest, ...fields } as T, overruled, ...extra };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* The warning for a `reviewable` declaration that was not honored. One
|
|
319
|
+
* phrasing, wherever it is noticed — registration for a policy that reaches it
|
|
320
|
+
* with its declaration intact, and the loader for one the collapse hardened
|
|
321
|
+
* before it got there.
|
|
322
|
+
*/
|
|
323
|
+
export function refusedAuthorityWarning(subject: string, reason: string): string {
|
|
324
|
+
return `${subject} asks to be reviewable, but ${reason} — it stays hard`;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const warnedAuthority = new Set<string>();
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Say that an authority declaration was not honored — once per process, and
|
|
331
|
+
* only once Jev is configured (a global `jev.json` exists).
|
|
332
|
+
*
|
|
333
|
+
* Without Jev, authority decides nothing, so there is nothing to tell anyone —
|
|
334
|
+
* and a warning is not free: it goes to the hook's stderr, which some CLIs show
|
|
335
|
+
* as the deny text itself, on every event, for every machine that installed a
|
|
336
|
+
* pack built against a newer semantic set. Once per process keeps the daemon's
|
|
337
|
+
* warm worker from repeating it for every tool call. Authors are told at build
|
|
338
|
+
* time as well: `failproofai publish` refuses what this would warn about.
|
|
339
|
+
*
|
|
340
|
+
* Presence of the file rather than a validated load: a machine where someone
|
|
341
|
+
* has started configuring Jev is where the answer to "why does Jev never clear
|
|
342
|
+
* this policy" is wanted, and a stat keeps the semantic modules unloaded.
|
|
343
|
+
*/
|
|
344
|
+
export function warnAuthority(message: string): void {
|
|
345
|
+
try {
|
|
346
|
+
if (!existsSync(jevConfigFile())) return;
|
|
347
|
+
} catch {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (warnedAuthority.has(message)) return;
|
|
351
|
+
warnedAuthority.add(message);
|
|
352
|
+
hookLogWarn(message);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Where a loaded hook's authority is declared, by the route it arrived on.
|
|
357
|
+
*
|
|
358
|
+
* - **Cloud-managed:** the artifact record in the active deployment. A cloud
|
|
359
|
+
* policy's authority is a central decision, so code inside the artifact
|
|
360
|
+
* cannot grant itself `reviewable`.
|
|
361
|
+
* - **Pack:** the pack's own manifest entry for that policy, matched by name —
|
|
362
|
+
* the same place its `params` schema is read from. A pack can only ever
|
|
363
|
+
* describe its own policies this way: its names cannot contain `/`, and they
|
|
364
|
+
* register under `pack/<id>@<version>/`, so no manifest can reach a builtin
|
|
365
|
+
* or another pack's policy. A policy the artifact registers but the manifest
|
|
366
|
+
* does not declare has no entry and is hard. When packs share one artifact,
|
|
367
|
+
* the loader has already merged their entries toward hard
|
|
368
|
+
* ({@link withMergedAuthority}), so no one of them decides for the others.
|
|
369
|
+
* - **The user's own file:** the hook itself.
|
|
370
|
+
*/
|
|
371
|
+
export function authorityDeclarationFor(
|
|
372
|
+
hook: Pick<CustomHook, "name" | "authority" | "reviewedBy">,
|
|
373
|
+
source: {
|
|
374
|
+
cloudManaged?: { authority?: unknown; reviewedBy?: unknown };
|
|
375
|
+
pack?: { policies: PolicyCatalogEntry[] };
|
|
376
|
+
},
|
|
377
|
+
): AuthorityDeclaration {
|
|
378
|
+
if (source.cloudManaged) {
|
|
379
|
+
return { authority: source.cloudManaged.authority, reviewedBy: source.cloudManaged.reviewedBy };
|
|
380
|
+
}
|
|
381
|
+
if (source.pack) {
|
|
382
|
+
const entry = source.pack.policies.find((p) => p.name === hook.name);
|
|
383
|
+
return { authority: entry?.authority, reviewedBy: entry?.reviewedBy };
|
|
384
|
+
}
|
|
385
|
+
return { authority: hook.authority, reviewedBy: hook.reviewedBy };
|
|
386
|
+
}
|