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
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Multi-value option support.
|
|
2
|
+
|
|
3
|
+
Covers the reusable `collect_multi` normalizer (repeated flags + comma-separated → one
|
|
4
|
+
flat, trimmed, de-duped, order-preserving list) and its end-to-end wiring on the `events`
|
|
5
|
+
command's `--session-id` / `--env` / `--event-type` / `--agent-id` filters (each serialized
|
|
6
|
+
to a CSV `IN(...)` on the wire, single value back-compatible).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
import respx
|
|
13
|
+
|
|
14
|
+
from fp_cli._context import collect_multi
|
|
15
|
+
from fp_cli.app import app
|
|
16
|
+
|
|
17
|
+
BASE = "http://dash.test"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# --- the pure normalizer ----------------------------------------------------
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_collect_multi_single_value():
|
|
24
|
+
# Always an array internally, even for one value.
|
|
25
|
+
assert collect_multi(["prod"]) == ["prod"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_collect_multi_repeated_flags():
|
|
29
|
+
assert collect_multi(["prod", "staging"]) == ["prod", "staging"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_collect_multi_comma_separated():
|
|
33
|
+
assert collect_multi(["prod,staging"]) == ["prod", "staging"]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_collect_multi_repeated_and_comma_combined():
|
|
37
|
+
assert collect_multi(["prod,staging", "dev"]) == ["prod", "staging", "dev"]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_collect_multi_trims_whitespace():
|
|
41
|
+
assert collect_multi(["prod, staging"]) == ["prod", "staging"]
|
|
42
|
+
assert collect_multi([" prod ", " dev"]) == ["prod", "dev"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_collect_multi_drops_empty_from_trailing_comma():
|
|
46
|
+
assert collect_multi(["prod,"]) == ["prod"]
|
|
47
|
+
assert collect_multi(["prod,,staging"]) == ["prod", "staging"]
|
|
48
|
+
assert collect_multi([","]) is None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_collect_multi_dedup_preserves_first_seen_order():
|
|
52
|
+
assert collect_multi(["prod", "prod"]) == ["prod"]
|
|
53
|
+
assert collect_multi(["b", "a", "b", "c", "a"]) == ["b", "a", "c"]
|
|
54
|
+
assert collect_multi(["prod,staging", "staging,prod"]) == ["prod", "staging"]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_collect_multi_empty_and_none():
|
|
58
|
+
assert collect_multi(None) is None
|
|
59
|
+
assert collect_multi([]) is None
|
|
60
|
+
assert collect_multi(["", " "]) is None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# --- end-to-end on the events command (what reaches the wire) ---------------
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _captured_params(logged_in, runner, argv):
|
|
67
|
+
"""Run `events` with argv and return the query params the CLI sent.
|
|
68
|
+
|
|
69
|
+
`events` routes to the light feed (/api/events/summary) by default and to the full feed
|
|
70
|
+
(/api/events) only when payload is needed (e.g. --session-id). Both accept the identical
|
|
71
|
+
query surface, so mock BOTH and read params from whichever the CLI actually called.
|
|
72
|
+
"""
|
|
73
|
+
resp = httpx.Response(200, json={"events": [], "next_cursor": None})
|
|
74
|
+
light = respx.get(f"{BASE}/api/events/summary").mock(return_value=resp)
|
|
75
|
+
full = respx.get(f"{BASE}/api/events").mock(return_value=resp)
|
|
76
|
+
result = runner.invoke(app, argv)
|
|
77
|
+
assert result.exit_code == 0, result.output
|
|
78
|
+
route = full if full.called else light
|
|
79
|
+
return dict(route.calls.last.request.url.params)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@respx.mock
|
|
83
|
+
def test_events_env_single_value_unchanged(logged_in, runner):
|
|
84
|
+
# Backward compatibility: one value serializes to a bare `environment=prod`.
|
|
85
|
+
params = _captured_params(logged_in, runner, ["events", "--env", "prod"])
|
|
86
|
+
assert params["environment"] == "prod"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@respx.mock
|
|
90
|
+
def test_events_env_repeated_flags_merge(logged_in, runner):
|
|
91
|
+
# The original failing case: repeated flags must keep BOTH, not last-wins.
|
|
92
|
+
params = _captured_params(logged_in, runner, ["events", "--env", "prod", "--env", "staging"])
|
|
93
|
+
assert params["environment"] == "prod,staging"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@respx.mock
|
|
97
|
+
def test_events_env_comma_separated(logged_in, runner):
|
|
98
|
+
params = _captured_params(logged_in, runner, ["events", "--env", "prod,staging"])
|
|
99
|
+
assert params["environment"] == "prod,staging"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@respx.mock
|
|
103
|
+
def test_events_env_combined_and_deduped(logged_in, runner):
|
|
104
|
+
params = _captured_params(
|
|
105
|
+
logged_in, runner, ["events", "--env", "prod,staging", "--env", "dev", "--env", "prod"]
|
|
106
|
+
)
|
|
107
|
+
assert params["environment"] == "prod,staging,dev"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@respx.mock
|
|
111
|
+
def test_events_all_four_filters_multi(logged_in, runner):
|
|
112
|
+
# session-id / agent-id / event-type / env all become CSV IN(...) on the wire.
|
|
113
|
+
params = _captured_params(
|
|
114
|
+
logged_in,
|
|
115
|
+
runner,
|
|
116
|
+
[
|
|
117
|
+
"events",
|
|
118
|
+
"--session-id", "s1", "--session-id", "s2",
|
|
119
|
+
"--agent-id", "a1,a2",
|
|
120
|
+
"--event-type", "tool_use", "--event-type", "tool_result",
|
|
121
|
+
"--env", "prod",
|
|
122
|
+
],
|
|
123
|
+
)
|
|
124
|
+
assert params["session_id"] == "s1,s2"
|
|
125
|
+
assert params["agent_id"] == "a1,a2"
|
|
126
|
+
assert params["event_type"] == "tool_use,tool_result"
|
|
127
|
+
assert params["environment"] == "prod"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# --- end-to-end on the sessions command (/api/sessions) ---------------------
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _captured_session_params(logged_in, runner, argv):
|
|
134
|
+
"""Run `sessions` with argv and return the query params the CLI sent to /api/sessions."""
|
|
135
|
+
route = respx.get(f"{BASE}/api/sessions").mock(
|
|
136
|
+
return_value=httpx.Response(200, json={"sessions": [], "next_cursor": None})
|
|
137
|
+
)
|
|
138
|
+
result = runner.invoke(app, argv)
|
|
139
|
+
assert result.exit_code == 0, result.output
|
|
140
|
+
return dict(route.calls.last.request.url.params)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@respx.mock
|
|
144
|
+
def test_sessions_status_repeated_flags_merge(logged_in, runner):
|
|
145
|
+
# --status was the one that 400'd as multi-value on the old endpoint; now CSV IN.
|
|
146
|
+
params = _captured_session_params(
|
|
147
|
+
logged_in, runner, ["sessions", "--status", "error", "--status", "timeout"]
|
|
148
|
+
)
|
|
149
|
+
assert params["status"] == "error,timeout"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@respx.mock
|
|
153
|
+
def test_sessions_all_four_filters_multi(logged_in, runner):
|
|
154
|
+
# env / status / agent-id / session-id all become CSV IN(...) on the wire.
|
|
155
|
+
params = _captured_session_params(
|
|
156
|
+
logged_in,
|
|
157
|
+
runner,
|
|
158
|
+
[
|
|
159
|
+
"sessions",
|
|
160
|
+
"--env", "prod,staging",
|
|
161
|
+
"--status", "done", "--status", "error",
|
|
162
|
+
"--agent-id", "a1", "--agent-id", "a2",
|
|
163
|
+
"--session-id", "s1,s2",
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
assert params["environment"] == "prod,staging"
|
|
167
|
+
assert params["status"] == "done,error"
|
|
168
|
+
assert params["agent_id"] == "a1,a2"
|
|
169
|
+
assert params["session_id"] == "s1,s2"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@respx.mock
|
|
173
|
+
def test_sessions_single_value_unchanged(logged_in, runner):
|
|
174
|
+
# Backward compatibility: one value serializes to a bare param.
|
|
175
|
+
params = _captured_session_params(logged_in, runner, ["sessions", "--env", "prod"])
|
|
176
|
+
assert params["environment"] == "prod"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_sessions_bad_status_is_usage_error(logged_in, runner):
|
|
180
|
+
# An invalid --status value is caught client-side (exit 2), not a server 400.
|
|
181
|
+
assert runner.invoke(app, ["sessions", "--status", "bogus"]).exit_code == 2
|
|
182
|
+
# ...even when mixed with a valid one.
|
|
183
|
+
assert runner.invoke(app, ["sessions", "--status", "done,bogus"]).exit_code == 2
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""This package is PUBLIC and its wheel is published to PyPI.
|
|
2
|
+
|
|
3
|
+
A real customer's tenant slug and company name reached this tree once, in a source
|
|
4
|
+
comment that shipped in the wheel and in four test files. It came across in a bulk
|
|
5
|
+
copy out of a private monorepo, where naming a live tenant in a fixture was harmless.
|
|
6
|
+
|
|
7
|
+
Fixtures must use obviously-fake names. This is the tripwire.
|
|
8
|
+
|
|
9
|
+
Customer names are held as SHA-256 digests, never in the clear. A deny-list that
|
|
10
|
+
spells out the name it exists to keep out of a public wheel publishes that name just
|
|
11
|
+
as surely as the fixture did — and this file ships in the sdist. Our OWN names stay
|
|
12
|
+
readable: they are already in LICENSE, SECURITY.md and package.json, so there is
|
|
13
|
+
nothing to withhold, and a contributor who trips over one needs to see which it was.
|
|
14
|
+
|
|
15
|
+
The match is over SUBSTRINGS of each token, not whole tokens, because the original
|
|
16
|
+
leak was both a bare tenant slug and a longer company name built from that same slug
|
|
17
|
+
— one name inside the other. To add an identifier:
|
|
18
|
+
|
|
19
|
+
python3 -c 'import hashlib,sys;print(hashlib.sha256(sys.argv[1].lower().encode()).hexdigest())' NAME
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import functools
|
|
25
|
+
import hashlib
|
|
26
|
+
import pathlib
|
|
27
|
+
import re
|
|
28
|
+
|
|
29
|
+
import fp_cli
|
|
30
|
+
|
|
31
|
+
PKG = pathlib.Path(fp_cli.__file__).resolve().parent
|
|
32
|
+
ROOT = PKG.parent
|
|
33
|
+
|
|
34
|
+
# Our own organisation names — public in this repo already, so in the clear. A fixture
|
|
35
|
+
# must still not use them: they identify a real tenant on a real deployment.
|
|
36
|
+
FORBIDDEN_OWN = {
|
|
37
|
+
"exosphere",
|
|
38
|
+
"exospherehost",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Customer / vendor identifiers, digest → what it is (never the name itself).
|
|
42
|
+
FORBIDDEN_DIGESTS = {
|
|
43
|
+
"140bd3c7a8606c97e18fb1f01c3a94f558eab6e2c5b27a56f9c3f5a940d8e2fd": "a customer's tenant slug",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# The vocabulary fixtures are supposed to use.
|
|
47
|
+
SANCTIONED_FIXTURE_ORGS = {"acme", "globex", "example", "initech", "umbrella"}
|
|
48
|
+
|
|
49
|
+
_TOKEN = re.compile(r"[a-z0-9]+")
|
|
50
|
+
_URL = re.compile(r"https?://([a-z0-9.-]+)", re.I)
|
|
51
|
+
|
|
52
|
+
# Substring lengths considered when hashing. The floor keeps the scan off two- and
|
|
53
|
+
# three-letter noise; the ceiling bounds the work on long tokens (hex digests, base64).
|
|
54
|
+
_MIN_LEN = 5
|
|
55
|
+
_MAX_LEN = 24
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@functools.lru_cache(maxsize=None)
|
|
59
|
+
def _digest(text: str) -> str:
|
|
60
|
+
return hashlib.sha256(text.encode()).hexdigest()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _hashed_hits(text: str, needles: frozenset[str] | None = None) -> set[str]:
|
|
64
|
+
"""Digests from ``needles`` whose plaintext appears anywhere in ``text``.
|
|
65
|
+
|
|
66
|
+
``text`` need not be lowercased by the caller. Returns digests, not matched text:
|
|
67
|
+
a failure message must not echo the identifier into a public CI log.
|
|
68
|
+
"""
|
|
69
|
+
want = FORBIDDEN_DIGESTS.keys() if needles is None else needles
|
|
70
|
+
found = set()
|
|
71
|
+
for token in set(_TOKEN.findall(text.lower())):
|
|
72
|
+
for start in range(len(token)):
|
|
73
|
+
stop = min(len(token), start + _MAX_LEN)
|
|
74
|
+
for end in range(start + _MIN_LEN, stop + 1):
|
|
75
|
+
d = _digest(token[start:end])
|
|
76
|
+
if d in want:
|
|
77
|
+
found.add(d)
|
|
78
|
+
return found
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _sources() -> list[pathlib.Path]:
|
|
82
|
+
out = []
|
|
83
|
+
for base in (PKG, ROOT / "tests"):
|
|
84
|
+
out.extend(p for p in base.rglob("*.py") if "__pycache__" not in p.parts)
|
|
85
|
+
for name in ("README.md", "CHANGELOG.md"):
|
|
86
|
+
p = ROOT / name
|
|
87
|
+
if p.is_file():
|
|
88
|
+
out.append(p)
|
|
89
|
+
for p in (ROOT / "skill").rglob("*"):
|
|
90
|
+
if p.is_file() and p.suffix in {".md", ".yaml", ".yml"}:
|
|
91
|
+
out.append(p)
|
|
92
|
+
return out
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _scannable() -> list[pathlib.Path]:
|
|
96
|
+
"""Everything but this file, which names our own orgs to deny them."""
|
|
97
|
+
return [p for p in _sources() if p.name != pathlib.Path(__file__).name]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_no_real_customer_or_vendor_identifiers():
|
|
101
|
+
hits = []
|
|
102
|
+
for p in _scannable():
|
|
103
|
+
for i, line in enumerate(p.read_text(encoding="utf-8", errors="replace").split("\n"), 1):
|
|
104
|
+
lowered = line.lower()
|
|
105
|
+
for needle in FORBIDDEN_OWN:
|
|
106
|
+
if needle in lowered:
|
|
107
|
+
hits.append(f"{p.relative_to(ROOT)}:{i}: {needle}")
|
|
108
|
+
# Report the location and what class of identifier it is — never the name.
|
|
109
|
+
for digest in _hashed_hits(line):
|
|
110
|
+
hits.append(f"{p.relative_to(ROOT)}:{i}: {FORBIDDEN_DIGESTS[digest]}")
|
|
111
|
+
assert not hits, (
|
|
112
|
+
"real organisation names must not appear in a public package — use a fixture "
|
|
113
|
+
f"name such as {sorted(SANCTIONED_FIXTURE_ORGS)}:\n " + "\n ".join(hits)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_the_scan_actually_has_files_to_scan():
|
|
118
|
+
"""Keeps the assertion above from passing vacuously if the layout moves."""
|
|
119
|
+
files = _sources()
|
|
120
|
+
assert len(files) > 40, f"only {len(files)} files scanned — the walk is not finding the package"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_the_hashed_scan_matches_substrings_and_only_them():
|
|
124
|
+
"""The digests are opaque, so prove the matcher on a planted, invented name.
|
|
125
|
+
|
|
126
|
+
Without this, an off-by-one in the substring window turns the whole hashed
|
|
127
|
+
deny-list into an assertion that passes because it matches nothing.
|
|
128
|
+
"""
|
|
129
|
+
planted = frozenset({_digest("quuxcorp")})
|
|
130
|
+
assert _hashed_hits("slug: quuxcorp", planted) == planted # bare token
|
|
131
|
+
assert _hashed_hits('name: "QuuxcorpInc"', planted) == planted # inside a longer name
|
|
132
|
+
assert _hashed_hits("host: quuxcorp-prod.example.com", planted) == planted
|
|
133
|
+
assert not _hashed_hits("slug: acme, name: Globex Corp", planted) # sanctioned fixtures
|
|
134
|
+
assert not _hashed_hits("quux corp", planted) # not one token
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_this_file_does_not_name_the_customers_it_denies():
|
|
138
|
+
"""The deny-list must not restate, in the clear, what it holds as a digest.
|
|
139
|
+
|
|
140
|
+
``_scannable()`` skips this file so the ``FORBIDDEN_OWN`` literals above do not
|
|
141
|
+
trip the scan on themselves. That exemption is about OUR names, which are public
|
|
142
|
+
in this repo already. It must never extend to a customer's: this file ships in
|
|
143
|
+
the sdist, so a name written here is published exactly like the fixture that
|
|
144
|
+
started all this. It needs its own test precisely because the exemption is what
|
|
145
|
+
blinds the main scan to it.
|
|
146
|
+
"""
|
|
147
|
+
src = pathlib.Path(__file__)
|
|
148
|
+
hits = [
|
|
149
|
+
f"{src.name}:{i}: {FORBIDDEN_DIGESTS[digest]}"
|
|
150
|
+
for i, line in enumerate(src.read_text(encoding="utf-8", errors="replace").split("\n"), 1)
|
|
151
|
+
for digest in _hashed_hits(line)
|
|
152
|
+
]
|
|
153
|
+
assert not hits, (
|
|
154
|
+
"this file names, in the clear, an identifier it exists to keep out of a "
|
|
155
|
+
"public package:\n " + "\n ".join(hits)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_no_internal_hostnames_leaked():
|
|
160
|
+
"""A customer's deployment hostname identifies them as surely as their name."""
|
|
161
|
+
hits = []
|
|
162
|
+
for p in _scannable():
|
|
163
|
+
for i, line in enumerate(p.read_text(encoding="utf-8", errors="replace").split("\n"), 1):
|
|
164
|
+
for host in _URL.findall(line):
|
|
165
|
+
labels = host.lower().split(".")
|
|
166
|
+
if any(label in FORBIDDEN_OWN for label in labels) or _hashed_hits(host):
|
|
167
|
+
hits.append(f"{p.relative_to(ROOT)}:{i}")
|
|
168
|
+
assert not hits, f"internal/customer hostnames in a public package: {hits}"
|