failproofai 1.0.0-beta.4 → 1.0.0-beta.6
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/app-path-routes-manifest.json +2 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +6 -0
- 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 +3 -1
- 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 +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- 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 +3 -1
- 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/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- 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 +4 -3
- 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 +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 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
- 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 +3 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
- 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 +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 +5 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- 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 +3 -1
- 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 +10 -10
- package/.next/standalone/.next/server/app/policies/page.js +4 -2
- 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 +4 -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 +6 -4
- 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 +4 -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/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
- package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
- package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
- package/.next/standalone/.next/server/app/settings/page.js +18 -0
- package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.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]__0ed01_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_a_gwn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e7-pa7._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0igtyj5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- 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/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
- package/.next/standalone/.next/static/chunks/{2c90h1g6x8z8y.js → 0_2n13i94rnw5.js} +1 -1
- package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/23557z4e6dtsr.js +1 -0
- package/.next/standalone/.next/static/chunks/28zkwzu50puki.js +1 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +1 -0
- package/.next/standalone/.next/static/chunks/{06jakt_xhoolk.js → 34fa65k0cldkj.js} +1 -1
- package/.next/standalone/.next/static/chunks/35v07j9gc1pvr.js +6 -0
- package/.next/standalone/.next/static/chunks/{2zb3m1tzq6h98.js → 3f_939wi3kfnx.js} +22 -22
- package/.next/standalone/.next/static/chunks/{31cqiv_cpgj9m.js → 3p1vpm2_-tfwm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ue9ak_xexiqh.js → 3rbpw_waieafm.js} +1 -1
- package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +1 -0
- package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
- package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
- package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
- package/.next/standalone/app/api/audit/run/route.ts +28 -0
- package/.next/standalone/app/api/audit/status/route.ts +13 -1
- package/.next/standalone/app/api/auth/status/route.ts +1 -1
- package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
- package/.next/standalone/app/audit/audit-styles.css +6 -149
- package/.next/standalone/app/settings/page.tsx +31 -0
- package/.next/standalone/app/settings/settings-client.tsx +488 -0
- package/.next/standalone/components/navbar.tsx +2 -0
- package/.next/standalone/lib/auth/api-server-client.ts +2 -3
- package/.next/standalone/lib/auth/auth-store.ts +4 -4
- package/.next/standalone/lib/codex-sessions.ts +2 -1
- package/.next/standalone/lib/dashboard-host.ts +101 -0
- package/.next/standalone/lib/install-check.ts +22 -7
- package/.next/standalone/lib/pi-sessions.ts +99 -14
- package/.next/standalone/lib/telemetry-enabled.ts +54 -0
- package/.next/standalone/lib/telemetry-id.ts +52 -1
- package/.next/standalone/lib/telemetry.ts +8 -4
- package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
- package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
- package/.next/standalone/node_modules/react/package.json +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/package.json +4 -4
- package/.next/standalone/package.json +7 -6
- package/.next/standalone/proxy.ts +89 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +197 -80
- package/dist/cli.mjs +17699 -15345
- package/dist/worker.mjs +1620 -257
- package/lib/auth/api-server-client.ts +2 -3
- package/lib/auth/auth-store.ts +4 -4
- package/lib/codex-sessions.ts +2 -1
- package/lib/dashboard-host.ts +101 -0
- package/lib/install-check.ts +22 -7
- package/lib/pi-sessions.ts +99 -14
- package/lib/telemetry-enabled.ts +54 -0
- package/lib/telemetry-id.ts +52 -1
- package/lib/telemetry.ts +8 -4
- package/package.json +7 -6
- package/scripts/install-telemetry.mjs +8 -1
- package/scripts/launch.ts +25 -3
- package/scripts/parse-script-args.ts +17 -1
- package/scripts/prune-standalone.mjs +20 -0
- package/scripts/translate-docs/readme-translator.ts +163 -4
- package/scripts/validate-mdx.ts +153 -13
- package/src/audit/audit-lock.ts +285 -0
- package/src/audit/audit-schedule.ts +111 -0
- package/src/audit/cache.ts +18 -4
- package/src/audit/cli-adapters/goose.ts +2 -1
- package/src/audit/cli-adapters/hermes.ts +28 -10
- package/src/audit/cli.ts +191 -35
- package/src/audit/dashboard-cache.ts +2 -1
- package/src/hooks/builtin-policies.ts +100 -3
- package/src/hooks/cloud-connection.ts +163 -14
- package/src/hooks/cloud-enrollment-cli.ts +119 -21
- package/src/hooks/cloud-enrollment.ts +87 -17
- package/src/hooks/cloud-introspect.ts +147 -0
- package/src/hooks/cloud-managed-policies.ts +33 -2
- package/src/hooks/collector-config.ts +32 -40
- package/src/hooks/configure-wizard.ts +696 -318
- package/src/hooks/custom-hooks-loader.ts +125 -11
- package/src/hooks/daemon-client.ts +83 -17
- package/src/hooks/daemon-download.ts +54 -2
- package/src/hooks/daemon-service.ts +595 -27
- package/src/hooks/first-run-gate.ts +39 -0
- package/src/hooks/fp-config.ts +497 -0
- package/src/hooks/fp-home.ts +342 -0
- package/src/hooks/fp-reset.ts +332 -0
- package/src/hooks/handler.ts +42 -1
- package/src/hooks/hook-activity-store.ts +35 -20
- package/src/hooks/hook-logger.ts +2 -1
- package/src/hooks/hook-telemetry.ts +5 -1
- package/src/hooks/hooks-config.ts +4 -3
- package/src/hooks/loader-utils.ts +166 -5
- package/src/hooks/manager.ts +5 -4
- package/src/hooks/onboarding-lock.ts +119 -0
- package/src/hooks/policy-types.ts +0 -7
- package/src/hooks/session-pause-cli.ts +15 -13
- package/src/hooks/session-pause.ts +36 -4
- package/src/hooks/setup-state.ts +256 -0
- package/src/hooks/tui.ts +4 -4
- package/src/hooks/worker-server.ts +53 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cmdyn_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sdrz-j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1q9xxca.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
- package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
- package/.next/standalone/.next/static/chunks/0oe2-hp0_2tzs.js +0 -6
- package/.next/standalone/.next/static/chunks/1fw3pxobk_otl.js +0 -1
- package/.next/standalone/.next/static/chunks/3h5_3u46gu9jx.js +0 -1
- package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
- package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
- package/.next/standalone/.next/static/chunks/43a1ywqsg9bq9.js +0 -1
- package/.next/standalone/Cargo.lock +0 -2222
- package/.next/standalone/Cargo.toml +0 -9
- package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
- package/.next/standalone/crates/PROTOCOL.md +0 -122
- package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
- package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
- package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
- package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
- package/.next/standalone/crates/failproofaid/src/main.rs +0 -532
- package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
- package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
- package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
- package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
- package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
- package/.next/standalone/crates/fpai-collect/src/config.rs +0 -412
- package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
- package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
- package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -484
- package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
- package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
- package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
- package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
- package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
- package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
- package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
- package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
- package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -310
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
- package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
- package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
- package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
- package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -458
- package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -387
- package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
- package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
- package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -738
- package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -393
- package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -975
- package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
- package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1019
- package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
- package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1008
- package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1129
- package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -621
- package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -854
- package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
- package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1191
- package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
- package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
- package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
- package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
- package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
- package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
- package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
- package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
- package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
- package/.next/standalone/integration-suite/Dockerfile +0 -47
- package/.next/standalone/integration-suite/README.md +0 -129
- package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
- package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
- package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
- package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
- package/.next/standalone/integration-suite/install-clis.sh +0 -136
- package/.next/standalone/integration-suite/probe-cli.sh +0 -248
- package/.next/standalone/integration-suite/report.js +0 -120
- package/.next/standalone/integration-suite/run.sh +0 -159
- package/.next/standalone/openclaw-plugin/index.js +0 -223
- package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
- package/.next/standalone/openclaw-plugin/package.json +0 -12
- package/.next/standalone/osv-scanner.toml +0 -17
- package/.next/standalone/pi-extension/index.ts +0 -524
- package/.next/standalone/pi-extension/package.json +0 -12
- package/.next/standalone/postcss.config.mjs +0 -8
- package/.next/standalone/readme-arch-hq.gif +0 -0
- package/.next/standalone/rust-toolchain.toml +0 -4
- package/src/auth/cli.ts +0 -371
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_ssgManifest.js +0 -0
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
//! Length-prefixed JSON framing shared by the daemon and every client of it.
|
|
2
|
-
//!
|
|
3
|
-
//! Frame = 4-byte big-endian `u32` byte length, followed by that many bytes
|
|
4
|
-
//! of UTF-8 JSON. One frame in, one frame out, per connection — the daemon
|
|
5
|
-
//! never keeps a connection open across multiple logical requests, so there
|
|
6
|
-
//! is no need for a request-id-multiplexed protocol.
|
|
7
|
-
|
|
8
|
-
use serde::Serialize;
|
|
9
|
-
use serde::de::DeserializeOwned;
|
|
10
|
-
use std::io::{self, Read, Write};
|
|
11
|
-
|
|
12
|
-
/// Hard cap on a single frame's declared length. A hook payload is at most
|
|
13
|
-
/// 1 MiB (see `handler.ts`'s own stdin cap); 16 MiB leaves headroom without
|
|
14
|
-
/// letting a corrupt or hostile length prefix trigger an unbounded
|
|
15
|
-
/// allocation before a single byte of the body has even been read.
|
|
16
|
-
pub const MAX_FRAME_LEN: u32 = 16 * 1024 * 1024;
|
|
17
|
-
|
|
18
|
-
#[derive(Debug)]
|
|
19
|
-
pub enum FramingError {
|
|
20
|
-
Io(io::Error),
|
|
21
|
-
FrameTooLarge { declared: u32, max: u32 },
|
|
22
|
-
Json(serde_json::Error),
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
impl std::fmt::Display for FramingError {
|
|
26
|
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
27
|
-
match self {
|
|
28
|
-
FramingError::Io(e) => write!(f, "io error: {e}"),
|
|
29
|
-
FramingError::FrameTooLarge { declared, max } => {
|
|
30
|
-
write!(f, "frame length {declared} exceeds max {max}")
|
|
31
|
-
}
|
|
32
|
-
FramingError::Json(e) => write!(f, "invalid JSON frame: {e}"),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
impl std::error::Error for FramingError {}
|
|
38
|
-
|
|
39
|
-
impl From<io::Error> for FramingError {
|
|
40
|
-
fn from(e: io::Error) -> Self {
|
|
41
|
-
FramingError::Io(e)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
impl From<serde_json::Error> for FramingError {
|
|
46
|
-
fn from(e: serde_json::Error) -> Self {
|
|
47
|
-
FramingError::Json(e)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/// Serializes `value` to JSON and writes it as one length-prefixed frame.
|
|
52
|
-
pub fn write_message<W: Write, T: Serialize>(
|
|
53
|
-
writer: &mut W,
|
|
54
|
-
value: &T,
|
|
55
|
-
) -> Result<(), FramingError> {
|
|
56
|
-
let body = serde_json::to_vec(value)?;
|
|
57
|
-
let len = u32::try_from(body.len()).map_err(|_| FramingError::FrameTooLarge {
|
|
58
|
-
declared: u32::MAX,
|
|
59
|
-
max: MAX_FRAME_LEN,
|
|
60
|
-
})?;
|
|
61
|
-
if len > MAX_FRAME_LEN {
|
|
62
|
-
return Err(FramingError::FrameTooLarge {
|
|
63
|
-
declared: len,
|
|
64
|
-
max: MAX_FRAME_LEN,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
writer.write_all(&len.to_be_bytes())?;
|
|
68
|
-
writer.write_all(&body)?;
|
|
69
|
-
writer.flush()?;
|
|
70
|
-
Ok(())
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/// Reads one length-prefixed frame and deserializes it as `T`. Rejects the
|
|
74
|
-
/// frame (without allocating a body buffer) if the declared length exceeds
|
|
75
|
-
/// [`MAX_FRAME_LEN`], so a corrupt or adversarial length prefix can't be
|
|
76
|
-
/// used to force a large allocation.
|
|
77
|
-
pub fn read_message<R: Read, T: DeserializeOwned>(reader: &mut R) -> Result<T, FramingError> {
|
|
78
|
-
let mut len_bytes = [0u8; 4];
|
|
79
|
-
reader.read_exact(&mut len_bytes)?;
|
|
80
|
-
let len = u32::from_be_bytes(len_bytes);
|
|
81
|
-
if len > MAX_FRAME_LEN {
|
|
82
|
-
return Err(FramingError::FrameTooLarge {
|
|
83
|
-
declared: len,
|
|
84
|
-
max: MAX_FRAME_LEN,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
let mut body = vec![0u8; len as usize];
|
|
88
|
-
reader.read_exact(&mut body)?;
|
|
89
|
-
let value = serde_json::from_slice(&body)?;
|
|
90
|
-
Ok(value)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
#[cfg(test)]
|
|
94
|
-
mod tests {
|
|
95
|
-
use super::*;
|
|
96
|
-
use serde::Deserialize;
|
|
97
|
-
use std::io::Cursor;
|
|
98
|
-
|
|
99
|
-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
100
|
-
struct Sample {
|
|
101
|
-
a: u32,
|
|
102
|
-
b: String,
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
#[test]
|
|
106
|
-
fn round_trips_a_simple_value() {
|
|
107
|
-
let mut buf = Vec::new();
|
|
108
|
-
let msg = Sample {
|
|
109
|
-
a: 42,
|
|
110
|
-
b: "hello".to_string(),
|
|
111
|
-
};
|
|
112
|
-
write_message(&mut buf, &msg).unwrap();
|
|
113
|
-
let mut cursor = Cursor::new(buf);
|
|
114
|
-
let decoded: Sample = read_message(&mut cursor).unwrap();
|
|
115
|
-
assert_eq!(decoded, msg);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
#[test]
|
|
119
|
-
fn round_trips_empty_string_fields() {
|
|
120
|
-
let mut buf = Vec::new();
|
|
121
|
-
let msg = Sample {
|
|
122
|
-
a: 0,
|
|
123
|
-
b: String::new(),
|
|
124
|
-
};
|
|
125
|
-
write_message(&mut buf, &msg).unwrap();
|
|
126
|
-
let mut cursor = Cursor::new(buf);
|
|
127
|
-
let decoded: Sample = read_message(&mut cursor).unwrap();
|
|
128
|
-
assert_eq!(decoded, msg);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
#[test]
|
|
132
|
-
fn rejects_a_declared_length_over_the_cap_without_reading_a_body() {
|
|
133
|
-
let mut buf = Vec::new();
|
|
134
|
-
buf.extend_from_slice(&(MAX_FRAME_LEN + 1).to_be_bytes());
|
|
135
|
-
// Deliberately no body bytes follow — if `read_message` tried to
|
|
136
|
-
// allocate/read the declared length before checking the cap, this
|
|
137
|
-
// would hang or panic on the short read instead of erroring cleanly.
|
|
138
|
-
let mut cursor = Cursor::new(buf);
|
|
139
|
-
let result: Result<Sample, _> = read_message(&mut cursor);
|
|
140
|
-
assert!(matches!(result, Err(FramingError::FrameTooLarge { .. })));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
#[test]
|
|
144
|
-
fn refuses_to_write_a_frame_over_the_cap() {
|
|
145
|
-
#[derive(Serialize)]
|
|
146
|
-
struct Big {
|
|
147
|
-
data: String,
|
|
148
|
-
}
|
|
149
|
-
let big = Big {
|
|
150
|
-
data: "x".repeat((MAX_FRAME_LEN as usize) + 1),
|
|
151
|
-
};
|
|
152
|
-
let mut buf = Vec::new();
|
|
153
|
-
let result = write_message(&mut buf, &big);
|
|
154
|
-
assert!(matches!(result, Err(FramingError::FrameTooLarge { .. })));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
#[test]
|
|
158
|
-
fn rejects_truncated_frames() {
|
|
159
|
-
let mut buf = Vec::new();
|
|
160
|
-
buf.extend_from_slice(&10u32.to_be_bytes());
|
|
161
|
-
buf.extend_from_slice(b"short"); // fewer than the declared 10 bytes
|
|
162
|
-
let mut cursor = Cursor::new(buf);
|
|
163
|
-
let result: Result<Sample, _> = read_message(&mut cursor);
|
|
164
|
-
assert!(matches!(result, Err(FramingError::Io(_))));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
#[test]
|
|
168
|
-
fn rejects_malformed_json_inside_a_valid_frame() {
|
|
169
|
-
let mut buf = Vec::new();
|
|
170
|
-
let body = b"not json";
|
|
171
|
-
buf.extend_from_slice(&(body.len() as u32).to_be_bytes());
|
|
172
|
-
buf.extend_from_slice(body);
|
|
173
|
-
let mut cursor = Cursor::new(buf);
|
|
174
|
-
let result: Result<Sample, _> = read_message(&mut cursor);
|
|
175
|
-
assert!(matches!(result, Err(FramingError::Json(_))));
|
|
176
|
-
}
|
|
177
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
//! Wire protocol shared by `failproofaid` and every client/test that talks
|
|
2
|
-
//! to it: message framing, the JSON envelope, and Unix-socket peer
|
|
3
|
-
//! verification.
|
|
4
|
-
|
|
5
|
-
pub mod envelope;
|
|
6
|
-
pub mod framing;
|
|
7
|
-
pub mod peer;
|
|
8
|
-
|
|
9
|
-
pub use envelope::{ClientMessage, PROTOCOL_VERSION, ServerMessage};
|
|
10
|
-
pub use framing::{FramingError, MAX_FRAME_LEN, read_message, write_message};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
//! Verifies that a Unix socket peer is running as the same OS user as this
|
|
2
|
-
//! process.
|
|
3
|
-
//!
|
|
4
|
-
//! failproofaid is user-scope only (see the plan: "no elevation, the daemon
|
|
5
|
-
//! spawns the worker because the daemon already runs as the user"): the
|
|
6
|
-
//! socket directory is `0700` and the socket file `0600`, which is the
|
|
7
|
-
//! actual access-control boundary. This check is a second, defense-in-depth
|
|
8
|
-
//! layer against the narrow window between a socket file existing and its
|
|
9
|
-
//! permissions having been fully applied, and against misconfigured
|
|
10
|
-
//! filesystems (e.g. a shared mount with unexpectedly loose permissions).
|
|
11
|
-
//! It is not a stronger security boundary than the filesystem permissions
|
|
12
|
-
//! already provide — same OS user can always reach this daemon regardless.
|
|
13
|
-
|
|
14
|
-
use std::io;
|
|
15
|
-
use std::os::unix::io::AsRawFd;
|
|
16
|
-
use std::os::unix::net::UnixStream;
|
|
17
|
-
|
|
18
|
-
/// Returns the effective UID of the process on the other end of `stream`.
|
|
19
|
-
#[cfg(target_os = "linux")]
|
|
20
|
-
pub fn peer_uid(stream: &UnixStream) -> io::Result<u32> {
|
|
21
|
-
use std::mem;
|
|
22
|
-
|
|
23
|
-
let fd = stream.as_raw_fd();
|
|
24
|
-
let mut cred: libc::ucred = unsafe { mem::zeroed() };
|
|
25
|
-
let mut len = mem::size_of::<libc::ucred>() as libc::socklen_t;
|
|
26
|
-
|
|
27
|
-
let ret = unsafe {
|
|
28
|
-
libc::getsockopt(
|
|
29
|
-
fd,
|
|
30
|
-
libc::SOL_SOCKET,
|
|
31
|
-
libc::SO_PEERCRED,
|
|
32
|
-
&mut cred as *mut libc::ucred as *mut libc::c_void,
|
|
33
|
-
&mut len,
|
|
34
|
-
)
|
|
35
|
-
};
|
|
36
|
-
if ret != 0 {
|
|
37
|
-
return Err(io::Error::last_os_error());
|
|
38
|
-
}
|
|
39
|
-
Ok(cred.uid)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/// Returns the effective UID of the process on the other end of `stream`.
|
|
43
|
-
#[cfg(target_os = "macos")]
|
|
44
|
-
pub fn peer_uid(stream: &UnixStream) -> io::Result<u32> {
|
|
45
|
-
let fd = stream.as_raw_fd();
|
|
46
|
-
let mut uid: libc::uid_t = 0;
|
|
47
|
-
let mut gid: libc::gid_t = 0;
|
|
48
|
-
|
|
49
|
-
let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
|
|
50
|
-
if ret != 0 {
|
|
51
|
-
return Err(io::Error::last_os_error());
|
|
52
|
-
}
|
|
53
|
-
Ok(uid)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/// Returns this process's own effective UID, for comparison against
|
|
57
|
-
/// [`peer_uid`].
|
|
58
|
-
pub fn own_uid() -> u32 {
|
|
59
|
-
unsafe { libc::geteuid() }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/// `true` if `stream`'s peer is running as this process's own OS user.
|
|
63
|
-
pub fn is_same_user(stream: &UnixStream) -> io::Result<bool> {
|
|
64
|
-
Ok(peer_uid(stream)? == own_uid())
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
#[cfg(test)]
|
|
68
|
-
mod tests {
|
|
69
|
-
use super::*;
|
|
70
|
-
|
|
71
|
-
#[test]
|
|
72
|
-
fn a_local_socketpair_peer_is_always_the_same_user() {
|
|
73
|
-
// socketpair() connects two ends of the same process — the peer
|
|
74
|
-
// UID must equal our own, on every CI runner regardless of who's
|
|
75
|
-
// executing the test.
|
|
76
|
-
let (a, _b) = UnixStream::pair().unwrap();
|
|
77
|
-
assert!(is_same_user(&a).unwrap());
|
|
78
|
-
assert_eq!(peer_uid(&a).unwrap(), own_uid());
|
|
79
|
-
}
|
|
80
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Self-contained failproofai hook-sync container.
|
|
2
|
-
#
|
|
3
|
-
# A single-shot daily job (run by a k8s CronJob) that clones failproofai, runs
|
|
4
|
-
# Claude Code in `--effort ultracode` mode to detect drift between every agent-CLI
|
|
5
|
-
# harness we integrate with and this repo, and opens ONE auto-PR with the fix.
|
|
6
|
-
#
|
|
7
|
-
# Bundles:
|
|
8
|
-
# - Node 20 + npm (npm is a fallback bun installer for scripts/dev-hook.mjs;
|
|
9
|
-
# node runs the launcher itself)
|
|
10
|
-
# - bun (STILL REQUIRED: the cloned repo's .claude/settings.json fires hooks via
|
|
11
|
-
# `node "$CLAUDE_PROJECT_DIR/scripts/dev-hook.mjs" --hook <Event>`, and that
|
|
12
|
-
# launcher only *locates* bun — it cannot conjure one. Without this layer the
|
|
13
|
-
# dogfooded require-*-before-stop policies never fire and the auto-PR is
|
|
14
|
-
# never committed/pushed. We install to BUN_INSTALL=/home/appuser/.bun, which
|
|
15
|
-
# the launcher probes explicitly, so enforcement survives a broken PATH.)
|
|
16
|
-
# - Claude Code CLI (`claude`) — run headless with --effort ultracode
|
|
17
|
-
# - failproofai@latest on PATH (belt-and-suspenders; the dogfood hooks actually
|
|
18
|
-
# run the clone's SOURCE via bun, not this global)
|
|
19
|
-
# - git + gh + jq + dumb-init + `script` (PTY wrap for stream-json)
|
|
20
|
-
#
|
|
21
|
-
# Build: docker build -t hook-sync:latest docker-hook-sync/
|
|
22
|
-
# Run: docker run --rm -e CLAUDE_CODE_OAUTH_TOKEN=... -e GH_TOKEN=... hook-sync:latest
|
|
23
|
-
#
|
|
24
|
-
# Every dependency is installed at build time. The daily GitHub Actions rebuild
|
|
25
|
-
# (.github/workflows/build-image.yml) keeps claude-code@latest + failproofai@latest fresh.
|
|
26
|
-
FROM node:20-bookworm-slim
|
|
27
|
-
|
|
28
|
-
ENV DEBIAN_FRONTEND=noninteractive \
|
|
29
|
-
HOME=/home/appuser \
|
|
30
|
-
BUN_INSTALL=/home/appuser/.bun \
|
|
31
|
-
FAILPROOFAI_TELEMETRY_DISABLED=1 \
|
|
32
|
-
PATH="/home/appuser/.bun/bin:/home/appuser/.local/bin:${PATH}"
|
|
33
|
-
|
|
34
|
-
# Layer 1: apt deps. dumb-init for PID 1 signal handling; git+gh for the agent's
|
|
35
|
-
# clone/branch/push/PR flow AND the require-*-before-stop hooks; jq for the
|
|
36
|
-
# entrypoint's policy-config edit; bsdextrautils provides `script` (PTY wrap so
|
|
37
|
-
# Node line-flushes --output-format stream-json); curl/gnupg for the gh apt key
|
|
38
|
-
# and the bun installer; unzip is required by the bun installer.
|
|
39
|
-
RUN apt-get update \
|
|
40
|
-
&& apt-get install -y --no-install-recommends \
|
|
41
|
-
ca-certificates curl gnupg dumb-init jq git bsdextrautils unzip \
|
|
42
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
43
|
-
|
|
44
|
-
# Layer 2: GitHub CLI (gh). Used by the agent for `gh pr create/list` and by the
|
|
45
|
-
# require-pr-before-stop hook.
|
|
46
|
-
RUN install -d /etc/apt/keyrings \
|
|
47
|
-
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
48
|
-
| gpg --dearmor -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
|
|
49
|
-
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
|
50
|
-
> /etc/apt/sources.list.d/github-cli.list \
|
|
51
|
-
&& apt-get update \
|
|
52
|
-
&& apt-get install -y --no-install-recommends gh \
|
|
53
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
54
|
-
|
|
55
|
-
# Layer 3: npm globals. Claude Code CLI + failproofai, pinned to latest at build
|
|
56
|
-
# time; the daily workflow rebuild keeps them fresh. Root install so symlinks land
|
|
57
|
-
# in /usr/local/bin (executable by the non-root appuser).
|
|
58
|
-
RUN npm install -g --omit=dev \
|
|
59
|
-
@anthropic-ai/claude-code@latest \
|
|
60
|
-
failproofai@latest \
|
|
61
|
-
&& npm cache clean --force
|
|
62
|
-
|
|
63
|
-
# Layer 4: non-root user + chowned workspace.
|
|
64
|
-
RUN useradd --create-home --uid 10001 --shell /bin/bash appuser \
|
|
65
|
-
&& mkdir -p /workspace \
|
|
66
|
-
&& chown -R appuser:appuser /workspace /home/appuser
|
|
67
|
-
|
|
68
|
-
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
69
|
-
RUN chmod 0755 /usr/local/bin/entrypoint.sh
|
|
70
|
-
|
|
71
|
-
USER appuser
|
|
72
|
-
WORKDIR /home/appuser
|
|
73
|
-
|
|
74
|
-
# Layer 5: bun (installs into $BUN_INSTALL=/home/appuser/.bun, on PATH per ENV).
|
|
75
|
-
# The dogfood hook fast-path runs TypeScript from src/ directly — bun executes TS
|
|
76
|
-
# natively, so no build step is needed for the hooks to work.
|
|
77
|
-
RUN curl -fsSL https://bun.sh/install | bash
|
|
78
|
-
|
|
79
|
-
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/entrypoint.sh"]
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# failproofai hook-sync entrypoint (runs as PID 1 under dumb-init).
|
|
4
|
-
#
|
|
5
|
-
# Lifecycle:
|
|
6
|
-
# 1. Validate env (CLAUDE_CODE_OAUTH_TOKEN, GH_TOKEN).
|
|
7
|
-
# 2. gh auth setup-git + git identity.
|
|
8
|
-
# 3. Clone failproofai --depth=1; cut a fresh auto/sync-cli-harnesses-<UTC> branch.
|
|
9
|
-
# 4. NEUTRALIZE two policies in the THROWAWAY clone's .failproofai config
|
|
10
|
-
# (require-ci-green-before-stop, block-read-outside-cwd) via jq, then
|
|
11
|
-
# `git update-index --skip-worktree` so the edit is invisible to
|
|
12
|
-
# git status/add and never enters the agent's commit/PR — while failproofai
|
|
13
|
-
# reads the edited WORKTREE file at runtime and sees them gone. The
|
|
14
|
-
# require-commit/push/pr-before-stop gates stay ACTIVE (dogfooding).
|
|
15
|
-
# 5. exec `claude --effort ultracode -p <prompt>` wrapped in a PTY so
|
|
16
|
-
# --output-format stream-json line-flushes to `kubectl logs -f`.
|
|
17
|
-
# 6. Exit with claude's return code (all output streams to stdout / the pod log).
|
|
18
|
-
#
|
|
19
|
-
# Exit codes: 0 = agent finished (claude's rc) · 64 = missing required env ·
|
|
20
|
-
# 65 = prompt file missing in clone · 66 = unsafe WORKSPACE · else = claude's rc.
|
|
21
|
-
set -euo pipefail
|
|
22
|
-
|
|
23
|
-
CLAUDE_CODE_OAUTH_TOKEN="${CLAUDE_CODE_OAUTH_TOKEN:-}"
|
|
24
|
-
GH_TOKEN="${GH_TOKEN:-}"
|
|
25
|
-
REPO_URL="${REPO_URL:-https://github.com/failproofai/failproofai.git}"
|
|
26
|
-
REPO_BRANCH_FROM="${REPO_BRANCH_FROM:-main}"
|
|
27
|
-
WORKSPACE="${WORKSPACE:-/workspace}"
|
|
28
|
-
PROMPT_PATH="${PROMPT_PATH:-scripts/sync-agent-cli-harnesses-prompt.md}"
|
|
29
|
-
CLAUDE_MODEL="${CLAUDE_MODEL:-claude-opus-4-8}"
|
|
30
|
-
|
|
31
|
-
export HOME="${HOME:-/home/appuser}"
|
|
32
|
-
export CLAUDE_CODE_OAUTH_TOKEN
|
|
33
|
-
export GH_TOKEN
|
|
34
|
-
export GITHUB_TOKEN="${GITHUB_TOKEN:-$GH_TOKEN}"
|
|
35
|
-
export FAILPROOFAI_TELEMETRY_DISABLED=1
|
|
36
|
-
# Keep ultracode background subagents alive in headless -p mode (default is ~10 min).
|
|
37
|
-
export CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS="${CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS:-1800000}"
|
|
38
|
-
|
|
39
|
-
log() { printf '[entrypoint %s] %s\n' "$(date -u +%FT%TZ)" "$*"; }
|
|
40
|
-
|
|
41
|
-
# ---------------- 1. env validation ----------------
|
|
42
|
-
if [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then log "ERROR: CLAUDE_CODE_OAUTH_TOKEN not set"; exit 64; fi
|
|
43
|
-
if [ -z "$GH_TOKEN" ]; then log "ERROR: GH_TOKEN not set"; exit 64; fi
|
|
44
|
-
|
|
45
|
-
# ---------------- 2. gh + git auth ----------------
|
|
46
|
-
log "authenticating gh"
|
|
47
|
-
gh auth setup-git >/dev/null
|
|
48
|
-
git config --global user.name "failproofai-hook-sync"
|
|
49
|
-
git config --global user.email "hook-sync-bot@exosphere.host"
|
|
50
|
-
git config --global init.defaultBranch main
|
|
51
|
-
|
|
52
|
-
# ---------------- 3. clone + fresh branch ----------------
|
|
53
|
-
case "$WORKSPACE" in
|
|
54
|
-
""|"/"|"."|"..") log "ERROR: refusing unsafe WORKSPACE '$WORKSPACE'"; exit 66 ;;
|
|
55
|
-
esac
|
|
56
|
-
mkdir -p "$WORKSPACE"
|
|
57
|
-
if [ -n "$(ls -A "$WORKSPACE" 2>/dev/null)" ]; then
|
|
58
|
-
find "$WORKSPACE" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
|
59
|
-
fi
|
|
60
|
-
log "cloning $REPO_URL@$REPO_BRANCH_FROM -> $WORKSPACE"
|
|
61
|
-
git clone --depth=1 --branch "$REPO_BRANCH_FROM" "$REPO_URL" "$WORKSPACE"
|
|
62
|
-
cd "$WORKSPACE"
|
|
63
|
-
# Fetch the base ref (shallow) so require-*-before-stop can diff against origin/<base>.
|
|
64
|
-
git fetch --depth=1 origin "$REPO_BRANCH_FROM" >/dev/null 2>&1 || true
|
|
65
|
-
BRANCH="auto/sync-cli-harnesses-$(date -u +%Y%m%dT%H%M%SZ)"
|
|
66
|
-
git checkout -b "$BRANCH"
|
|
67
|
-
log "working on branch $BRANCH"
|
|
68
|
-
|
|
69
|
-
# ---------------- 4. policy-config neutralization ----------------
|
|
70
|
-
# enabledPolicies is a UNION across scopes with no disable field, so a policy must
|
|
71
|
-
# be removed from the file that lists it. --skip-worktree then hides that edit from
|
|
72
|
-
# git status/add (so it never lands in the PR) while failproofai still reads the
|
|
73
|
-
# edited worktree file at runtime. Keeps require-commit/push/pr-before-stop active.
|
|
74
|
-
CFG=".failproofai/policies-config.json"
|
|
75
|
-
if [ -f "$CFG" ]; then
|
|
76
|
-
cfg_tmp="$(mktemp)"
|
|
77
|
-
jq '.enabledPolicies |= map(select(. != "require-ci-green-before-stop" and . != "block-read-outside-cwd"))' "$CFG" > "$cfg_tmp" && mv "$cfg_tmp" "$CFG"
|
|
78
|
-
git update-index --skip-worktree "$CFG"
|
|
79
|
-
log "neutralized require-ci-green-before-stop + block-read-outside-cwd for this run (skip-worktree; not committed)"
|
|
80
|
-
else
|
|
81
|
-
log "WARN: $CFG not found; running with the repo's default policy set"
|
|
82
|
-
fi
|
|
83
|
-
|
|
84
|
-
# ---------------- 5. invoke claude (ULTRACODE, headless, PTY-wrapped) ----------------
|
|
85
|
-
PROMPT_FILE="$WORKSPACE/$PROMPT_PATH"
|
|
86
|
-
if [ ! -f "$PROMPT_FILE" ]; then log "ERROR: prompt missing at $PROMPT_FILE"; exit 65; fi
|
|
87
|
-
|
|
88
|
-
# Node block-buffers stdout when it's a pipe; `script -qefc ... /dev/null` gives
|
|
89
|
-
# claude a PTY so --output-format stream-json line-flushes to the pod logs. `-e`
|
|
90
|
-
# ties script's exit code to claude's.
|
|
91
|
-
RUN_SH="$(mktemp /tmp/run-claude.XXXXXX.sh)"
|
|
92
|
-
cat >"$RUN_SH" <<EOF
|
|
93
|
-
#!/usr/bin/env bash
|
|
94
|
-
exec claude --effort ultracode --model ${CLAUDE_MODEL} \\
|
|
95
|
-
--verbose --output-format stream-json \\
|
|
96
|
-
--dangerously-skip-permissions \\
|
|
97
|
-
-p "\$(cat "$PROMPT_FILE")" 2>&1
|
|
98
|
-
EOF
|
|
99
|
-
chmod +x "$RUN_SH"
|
|
100
|
-
|
|
101
|
-
log "invoking claude --effort ultracode --model ${CLAUDE_MODEL} (prompt: $PROMPT_PATH)"
|
|
102
|
-
set +e
|
|
103
|
-
script -qefc "$RUN_SH" /dev/null
|
|
104
|
-
rc=$?
|
|
105
|
-
set -e
|
|
106
|
-
rm -f "$RUN_SH"
|
|
107
|
-
log "claude exited $rc"
|
|
108
|
-
|
|
109
|
-
exit "$rc"
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# failproofai CLI-canary sandbox — base image
|
|
2
|
-
#
|
|
3
|
-
# Design goals (see failproofai-cli-canary-design.md §4):
|
|
4
|
-
# - SAFE: non-root user, NO sudo installed, no host FS mounted at runtime.
|
|
5
|
-
# The canary fires `sudo whoami` / `.env`-read deny-probes; here they
|
|
6
|
-
# are inert BY CONSTRUCTION even on a day enforcement is broken.
|
|
7
|
-
# - LIGHT: ephemeral daily container (`docker run --rm`), not a daemon.
|
|
8
|
-
# Only this image + one named volume persist; zero idle CPU/RAM.
|
|
9
|
-
# - FRESH: CLIs are NOT baked in — they are `@latest`-installed into the
|
|
10
|
-
# persistent HOME volume at run time (the whole point of the canary),
|
|
11
|
-
# so this base image rebuilds rarely.
|
|
12
|
-
#
|
|
13
|
-
# The HOME volume (mounted at /home/canary) holds: npm-global CLIs, every
|
|
14
|
-
# vendor login/token, and per-CLI config — so logins survive across daily runs.
|
|
15
|
-
|
|
16
|
-
FROM node:22-bookworm-slim
|
|
17
|
-
|
|
18
|
-
# bun from the official image — no `curl | bash` needed at build time.
|
|
19
|
-
COPY --from=oven/bun:latest /usr/local/bin/bun /usr/local/bin/bun
|
|
20
|
-
|
|
21
|
-
# Minimal tooling for the various vendor CLI installers. Deliberately NO sudo.
|
|
22
|
-
# Tooling for the various vendor installers. Deliberately NO sudo.
|
|
23
|
-
# bzip2/xz-utils : goose extracts its Rust binary with these
|
|
24
|
-
# libsecret-1-0 : antigravity caches login tokens via libsecret (best-effort)
|
|
25
|
-
RUN apt-get update -qq \
|
|
26
|
-
&& apt-get install -y -qq --no-install-recommends \
|
|
27
|
-
git ca-certificates curl unzip bzip2 xz-utils libsecret-1-0 \
|
|
28
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
29
|
-
|
|
30
|
-
# Unprivileged user. HOME is the mount point for the persistent named volume;
|
|
31
|
-
# because the image ships a canary-owned /home/canary, an empty named volume
|
|
32
|
-
# mounted here is initialised canary-owned (Docker copies image content+owner).
|
|
33
|
-
# node:22-slim already ships a `node` user at UID 1000, so pin canary to 1001.
|
|
34
|
-
RUN useradd --create-home --uid 1001 --shell /bin/bash canary
|
|
35
|
-
USER canary
|
|
36
|
-
WORKDIR /home/canary
|
|
37
|
-
RUN mkdir -p /home/canary/.npm-global/bin /home/canary/.local/bin
|
|
38
|
-
|
|
39
|
-
# NPM_CONFIG_PREFIX via ENV (not `npm config set`) so it survives the volume
|
|
40
|
-
# mount shadowing /home/canary at runtime. Runtime `npm i -g` lands in the volume.
|
|
41
|
-
ENV NPM_CONFIG_PREFIX=/home/canary/.npm-global
|
|
42
|
-
ENV PATH=/home/canary/.npm-global/bin:/home/canary/.local/bin:/usr/local/bin:/usr/bin:/bin
|
|
43
|
-
|
|
44
|
-
# Sanity: fail the build if bun/node/npm aren't all runnable as the canary user.
|
|
45
|
-
RUN bun --version && node --version && npm --version
|
|
46
|
-
|
|
47
|
-
CMD ["bash"]
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Integration suite
|
|
2
|
-
|
|
3
|
-
A daily **live-enforcement integration test** for failproofai. It answers one
|
|
4
|
-
question the unit/e2e suites can't: *does failproofai still enforce against every
|
|
5
|
-
supported agent CLI, at the versions users actually install today?*
|
|
6
|
-
|
|
7
|
-
Every day (`.github/workflows/integration-suite.yml`) it installs all 12 agent
|
|
8
|
-
CLIs **@latest** into an isolated Docker sandbox, drives each one against
|
|
9
|
-
failproofai's own policies (built from this repo's HEAD), and confirms the hook
|
|
10
|
-
log shows a **DENY**. A *silent-allow* — a blocked action that ran with no deny —
|
|
11
|
-
means enforcement broke against that CLI (e.g. a vendor changed their hook schema
|
|
12
|
-
out from under us). The test asserts the deny **positively**, so drift surfaces
|
|
13
|
-
as a red run + a Slack alert instead of going unnoticed until a user hits it.
|
|
14
|
-
|
|
15
|
-
## Why it's separate from `__tests__/`
|
|
16
|
-
|
|
17
|
-
It drives **real vendor CLIs against real gateway models** — it needs network,
|
|
18
|
-
Docker, credentials, and ~7-10 min, none of which belong in the fast in-process
|
|
19
|
-
vitest suites. So it's a scheduled workflow, not a PR gate.
|
|
20
|
-
|
|
21
|
-
## How a run works
|
|
22
|
-
|
|
23
|
-
The workflow is a thin trigger; `ci-entrypoint.sh` is the front door and does
|
|
24
|
-
everything below except the Actions cache restore/save.
|
|
25
|
-
|
|
26
|
-
1. Restore `integration-suite-state.json` from Actions cache (version-gate +
|
|
27
|
-
broke/recovered diff) — *workflow*.
|
|
28
|
-
2. Build failproofai under test (`dist/index.js` + `dist/cli.mjs`) from this repo.
|
|
29
|
-
3. Decode the OAuth token secrets, build the sandbox image, create the per-run
|
|
30
|
-
HOME volume, install all 12 CLIs (`install-clis.sh`), inject the credential
|
|
31
|
-
files (`inject-tokens.sh`), assemble the gateway env-file.
|
|
32
|
-
4. `run.sh` probes each non-gated CLI (`probe-cli.sh`), builds the report
|
|
33
|
-
(`report.js`), and POSTs it to Slack.
|
|
34
|
-
5. Cleanup (env-file + volume) runs via `trap`, so it happens on failure too.
|
|
35
|
-
|
|
36
|
-
Run it locally the same way CI does — every input is an env var:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
CANARY_LLM_API_KEY=... CANARY_SKIP_BUILD=1 \
|
|
40
|
-
bash integration-suite/ci-entrypoint.sh
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Version-gate:** a CLI is re-probed only when its binary version **or**
|
|
44
|
-
failproofai's HEAD changed since its last green run — unchanged ⇒ can't have
|
|
45
|
-
drifted ⇒ skip, protecting LLM/vendor quota. `FAIL`/`INCONCLUSIVE`/`ERROR` always
|
|
46
|
-
re-probe until they recover. Dispatch with **force** to probe everything.
|
|
47
|
-
|
|
48
|
-
## Two channels: `stable` and `beta`
|
|
49
|
-
|
|
50
|
-
The workflow runs as a **matrix over `CANARY_CHANNEL`**, in two concurrent legs
|
|
51
|
-
answering different questions:
|
|
52
|
-
|
|
53
|
-
| Leg | Installs | Question | On failure |
|
|
54
|
-
|-----|----------|----------|------------|
|
|
55
|
-
| `stable` | what users get, all 12 CLIs | *is enforcement broken now?* | **fails the job** + Slack |
|
|
56
|
-
| `beta` | each vendor's public pre-release ref, 6 CLIs | *is it about to break?* | **advisory only** — never fails |
|
|
57
|
-
|
|
58
|
-
Only six vendors publish something usable ahead of their release, so the beta leg
|
|
59
|
-
skips the rest rather than re-installing a stable build and reporting it as
|
|
60
|
-
pre-release coverage:
|
|
61
|
-
|
|
62
|
-
| CLI | Pre-release ref | Typical lead |
|
|
63
|
-
|-----|-----------------|--------------|
|
|
64
|
-
| codex | npm `alpha` | up to ~12 d (minor bumps only — patches ship blind) |
|
|
65
|
-
| copilot | npm `prerelease` | 0.6–5.8 d |
|
|
66
|
-
| openclaw | npm `beta` | 0.3–11.4 d |
|
|
67
|
-
| cursor | `install?channel=lab` | 2–4 d |
|
|
68
|
-
| goose | `CANARY=true` (rolling tag) | ~1 release cycle |
|
|
69
|
-
| claude | `latest` — **inverted**, see below | ~13 d |
|
|
70
|
-
|
|
71
|
-
**claude runs backwards.** Nothing ships ahead of `latest`, which *is* the
|
|
72
|
-
bleeding edge (~1 release/day); what exists is `stable`, ~13 days behind. So the
|
|
73
|
-
stable leg pins `bash -s stable` — testing what conservative users run, and
|
|
74
|
-
stopping a same-day Anthropic release from red-lighting an unrelated PR — and
|
|
75
|
-
`latest` becomes the early-warning ref. **hermes** is inverted too but has no fix:
|
|
76
|
-
its installer git-clones `main`, which is also what every hermes user gets, so
|
|
77
|
-
there is nothing ahead of us to probe.
|
|
78
|
-
|
|
79
|
-
**Escalation is a cross-leg comparison, not a beta failure.** A CLI red on both
|
|
80
|
-
legs is already broken and belongs to the stable leg's alarm. The early warning is
|
|
81
|
-
`stable green + beta not-green`, held for **two consecutive runs** so a broken
|
|
82
|
-
alpha that gets reverted before release doesn't burn attention. Note the signal is
|
|
83
|
-
usually `INCONCLUSIVE`/`ERROR`, not `FAIL` — a vendor payload change stops the
|
|
84
|
-
model before it ever calls a tool — so a FAIL-only rule would miss it entirely.
|
|
85
|
-
|
|
86
|
-
Each leg has its own Docker volume and Actions cache key: a pre-release install
|
|
87
|
-
overwrites the stable binary in a shared `$HOME`, and a beta result must never be
|
|
88
|
-
able to overwrite the stable leg's gating record.
|
|
89
|
-
|
|
90
|
-
## Auth & secrets (the `cli-integration` Environment)
|
|
91
|
-
|
|
92
|
-
> The GitHub **Environment** is still named `cli-integration` — it's configured in
|
|
93
|
-
> repo settings, not in this tree, so it was deliberately left alone when this
|
|
94
|
-
> directory was renamed. Renaming it there means renaming `environment:` in the
|
|
95
|
-
> workflow at the same time, or the job loses access to every secret.
|
|
96
|
-
|
|
97
|
-
Because this repo is public, all credentials live in a scoped **GitHub
|
|
98
|
-
Environment** (`cli-integration`) — only this workflow's job can read them — and
|
|
99
|
-
the workflow triggers on `schedule`/`workflow_dispatch` **only**, so fork PRs can
|
|
100
|
-
never reach them.
|
|
101
|
-
|
|
102
|
-
| Auth | CLIs | Secret(s) |
|
|
103
|
-
|------|------|-----------|
|
|
104
|
-
| Env-var (gateway) | claude, codex, goose, opencode, pi, hermes, openclaw, factory | `CANARY_LLM_API_KEY`, `CANARY_LLM_BASE_URL` |
|
|
105
|
-
| Env-var (PAT) | copilot | `COPILOT_GITHUB_TOKEN` |
|
|
106
|
-
| Injected token file | cursor, devin, antigravity | `CURSOR_/DEVIN_/ANTIGRAVITY_TOKEN_TGZ_B64` |
|
|
107
|
-
| Delivery | — | `SLACK_WEBHOOK_URL` |
|
|
108
|
-
|
|
109
|
-
The injected-token CLIs carry OAuth session tokens captured from a logged-in
|
|
110
|
-
machine (see `capture-tokens.sh`). They authenticate on a fresh runner, but may
|
|
111
|
-
eventually expire — when that happens the test reports `⚠️ ERROR` for that CLI;
|
|
112
|
-
re-login on the capture machine and refresh the secret.
|
|
113
|
-
|
|
114
|
-
> Note: env-var / secret names keep the historical `CANARY_` prefix internally —
|
|
115
|
-
> renaming them across the harness would be churn with no user-visible benefit.
|
|
116
|
-
|
|
117
|
-
## Files
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
ci-entrypoint.sh CI front door: build -> sandbox -> install -> probe -> cleanup
|
|
121
|
-
Dockerfile non-root sandbox base image
|
|
122
|
-
install-clis.sh install/upgrade the CLIs for $CANARY_CHANNEL (with retries)
|
|
123
|
-
inject-tokens.sh write captured OAuth creds into the fresh volume
|
|
124
|
-
probe-cli.sh live enforcement probe for ONE CLI (the oracle)
|
|
125
|
-
canary-policies.mjs benign-marker custom policies the probe trips
|
|
126
|
-
run.sh orchestrator (gate → probe → report → Slack)
|
|
127
|
-
report.js build the Slack report + diff state (broke/recovered)
|
|
128
|
-
capture-tokens.sh (run on a logged-in machine) refresh the OAuth token secrets
|
|
129
|
-
```
|