failproofai 1.0.1 → 1.0.2-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 +6 -6
- 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 +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 +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 +2 -2
- 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 +3 -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 +5 -4
- 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 +2 -2
- 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 +4 -3
- 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 +4 -4
- 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 +4 -4
- 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 +2 -2
- 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 +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/server-reference-manifest.json +66 -22
- package/.next/standalone/.next/server/app/policies/page.js +5 -4
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +4 -4
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- 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]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
- package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
- package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
- 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_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +1 -1
- 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 +71 -27
- package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
- package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
- package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
- package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
- package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
- package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
- package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
- package/.next/standalone/SECURITY.md +5 -4
- package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
- package/.next/standalone/app/actions/pack-actions.ts +153 -0
- package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
- package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
- package/.next/standalone/app/policies/hooks-client.tsx +320 -14
- package/.next/standalone/components/navbar.tsx +2 -28
- package/.next/standalone/components/reach-developers.tsx +8 -1
- package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
- package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
- package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
- package/.next/standalone/docs-old/i18n/README.de.md +1 -0
- package/.next/standalone/docs-old/i18n/README.es.md +1 -0
- package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
- package/.next/standalone/docs-old/i18n/README.he.md +1 -0
- package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
- package/.next/standalone/docs-old/i18n/README.it.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
- package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
- package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
- package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
- package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
- package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
- package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
- package/.next/standalone/fp-cloud-cli/README.md +259 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
- package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
- package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
- package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
- package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
- package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
- package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
- package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
- package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
- package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
- package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
- package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
- package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
- package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
- package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
- package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
- package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
- package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
- package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
- package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
- package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
- package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
- package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
- package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
- package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
- package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
- package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
- package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
- package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
- package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
- package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
- package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
- package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
- package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
- package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
- package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
- package/.next/standalone/package.json +29 -22
- package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
- package/.next/standalone/sdk/python/LICENSE +42 -0
- package/.next/standalone/sdk/python/MANIFEST.in +21 -0
- package/.next/standalone/sdk/python/README.md +466 -0
- package/.next/standalone/sdk/python/docs/README.md +249 -0
- package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
- package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
- package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
- package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
- package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
- package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
- package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
- package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
- package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
- package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
- package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
- package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
- package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
- package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
- package/.next/standalone/sdk/python/pyproject.toml +92 -0
- package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
- package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
- package/.next/standalone/sdk/python/skill/references/events.md +234 -0
- package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
- package/.next/standalone/sdk/python/skill/references/install.md +100 -0
- package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
- package/.next/standalone/sdk/python/tests/__init__.py +0 -0
- package/.next/standalone/sdk/python/tests/conftest.py +169 -0
- package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
- package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
- package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
- package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
- package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
- package/.next/standalone/sdk/python/tests/test_context.py +410 -0
- package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
- package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
- package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
- package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
- package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
- package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
- package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
- package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
- package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
- package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
- package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
- package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
- package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
- package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
- package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
- package/.next/standalone/sdk/python/uv.lock +6005 -0
- package/.next/standalone/server.js +1 -1
- package/README.md +77 -21
- package/bin/failproofai.mjs +145 -11
- package/dist/cli.mjs +4482 -2205
- package/dist/index.js +5 -5
- package/dist/worker.mjs +2399 -1978
- package/package.json +29 -22
- package/policy-pack/SHA256SUMS +2 -0
- package/policy-pack/failproofai-pack.json +732 -0
- package/policy-pack/failproofai-pack.mjs +2017 -0
- package/scripts/build-policy-pack.mjs +121 -0
- package/scripts/changelog-section.py +77 -0
- package/scripts/prune-standalone.mjs +3 -0
- package/scripts/python-version.py +232 -0
- package/scripts/translate-docs/cli.ts +21 -0
- package/scripts/translate-docs/mintlify-nav.ts +85 -13
- package/scripts/translate-docs/translator.ts +66 -11
- package/src/audit/cache.ts +40 -3
- package/src/audit/cli.ts +1 -1
- package/src/audit/index.ts +1 -1
- package/src/audit/replay.ts +89 -3
- package/src/audit/report.ts +5 -5
- package/src/audit/schedule-cli.ts +49 -53
- package/src/hooks/builtin-policies.ts +217 -579
- package/src/hooks/cloud-enrollment-cli.ts +66 -27
- package/src/hooks/cloud-managed-policies.ts +6 -1
- package/src/hooks/configure-wizard.ts +1 -1
- package/src/hooks/custom-hooks-loader.ts +89 -6
- package/src/hooks/fp-home.ts +92 -4
- package/src/hooks/fp-reset.ts +26 -2
- package/src/hooks/handler.ts +181 -11
- package/src/hooks/harness-cli.ts +79 -25
- package/src/hooks/hook-activity-store.ts +13 -3
- package/src/hooks/install-prompt.ts +25 -3
- package/src/hooks/manager.ts +418 -172
- package/src/hooks/migrations.ts +2 -2
- package/src/hooks/pack-cli.ts +505 -0
- package/src/hooks/pack-failclosed.ts +189 -0
- package/src/hooks/pack-manifest.ts +344 -0
- package/src/hooks/pack-store.ts +930 -0
- package/src/hooks/policy-catalog.ts +535 -0
- package/src/hooks/policy-evaluator.ts +24 -16
- package/src/hooks/policy-presets.ts +4 -2
- package/src/hooks/policy-registry.ts +8 -2
- package/src/hooks/policy-types.ts +26 -0
- package/src/hooks/session-pause-cli.ts +33 -9
- package/src/hooks/tui.ts +570 -0
- package/src/hooks/types.ts +15 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
- package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
- package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
- package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
package/src/hooks/handler.ts
CHANGED
|
@@ -43,6 +43,8 @@ import { getInstanceId } from "../../lib/telemetry-id";
|
|
|
43
43
|
import { hookLogInfo, hookLogWarn } from "./hook-logger";
|
|
44
44
|
import { readStdinPayload } from "./read-stdin";
|
|
45
45
|
import { readActiveCloudManagedPolicies, type CloudManagedPolicyArtifact } from "./cloud-managed-policies";
|
|
46
|
+
import { hasInstalledPacks, readInstalledPacks, type PackError, type ResolvedPack } from "./pack-manifest";
|
|
47
|
+
import { missingGuards, packFailureReason } from "./pack-failclosed";
|
|
46
48
|
import { readActivePause, type ActivePause } from "./session-pause";
|
|
47
49
|
import { layoutWarningForHook } from "./fp-reset";
|
|
48
50
|
|
|
@@ -255,13 +257,23 @@ export async function evaluateHookEvent(
|
|
|
255
257
|
/** Registered policy name → where it came from. See the set() below. */
|
|
256
258
|
const policyAttribution = new Map<
|
|
257
259
|
string,
|
|
258
|
-
{
|
|
260
|
+
{
|
|
261
|
+
source: "custom" | "convention" | "cloud" | "pack";
|
|
262
|
+
cloudPolicyId?: string;
|
|
263
|
+
cloudVersion?: number;
|
|
264
|
+
packId?: string;
|
|
265
|
+
packVersion?: string;
|
|
266
|
+
}
|
|
259
267
|
>();
|
|
260
268
|
let cloudDeployment: number | undefined;
|
|
269
|
+
/** Policy names each pack actually got registered, for the fail-closed check. */
|
|
270
|
+
const registeredByPack = new Map<string, Set<string>>();
|
|
271
|
+
let packErrors: PackError[] = [];
|
|
261
272
|
/** What observe-mode policies WOULD have done, had they been enforcing. */
|
|
262
273
|
const observedResults: Array<{
|
|
263
274
|
policyId: string;
|
|
264
|
-
version
|
|
275
|
+
/** A cloud deployment counts; a pack carries a version STRING. */
|
|
276
|
+
version: string | number;
|
|
265
277
|
decision: "deny" | "instruct";
|
|
266
278
|
reason: string | null;
|
|
267
279
|
}> = [];
|
|
@@ -290,7 +302,34 @@ export async function evaluateHookEvent(
|
|
|
290
302
|
// already exempts them: a locally-issued command that could switch off a
|
|
291
303
|
// centrally assigned policy would make cloud enforcement decorative.
|
|
292
304
|
activePause = readActivePause(session.sessionId);
|
|
293
|
-
|
|
305
|
+
// Enforcement comes from PACKS now. What still registers from this build is
|
|
306
|
+
// the always-on self-protection guard, and nothing else: a pack may not
|
|
307
|
+
// declare `alwaysOn` — a downloaded file that no local command can switch
|
|
308
|
+
// off is the thing that guard exists to prevent — so it cannot travel the
|
|
309
|
+
// pack lane and has to ship compiled in.
|
|
310
|
+
//
|
|
311
|
+
// The second argument is the migration shim, not a feature. A machine that
|
|
312
|
+
// upgraded into this build has `enabledPolicies` and no pack installed
|
|
313
|
+
// yet, and it must not lose enforcement in the gap before `failproofai
|
|
314
|
+
// update` runs. It disappears for that machine the moment a pack is
|
|
315
|
+
// installed, and never fires for a machine set up by this version.
|
|
316
|
+
const packsInstalledHere = hasInstalledPacks();
|
|
317
|
+
const legacyNames =
|
|
318
|
+
activePause || packsInstalledHere ? [] : config.enabledPolicies;
|
|
319
|
+
// `alwaysOn` policies bypass the enabled set inside `registerBuiltinPolicies`,
|
|
320
|
+
// so an empty list still registers the guard — which is exactly what this
|
|
321
|
+
// build should contribute once packs carry everything else.
|
|
322
|
+
registerBuiltinPolicies(activePause ? [] : legacyNames);
|
|
323
|
+
if (legacyNames.length > 0) {
|
|
324
|
+
hookLogWarn(
|
|
325
|
+
`enforcing ${legacyNames.length} policies from this build because no pack is installed — ` +
|
|
326
|
+
`run \`failproofai update\` to move them into the pack that ships with it`,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
// What actually registered, for the pack-duplicate check below. A paused
|
|
330
|
+
// session registers none, and then a pack twin is not a duplicate of
|
|
331
|
+
// anything — but a pause already skips every local policy, pack included.
|
|
332
|
+
const enabledBuiltinNames = new Set(legacyNames);
|
|
294
333
|
|
|
295
334
|
// Cloud-managed policies are daemon-reconciled artifacts, but they use
|
|
296
335
|
// the same public JS policy API as local custom policies. Verify and add
|
|
@@ -334,13 +373,31 @@ export async function evaluateHookEvent(
|
|
|
334
373
|
// separate question from "what decided", and only the former can tell a
|
|
335
374
|
// rollout that changed nothing from one that never reached the machine.
|
|
336
375
|
cloudDeployment = cloudManagedPolicies[0]?.deployment;
|
|
376
|
+
// Installed packs. `readInstalledPacks` never throws: a bad manifest or a
|
|
377
|
+
// tampered artifact yields zero packs and a recorded reason, which is
|
|
378
|
+
// sound ONLY because the builtins still ship compiled in and keep
|
|
379
|
+
// enforcing underneath. See the fail-open note in pack-manifest.ts — the
|
|
380
|
+
// day builtins become a fetched pack this posture has to change with them.
|
|
381
|
+
let installedPacks: ResolvedPack[] = [];
|
|
382
|
+
try {
|
|
383
|
+
const packResult = readInstalledPacks();
|
|
384
|
+
installedPacks = packResult.packs;
|
|
385
|
+
packErrors = packResult.errors;
|
|
386
|
+
for (const err of packResult.errors) {
|
|
387
|
+
hookLogWarn(`pack ${err.id ?? "(unnamed)"} not loaded: ${err.reason}`);
|
|
388
|
+
}
|
|
389
|
+
} catch (err) {
|
|
390
|
+
hookLogWarn(`pack manifest unreadable: ${err instanceof Error ? err.message : String(err)}`);
|
|
391
|
+
}
|
|
392
|
+
|
|
337
393
|
const configuredCustomPaths = config.customPoliciesPaths ?? config.customPoliciesPath;
|
|
338
394
|
const allExplicitPaths =
|
|
339
|
-
cloudManagedPolicies.length === 0
|
|
395
|
+
cloudManagedPolicies.length === 0 && installedPacks.length === 0
|
|
340
396
|
? configuredCustomPaths
|
|
341
397
|
: [
|
|
342
398
|
...(typeof configuredCustomPaths === "string" ? [configuredCustomPaths] : configuredCustomPaths ?? []),
|
|
343
399
|
...cloudManagedPolicies.map((policy) => policy.path),
|
|
400
|
+
...installedPacks.map((pack) => pack.path),
|
|
344
401
|
];
|
|
345
402
|
|
|
346
403
|
// Load and register custom hooks (layer 2, after builtins)
|
|
@@ -348,6 +405,7 @@ export async function evaluateHookEvent(
|
|
|
348
405
|
sessionCwd: session.cwd,
|
|
349
406
|
customPoliciesEnabled: config.customPoliciesEnabled,
|
|
350
407
|
...(cloudManagedPolicies.length > 0 ? { cloudManagedPolicies } : {}),
|
|
408
|
+
...(installedPacks.length > 0 ? { packs: installedPacks } : {}),
|
|
351
409
|
});
|
|
352
410
|
customHooksList = loadResult.hooks;
|
|
353
411
|
const disabledCustomPolicies = new Set(config.disabledCustomPolicies ?? []);
|
|
@@ -357,34 +415,78 @@ export async function evaluateHookEvent(
|
|
|
357
415
|
const taggedHook = hook as CustomHook & {
|
|
358
416
|
__policyId?: string;
|
|
359
417
|
__cloudManaged?: CloudManagedPolicyArtifact;
|
|
418
|
+
__pack?: ResolvedPack;
|
|
360
419
|
};
|
|
361
420
|
const policyId = taggedHook.__policyId;
|
|
362
421
|
const cloudManaged = taggedHook.__cloudManaged;
|
|
422
|
+
const pack = taggedHook.__pack;
|
|
363
423
|
// Local config cannot disable a centrally assigned policy merely by
|
|
364
424
|
// copying its generated ID into disabledCustomPolicies.
|
|
365
425
|
if (!cloudManaged && policyId && disabledCustomPolicies.has(policyId)) continue;
|
|
366
426
|
// Same rule for a session pause — it suspends local policy, never cloud.
|
|
367
427
|
if (!cloudManaged && activePause) continue;
|
|
428
|
+
// A pack's artifact registers everything it contains; the user may have
|
|
429
|
+
// taken only some of it. `enabled: null` means the whole pack, which is
|
|
430
|
+
// what `pack add` writes when no selection was made.
|
|
431
|
+
if (pack?.enabled && !pack.enabled.includes(hook.name)) continue;
|
|
432
|
+
// A pack policy whose name is an ENABLED BUILTIN is the same guard
|
|
433
|
+
// twice. The two register under different keys — `failproofai/block-sudo`
|
|
434
|
+
// and `pack/<id>@<version>/block-sudo` — so nothing deduped them, and
|
|
435
|
+
// the bundled pack carries the builtins under exactly these names.
|
|
436
|
+
//
|
|
437
|
+
// A deny hides it (the first verdict short-circuits) but an INSTRUCT does
|
|
438
|
+
// not: instructions accumulate and are joined, so the agent received the
|
|
439
|
+
// identical paragraph twice. Every duplicate also ran its policy function
|
|
440
|
+
// a second time, inside its own 10s timeout race, against a 150ms daemon
|
|
441
|
+
// budget.
|
|
442
|
+
//
|
|
443
|
+
// The builtin wins, because a bare name means the builtin everywhere else
|
|
444
|
+
// — `policies --uninstall block-sudo` disables the compiled one, and a
|
|
445
|
+
// machine that wants the pack's copy instead turns the builtin off.
|
|
446
|
+
// A pack policy whose name matches one the MIGRATION SHIM registered.
|
|
447
|
+
// Only reachable on a machine that has not migrated yet and somehow has
|
|
448
|
+
// a pack too; once the shim stops, nothing else registers by name.
|
|
449
|
+
if (pack && enabledBuiltinNames.has(hook.name)) continue;
|
|
450
|
+
if (pack) {
|
|
451
|
+
const seen = registeredByPack.get(pack.id) ?? new Set<string>();
|
|
452
|
+
seen.add(hook.name);
|
|
453
|
+
registeredByPack.set(pack.id, seen);
|
|
454
|
+
}
|
|
368
455
|
const hookName = hook.name;
|
|
369
456
|
const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope;
|
|
370
457
|
const isConvention = !!conventionScope;
|
|
458
|
+
// A pack's prefix carries its id and version, and it always contains a
|
|
459
|
+
// `/` — which is what keeps a pack policy structurally unable to
|
|
460
|
+
// normalize into the `failproofai/` namespace and REPLACE a builtin.
|
|
461
|
+
// pack-manifest.ts refuses a `/` in the declared name for the same
|
|
462
|
+
// reason; this is the second half of that guard.
|
|
371
463
|
const prefix = cloudManaged
|
|
372
464
|
? `cloud/${cloudManaged.id}@${cloudManaged.version}`
|
|
373
|
-
:
|
|
374
|
-
?
|
|
375
|
-
:
|
|
465
|
+
: pack
|
|
466
|
+
? `pack/${pack.id}@${pack.version}`
|
|
467
|
+
: isConvention
|
|
468
|
+
? `.failproofai-${conventionScope}`
|
|
469
|
+
: "custom";
|
|
376
470
|
// Observe mode: run it for real, record what it decided, then hand back
|
|
377
471
|
// an allow. Evaluating and discarding is the whole point — a rollout is
|
|
378
472
|
// measured against real traffic before it can break anyone's work, and
|
|
379
473
|
// a policy that did not actually run would measure nothing.
|
|
380
|
-
const observeOnly = cloudManaged?.effect === "observe";
|
|
474
|
+
const observeOnly = cloudManaged?.effect === "observe" || pack?.effect === "observe";
|
|
381
475
|
const fn: PolicyFunction = async (ctx): Promise<PolicyResult> => {
|
|
382
476
|
if (observeOnly) {
|
|
383
477
|
const shadow = await runObserved(hook, ctx, hookName, eventType, cli);
|
|
384
478
|
if (shadow.decision !== "allow") {
|
|
479
|
+
// Sourced from whichever layer asked to observe. This read
|
|
480
|
+
// `cloudManaged!.id` — a non-null assertion that is simply false
|
|
481
|
+
// for a pack, so an observe-mode PACK threw on its first non-allow
|
|
482
|
+
// verdict. The throw escapes before the wrapper's own try below,
|
|
483
|
+
// so policy-evaluator swallowed it and `continue`d: nothing was
|
|
484
|
+
// recorded, the row read as a clean allow, and the rollout being
|
|
485
|
+
// trialled measured nothing while reporting healthy.
|
|
486
|
+
const observer = cloudManaged ?? pack;
|
|
385
487
|
observedResults.push({
|
|
386
|
-
policyId:
|
|
387
|
-
version:
|
|
488
|
+
policyId: observer!.id,
|
|
489
|
+
version: observer!.version,
|
|
388
490
|
decision: shadow.decision,
|
|
389
491
|
reason: shadow.reason ?? null,
|
|
390
492
|
});
|
|
@@ -419,8 +521,14 @@ export async function evaluateHookEvent(
|
|
|
419
521
|
// question cloud attribution has to answer, "which rollout produced
|
|
420
522
|
// this decision", could only be answered by re-parsing our own label.
|
|
421
523
|
policyAttribution.set(registeredName, {
|
|
422
|
-
|
|
524
|
+
// `pack` was in scope here and simply not consulted, so every pack
|
|
525
|
+
// decision was filed as "custom" — which is also what a user's own
|
|
526
|
+
// local .mjs gets, making the two indistinguishable without
|
|
527
|
+
// re-parsing the `pack/` prefix off the display name. That re-parsing
|
|
528
|
+
// is exactly the practice these fields exist to replace.
|
|
529
|
+
source: cloudManaged ? "cloud" : pack ? "pack" : isConvention ? "convention" : "custom",
|
|
423
530
|
...(cloudManaged ? { cloudPolicyId: cloudManaged.id, cloudVersion: cloudManaged.version } : {}),
|
|
531
|
+
...(pack ? { packId: pack.id, packVersion: pack.version } : {}),
|
|
424
532
|
});
|
|
425
533
|
registerPolicy(
|
|
426
534
|
registeredName,
|
|
@@ -428,9 +536,69 @@ export async function evaluateHookEvent(
|
|
|
428
536
|
fn,
|
|
429
537
|
hook.match ?? {},
|
|
430
538
|
-1, // Custom hooks run after builtins (priority 0)
|
|
539
|
+
// A pack declares its policies' params in its manifest, so they work
|
|
540
|
+
// exactly like a builtin's — defaults merged under whatever the user
|
|
541
|
+
// configured. Matched by the pack's own name for the policy, which is
|
|
542
|
+
// the name before the `pack/<id>@<version>/` prefix is applied.
|
|
543
|
+
pack?.policies.find((p) => p.name === hook.name)?.params,
|
|
431
544
|
);
|
|
432
545
|
}
|
|
433
546
|
|
|
547
|
+
// Fail closed on enforcement this machine was told it had and does not.
|
|
548
|
+
//
|
|
549
|
+
// Additive, and deliberately NOT a clearPolicies() the way the
|
|
550
|
+
// daemon-unreachable branch is: `registerBuiltinPolicies` registers the
|
|
551
|
+
// alwaysOn self-protection guard unconditionally, and clearing here would
|
|
552
|
+
// let a corrupt third-party download switch off the one policy nothing may
|
|
553
|
+
// disable.
|
|
554
|
+
//
|
|
555
|
+
// Skipped entirely under a session pause. A pause suspends local policy for
|
|
556
|
+
// a bounded, deliberate window; a check derived from registrations would
|
|
557
|
+
// fire for every pack on every paused event and convert that into a
|
|
558
|
+
// machine-wide deny — the exact inversion of what a pause is for.
|
|
559
|
+
if (!activePause) {
|
|
560
|
+
const guards = missingGuards({
|
|
561
|
+
errors: packErrors,
|
|
562
|
+
packs: installedPacks,
|
|
563
|
+
registered: registeredByPack,
|
|
564
|
+
failed: loadResult.packFailures,
|
|
565
|
+
disabled: disabledCustomPolicies,
|
|
566
|
+
});
|
|
567
|
+
if (guards.length > 0) {
|
|
568
|
+
const reason = packFailureReason(guards);
|
|
569
|
+
const match = guards.length === 1
|
|
570
|
+
? guards[0].match
|
|
571
|
+
: {
|
|
572
|
+
events: guards.every((g) => g.match.events)
|
|
573
|
+
? [...new Set(guards.flatMap((g) => g.match.events ?? []))]
|
|
574
|
+
: undefined,
|
|
575
|
+
};
|
|
576
|
+
const name = "pack/failproofai-pack-unavailable";
|
|
577
|
+
policyAttribution.set(name, {
|
|
578
|
+
source: "pack",
|
|
579
|
+
packId: guards[0].packId,
|
|
580
|
+
...(guards[0].packVersion ? { packVersion: guards[0].packVersion } : {}),
|
|
581
|
+
});
|
|
582
|
+
registerPolicy(
|
|
583
|
+
name,
|
|
584
|
+
"A policy pack this machine enforces could not be loaded",
|
|
585
|
+
async (): Promise<PolicyResult> =>
|
|
586
|
+
// UserPromptSubmit instructs rather than denies, whatever the
|
|
587
|
+
// missing policies declared: a deny there locks the user out of
|
|
588
|
+
// their own agent, which is the one thing that stops them fixing it.
|
|
589
|
+
canonicalEventType === "UserPromptSubmit"
|
|
590
|
+
? { decision: "instruct", reason }
|
|
591
|
+
: { decision: "deny", reason },
|
|
592
|
+
match,
|
|
593
|
+
// Above builtins (0) and custom (-1), so the short-circuit attributes
|
|
594
|
+
// the deny to the missing pack rather than to whichever surviving
|
|
595
|
+
// policy happened to fire first.
|
|
596
|
+
1,
|
|
597
|
+
);
|
|
598
|
+
hookLogWarn(reason);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
434
602
|
// Fire telemetry once per invocation for custom hook loads
|
|
435
603
|
if (customHooksList.length > 0) {
|
|
436
604
|
void trackHookEvent(getInstanceId(), "custom_hooks_loaded", {
|
|
@@ -501,6 +669,8 @@ export async function evaluateHookEvent(
|
|
|
501
669
|
...(attribution?.cloudVersion !== undefined
|
|
502
670
|
? { cloudVersion: attribution.cloudVersion }
|
|
503
671
|
: {}),
|
|
672
|
+
...(attribution?.packId ? { packId: attribution.packId } : {}),
|
|
673
|
+
...(attribution?.packVersion ? { packVersion: attribution.packVersion } : {}),
|
|
504
674
|
};
|
|
505
675
|
})()
|
|
506
676
|
: {}),
|
package/src/hooks/harness-cli.ts
CHANGED
|
@@ -39,6 +39,16 @@ import { homedir } from "node:os";
|
|
|
39
39
|
import { resolve } from "node:path";
|
|
40
40
|
import { readConfig, updateConfig } from "./fp-config";
|
|
41
41
|
import { configFile } from "./fp-home";
|
|
42
|
+
import {
|
|
43
|
+
emptyState,
|
|
44
|
+
note,
|
|
45
|
+
table,
|
|
46
|
+
optsFor,
|
|
47
|
+
rule,
|
|
48
|
+
stack,
|
|
49
|
+
title,
|
|
50
|
+
warning,
|
|
51
|
+
} from "./tui";
|
|
42
52
|
|
|
43
53
|
/**
|
|
44
54
|
* Harness keys `collector.sources.<key>` accepts.
|
|
@@ -314,45 +324,89 @@ export function listPaths(harness?: string): HarnessResult {
|
|
|
314
324
|
(k) => !(HARNESS_KEYS as readonly string[]).includes(k),
|
|
315
325
|
);
|
|
316
326
|
|
|
327
|
+
const opts = optsFor(process.stdout);
|
|
328
|
+
const head = (extra: number) =>
|
|
329
|
+
title(
|
|
330
|
+
"failproofai harness list",
|
|
331
|
+
`${HARNESS_KEYS.length} harnesses · ${extra} extra path${extra === 1 ? "" : "s"}`,
|
|
332
|
+
opts,
|
|
333
|
+
);
|
|
334
|
+
|
|
317
335
|
if (names.length === 0 && unknown.length === 0) {
|
|
318
|
-
return ok(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
336
|
+
return ok(
|
|
337
|
+
stack(
|
|
338
|
+
head(0),
|
|
339
|
+
emptyState(
|
|
340
|
+
{
|
|
341
|
+
what: "No extra capture paths configured. Every harness is watching only its default location.",
|
|
342
|
+
hint: "Add one with:",
|
|
343
|
+
cmd: "failproofai harness add-path <harness> [<label>=]<path>",
|
|
344
|
+
},
|
|
345
|
+
opts,
|
|
346
|
+
),
|
|
347
|
+
// Wrapped, not joined into one line: twelve names ran off the right edge
|
|
348
|
+
// of an 80-column terminal, and the twelfth is as real as the first.
|
|
349
|
+
note(`Harnesses: ${HARNESS_KEYS.join(", ")}`, opts),
|
|
350
|
+
),
|
|
351
|
+
);
|
|
326
352
|
}
|
|
327
353
|
|
|
328
|
-
const
|
|
354
|
+
const configured = names.reduce((n, name) => n + (sources[name]?.extraPaths?.length ?? 0), 0);
|
|
355
|
+
const groups: Array<string[] | null> = [head(configured)];
|
|
329
356
|
for (const name of names) {
|
|
330
357
|
const entries = sources[name]?.extraPaths ?? [];
|
|
331
358
|
if (entries.length === 0) {
|
|
332
|
-
if (harness)
|
|
359
|
+
if (harness) {
|
|
360
|
+
groups.push(rule(name, opts));
|
|
361
|
+
groups.push(note("no extra paths configured (default location only)", opts));
|
|
362
|
+
}
|
|
333
363
|
continue;
|
|
334
364
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
365
|
+
groups.push(rule(name, opts));
|
|
366
|
+
// A table, not label/value rows: the PATH is the fact here, and a row's
|
|
367
|
+
// label column would have capped it at 24 columns — a truncated path cannot
|
|
368
|
+
// be copied, which makes the listing useless for the one thing it is for.
|
|
369
|
+
groups.push(
|
|
370
|
+
table(
|
|
371
|
+
{
|
|
372
|
+
head: ["Path", "Agent ids"],
|
|
373
|
+
rows: entries.map((e) => {
|
|
374
|
+
const label = labelOf(e);
|
|
375
|
+
return [
|
|
376
|
+
pathOf(e),
|
|
377
|
+
label ? `${label}-*` : "derived from the folder name",
|
|
378
|
+
];
|
|
379
|
+
}),
|
|
380
|
+
flex: 1,
|
|
381
|
+
// The path is the value this listing exists to hand back; it is never
|
|
382
|
+
// the column that gives way.
|
|
383
|
+
protect: [0],
|
|
384
|
+
},
|
|
385
|
+
opts,
|
|
386
|
+
),
|
|
387
|
+
);
|
|
344
388
|
}
|
|
389
|
+
const lines: string[] = stack(...groups);
|
|
345
390
|
// Unknown tables are surfaced here as well as by the daemon: a user who
|
|
346
391
|
// hand-edited config.json runs `list` to check it, and that is the moment the
|
|
347
392
|
// typo is cheapest to find.
|
|
348
393
|
if (unknown.length > 0) {
|
|
349
|
-
|
|
350
|
-
|
|
394
|
+
const body =
|
|
395
|
+
configured === 0
|
|
396
|
+
? [...head(0), "", ...note("No extra capture paths configured for any known harness.", opts)]
|
|
397
|
+
: lines;
|
|
398
|
+
return ok([
|
|
399
|
+
...body,
|
|
351
400
|
"",
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
401
|
+
...warning(
|
|
402
|
+
[
|
|
403
|
+
`config.json configures ${unknown.length} unknown harness(es): ${unknown.join(", ")}`,
|
|
404
|
+
"Nothing is captured from them.",
|
|
405
|
+
`Known: ${HARNESS_KEYS.join(", ")}`,
|
|
406
|
+
],
|
|
407
|
+
opts,
|
|
408
|
+
),
|
|
409
|
+
]);
|
|
356
410
|
}
|
|
357
411
|
return ok(lines);
|
|
358
412
|
}
|
|
@@ -96,11 +96,20 @@ export interface HookActivityEntry {
|
|
|
96
96
|
* plain allow) and on rows written before this existed — so, like
|
|
97
97
|
* `matchedPolicies`, `undefined` means "unknown", not "builtin".
|
|
98
98
|
*/
|
|
99
|
-
policySource?: "builtin" | "custom" | "convention" | "cloud";
|
|
99
|
+
policySource?: "builtin" | "custom" | "convention" | "cloud" | "pack";
|
|
100
100
|
/** Cloud policy id of the decider. Present only when `policySource` is "cloud". */
|
|
101
101
|
cloudPolicyId?: string;
|
|
102
102
|
/** Immutable version of that policy — the half of attribution that identifies WHICH version ran. */
|
|
103
103
|
cloudVersion?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Pack id and version of the decider. Present only when `policySource` is
|
|
106
|
+
* "pack", and here for the same reason the cloud pair is: the display name
|
|
107
|
+
* encodes both ("pack/acme/finance@1.2.0/…") but only as a string, so without
|
|
108
|
+
* these the question "which pack, which version decided this" could only be
|
|
109
|
+
* answered by re-parsing our own label.
|
|
110
|
+
*/
|
|
111
|
+
packId?: string;
|
|
112
|
+
packVersion?: string;
|
|
104
113
|
/**
|
|
105
114
|
* The cloud deployment active when this event was evaluated, recorded on
|
|
106
115
|
* every row of a managed machine regardless of what decided. "What was
|
|
@@ -117,7 +126,8 @@ export interface HookActivityEntry {
|
|
|
117
126
|
*/
|
|
118
127
|
observed?: Array<{
|
|
119
128
|
policyId: string;
|
|
120
|
-
version
|
|
129
|
+
/** A cloud deployment number, or a pack's version string. */
|
|
130
|
+
version: string | number;
|
|
121
131
|
decision: "deny" | "instruct";
|
|
122
132
|
reason: string | null;
|
|
123
133
|
}>;
|
|
@@ -134,7 +144,7 @@ export interface HookActivityFilters {
|
|
|
134
144
|
* organization's policies decided" is the question cloud rollout reporting
|
|
135
145
|
* is built on, and it is unanswerable without this.
|
|
136
146
|
*/
|
|
137
|
-
source?: "builtin" | "custom" | "convention" | "cloud";
|
|
147
|
+
source?: "builtin" | "custom" | "convention" | "cloud" | "pack";
|
|
138
148
|
}
|
|
139
149
|
|
|
140
150
|
export interface HookActivityStats {
|
|
@@ -358,7 +358,16 @@ export async function promptPolicySelection(
|
|
|
358
358
|
// If stdin is not a TTY (piped/CI), return defaults
|
|
359
359
|
if (!process.stdin.isTTY) {
|
|
360
360
|
const available = BUILTIN_POLICIES.filter((p) => includeBeta || !p.beta);
|
|
361
|
-
|
|
361
|
+
// Returned UNCHANGED, deliberately. This used to intersect with the builtin
|
|
362
|
+
// catalog, and manager.ts writes the result straight back — so a piped
|
|
363
|
+
// `policies --install` silently deleted every enabled name the catalog did
|
|
364
|
+
// not contain: a `failproofai/`-qualified name (a form the enforcement path
|
|
365
|
+
// explicitly accepts, `registerBuiltinPolicies` canonicalizes both), a beta
|
|
366
|
+
// policy enabled with `--beta`, and now any pack policy. The line that
|
|
367
|
+
// reports what was enabled prints only the survivors, so the loss was
|
|
368
|
+
// invisible. Carrying an unknown name costs nothing — registration looks it
|
|
369
|
+
// up in a Set and finds nothing — while dropping one destroys configuration.
|
|
370
|
+
if (preSelected) return [...preSelected];
|
|
362
371
|
return available.filter((p) => p.defaultEnabled).map((p) => p.name);
|
|
363
372
|
}
|
|
364
373
|
|
|
@@ -374,6 +383,14 @@ export async function promptPolicySelection(
|
|
|
374
383
|
beta: !!p.beta,
|
|
375
384
|
}));
|
|
376
385
|
|
|
386
|
+
// Everything the user has enabled that this picker cannot show a row for, for
|
|
387
|
+
// the same reason as the non-TTY branch above: the picker's universe is the
|
|
388
|
+
// builtin catalog, and resolving from it alone deletes anything else. Kept in
|
|
389
|
+
// their original order and appended to whatever the user picks.
|
|
390
|
+
const carried = preSelected
|
|
391
|
+
? preSelected.filter((name) => !items.some((i) => i.name === name))
|
|
392
|
+
: [];
|
|
393
|
+
|
|
377
394
|
const total = items.length;
|
|
378
395
|
const WINDOW_SIZE = 10;
|
|
379
396
|
|
|
@@ -570,10 +587,15 @@ export async function promptPolicySelection(
|
|
|
570
587
|
cleanup();
|
|
571
588
|
const selected = items.filter((i) => i.selected).map((i) => i.name);
|
|
572
589
|
if (lastLineCount > 0) process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
590
|
+
// Carried entries are NAMED, not counted. "3 kept" reads as fine right
|
|
591
|
+
// up until someone needs to know which three.
|
|
592
|
+
const summary = carried.length > 0
|
|
593
|
+
? `${selected.length} selected, kept ${carried.join(", ")}`
|
|
594
|
+
: `${selected.length} selected`;
|
|
573
595
|
process.stdout.write(
|
|
574
|
-
`${dim(BAR)}\n${dim(DONE)} Policies\n${dim(BAR)} ${dim(
|
|
596
|
+
`${dim(BAR)}\n${dim(DONE)} Policies\n${dim(BAR)} ${dim(summary)}\n`,
|
|
575
597
|
);
|
|
576
|
-
resolve(selected);
|
|
598
|
+
resolve([...selected, ...carried]);
|
|
577
599
|
} else if (key.name === "escape") {
|
|
578
600
|
// Clear search filter
|
|
579
601
|
search = "";
|