@akasecurity/cli 0.9.5 → 0.9.7
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/dist/cli.js +8177 -7248
- package/extension/manifest.json +1 -1
- package/native-host/host.js +1542 -1011
- package/native-host/scan-worker.js +1056 -927
- package/package.json +11 -10
- package/web-ui/package.json +11 -7
- package/web-ui/packages/dashboard-ui/package.json +8 -4
- package/web-ui/packages/detections/package.json +5 -3
- package/web-ui/packages/local-ops/package.json +6 -5
- package/web-ui/packages/persistence/package.json +5 -3
- package/web-ui/packages/plugin-sdk/package.json +5 -2
- package/web-ui/packages/schema/package.json +2 -1
- package/web-ui/packages/ui-kit/package.json +9 -5
- package/web-ui/web-ui/.next/BUILD_ID +1 -1
- package/web-ui/web-ui/.next/app-build-manifest.json +253 -253
- package/web-ui/web-ui/.next/app-path-routes-manifest.json +8 -8
- package/web-ui/web-ui/.next/build-manifest.json +14 -14
- package/web-ui/web-ui/.next/prerender-manifest.json +10 -10
- package/web-ui/web-ui/.next/required-server-files.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/activity/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/activity/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/activity/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/data-shares/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/data-shares/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/data-shares/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/detections/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/detections/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/detections/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/findings/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/findings/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/findings/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/inventory/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/inventory/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/inventory/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/policies/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/policies/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/policies/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/scan/page.js +3 -2
- package/web-ui/web-ui/.next/server/app/(app)/scan/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/scan/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/security/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/security/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/security/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/settings/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/settings/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/updates/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/updates/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/updates/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/vault/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/vault/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/vault/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found.html +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found.rsc +10 -10
- package/web-ui/web-ui/.next/server/app/icon.svg/route.js +1 -1
- package/web-ui/web-ui/.next/server/app/icon.svg/route.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/index.html +1 -1
- package/web-ui/web-ui/.next/server/app/index.rsc +10 -10
- package/web-ui/web-ui/.next/server/app/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app-paths-manifest.json +8 -8
- package/web-ui/web-ui/.next/server/chunks/129.js +783 -0
- package/web-ui/web-ui/.next/server/chunks/214.js +73 -0
- package/web-ui/web-ui/.next/server/chunks/{330.js → 258.js} +1 -1
- package/web-ui/web-ui/.next/server/chunks/261.js +22 -0
- package/web-ui/web-ui/.next/server/chunks/271.js +6 -0
- package/web-ui/web-ui/.next/server/chunks/326.js +12 -0
- package/web-ui/web-ui/.next/server/chunks/477.js +791 -0
- package/web-ui/web-ui/.next/server/chunks/523.js +1 -0
- package/web-ui/web-ui/.next/server/chunks/68.js +123 -0
- package/web-ui/web-ui/.next/server/chunks/803.js +6 -0
- package/web-ui/web-ui/.next/server/chunks/853.js +11 -0
- package/web-ui/web-ui/.next/server/chunks/967.js +1 -0
- package/web-ui/web-ui/.next/server/functions-config-manifest.json +5 -5
- package/web-ui/web-ui/.next/server/middleware-build-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/middleware-manifest.json +5 -5
- package/web-ui/web-ui/.next/server/middleware.js +2 -2
- package/web-ui/web-ui/.next/server/pages/404.html +1 -1
- package/web-ui/web-ui/.next/server/pages/500.html +1 -1
- package/web-ui/web-ui/.next/server/pages/_app.js +1 -1
- package/web-ui/web-ui/.next/server/pages/_app.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/pages/_document.js +1 -1
- package/web-ui/web-ui/.next/server/pages/_document.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/pages/_error.js +9 -9
- package/web-ui/web-ui/.next/server/pages/_error.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/pages-manifest.json +1 -1
- package/web-ui/web-ui/.next/server/server-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/server-reference-manifest.json +1 -1
- package/web-ui/web-ui/.next/static/{x4ixG3_q4UeyC_WNmSFdI → YqH1rSLTmXzavf3MtB9ZX}/_buildManifest.js +1 -1
- package/web-ui/web-ui/.next/static/chunks/180-0ab5475b6174d4b3.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/202-12a474de79b2ad1c.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/392-0af97129ba2175ca.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/{d043c60e-31360d0d5cb78983.js → 39f60ebf-2d09993ae96ffb2f.js} +1 -1
- package/web-ui/web-ui/.next/static/chunks/622-e65110f232ad3136.js +62 -0
- package/web-ui/web-ui/.next/static/chunks/699-3a550a0d6101e35c.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/activity/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/activity/page-2011aeec5114533f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/page-e8fbf441cdc78d7e.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/page-0cf86550a9f22cf8.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/error-b23da3100319d95d.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/page-3b57fa7a28949fdf.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/page-5524f6b8dd008924.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/page-5fcea0008a2c0bfc.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/findings/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/findings/page-5e9249b49d619cf7.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/page-b1676f9a9b4673f1.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/layout-bf74f5338553e0b3.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/policies/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/policies/page-5bdaaab9140bb24a.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/page-3560c03478bda4c7.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/security/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/security/page-d9a6be4fb74dd62b.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/settings/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/settings/page-bc4551c2cd096584.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/updates/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/updates/page-d0b9a88e5cff5d9b.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/vault/loading-6dba555198465a8f.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/vault/page-de6afbc0036fcb0d.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/_not-found/page-70d570cb7ebebf40.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/layout-0c542f2984281272.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/page-3fecd9ee711fb63b.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/framework-ad79db97790c5c58.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/main-62317e1f0973aad9.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/main-app-54d1703ac3de3a4b.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/pages/_app-58f8bdc469e1bada.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/pages/_error-bfbac2b89a182714.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/{webpack-61986b0a62ba55ed.js → webpack-1b293f289da20845.js} +1 -1
- package/web-ui/web-ui/.next/static/css/3be78f90024fcfd7.css +2 -0
- package/web-ui/web-ui/dist/scan-worker.js +1056 -927
- package/web-ui/web-ui/package.json +10 -8
- package/web-ui/web-ui/.next/server/chunks/114.js +0 -792
- package/web-ui/web-ui/.next/server/chunks/160.js +0 -785
- package/web-ui/web-ui/.next/server/chunks/243.js +0 -1
- package/web-ui/web-ui/.next/server/chunks/333.js +0 -1
- package/web-ui/web-ui/.next/server/chunks/363.js +0 -12
- package/web-ui/web-ui/.next/server/chunks/447.js +0 -6
- package/web-ui/web-ui/.next/server/chunks/528.js +0 -73
- package/web-ui/web-ui/.next/server/chunks/539.js +0 -22
- package/web-ui/web-ui/.next/server/chunks/557.js +0 -5
- package/web-ui/web-ui/.next/server/chunks/561.js +0 -123
- package/web-ui/web-ui/.next/server/chunks/935.js +0 -11
- package/web-ui/web-ui/.next/static/chunks/133-14f0f297836736b9.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/321-46ce36c1ef95d231.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/539-b35890d398017f99.js +0 -62
- package/web-ui/web-ui/.next/static/chunks/89-d23f5e27ab3b468f.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/992-ba273ebe2ac236a5.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/activity/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/activity/page-90ea4cb1f1956a03.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/page-d96aa1158bb1c630.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/page-269fa2d4f47e6125.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/error-092d6780c93209d5.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/page-4ad5b60f476d7c6e.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/page-2bf76696fbe6e76d.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/page-5d2511a7c06dd645.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/findings/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/findings/page-1891ec610b461455.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/page-bc090490b3416d48.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/layout-d7a290e9b0dd8a15.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/policies/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/policies/page-1d1a93a1e561ca82.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/page-7a1a29a230626f96.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/security/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/security/page-a7fa0e028623b7cb.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/settings/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/settings/page-9729632fc8128534.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/updates/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/updates/page-bda9e826a1ac1a00.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/vault/loading-0e999b82265bac84.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/vault/page-28116d3ce827e152.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/_not-found/page-3cf97f2dd544e8cb.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/layout-f1727d7b45e0779b.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/page-315a9068831a3ad5.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/framework-a566532c222ba944.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/main-app-9e734a14592bc9c4.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/main-f710385bb68f9de5.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/pages/_app-63f369037199ea68.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/pages/_error-41a11264bde7b852.js +0 -1
- package/web-ui/web-ui/.next/static/css/0af7782f7a750368.css +0 -2
- /package/web-ui/web-ui/.next/static/{x4ixG3_q4UeyC_WNmSFdI → YqH1rSLTmXzavf3MtB9ZX}/_ssgManifest.js +0 -0
package/native-host/host.js
CHANGED
|
@@ -588,6 +588,10 @@ var SQLITE_MIGRATIONS = [
|
|
|
588
588
|
{
|
|
589
589
|
tag: "0020_secret_vault_pagination_indexes",
|
|
590
590
|
sql: "CREATE INDEX `idx_secret_vault_last_seen` ON `secret_vault` (`last_seen`,`pointer_id`);--> statement-breakpoint\nCREATE INDEX `idx_secret_vault_reuse` ON `secret_vault` (`occurrence_count`,`pointer_id`);--> statement-breakpoint\nCREATE INDEX `idx_secret_vault_deref_at` ON `secret_vault_deref` (`at`,`id`);--> statement-breakpoint\nCREATE INDEX `idx_secret_vault_deref_signal` ON `secret_vault_deref` (`at`,`id`) WHERE `reason` NOT IN ('display', 'view-render');"
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
tag: "0021_finding_resolution_resolved_at_index",
|
|
594
|
+
sql: "CREATE INDEX `idx_finding_resolution_resolved_at` ON `finding_resolution` (`resolved_at`);\n"
|
|
591
595
|
}
|
|
592
596
|
];
|
|
593
597
|
|
|
@@ -15303,6 +15307,50 @@ function date4(params) {
|
|
|
15303
15307
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
15304
15308
|
config(en_default());
|
|
15305
15309
|
|
|
15310
|
+
// ../../packages/schema/src/zod/harness-map.ts
|
|
15311
|
+
var HARNESS = {
|
|
15312
|
+
ClaudeCode: "claudecode",
|
|
15313
|
+
Cursor: "cursor",
|
|
15314
|
+
Copilot: "copilot",
|
|
15315
|
+
Codex: "codex",
|
|
15316
|
+
Antigravity: "antigravity",
|
|
15317
|
+
Windsurf: "windsurf",
|
|
15318
|
+
ClaudeDesktop: "claudedesktop",
|
|
15319
|
+
ChatGpt: "chatgpt",
|
|
15320
|
+
ClaudeAi: "claudeai",
|
|
15321
|
+
Api: "api"
|
|
15322
|
+
};
|
|
15323
|
+
var Harness = external_exports.enum(HARNESS).meta({ id: "Harness" });
|
|
15324
|
+
var SOURCE_TOOL = {
|
|
15325
|
+
ClaudeCode: "claude-code",
|
|
15326
|
+
ClaudeDesktop: "claude-desktop",
|
|
15327
|
+
Cursor: "cursor",
|
|
15328
|
+
ChatGpt: "chatgpt",
|
|
15329
|
+
ClaudeAi: "claude-ai",
|
|
15330
|
+
Copilot: "github-copilot",
|
|
15331
|
+
Codex: "codex",
|
|
15332
|
+
Antigravity: "antigravity",
|
|
15333
|
+
// No harness counterpart, deliberately: the CLI's own captures and a capture
|
|
15334
|
+
// whose tool could not be identified both render through the read side's
|
|
15335
|
+
// miss path rather than as a harness of their own.
|
|
15336
|
+
Cli: "cli",
|
|
15337
|
+
Unknown: "unknown"
|
|
15338
|
+
};
|
|
15339
|
+
var SourceTool = external_exports.enum(SOURCE_TOOL).meta({ id: "SourceTool" });
|
|
15340
|
+
var TOOL_TO_HARNESS = {
|
|
15341
|
+
[SOURCE_TOOL.ClaudeCode]: HARNESS.ClaudeCode,
|
|
15342
|
+
[SOURCE_TOOL.ClaudeDesktop]: HARNESS.ClaudeDesktop,
|
|
15343
|
+
[SOURCE_TOOL.Copilot]: HARNESS.Copilot,
|
|
15344
|
+
[SOURCE_TOOL.Cursor]: HARNESS.Cursor,
|
|
15345
|
+
[SOURCE_TOOL.ChatGpt]: HARNESS.ChatGpt,
|
|
15346
|
+
[SOURCE_TOOL.Codex]: HARNESS.Codex,
|
|
15347
|
+
[SOURCE_TOOL.Antigravity]: HARNESS.Antigravity,
|
|
15348
|
+
[SOURCE_TOOL.ClaudeAi]: HARNESS.ClaudeAi
|
|
15349
|
+
};
|
|
15350
|
+
function harnessFromTool(tool) {
|
|
15351
|
+
return TOOL_TO_HARNESS[tool] ?? tool;
|
|
15352
|
+
}
|
|
15353
|
+
|
|
15306
15354
|
// ../../packages/schema/src/zod/finding.ts
|
|
15307
15355
|
var DetectionCategory = external_exports.enum(["pii", "financial", "secret", "phi", "code_context", "code_flaw", "custom", "config"]).meta({ id: "DetectionCategory" });
|
|
15308
15356
|
var Severity = external_exports.enum(["critical", "high", "medium", "low"]).meta({ id: "Severity" });
|
|
@@ -15325,21 +15373,22 @@ var Finding = external_exports.object({
|
|
|
15325
15373
|
}).meta({ id: "Finding" });
|
|
15326
15374
|
var DetectedFinding = Finding.meta({ id: "DetectedFinding" });
|
|
15327
15375
|
var FindingAction = external_exports.enum(["blocked", "redacted", "warned", "allowed", "quarantined", "monitored"]).meta({ id: "FindingAction" });
|
|
15328
|
-
var FindingProvider =
|
|
15329
|
-
"
|
|
15330
|
-
"
|
|
15331
|
-
"
|
|
15332
|
-
"
|
|
15333
|
-
"
|
|
15334
|
-
"
|
|
15335
|
-
"
|
|
15336
|
-
"
|
|
15337
|
-
"
|
|
15376
|
+
var FindingProvider = Harness.extract([
|
|
15377
|
+
"ClaudeCode",
|
|
15378
|
+
"ClaudeDesktop",
|
|
15379
|
+
"Cursor",
|
|
15380
|
+
"Copilot",
|
|
15381
|
+
"ChatGpt",
|
|
15382
|
+
"ClaudeAi",
|
|
15383
|
+
"Codex",
|
|
15384
|
+
"Antigravity",
|
|
15385
|
+
"Api"
|
|
15338
15386
|
]).meta({ id: "FindingProvider" });
|
|
15339
15387
|
var FindingCategory = external_exports.enum([
|
|
15340
15388
|
"secret",
|
|
15341
15389
|
"pii",
|
|
15342
15390
|
"source_code",
|
|
15391
|
+
"code_flaw",
|
|
15343
15392
|
"external_share",
|
|
15344
15393
|
"mcp_server",
|
|
15345
15394
|
"customer_data",
|
|
@@ -15519,6 +15568,7 @@ var FindingInstanceDetail = FindingInstance.extend({
|
|
|
15519
15568
|
policy: FindingPolicyRef
|
|
15520
15569
|
}).meta({ id: "FindingInstanceDetail" });
|
|
15521
15570
|
var DEFAULT_FLAT_FINDINGS_LIMIT = 50;
|
|
15571
|
+
var MAX_FLAT_FINDINGS_LIMIT = 200;
|
|
15522
15572
|
var ListFindingInstancesQuery = external_exports.object({
|
|
15523
15573
|
severity: external_exports.array(Severity).optional(),
|
|
15524
15574
|
// Rule ids, the same vocabulary the grouped list's `subtype` carries.
|
|
@@ -15538,7 +15588,7 @@ var ListFindingInstancesQuery = external_exports.object({
|
|
|
15538
15588
|
q: external_exports.string().optional(),
|
|
15539
15589
|
sessionId: external_exports.string().optional(),
|
|
15540
15590
|
from: external_exports.iso.datetime().optional(),
|
|
15541
|
-
limit: external_exports.coerce.number().int().min(1).max(
|
|
15591
|
+
limit: external_exports.coerce.number().int().min(1).max(MAX_FLAT_FINDINGS_LIMIT).optional(),
|
|
15542
15592
|
cursor: external_exports.string().optional()
|
|
15543
15593
|
});
|
|
15544
15594
|
var ListFindingInstancesResponse = external_exports.object({
|
|
@@ -15600,33 +15650,6 @@ var ListFindingLocationsResponse = external_exports.object({
|
|
|
15600
15650
|
hasMore: external_exports.boolean()
|
|
15601
15651
|
}).meta({ id: "ListFindingLocationsResponse" });
|
|
15602
15652
|
|
|
15603
|
-
// ../../packages/schema/src/zod/harness-map.ts
|
|
15604
|
-
var Harness = external_exports.enum([
|
|
15605
|
-
"claudecode",
|
|
15606
|
-
"cursor",
|
|
15607
|
-
"copilot",
|
|
15608
|
-
"codex",
|
|
15609
|
-
"antigravity",
|
|
15610
|
-
"windsurf",
|
|
15611
|
-
"claudedesktop",
|
|
15612
|
-
"chatgpt",
|
|
15613
|
-
"claudeai",
|
|
15614
|
-
"api"
|
|
15615
|
-
]).meta({ id: "Harness" });
|
|
15616
|
-
var TOOL_TO_HARNESS = {
|
|
15617
|
-
"claude-code": "claudecode",
|
|
15618
|
-
"claude-desktop": "claudedesktop",
|
|
15619
|
-
"github-copilot": "copilot",
|
|
15620
|
-
cursor: "cursor",
|
|
15621
|
-
chatgpt: "chatgpt",
|
|
15622
|
-
codex: "codex",
|
|
15623
|
-
antigravity: "antigravity",
|
|
15624
|
-
"claude-ai": "claudeai"
|
|
15625
|
-
};
|
|
15626
|
-
function harnessFromTool(tool) {
|
|
15627
|
-
return TOOL_TO_HARNESS[tool] ?? tool;
|
|
15628
|
-
}
|
|
15629
|
-
|
|
15630
15653
|
// ../../packages/schema/src/zod/meta.ts
|
|
15631
15654
|
var InventoryObjectType = external_exports.enum(["host", "harness", "user", "skill", "hook", "mcp_server", "config_file"]).meta({ id: "InventoryObjectType" });
|
|
15632
15655
|
var AuditEventType = external_exports.enum([
|
|
@@ -16079,686 +16102,37 @@ var ActivityOverviewResponse = external_exports.object({
|
|
|
16079
16102
|
sessions: ListActivitySessionsResponse
|
|
16080
16103
|
}).meta({ id: "ActivityOverviewResponse" });
|
|
16081
16104
|
|
|
16082
|
-
// ../../packages/schema/src/zod/
|
|
16083
|
-
var
|
|
16084
|
-
var
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
filePath: external_exports.string().optional(),
|
|
16101
|
-
// The host tool whose input/output was scanned (e.g. 'Bash', 'WebFetch'),
|
|
16102
|
-
// set by the tool-scanning hooks. The tool NAME only — never the tool's
|
|
16103
|
-
// arguments or output, which can carry the very value a finding masked
|
|
16104
|
-
// (metadata is stored unredacted). Gives findings on non-file captures a
|
|
16105
|
-
// display location ("via Bash") when no filePath exists.
|
|
16106
|
-
toolName: external_exports.string().optional(),
|
|
16107
|
-
// Set (true) by the worktree scanner when the file is excluded by the
|
|
16108
|
-
// repo's .gitignore. Gitignored files ARE still scanned — local scratch and
|
|
16109
|
-
// generated code can leak real secrets — but the provenance is recorded so
|
|
16110
|
-
// policy/dashboards can treat those findings as informational rather than
|
|
16111
|
-
// blocking. Omitted (not false) for tracked files and non-scan events.
|
|
16112
|
-
gitignored: external_exports.boolean().optional(),
|
|
16113
|
-
// Set (true) ONLY when the event's `content` is the COMPLETE file at
|
|
16114
|
-
// capture time (a worktree scan reading from disk). Hook-captured edits
|
|
16115
|
-
// (e.g. an Edit tool's new_string) are partial fragments and MUST NOT set
|
|
16116
|
-
// this. The resolver-on-ingest keys its fixed-at-source dropout
|
|
16117
|
-
// diff on this marker: only a whole-file snapshot can prove a previously
|
|
16118
|
-
// open finding is gone; a fragment's absence proves nothing (the secret
|
|
16119
|
-
// may live outside the hunk). Omitted (not false) for fragments and
|
|
16120
|
-
// non-scan events, so pre-marker clients safely default to the
|
|
16121
|
-
// non-authoritative path.
|
|
16122
|
-
wholeFile: external_exports.boolean().optional(),
|
|
16123
|
-
model: external_exports.string().optional(),
|
|
16124
|
-
turnIndex: external_exports.number().int().nonnegative().optional(),
|
|
16125
|
-
// Distributed-tracing correlation. `correlationId` ties a recorded event back
|
|
16126
|
-
// to the request that captured/ingested it (a UUID, generated independently of
|
|
16127
|
-
// the trace id); `traceId` is the W3C trace id (32 lowercase hex chars) of the
|
|
16128
|
-
// originating span when telemetry is enabled. Both optional + backward
|
|
16129
|
-
// compatible — populated by the plugin (see @akasecurity/plugin-sdk).
|
|
16130
|
-
correlationId: external_exports.uuid().optional(),
|
|
16131
|
-
traceId: external_exports.string().regex(/^[0-9a-f]{32}$/).optional(),
|
|
16132
|
-
// Ids of the detection exceptions that downgraded findings in this capture
|
|
16133
|
-
// to 'allow' — the enforcement audit trail's link back to the grant that
|
|
16134
|
-
// authorized the bypass. Absent on captures where no exception applied.
|
|
16135
|
-
exceptionIds: external_exports.array(external_exports.guid()).optional()
|
|
16136
|
-
}).meta({ id: "EventMetadata" });
|
|
16137
|
-
var Event = external_exports.object({
|
|
16138
|
-
id: external_exports.guid(),
|
|
16139
|
-
sourceTool: SourceTool,
|
|
16140
|
-
kind: EventKind,
|
|
16141
|
-
occurredAt: external_exports.iso.datetime(),
|
|
16142
|
-
contentHash: external_exports.string(),
|
|
16143
|
-
content: external_exports.string(),
|
|
16144
|
-
metadata: EventMetadata.optional()
|
|
16145
|
-
}).meta({ id: "Event" });
|
|
16146
|
-
var IngestEvent = Event.meta({ id: "IngestEvent" });
|
|
16147
|
-
var IngestBatch = external_exports.object({
|
|
16148
|
-
events: external_exports.array(IngestEvent).min(1).max(100),
|
|
16149
|
-
// Dedup policy for this batch. Id-dedup ALWAYS applies. 'content-hash'
|
|
16150
|
-
// additionally rejects any event whose contentHash the store has already
|
|
16151
|
-
// recorded — for re-runnable bulk ingest (worktree scan, transcript
|
|
16152
|
-
// backfill), where a re-run mints fresh event ids for identical content and
|
|
16153
|
-
// would otherwise accumulate duplicates. Live hook traffic must NOT set it:
|
|
16154
|
-
// two genuinely separate prompts can be byte-identical and both belong on
|
|
16155
|
-
// the timeline.
|
|
16156
|
-
dedupe: external_exports.literal("content-hash").optional()
|
|
16157
|
-
}).meta({ id: "IngestBatch" });
|
|
16158
|
-
|
|
16159
|
-
// ../../packages/schema/src/zod/inventory.ts
|
|
16160
|
-
var AssetType = external_exports.enum(["project", "skill", "mcp", "hook", "config"]).meta({ id: "AssetType" });
|
|
16161
|
-
var AccessLevel = external_exports.enum(["open", "approved", "blocked"]).meta({ id: "AccessLevel" });
|
|
16162
|
-
var Origin = external_exports.enum(["source", "public-dep", "vendored", "config", "data", "docs", "generated"]).meta({ id: "Origin" });
|
|
16163
|
-
var TrustLevel = external_exports.enum(["known-good", "risky", "unapproved"]).meta({ id: "TrustLevel" });
|
|
16164
|
-
var Flag = external_exports.enum(["update", "stale", "conflict", "unknown", "change", "untracked", "risk", "findings"]).meta({ id: "Flag" });
|
|
16165
|
-
var Visibility = external_exports.enum(["public", "private"]).meta({ id: "Visibility" });
|
|
16166
|
-
var HarnessEventKind = external_exports.enum(["block", "redact", "warn"]).meta({ id: "HarnessEventKind" });
|
|
16167
|
-
var HarnessId = external_exports.enum(["claudecode", "cursor", "codex", "antigravity"]).meta({ id: "HarnessId" });
|
|
16168
|
-
var AccessCounts = external_exports.object({
|
|
16169
|
-
open: external_exports.number().int().nonnegative(),
|
|
16170
|
-
approved: external_exports.number().int().nonnegative(),
|
|
16171
|
-
blocked: external_exports.number().int().nonnegative(),
|
|
16172
|
-
total: external_exports.number().int().nonnegative()
|
|
16173
|
-
}).meta({ id: "AccessCounts" });
|
|
16174
|
-
var AssetSummary = external_exports.object({
|
|
16175
|
-
id: external_exports.string(),
|
|
16176
|
-
type: AssetType,
|
|
16177
|
-
name: external_exports.string(),
|
|
16178
|
-
sub: external_exports.string(),
|
|
16179
|
-
flags: external_exports.array(Flag),
|
|
16180
|
-
/** MCP servers only — omitted for all other types. */
|
|
16181
|
-
trust: TrustLevel.optional()
|
|
16182
|
-
}).meta({ id: "AssetSummary" });
|
|
16183
|
-
var ProjectSummary = external_exports.object({
|
|
16184
|
-
id: external_exports.string(),
|
|
16185
|
-
name: external_exports.string(),
|
|
16186
|
-
repo: external_exports.string(),
|
|
16187
|
-
visibility: Visibility,
|
|
16188
|
-
language: external_exports.string(),
|
|
16189
|
-
policyDefault: AccessLevel,
|
|
16190
|
-
updatedAt: external_exports.iso.datetime(),
|
|
16191
|
-
accessCounts: AccessCounts,
|
|
16192
|
-
findingsCount: external_exports.number().int().nonnegative()
|
|
16193
|
-
}).meta({ id: "ProjectSummary" });
|
|
16194
|
-
var HarnessCategory = external_exports.object({
|
|
16195
|
-
/** One of config/skill/mcp/hook — never project (enforced at service layer). */
|
|
16196
|
-
type: AssetType,
|
|
16197
|
-
assets: external_exports.array(AssetSummary)
|
|
16105
|
+
// ../../packages/schema/src/zod/config-inventory.ts
|
|
16106
|
+
var ConfigScope = external_exports.enum(["user", "project", "local", "plugin"]);
|
|
16107
|
+
var SkillScanEntry = external_exports.object({
|
|
16108
|
+
name: external_exports.string().min(1),
|
|
16109
|
+
// The identity source: a marketplace repo for plugin skills (e.g.
|
|
16110
|
+
// 'anthropics/skills'), 'local' for personal ~/.claude/skills, or
|
|
16111
|
+
// 'project:<repo-identity>' for checked-in project skills. The surrogate keeps
|
|
16112
|
+
// a personal skill named 'pdf' from colliding with the marketplace 'pdf'.
|
|
16113
|
+
source: external_exports.string().min(1),
|
|
16114
|
+
scope: ConfigScope,
|
|
16115
|
+
pluginName: external_exports.string().optional(),
|
|
16116
|
+
// Volatile — rides the attribute bag, never the identity hash.
|
|
16117
|
+
version: external_exports.string().optional(),
|
|
16118
|
+
description: external_exports.string().optional(),
|
|
16119
|
+
// Skill directory mtime (ISO) — the "updated Nd ago" freshness signal.
|
|
16120
|
+
updatedAt: external_exports.iso.datetime().optional(),
|
|
16121
|
+
// Filesystem path — the promoted inventory `location` column.
|
|
16122
|
+
location: external_exports.string().optional()
|
|
16198
16123
|
});
|
|
16199
|
-
var
|
|
16200
|
-
|
|
16201
|
-
|
|
16202
|
-
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
var AssetGroup = external_exports.object({
|
|
16212
|
-
/** Group key — never project (enforced at service layer). */
|
|
16213
|
-
type: AssetType,
|
|
16214
|
-
total: external_exports.number().int().nonnegative(),
|
|
16215
|
-
/**
|
|
16216
|
-
* MCP group only — omitted for all other types.
|
|
16217
|
-
* Partial: only TrustLevel keys with non-zero counts are included.
|
|
16218
|
-
* Strict: unknown keys are rejected — only TrustLevel values are valid keys.
|
|
16219
|
-
*/
|
|
16220
|
-
trustRollup: external_exports.object({
|
|
16221
|
-
"known-good": external_exports.number().int().nonnegative(),
|
|
16222
|
-
risky: external_exports.number().int().nonnegative(),
|
|
16223
|
-
unapproved: external_exports.number().int().nonnegative()
|
|
16224
|
-
}).partial().strict().optional(),
|
|
16225
|
-
/**
|
|
16226
|
-
* Partial: only Flag keys with non-zero counts are included.
|
|
16227
|
-
* Strict: unknown keys are rejected — only Flag values are valid keys.
|
|
16228
|
-
*/
|
|
16229
|
-
flagRollup: external_exports.object({
|
|
16230
|
-
update: external_exports.number().int().nonnegative(),
|
|
16231
|
-
stale: external_exports.number().int().nonnegative(),
|
|
16232
|
-
conflict: external_exports.number().int().nonnegative(),
|
|
16233
|
-
unknown: external_exports.number().int().nonnegative(),
|
|
16234
|
-
change: external_exports.number().int().nonnegative(),
|
|
16235
|
-
untracked: external_exports.number().int().nonnegative(),
|
|
16236
|
-
risk: external_exports.number().int().nonnegative(),
|
|
16237
|
-
findings: external_exports.number().int().nonnegative()
|
|
16238
|
-
}).partial().strict(),
|
|
16239
|
-
items: external_exports.array(AssetSummary)
|
|
16240
|
-
}).meta({ id: "AssetGroup" });
|
|
16241
|
-
var ListAssetsResponse = external_exports.object({ groups: external_exports.array(AssetGroup) }).meta({ id: "ListAssetsResponse" });
|
|
16242
|
-
var McpTool = external_exports.object({
|
|
16243
|
-
name: external_exports.string(),
|
|
16244
|
-
signature: external_exports.string(),
|
|
16245
|
-
description: external_exports.string(),
|
|
16246
|
-
write: external_exports.boolean(),
|
|
16247
|
-
/** Non-null string when tool is dangerous / blocked; null otherwise. */
|
|
16248
|
-
risk: external_exports.string().nullable()
|
|
16249
|
-
}).meta({ id: "McpTool" });
|
|
16250
|
-
var AssetFindingRef = external_exports.object({
|
|
16251
|
-
id: external_exports.string(),
|
|
16252
|
-
title: external_exports.string(),
|
|
16253
|
-
note: external_exports.string()
|
|
16254
|
-
});
|
|
16255
|
-
var AssetDetail = AssetSummary.extend({
|
|
16256
|
-
/** string | null — null when no description is available. */
|
|
16257
|
-
description: external_exports.string().nullable(),
|
|
16258
|
-
/** trustLevel | null — null for non-MCP assets. */
|
|
16259
|
-
trust: TrustLevel.nullable(),
|
|
16260
|
-
/** Type-specific raw key/values — FE renders the grid. */
|
|
16261
|
-
meta: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
16262
|
-
/** always present — object when there is an active finding, null when absent. */
|
|
16263
|
-
finding: AssetFindingRef.nullable(),
|
|
16264
|
-
/** MCP exposed-tools list — omitted for non-mcp. */
|
|
16265
|
-
tools: external_exports.array(McpTool).optional()
|
|
16266
|
-
}).meta({ id: "AssetDetail" });
|
|
16267
|
-
var ListProjectsResponse = external_exports.object({ items: external_exports.array(ProjectSummary) }).meta({ id: "ListProjectsResponse" });
|
|
16268
|
-
var InventoryStats = external_exports.object({
|
|
16269
|
-
/** Total assets/projects with ≥1 flag or finding (drives the attention header chip). */
|
|
16270
|
-
attention: external_exports.number().int().nonnegative(),
|
|
16271
|
-
byType: external_exports.object({
|
|
16272
|
-
project: external_exports.number().int().nonnegative(),
|
|
16273
|
-
skill: external_exports.number().int().nonnegative(),
|
|
16274
|
-
mcp: external_exports.number().int().nonnegative(),
|
|
16275
|
-
hook: external_exports.number().int().nonnegative(),
|
|
16276
|
-
config: external_exports.number().int().nonnegative()
|
|
16277
|
-
}),
|
|
16278
|
-
harnesses: external_exports.number().int().nonnegative(),
|
|
16279
|
-
mcpTrust: external_exports.object({
|
|
16280
|
-
"known-good": external_exports.number().int().nonnegative(),
|
|
16281
|
-
risky: external_exports.number().int().nonnegative(),
|
|
16282
|
-
unapproved: external_exports.number().int().nonnegative()
|
|
16283
|
-
})
|
|
16284
|
-
}).meta({ id: "InventoryStats" });
|
|
16285
|
-
var FileSummary = external_exports.object({
|
|
16286
|
-
path: external_exports.string(),
|
|
16287
|
-
name: external_exports.string(),
|
|
16288
|
-
origin: Origin,
|
|
16289
|
-
/** Effective access (override applied). */
|
|
16290
|
-
access: AccessLevel,
|
|
16291
|
-
/** True when a file_access_override differs from the computed default. */
|
|
16292
|
-
isCustom: external_exports.boolean(),
|
|
16293
|
-
findings: external_exports.number().int().nonnegative(),
|
|
16294
|
-
/** When the file was auto-blocked by a detection; null when not blocked. */
|
|
16295
|
-
blockedAt: external_exports.iso.datetime().nullable().optional(),
|
|
16296
|
-
/** Why the file was blocked; null when absent. */
|
|
16297
|
-
note: external_exports.string().nullable().optional()
|
|
16298
|
-
}).meta({ id: "FileSummary" });
|
|
16299
|
-
var FolderSummary = external_exports.object({
|
|
16300
|
-
name: external_exports.string(),
|
|
16301
|
-
path: external_exports.string(),
|
|
16302
|
-
/** Rollup of effective access across all descendants. */
|
|
16303
|
-
accessCounts: AccessCounts
|
|
16304
|
-
}).meta({ id: "FolderSummary" });
|
|
16305
|
-
var ProjectTreeResponse = external_exports.object({
|
|
16306
|
-
project: external_exports.object({
|
|
16307
|
-
id: external_exports.string(),
|
|
16308
|
-
repo: external_exports.string(),
|
|
16309
|
-
visibility: Visibility
|
|
16310
|
-
}),
|
|
16311
|
-
path: external_exports.string(),
|
|
16312
|
-
/** Browse mode: one-level folders at the current path. Omitted in search mode. */
|
|
16313
|
-
folders: external_exports.array(FolderSummary).optional(),
|
|
16314
|
-
files: external_exports.array(FileSummary)
|
|
16315
|
-
}).meta({ id: "ProjectTreeResponse" });
|
|
16316
|
-
var FileDetail = FileSummary.extend({
|
|
16317
|
-
project: external_exports.object({
|
|
16318
|
-
repo: external_exports.string(),
|
|
16319
|
-
visibility: Visibility,
|
|
16320
|
-
language: external_exports.string(),
|
|
16321
|
-
policyDefault: AccessLevel,
|
|
16322
|
-
updatedAt: external_exports.iso.datetime()
|
|
16323
|
-
}),
|
|
16324
|
-
findingsRefs: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string() }))
|
|
16325
|
-
}).meta({ id: "FileDetail" });
|
|
16326
|
-
var SetFileAccessBody = external_exports.object({
|
|
16327
|
-
path: external_exports.string(),
|
|
16328
|
-
access: AccessLevel
|
|
16329
|
-
}).meta({ id: "SetFileAccessBody" });
|
|
16330
|
-
var SetFileAccessResponse = external_exports.object({
|
|
16331
|
-
file: FileSummary,
|
|
16332
|
-
accessCounts: AccessCounts
|
|
16333
|
-
}).meta({ id: "SetFileAccessResponse" });
|
|
16334
|
-
var SetMcpTrustBody = external_exports.object({ trust: TrustLevel }).meta({ id: "SetMcpTrustBody" });
|
|
16335
|
-
var HarnessEventItem = external_exports.object({
|
|
16336
|
-
kind: HarnessEventKind,
|
|
16337
|
-
title: external_exports.string(),
|
|
16338
|
-
detail: external_exports.string(),
|
|
16339
|
-
occurredAt: external_exports.iso.datetime(),
|
|
16340
|
-
findingId: external_exports.string().nullable().optional()
|
|
16341
|
-
}).meta({ id: "HarnessEventItem" });
|
|
16342
|
-
var HarnessEventsResponse = external_exports.object({
|
|
16343
|
-
counts: external_exports.object({
|
|
16344
|
-
block: external_exports.number().int().nonnegative(),
|
|
16345
|
-
redact: external_exports.number().int().nonnegative(),
|
|
16346
|
-
warn: external_exports.number().int().nonnegative()
|
|
16347
|
-
}),
|
|
16348
|
-
items: external_exports.array(HarnessEventItem)
|
|
16349
|
-
}).meta({ id: "HarnessEventsResponse" });
|
|
16350
|
-
var RescanResponse = external_exports.object({
|
|
16351
|
-
jobId: external_exports.string(),
|
|
16352
|
-
startedAt: external_exports.iso.datetime()
|
|
16353
|
-
}).meta({ id: "RescanResponse" });
|
|
16354
|
-
var ConnectProjectBody = external_exports.object({ repo: external_exports.string() }).meta({ id: "ConnectProjectBody" });
|
|
16355
|
-
var ListAssetsQuery = external_exports.object({
|
|
16356
|
-
/** Filter by one or more AssetType values; absent means all types. */
|
|
16357
|
-
type: external_exports.array(AssetType).optional(),
|
|
16358
|
-
/** Free-text search term. */
|
|
16359
|
-
q: external_exports.string().optional()
|
|
16360
|
-
});
|
|
16361
|
-
var GetProjectTreeQuery = external_exports.object({
|
|
16362
|
-
/** Subtree root path; defaults to repository root when absent. */
|
|
16363
|
-
path: external_exports.string().optional(),
|
|
16364
|
-
/** Free-text filter applied to file paths. */
|
|
16365
|
-
q: external_exports.string().optional(),
|
|
16366
|
-
/**
|
|
16367
|
-
* Special listing mode. `blocked` returns every effectively-blocked, auto-blocked
|
|
16368
|
-
* file across the whole repo (folders omitted, most-recent first), ignoring
|
|
16369
|
-
* `path`/`q` — powers the project-wide "recently blocked" strip.
|
|
16370
|
-
*/
|
|
16371
|
-
filter: external_exports.enum(["blocked"]).optional()
|
|
16372
|
-
});
|
|
16373
|
-
var GetProjectFileQuery = external_exports.object({
|
|
16374
|
-
/** Repository-relative file path; absent or empty → 400. */
|
|
16375
|
-
path: external_exports.string()
|
|
16376
|
-
});
|
|
16377
|
-
var GetHarnessEventsQuery = external_exports.object({
|
|
16378
|
-
/** Maximum number of events to return. Range: 1–50; default: 7. */
|
|
16379
|
-
limit: external_exports.coerce.number().int().min(1).max(50).default(7)
|
|
16380
|
-
});
|
|
16381
|
-
|
|
16382
|
-
// ../../packages/schema/src/zod/exception.ts
|
|
16383
|
-
var ExceptionScope = external_exports.enum(["once", "temporary", "permanent"]);
|
|
16384
|
-
var ExceptionConditions = external_exports.object({
|
|
16385
|
-
repo: external_exports.string().optional(),
|
|
16386
|
-
sourceTool: external_exports.string().optional(),
|
|
16387
|
-
provider: external_exports.string().optional()
|
|
16388
|
-
}).strict();
|
|
16389
|
-
var ExceptionCapability = external_exports.enum(["suppress", "reveal_to_model"]);
|
|
16390
|
-
var DetectionException = external_exports.object({
|
|
16391
|
-
id: external_exports.guid(),
|
|
16392
|
-
ruleId: external_exports.string(),
|
|
16393
|
-
// Denormalized from the rule, for reporting — never matched on.
|
|
16394
|
-
category: DetectionCategory,
|
|
16395
|
-
// HMAC-SHA256 hex of the raw match under a machine-local key: a KEYED
|
|
16396
|
-
// fingerprint, never the raw value, and never reversible. Matching recomputes
|
|
16397
|
-
// the fingerprint from a fresh capture; the value itself is never stored.
|
|
16398
|
-
// Shape-constrained so a malformed — or accidentally raw — value is rejected
|
|
16399
|
-
// at the boundary rather than persisted.
|
|
16400
|
-
valueFingerprint: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
16401
|
-
// Version of the fingerprint key the grant was written under; a rotated key
|
|
16402
|
-
// invalidates old grants rather than silently mismatching them.
|
|
16403
|
-
keyVersion: external_exports.number().int().positive(),
|
|
16404
|
-
// maskMatch() preview of the approved value — never the raw value.
|
|
16405
|
-
maskedValue: external_exports.string(),
|
|
16406
|
-
capability: ExceptionCapability.default("suppress"),
|
|
16407
|
-
scope: ExceptionScope,
|
|
16408
|
-
expiresAt: external_exports.iso.datetime().nullable(),
|
|
16409
|
-
maxUses: external_exports.number().int().positive().nullable(),
|
|
16410
|
-
useCount: external_exports.number().int().nonnegative(),
|
|
16411
|
-
lastUsedAt: external_exports.iso.datetime().nullable(),
|
|
16412
|
-
// Mandatory: every grant carries the human reason it exists.
|
|
16413
|
-
justification: external_exports.string().min(1),
|
|
16414
|
-
conditions: ExceptionConditions.nullable(),
|
|
16415
|
-
createdBy: external_exports.string(),
|
|
16416
|
-
createdVia: external_exports.enum(["cli-approve", "cli-add", "web-approve", "web-add", "api", "setup-triage"]),
|
|
16417
|
-
createdAt: external_exports.iso.datetime(),
|
|
16418
|
-
updatedAt: external_exports.iso.datetime(),
|
|
16419
|
-
// Revocation is terminal and retained — consumed/expired/revoked rows are
|
|
16420
|
-
// audit evidence; nothing in the exception lifecycle hard-deletes.
|
|
16421
|
-
revokedAt: external_exports.iso.datetime().nullable(),
|
|
16422
|
-
revokedBy: external_exports.string().nullable(),
|
|
16423
|
-
revokeReason: external_exports.string().nullable()
|
|
16424
|
-
});
|
|
16425
|
-
var ExceptionBundleEntry = DetectionException.pick({
|
|
16426
|
-
id: true,
|
|
16427
|
-
ruleId: true,
|
|
16428
|
-
valueFingerprint: true,
|
|
16429
|
-
keyVersion: true,
|
|
16430
|
-
capability: true,
|
|
16431
|
-
expiresAt: true,
|
|
16432
|
-
maxUses: true,
|
|
16433
|
-
useCount: true,
|
|
16434
|
-
conditions: true
|
|
16435
|
-
});
|
|
16436
|
-
var ExceptionDescriptor = DetectionException.omit({ valueFingerprint: true });
|
|
16437
|
-
|
|
16438
|
-
// ../../packages/schema/src/zod/rule.ts
|
|
16439
|
-
var MatcherType = external_exports.enum(["keyword", "regex", "validator"]).meta({ id: "MatcherType" });
|
|
16440
|
-
var RuleProbeVerdict = external_exports.enum(["safe", "quarantined"]).meta({ id: "RuleProbeVerdict" });
|
|
16441
|
-
var KeywordMatcher = external_exports.object({
|
|
16442
|
-
type: external_exports.literal("keyword"),
|
|
16443
|
-
// An empty keyword matches at every position, yielding one zero-length span
|
|
16444
|
-
// per character. Rejected here because a keyword that matches everything is
|
|
16445
|
-
// never intentional.
|
|
16446
|
-
keywords: external_exports.array(external_exports.string().min(1)).min(1),
|
|
16447
|
-
caseSensitive: external_exports.boolean().default(false)
|
|
16448
|
-
});
|
|
16449
|
-
function isValidRegex(pattern, flags) {
|
|
16450
|
-
try {
|
|
16451
|
-
new RegExp(pattern, flags);
|
|
16452
|
-
return true;
|
|
16453
|
-
} catch {
|
|
16454
|
-
return false;
|
|
16455
|
-
}
|
|
16456
|
-
}
|
|
16457
|
-
function matchesEmptyString(pattern, flags) {
|
|
16458
|
-
try {
|
|
16459
|
-
const re = new RegExp(pattern, flags.replace(/[gy]/g, ""));
|
|
16460
|
-
return re.exec("")?.[0].length === 0;
|
|
16461
|
-
} catch {
|
|
16462
|
-
return false;
|
|
16463
|
-
}
|
|
16464
|
-
}
|
|
16465
|
-
var MAX_PATTERN_LENGTH = 2e3;
|
|
16466
|
-
var RegexMatcher = external_exports.object({
|
|
16467
|
-
type: external_exports.literal("regex"),
|
|
16468
|
-
pattern: external_exports.string().min(1).max(MAX_PATTERN_LENGTH),
|
|
16469
|
-
flags: external_exports.string().default("gi"),
|
|
16470
|
-
captureGroup: external_exports.number().int().nonnegative().optional()
|
|
16471
|
-
}).refine((v) => isValidRegex(v.pattern, v.flags), {
|
|
16472
|
-
message: "pattern/flags do not form a valid JavaScript regular expression",
|
|
16473
|
-
path: ["pattern"]
|
|
16474
|
-
}).refine((v) => v.captureGroup !== void 0 || !matchesEmptyString(v.pattern, v.flags), {
|
|
16475
|
-
message: 'a whole-match regex that can match the empty string (e.g. "\\d*", "a?", "(?:)") can hang the matcher \u2014 scope the quantifier to a captureGroup, or require at least one character',
|
|
16476
|
-
path: ["pattern"]
|
|
16477
|
-
});
|
|
16478
|
-
var ValidatorMatcher = external_exports.object({
|
|
16479
|
-
type: external_exports.literal("validator"),
|
|
16480
|
-
name: external_exports.enum(["luhn", "entropy", "ssn-checksum"]),
|
|
16481
|
-
config: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
16482
|
-
});
|
|
16483
|
-
var Matcher = external_exports.discriminatedUnion("type", [KeywordMatcher, RegexMatcher, ValidatorMatcher]).meta({ id: "Matcher" });
|
|
16484
|
-
var AppliesTo = external_exports.object({
|
|
16485
|
-
// Dot-prefixed, e.g. ".py" — matches the scanner's SOURCE_EXTENSIONS shape.
|
|
16486
|
-
extensions: external_exports.array(external_exports.string().regex(/^\.[A-Za-z0-9]+$/)).min(1)
|
|
16487
|
-
}).meta({ id: "AppliesTo" });
|
|
16488
|
-
var PostValidatorRef = external_exports.union([
|
|
16489
|
-
external_exports.string(),
|
|
16490
|
-
external_exports.object({
|
|
16491
|
-
name: external_exports.string(),
|
|
16492
|
-
config: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
16493
|
-
})
|
|
16494
|
-
]).meta({ id: "PostValidatorRef" });
|
|
16495
|
-
var RequiresNearby = external_exports.object({
|
|
16496
|
-
// Each array, when present, must be non-empty and contain non-empty strings —
|
|
16497
|
-
// an empty/blank criterion would either never fire or (for labels) match
|
|
16498
|
-
// everything.
|
|
16499
|
-
categories: external_exports.array(DetectionCategory).min(1).optional(),
|
|
16500
|
-
ruleIds: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
16501
|
-
labels: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
16502
|
-
windowChars: external_exports.number().int().positive().default(160),
|
|
16503
|
-
// Optional confidence bump applied when a gated match is corroborated. Capped
|
|
16504
|
-
// small: it nudges confidence, it does not assert certainty.
|
|
16505
|
-
confidenceBoost: external_exports.number().min(0).max(0.3).optional()
|
|
16506
|
-
}).refine(
|
|
16507
|
-
(v) => (v.categories?.length ?? 0) + (v.ruleIds?.length ?? 0) + (v.labels?.length ?? 0) > 0,
|
|
16508
|
-
{ message: "requiresNearby needs at least one of categories, ruleIds, or labels" }
|
|
16509
|
-
).meta({ id: "RequiresNearby" });
|
|
16510
|
-
var RuleFixture = external_exports.object({
|
|
16511
|
-
label: external_exports.string(),
|
|
16512
|
-
text: external_exports.string().max(5e4),
|
|
16513
|
-
shouldMatch: external_exports.boolean(),
|
|
16514
|
-
// Simulated file context for the scan, so fixtures can assert `appliesTo`
|
|
16515
|
-
// gating (e.g. a Python-only pattern must NOT fire in a .ts file).
|
|
16516
|
-
filePath: external_exports.string().optional(),
|
|
16517
|
-
expectedSpans: external_exports.array(external_exports.object({ start: external_exports.number(), end: external_exports.number() })).optional()
|
|
16518
|
-
}).meta({ id: "RuleFixture" });
|
|
16519
|
-
var Rule = external_exports.object({
|
|
16520
|
-
specVersion: external_exports.literal(1),
|
|
16521
|
-
// `packId/ruleName` (e.g. `secrets/aws-access-key`). NOTE the first segment is
|
|
16522
|
-
// the PACK id, NOT a namespace — this is a DIFFERENT slug space from a
|
|
16523
|
-
// detection id (`namespace/packId`, decoded by splitDetectionId). A Rule.id
|
|
16524
|
-
// therefore carries no namespace and is not globally unique across publishers;
|
|
16525
|
-
// never feed one to splitDetectionId. `category` below (per-rule) is the
|
|
16526
|
-
// taxonomy axis; the pack's enforcement policy is installed_packs.policy_id.
|
|
16527
|
-
id: external_exports.string().regex(/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/),
|
|
16528
|
-
name: external_exports.string(),
|
|
16529
|
-
category: DetectionCategory,
|
|
16530
|
-
severity: Severity,
|
|
16531
|
-
matcher: Matcher,
|
|
16532
|
-
appliesTo: AppliesTo.optional(),
|
|
16533
|
-
postValidators: external_exports.array(PostValidatorRef).optional(),
|
|
16534
|
-
requiresNearby: RequiresNearby.optional(),
|
|
16535
|
-
examples: external_exports.array(external_exports.string()).optional()
|
|
16536
|
-
}).meta({ id: "Rule" });
|
|
16537
|
-
var Author = external_exports.object({
|
|
16538
|
-
name: external_exports.string(),
|
|
16539
|
-
email: external_exports.email().optional(),
|
|
16540
|
-
url: external_exports.url().optional()
|
|
16541
|
-
}).meta({ id: "Author" });
|
|
16542
|
-
var PackManifest = external_exports.object({
|
|
16543
|
-
specVersion: external_exports.literal(1),
|
|
16544
|
-
id: external_exports.string(),
|
|
16545
|
-
name: external_exports.string(),
|
|
16546
|
-
version: external_exports.string(),
|
|
16547
|
-
rules: external_exports.array(external_exports.string()),
|
|
16548
|
-
// Optional attribution/provenance — consumed by the rule marketplace.
|
|
16549
|
-
description: external_exports.string().optional(),
|
|
16550
|
-
author: Author.optional(),
|
|
16551
|
-
license: external_exports.string().optional(),
|
|
16552
|
-
sourceUrl: external_exports.url().optional()
|
|
16553
|
-
}).meta({ id: "PackManifest" });
|
|
16554
|
-
|
|
16555
|
-
// ../../packages/schema/src/zod/policy.ts
|
|
16556
|
-
var PolicyScope = external_exports.enum(["global", "repo", "user"]).meta({ id: "PolicyScope" });
|
|
16557
|
-
var PolicyTarget = external_exports.union([external_exports.object({ ruleId: external_exports.string() }), external_exports.object({ category: DetectionCategory })]).meta({ id: "PolicyTarget" });
|
|
16558
|
-
var Policy = external_exports.object({
|
|
16559
|
-
id: external_exports.guid(),
|
|
16560
|
-
scope: PolicyScope,
|
|
16561
|
-
target: PolicyTarget,
|
|
16562
|
-
action: ActionTaken,
|
|
16563
|
-
enabled: external_exports.boolean().default(true),
|
|
16564
|
-
customKeywords: external_exports.array(external_exports.string()).optional(),
|
|
16565
|
-
// Display name — optional so older policy rows without name still parse.
|
|
16566
|
-
// Added for the findings API (policy.name column migration).
|
|
16567
|
-
name: external_exports.string().optional()
|
|
16568
|
-
}).meta({ id: "Policy" });
|
|
16569
|
-
var PolicyBundle = external_exports.object({
|
|
16570
|
-
version: external_exports.string(),
|
|
16571
|
-
policies: external_exports.array(Policy),
|
|
16572
|
-
// Rules from the installed marketplace packs (snapshotted by the
|
|
16573
|
-
// control plane). The plugin registers these in addition to its bundled
|
|
16574
|
-
// packs. Optional so older backends — and older on-disk caches — that omit
|
|
16575
|
-
// the field still parse; consumers read `bundle.rules ?? []`.
|
|
16576
|
-
rules: external_exports.array(Rule).optional(),
|
|
16577
|
-
// When true, `rules` IS the complete effective ruleset and the runtime must
|
|
16578
|
-
// NOT merge its compiled-in bundled packs — the standalone gateway sets this
|
|
16579
|
-
// after reading the user's installed snapshot (installed_packs, enabled
|
|
16580
|
-
// packs only), which is how detection updates stay manual: new bundled
|
|
16581
|
-
// rules run only after the user applies the pack update. Absent/false keeps
|
|
16582
|
-
// the historical composition (bundled packs + rules) — older caches.
|
|
16583
|
-
rulesComplete: external_exports.boolean().optional(),
|
|
16584
|
-
// Active detection exceptions, evaluation subset only (see
|
|
16585
|
-
// ExceptionBundleEntry). Optional so older bundle producers — and older
|
|
16586
|
-
// on-disk caches — that omit the field still parse; consumers read
|
|
16587
|
-
// `bundle.exceptions ?? []`.
|
|
16588
|
-
exceptions: external_exports.array(ExceptionBundleEntry).optional(),
|
|
16589
|
-
// Installed pack version, keyed by ruleId, for rules in `rules` that came
|
|
16590
|
-
// from a versioned installed pack. Optional so older backends — and older
|
|
16591
|
-
// on-disk caches — that omit the field still parse; consumers fall back to
|
|
16592
|
-
// the rule's own spec version. NOT the bundle version above — see
|
|
16593
|
-
// installedRuleset's ruleVersions for the source of truth.
|
|
16594
|
-
ruleVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
16595
|
-
customKeywords: external_exports.array(external_exports.string()),
|
|
16596
|
-
fetchedAt: external_exports.iso.datetime()
|
|
16597
|
-
}).meta({ id: "PolicyBundle" });
|
|
16598
|
-
var OBSERVE_ONLY_CATEGORIES = ["config"];
|
|
16599
|
-
var ENFORCEABLE_CATEGORIES = DetectionCategory.options.filter((c) => !OBSERVE_ONLY_CATEGORIES.includes(c));
|
|
16600
|
-
var CATEGORY_PEAK_SEVERITY = {
|
|
16601
|
-
secret: "critical",
|
|
16602
|
-
financial: "critical",
|
|
16603
|
-
// core-financial/credit-card
|
|
16604
|
-
code_flaw: "critical",
|
|
16605
|
-
pii: "high",
|
|
16606
|
-
phi: "high",
|
|
16607
|
-
custom: "high",
|
|
16608
|
-
// user-defined; conservative
|
|
16609
|
-
code_context: "low",
|
|
16610
|
-
config: "low"
|
|
16611
|
-
// observe-only; floors to monitor regardless
|
|
16612
|
-
};
|
|
16613
|
-
function severityFloorPolicy(category) {
|
|
16614
|
-
if (OBSERVE_ONLY_CATEGORIES.includes(category)) return "monitor";
|
|
16615
|
-
const peak = CATEGORY_PEAK_SEVERITY[category];
|
|
16616
|
-
return peak === "critical" || peak === "high" ? "warn" : "monitor";
|
|
16617
|
-
}
|
|
16618
|
-
var PolicyKind = external_exports.enum(["builtin", "custom"]).meta({ id: "PolicyKind" });
|
|
16619
|
-
var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "block"];
|
|
16620
|
-
var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
|
|
16621
|
-
var BUILTIN_ORDER = KNOWN_BUILTIN_IDS;
|
|
16622
|
-
var BUILTIN_POLICY_SPECS = {
|
|
16623
|
-
monitor: {
|
|
16624
|
-
name: "Monitor",
|
|
16625
|
-
action: "log",
|
|
16626
|
-
description: "Log every match for audit. The request is allowed through untouched."
|
|
16627
|
-
},
|
|
16628
|
-
warn: {
|
|
16629
|
-
name: "Warn",
|
|
16630
|
-
action: "warn",
|
|
16631
|
-
description: "Allow the request, but warn the user inline before it is sent."
|
|
16632
|
-
},
|
|
16633
|
-
redact: {
|
|
16634
|
-
name: "Redact",
|
|
16635
|
-
action: "redact",
|
|
16636
|
-
description: "Automatically strip the matched value from the request, then continue."
|
|
16637
|
-
},
|
|
16638
|
-
block: {
|
|
16639
|
-
name: "Block",
|
|
16640
|
-
action: "block",
|
|
16641
|
-
description: "Refuse the request entirely whenever any rule in this detection matches."
|
|
16642
|
-
}
|
|
16643
|
-
};
|
|
16644
|
-
function builtinPolicyToAction(id) {
|
|
16645
|
-
return BUILTIN_POLICY_SPECS[id].action;
|
|
16646
|
-
}
|
|
16647
|
-
var DEFAULT_ACTIONS = Object.fromEntries(
|
|
16648
|
-
DetectionCategory.options.map((c) => [c, builtinPolicyToAction(severityFloorPolicy(c))])
|
|
16649
|
-
);
|
|
16650
|
-
var BUILTIN_POLICIES = Object.fromEntries(
|
|
16651
|
-
KNOWN_BUILTIN_IDS.map((id) => [id, { id, ...BUILTIN_POLICY_SPECS[id] }])
|
|
16652
|
-
);
|
|
16653
|
-
var DEFAULT_PACK_POLICY_ID = "monitor";
|
|
16654
|
-
function policyIdToAction(policyId) {
|
|
16655
|
-
const parsed = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
|
|
16656
|
-
const id = parsed.success ? parsed.data : DEFAULT_PACK_POLICY_ID;
|
|
16657
|
-
return BUILTIN_POLICIES[id].action;
|
|
16658
|
-
}
|
|
16659
|
-
var UsedByItem = external_exports.object({
|
|
16660
|
-
id: external_exports.string(),
|
|
16661
|
-
name: external_exports.string(),
|
|
16662
|
-
ruleCount: external_exports.number().int().nonnegative(),
|
|
16663
|
-
enabled: external_exports.boolean()
|
|
16664
|
-
}).meta({ id: "UsedByItem" });
|
|
16665
|
-
var PolicyListItem = external_exports.object({
|
|
16666
|
-
id: external_exports.string(),
|
|
16667
|
-
kind: PolicyKind,
|
|
16668
|
-
name: external_exports.string(),
|
|
16669
|
-
enabled: external_exports.boolean(),
|
|
16670
|
-
usedByCount: external_exports.number().int().nonnegative()
|
|
16671
|
-
}).meta({ id: "PolicyListItem" });
|
|
16672
|
-
var PolicyDetail = external_exports.object({
|
|
16673
|
-
specVersion: external_exports.literal(1),
|
|
16674
|
-
id: external_exports.string(),
|
|
16675
|
-
kind: PolicyKind,
|
|
16676
|
-
name: external_exports.string(),
|
|
16677
|
-
enabled: external_exports.boolean(),
|
|
16678
|
-
description: external_exports.string(),
|
|
16679
|
-
usedBy: external_exports.array(UsedByItem)
|
|
16680
|
-
}).meta({ id: "PolicyDetail" });
|
|
16681
|
-
var PolicyStatsResponse = external_exports.object({
|
|
16682
|
-
policies: external_exports.number().int().nonnegative(),
|
|
16683
|
-
builtin: external_exports.number().int().nonnegative(),
|
|
16684
|
-
custom: external_exports.number().int().nonnegative(),
|
|
16685
|
-
detectionsGoverned: external_exports.number().int().nonnegative()
|
|
16686
|
-
}).meta({ id: "PolicyStatsResponse" });
|
|
16687
|
-
|
|
16688
|
-
// ../../packages/schema/src/zod/api.ts
|
|
16689
|
-
var LIST_QUERY_MAX_LIMIT = 200;
|
|
16690
|
-
var ListEventsQuery = external_exports.object({
|
|
16691
|
-
cursor: external_exports.string().optional(),
|
|
16692
|
-
limit: external_exports.coerce.number().int().min(1).max(LIST_QUERY_MAX_LIMIT).default(50),
|
|
16693
|
-
sourceTool: external_exports.string().optional(),
|
|
16694
|
-
kind: external_exports.string().optional(),
|
|
16695
|
-
from: external_exports.iso.datetime().optional(),
|
|
16696
|
-
to: external_exports.iso.datetime().optional()
|
|
16697
|
-
});
|
|
16698
|
-
var ListEventsResponse = external_exports.object({
|
|
16699
|
-
items: external_exports.array(Event),
|
|
16700
|
-
nextCursor: external_exports.string().nullable()
|
|
16701
|
-
}).meta({ id: "ListEventsResponse" });
|
|
16702
|
-
var IngestResponse = external_exports.object({
|
|
16703
|
-
accepted: external_exports.number().int().nonnegative(),
|
|
16704
|
-
duplicates: external_exports.number().int().nonnegative()
|
|
16705
|
-
}).meta({ id: "IngestResponse" });
|
|
16706
|
-
var ListFindingsQuery = external_exports.object({
|
|
16707
|
-
cursor: external_exports.string().optional(),
|
|
16708
|
-
limit: external_exports.coerce.number().int().min(1).max(LIST_QUERY_MAX_LIMIT).default(50),
|
|
16709
|
-
severity: external_exports.string().optional(),
|
|
16710
|
-
category: external_exports.string().optional(),
|
|
16711
|
-
eventId: external_exports.guid().optional()
|
|
16712
|
-
});
|
|
16713
|
-
var ListFindingsResponse = external_exports.object({
|
|
16714
|
-
items: external_exports.array(Finding),
|
|
16715
|
-
nextCursor: external_exports.string().nullable()
|
|
16716
|
-
}).meta({ id: "ListFindingsResponse" });
|
|
16717
|
-
var ListPoliciesResponse = external_exports.object({ items: external_exports.array(PolicyListItem) }).meta({ id: "ListPoliciesResponse" });
|
|
16718
|
-
var CreatePolicyRequest = Policy.omit({ id: true }).meta({
|
|
16719
|
-
id: "CreatePolicyRequest"
|
|
16720
|
-
});
|
|
16721
|
-
var UpdatePolicyRequest = Policy.partial().required({ id: true }).meta({ id: "UpdatePolicyRequest" });
|
|
16722
|
-
var RecordAuditEventResponse = external_exports.object({ accepted: external_exports.boolean() }).meta({ id: "RecordAuditEventResponse" });
|
|
16723
|
-
var ErrorResponse = external_exports.object({
|
|
16724
|
-
error: external_exports.object({
|
|
16725
|
-
code: external_exports.string(),
|
|
16726
|
-
message: external_exports.string(),
|
|
16727
|
-
details: external_exports.unknown().optional()
|
|
16728
|
-
})
|
|
16729
|
-
}).meta({ id: "ErrorResponse" });
|
|
16730
|
-
|
|
16731
|
-
// ../../packages/schema/src/zod/config-inventory.ts
|
|
16732
|
-
var ConfigScope = external_exports.enum(["user", "project", "local", "plugin"]);
|
|
16733
|
-
var SkillScanEntry = external_exports.object({
|
|
16734
|
-
name: external_exports.string().min(1),
|
|
16735
|
-
// The identity source: a marketplace repo for plugin skills (e.g.
|
|
16736
|
-
// 'anthropics/skills'), 'local' for personal ~/.claude/skills, or
|
|
16737
|
-
// 'project:<repo-identity>' for checked-in project skills. The surrogate keeps
|
|
16738
|
-
// a personal skill named 'pdf' from colliding with the marketplace 'pdf'.
|
|
16739
|
-
source: external_exports.string().min(1),
|
|
16740
|
-
scope: ConfigScope,
|
|
16741
|
-
pluginName: external_exports.string().optional(),
|
|
16742
|
-
// Volatile — rides the attribute bag, never the identity hash.
|
|
16743
|
-
version: external_exports.string().optional(),
|
|
16744
|
-
description: external_exports.string().optional(),
|
|
16745
|
-
// Skill directory mtime (ISO) — the "updated Nd ago" freshness signal.
|
|
16746
|
-
updatedAt: external_exports.iso.datetime().optional(),
|
|
16747
|
-
// Filesystem path — the promoted inventory `location` column.
|
|
16748
|
-
location: external_exports.string().optional()
|
|
16749
|
-
});
|
|
16750
|
-
var HookScanEntry = external_exports.object({
|
|
16751
|
-
// Hook event name (PreToolUse, PostToolUse, …). Open string, not an enum: the
|
|
16752
|
-
// set is harness-defined and grows without a schema change.
|
|
16753
|
-
event: external_exports.string().min(1),
|
|
16754
|
-
// The tool matcher ('Bash', 'Edit|Write', …). Absent = matches all tools.
|
|
16755
|
-
matcher: external_exports.string().optional(),
|
|
16756
|
-
command: external_exports.string().min(1),
|
|
16757
|
-
timeout: external_exports.number().optional(),
|
|
16758
|
-
scope: ConfigScope,
|
|
16759
|
-
pluginName: external_exports.string().optional(),
|
|
16760
|
-
// The settings file / hooks.json the entry came from.
|
|
16761
|
-
location: external_exports.string().optional()
|
|
16124
|
+
var HookScanEntry = external_exports.object({
|
|
16125
|
+
// Hook event name (PreToolUse, PostToolUse, …). Open string, not an enum: the
|
|
16126
|
+
// set is harness-defined and grows without a schema change.
|
|
16127
|
+
event: external_exports.string().min(1),
|
|
16128
|
+
// The tool matcher ('Bash', 'Edit|Write', …). Absent = matches all tools.
|
|
16129
|
+
matcher: external_exports.string().optional(),
|
|
16130
|
+
command: external_exports.string().min(1),
|
|
16131
|
+
timeout: external_exports.number().optional(),
|
|
16132
|
+
scope: ConfigScope,
|
|
16133
|
+
pluginName: external_exports.string().optional(),
|
|
16134
|
+
// The settings file / hooks.json the entry came from.
|
|
16135
|
+
location: external_exports.string().optional()
|
|
16762
16136
|
});
|
|
16763
16137
|
var McpServerScanEntry = external_exports.object({
|
|
16764
16138
|
// The server's config key ("github", "filesystem", …) — identity, with the
|
|
@@ -16954,6 +16328,164 @@ var PackId = external_exports.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
|
16954
16328
|
var SemVer = external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?$/);
|
|
16955
16329
|
var PublisherKind = external_exports.enum(["labs", "user", "org"]);
|
|
16956
16330
|
|
|
16331
|
+
// ../../packages/schema/src/zod/rule.ts
|
|
16332
|
+
var MatcherType = external_exports.enum(["keyword", "regex"]).meta({ id: "MatcherType" });
|
|
16333
|
+
var RuleProbeVerdict = external_exports.enum(["safe", "quarantined"]).meta({ id: "RuleProbeVerdict" });
|
|
16334
|
+
var KeywordMatcher = external_exports.strictObject({
|
|
16335
|
+
type: external_exports.literal("keyword"),
|
|
16336
|
+
// An empty keyword matches at every position, yielding one zero-length span
|
|
16337
|
+
// per character. Rejected here because a keyword that matches everything is
|
|
16338
|
+
// never intentional.
|
|
16339
|
+
keywords: external_exports.array(external_exports.string().min(1)).min(1),
|
|
16340
|
+
caseSensitive: external_exports.boolean().default(false)
|
|
16341
|
+
});
|
|
16342
|
+
function isValidRegex(pattern, flags) {
|
|
16343
|
+
try {
|
|
16344
|
+
new RegExp(pattern, flags);
|
|
16345
|
+
return true;
|
|
16346
|
+
} catch {
|
|
16347
|
+
return false;
|
|
16348
|
+
}
|
|
16349
|
+
}
|
|
16350
|
+
function probeFlags(flags) {
|
|
16351
|
+
return flags.replace(/[gy]/g, "");
|
|
16352
|
+
}
|
|
16353
|
+
function matchesEmptyString(pattern, flags) {
|
|
16354
|
+
try {
|
|
16355
|
+
const re = new RegExp(pattern, probeFlags(flags));
|
|
16356
|
+
return re.exec("")?.[0].length === 0;
|
|
16357
|
+
} catch {
|
|
16358
|
+
return false;
|
|
16359
|
+
}
|
|
16360
|
+
}
|
|
16361
|
+
function spansWholeMatch(captureGroup) {
|
|
16362
|
+
return captureGroup === void 0 || captureGroup === 0;
|
|
16363
|
+
}
|
|
16364
|
+
function captureGroupCount(pattern, flags) {
|
|
16365
|
+
try {
|
|
16366
|
+
const probe = new RegExp(`${pattern}|`, probeFlags(flags));
|
|
16367
|
+
const result = probe.exec("");
|
|
16368
|
+
return result ? result.length - 1 : void 0;
|
|
16369
|
+
} catch {
|
|
16370
|
+
return void 0;
|
|
16371
|
+
}
|
|
16372
|
+
}
|
|
16373
|
+
var MAX_PATTERN_LENGTH = 2e3;
|
|
16374
|
+
var RegexMatcher = external_exports.strictObject({
|
|
16375
|
+
type: external_exports.literal("regex"),
|
|
16376
|
+
pattern: external_exports.string().min(1).max(MAX_PATTERN_LENGTH),
|
|
16377
|
+
flags: external_exports.string().default("gi"),
|
|
16378
|
+
captureGroup: external_exports.number().int().nonnegative().optional()
|
|
16379
|
+
}).refine((v) => isValidRegex(v.pattern, v.flags), {
|
|
16380
|
+
message: "pattern/flags do not form a valid JavaScript regular expression",
|
|
16381
|
+
path: ["pattern"]
|
|
16382
|
+
}).refine((v) => !spansWholeMatch(v.captureGroup) || !matchesEmptyString(v.pattern, v.flags), {
|
|
16383
|
+
message: 'a whole-match regex that can match the empty string (e.g. "\\d*", "a?", "(?:)") can hang the matcher \u2014 scope the quantifier to a captureGroup, or require at least one character',
|
|
16384
|
+
path: ["pattern"]
|
|
16385
|
+
}).superRefine((v, ctx) => {
|
|
16386
|
+
if (v.captureGroup === void 0) return;
|
|
16387
|
+
const groups = captureGroupCount(v.pattern, v.flags);
|
|
16388
|
+
if (groups === void 0 || v.captureGroup <= groups) return;
|
|
16389
|
+
ctx.addIssue({
|
|
16390
|
+
code: "custom",
|
|
16391
|
+
path: ["captureGroup"],
|
|
16392
|
+
message: `captureGroup ${String(v.captureGroup)} is out of range \u2014 the pattern declares ${String(groups)} capture group(s), so valid values are 0-${String(groups)}. An out-of-range group never matches, which would make the rule silently never fire.`
|
|
16393
|
+
});
|
|
16394
|
+
});
|
|
16395
|
+
var Matcher = external_exports.discriminatedUnion("type", [KeywordMatcher, RegexMatcher]).meta({ id: "Matcher" });
|
|
16396
|
+
var MATCHER_TYPES = MatcherType.options;
|
|
16397
|
+
var AppliesTo = external_exports.strictObject({
|
|
16398
|
+
// Dot-prefixed, e.g. ".py" — matches the scanner's SOURCE_EXTENSIONS shape.
|
|
16399
|
+
extensions: external_exports.array(external_exports.string().regex(/^\.[A-Za-z0-9]+$/)).min(1)
|
|
16400
|
+
}).meta({ id: "AppliesTo" });
|
|
16401
|
+
var PostValidatorName = external_exports.enum(["entropy", "luhn"]).meta({ id: "PostValidatorName" });
|
|
16402
|
+
var PostValidatorRef = external_exports.union(
|
|
16403
|
+
[
|
|
16404
|
+
PostValidatorName,
|
|
16405
|
+
external_exports.strictObject({
|
|
16406
|
+
name: PostValidatorName,
|
|
16407
|
+
config: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
16408
|
+
})
|
|
16409
|
+
],
|
|
16410
|
+
{
|
|
16411
|
+
// A union reports one collapsed issue for every way its arms can fail, so
|
|
16412
|
+
// this has to describe the whole shape rather than just the name — it is
|
|
16413
|
+
// what an author sees for a misspelled name AND for a stray key in the
|
|
16414
|
+
// object form. The names come from the enum so the message cannot go
|
|
16415
|
+
// stale. Without it Zod says only "Invalid input", which is precisely the
|
|
16416
|
+
// no-feedback outcome this schema exists to remove.
|
|
16417
|
+
error: () => `not a valid post-validator: use a bare name (${PostValidatorName.options.map((name) => JSON.stringify(name)).join(
|
|
16418
|
+
" or "
|
|
16419
|
+
)}) or { "name": ..., "config": { ... } }. An unrecognized name would be a false-positive guard that never runs.`
|
|
16420
|
+
}
|
|
16421
|
+
).meta({ id: "PostValidatorRef" });
|
|
16422
|
+
var RequiresNearby = external_exports.strictObject({
|
|
16423
|
+
// Each array, when present, must be non-empty and contain non-empty strings —
|
|
16424
|
+
// an empty/blank criterion would either never fire or (for labels) match
|
|
16425
|
+
// everything.
|
|
16426
|
+
categories: external_exports.array(DetectionCategory).min(1).optional(),
|
|
16427
|
+
ruleIds: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
16428
|
+
labels: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
16429
|
+
windowChars: external_exports.number().int().positive().default(160),
|
|
16430
|
+
// Optional confidence bump applied when a gated match is corroborated. Capped
|
|
16431
|
+
// small: it nudges confidence, it does not assert certainty.
|
|
16432
|
+
confidenceBoost: external_exports.number().min(0).max(0.3).optional()
|
|
16433
|
+
}).refine(
|
|
16434
|
+
(v) => (v.categories?.length ?? 0) + (v.ruleIds?.length ?? 0) + (v.labels?.length ?? 0) > 0,
|
|
16435
|
+
{ message: "requiresNearby needs at least one of categories, ruleIds, or labels" }
|
|
16436
|
+
).meta({ id: "RequiresNearby" });
|
|
16437
|
+
var RuleFixture = external_exports.strictObject({
|
|
16438
|
+
label: external_exports.string(),
|
|
16439
|
+
text: external_exports.string().max(5e4),
|
|
16440
|
+
shouldMatch: external_exports.boolean(),
|
|
16441
|
+
// Simulated file context for the scan, so fixtures can assert `appliesTo`
|
|
16442
|
+
// gating (e.g. a Python-only pattern must NOT fire in a .ts file).
|
|
16443
|
+
filePath: external_exports.string().optional(),
|
|
16444
|
+
expectedSpans: external_exports.array(external_exports.strictObject({ start: external_exports.number(), end: external_exports.number() })).optional()
|
|
16445
|
+
}).meta({ id: "RuleFixture" });
|
|
16446
|
+
var Rule = external_exports.strictObject({
|
|
16447
|
+
// A pinned literal over a STRICT object, and the two together decide how this
|
|
16448
|
+
// format may grow. A rule carrying a key not listed below is refused with
|
|
16449
|
+
// `unrecognized_keys`; a rule declaring `specVersion: 2` is refused with
|
|
16450
|
+
// `invalid_value`. So the only additive path is adding an OPTIONAL field here
|
|
16451
|
+
// — that keeps every rule authored before it valid — and a rule author has no
|
|
16452
|
+
// way to introduce a field of their own or to opt into a later version.
|
|
16453
|
+
// Widening the format means changing this literal and every consumer of it.
|
|
16454
|
+
specVersion: external_exports.literal(1),
|
|
16455
|
+
// `packId/ruleName` (e.g. `secrets/aws-access-key`). NOTE the first segment is
|
|
16456
|
+
// the PACK id, NOT a namespace — this is a DIFFERENT slug space from a
|
|
16457
|
+
// detection id (`namespace/packId`, decoded by splitDetectionId). A Rule.id
|
|
16458
|
+
// therefore carries no namespace and is not globally unique across publishers;
|
|
16459
|
+
// never feed one to splitDetectionId. `category` below (per-rule) is the
|
|
16460
|
+
// taxonomy axis; the pack's enforcement policy is installed_packs.policy_id.
|
|
16461
|
+
id: external_exports.string().regex(/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/),
|
|
16462
|
+
name: external_exports.string(),
|
|
16463
|
+
category: DetectionCategory,
|
|
16464
|
+
severity: Severity,
|
|
16465
|
+
matcher: Matcher,
|
|
16466
|
+
appliesTo: AppliesTo.optional(),
|
|
16467
|
+
postValidators: external_exports.array(PostValidatorRef).optional(),
|
|
16468
|
+
requiresNearby: RequiresNearby.optional(),
|
|
16469
|
+
examples: external_exports.array(external_exports.string()).optional()
|
|
16470
|
+
}).meta({ id: "Rule" });
|
|
16471
|
+
var Author = external_exports.object({
|
|
16472
|
+
name: external_exports.string(),
|
|
16473
|
+
email: external_exports.email().optional(),
|
|
16474
|
+
url: external_exports.url().optional()
|
|
16475
|
+
}).meta({ id: "Author" });
|
|
16476
|
+
var PackManifest = external_exports.object({
|
|
16477
|
+
specVersion: external_exports.literal(1),
|
|
16478
|
+
id: external_exports.string(),
|
|
16479
|
+
name: external_exports.string(),
|
|
16480
|
+
version: external_exports.string(),
|
|
16481
|
+
rules: external_exports.array(external_exports.string()),
|
|
16482
|
+
// Optional attribution/provenance — consumed by the rule marketplace.
|
|
16483
|
+
description: external_exports.string().optional(),
|
|
16484
|
+
author: Author.optional(),
|
|
16485
|
+
license: external_exports.string().optional(),
|
|
16486
|
+
sourceUrl: external_exports.url().optional()
|
|
16487
|
+
}).meta({ id: "PackManifest" });
|
|
16488
|
+
|
|
16957
16489
|
// ../../packages/schema/src/zod/detection.ts
|
|
16958
16490
|
var OriginEnum = external_exports.enum(["library"]).meta({ id: "OriginEnum" });
|
|
16959
16491
|
var DetectionFilterEnum = external_exports.enum(["all", "library", "custom", "customized", "updates"]);
|
|
@@ -17152,6 +16684,231 @@ function buildDetectionsList(summaries, query) {
|
|
|
17152
16684
|
return { counts, items: filtered.map(summaryToDetectionListItem) };
|
|
17153
16685
|
}
|
|
17154
16686
|
|
|
16687
|
+
// ../../packages/schema/src/zod/inventory.ts
|
|
16688
|
+
var AssetType = external_exports.enum(["project", "skill", "mcp", "hook", "config"]).meta({ id: "AssetType" });
|
|
16689
|
+
var AccessLevel = external_exports.enum(["open", "approved", "blocked"]).meta({ id: "AccessLevel" });
|
|
16690
|
+
var Origin = external_exports.enum(["source", "public-dep", "vendored", "config", "data", "docs", "generated"]).meta({ id: "Origin" });
|
|
16691
|
+
var TrustLevel = external_exports.enum(["known-good", "risky", "unapproved"]).meta({ id: "TrustLevel" });
|
|
16692
|
+
var Flag = external_exports.enum(["update", "stale", "conflict", "unknown", "change", "untracked", "risk", "findings"]).meta({ id: "Flag" });
|
|
16693
|
+
var Visibility = external_exports.enum(["public", "private"]).meta({ id: "Visibility" });
|
|
16694
|
+
var HarnessEventKind = external_exports.enum(["block", "redact", "warn"]).meta({ id: "HarnessEventKind" });
|
|
16695
|
+
var HarnessId = Harness.extract(["ClaudeCode", "Cursor", "Codex", "Antigravity"]).meta({
|
|
16696
|
+
id: "HarnessId"
|
|
16697
|
+
});
|
|
16698
|
+
var AccessCounts = external_exports.object({
|
|
16699
|
+
open: external_exports.number().int().nonnegative(),
|
|
16700
|
+
approved: external_exports.number().int().nonnegative(),
|
|
16701
|
+
blocked: external_exports.number().int().nonnegative(),
|
|
16702
|
+
total: external_exports.number().int().nonnegative()
|
|
16703
|
+
}).meta({ id: "AccessCounts" });
|
|
16704
|
+
var AssetSummary = external_exports.object({
|
|
16705
|
+
id: external_exports.string(),
|
|
16706
|
+
type: AssetType,
|
|
16707
|
+
name: external_exports.string(),
|
|
16708
|
+
sub: external_exports.string(),
|
|
16709
|
+
flags: external_exports.array(Flag),
|
|
16710
|
+
/** MCP servers only — omitted for all other types. */
|
|
16711
|
+
trust: TrustLevel.optional()
|
|
16712
|
+
}).meta({ id: "AssetSummary" });
|
|
16713
|
+
var ProjectSummary = external_exports.object({
|
|
16714
|
+
id: external_exports.string(),
|
|
16715
|
+
name: external_exports.string(),
|
|
16716
|
+
repo: external_exports.string(),
|
|
16717
|
+
visibility: Visibility,
|
|
16718
|
+
language: external_exports.string(),
|
|
16719
|
+
policyDefault: AccessLevel,
|
|
16720
|
+
updatedAt: external_exports.iso.datetime(),
|
|
16721
|
+
accessCounts: AccessCounts,
|
|
16722
|
+
findingsCount: external_exports.number().int().nonnegative()
|
|
16723
|
+
}).meta({ id: "ProjectSummary" });
|
|
16724
|
+
var HarnessCategory = external_exports.object({
|
|
16725
|
+
/** One of config/skill/mcp/hook — never project (enforced at service layer). */
|
|
16726
|
+
type: AssetType,
|
|
16727
|
+
assets: external_exports.array(AssetSummary)
|
|
16728
|
+
});
|
|
16729
|
+
var HarnessSummary = external_exports.object({
|
|
16730
|
+
id: HarnessId,
|
|
16731
|
+
label: external_exports.string(),
|
|
16732
|
+
kind: external_exports.string(),
|
|
16733
|
+
version: external_exports.string(),
|
|
16734
|
+
sessions: external_exports.number().int().nonnegative(),
|
|
16735
|
+
assetCount: external_exports.number().int().nonnegative(),
|
|
16736
|
+
flagCount: external_exports.number().int().nonnegative(),
|
|
16737
|
+
projects: external_exports.array(ProjectSummary),
|
|
16738
|
+
categories: external_exports.array(HarnessCategory)
|
|
16739
|
+
}).meta({ id: "HarnessSummary" });
|
|
16740
|
+
var ListHarnessesResponse = external_exports.object({ items: external_exports.array(HarnessSummary) }).meta({ id: "ListHarnessesResponse" });
|
|
16741
|
+
var AssetGroup = external_exports.object({
|
|
16742
|
+
/** Group key — never project (enforced at service layer). */
|
|
16743
|
+
type: AssetType,
|
|
16744
|
+
total: external_exports.number().int().nonnegative(),
|
|
16745
|
+
/**
|
|
16746
|
+
* MCP group only — omitted for all other types.
|
|
16747
|
+
* Partial: only TrustLevel keys with non-zero counts are included.
|
|
16748
|
+
* Strict: unknown keys are rejected — only TrustLevel values are valid keys.
|
|
16749
|
+
*/
|
|
16750
|
+
trustRollup: external_exports.object({
|
|
16751
|
+
"known-good": external_exports.number().int().nonnegative(),
|
|
16752
|
+
risky: external_exports.number().int().nonnegative(),
|
|
16753
|
+
unapproved: external_exports.number().int().nonnegative()
|
|
16754
|
+
}).partial().strict().optional(),
|
|
16755
|
+
/**
|
|
16756
|
+
* Partial: only Flag keys with non-zero counts are included.
|
|
16757
|
+
* Strict: unknown keys are rejected — only Flag values are valid keys.
|
|
16758
|
+
*/
|
|
16759
|
+
flagRollup: external_exports.object({
|
|
16760
|
+
update: external_exports.number().int().nonnegative(),
|
|
16761
|
+
stale: external_exports.number().int().nonnegative(),
|
|
16762
|
+
conflict: external_exports.number().int().nonnegative(),
|
|
16763
|
+
unknown: external_exports.number().int().nonnegative(),
|
|
16764
|
+
change: external_exports.number().int().nonnegative(),
|
|
16765
|
+
untracked: external_exports.number().int().nonnegative(),
|
|
16766
|
+
risk: external_exports.number().int().nonnegative(),
|
|
16767
|
+
findings: external_exports.number().int().nonnegative()
|
|
16768
|
+
}).partial().strict(),
|
|
16769
|
+
items: external_exports.array(AssetSummary)
|
|
16770
|
+
}).meta({ id: "AssetGroup" });
|
|
16771
|
+
var ListAssetsResponse = external_exports.object({ groups: external_exports.array(AssetGroup) }).meta({ id: "ListAssetsResponse" });
|
|
16772
|
+
var McpTool = external_exports.object({
|
|
16773
|
+
name: external_exports.string(),
|
|
16774
|
+
signature: external_exports.string(),
|
|
16775
|
+
description: external_exports.string(),
|
|
16776
|
+
write: external_exports.boolean(),
|
|
16777
|
+
/** Non-null string when tool is dangerous / blocked; null otherwise. */
|
|
16778
|
+
risk: external_exports.string().nullable()
|
|
16779
|
+
}).meta({ id: "McpTool" });
|
|
16780
|
+
var AssetFindingRef = external_exports.object({
|
|
16781
|
+
id: external_exports.string(),
|
|
16782
|
+
title: external_exports.string(),
|
|
16783
|
+
note: external_exports.string()
|
|
16784
|
+
});
|
|
16785
|
+
var AssetDetail = AssetSummary.extend({
|
|
16786
|
+
/** string | null — null when no description is available. */
|
|
16787
|
+
description: external_exports.string().nullable(),
|
|
16788
|
+
/** trustLevel | null — null for non-MCP assets. */
|
|
16789
|
+
trust: TrustLevel.nullable(),
|
|
16790
|
+
/** Type-specific raw key/values — FE renders the grid. */
|
|
16791
|
+
meta: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
16792
|
+
/** always present — object when there is an active finding, null when absent. */
|
|
16793
|
+
finding: AssetFindingRef.nullable(),
|
|
16794
|
+
/** MCP exposed-tools list — omitted for non-mcp. */
|
|
16795
|
+
tools: external_exports.array(McpTool).optional()
|
|
16796
|
+
}).meta({ id: "AssetDetail" });
|
|
16797
|
+
var ListProjectsResponse = external_exports.object({ items: external_exports.array(ProjectSummary) }).meta({ id: "ListProjectsResponse" });
|
|
16798
|
+
var InventoryStats = external_exports.object({
|
|
16799
|
+
/** Total assets/projects with ≥1 flag or finding (drives the attention header chip). */
|
|
16800
|
+
attention: external_exports.number().int().nonnegative(),
|
|
16801
|
+
byType: external_exports.object({
|
|
16802
|
+
project: external_exports.number().int().nonnegative(),
|
|
16803
|
+
skill: external_exports.number().int().nonnegative(),
|
|
16804
|
+
mcp: external_exports.number().int().nonnegative(),
|
|
16805
|
+
hook: external_exports.number().int().nonnegative(),
|
|
16806
|
+
config: external_exports.number().int().nonnegative()
|
|
16807
|
+
}),
|
|
16808
|
+
harnesses: external_exports.number().int().nonnegative(),
|
|
16809
|
+
mcpTrust: external_exports.object({
|
|
16810
|
+
"known-good": external_exports.number().int().nonnegative(),
|
|
16811
|
+
risky: external_exports.number().int().nonnegative(),
|
|
16812
|
+
unapproved: external_exports.number().int().nonnegative()
|
|
16813
|
+
})
|
|
16814
|
+
}).meta({ id: "InventoryStats" });
|
|
16815
|
+
var FileSummary = external_exports.object({
|
|
16816
|
+
path: external_exports.string(),
|
|
16817
|
+
name: external_exports.string(),
|
|
16818
|
+
origin: Origin,
|
|
16819
|
+
/** Effective access (override applied). */
|
|
16820
|
+
access: AccessLevel,
|
|
16821
|
+
/** True when a file_access_override differs from the computed default. */
|
|
16822
|
+
isCustom: external_exports.boolean(),
|
|
16823
|
+
findings: external_exports.number().int().nonnegative(),
|
|
16824
|
+
/** When the file was auto-blocked by a detection; null when not blocked. */
|
|
16825
|
+
blockedAt: external_exports.iso.datetime().nullable().optional(),
|
|
16826
|
+
/** Why the file was blocked; null when absent. */
|
|
16827
|
+
note: external_exports.string().nullable().optional()
|
|
16828
|
+
}).meta({ id: "FileSummary" });
|
|
16829
|
+
var FolderSummary = external_exports.object({
|
|
16830
|
+
name: external_exports.string(),
|
|
16831
|
+
path: external_exports.string(),
|
|
16832
|
+
/** Rollup of effective access across all descendants. */
|
|
16833
|
+
accessCounts: AccessCounts
|
|
16834
|
+
}).meta({ id: "FolderSummary" });
|
|
16835
|
+
var ProjectTreeResponse = external_exports.object({
|
|
16836
|
+
project: external_exports.object({
|
|
16837
|
+
id: external_exports.string(),
|
|
16838
|
+
repo: external_exports.string(),
|
|
16839
|
+
visibility: Visibility
|
|
16840
|
+
}),
|
|
16841
|
+
path: external_exports.string(),
|
|
16842
|
+
/** Browse mode: one-level folders at the current path. Omitted in search mode. */
|
|
16843
|
+
folders: external_exports.array(FolderSummary).optional(),
|
|
16844
|
+
files: external_exports.array(FileSummary)
|
|
16845
|
+
}).meta({ id: "ProjectTreeResponse" });
|
|
16846
|
+
var FileDetail = FileSummary.extend({
|
|
16847
|
+
project: external_exports.object({
|
|
16848
|
+
repo: external_exports.string(),
|
|
16849
|
+
visibility: Visibility,
|
|
16850
|
+
language: external_exports.string(),
|
|
16851
|
+
policyDefault: AccessLevel,
|
|
16852
|
+
updatedAt: external_exports.iso.datetime()
|
|
16853
|
+
}),
|
|
16854
|
+
findingsRefs: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string() }))
|
|
16855
|
+
}).meta({ id: "FileDetail" });
|
|
16856
|
+
var SetFileAccessBody = external_exports.object({
|
|
16857
|
+
path: external_exports.string(),
|
|
16858
|
+
access: AccessLevel
|
|
16859
|
+
}).meta({ id: "SetFileAccessBody" });
|
|
16860
|
+
var SetFileAccessResponse = external_exports.object({
|
|
16861
|
+
file: FileSummary,
|
|
16862
|
+
accessCounts: AccessCounts
|
|
16863
|
+
}).meta({ id: "SetFileAccessResponse" });
|
|
16864
|
+
var SetMcpTrustBody = external_exports.object({ trust: TrustLevel }).meta({ id: "SetMcpTrustBody" });
|
|
16865
|
+
var HarnessEventItem = external_exports.object({
|
|
16866
|
+
kind: HarnessEventKind,
|
|
16867
|
+
title: external_exports.string(),
|
|
16868
|
+
detail: external_exports.string(),
|
|
16869
|
+
occurredAt: external_exports.iso.datetime(),
|
|
16870
|
+
findingId: external_exports.string().nullable().optional()
|
|
16871
|
+
}).meta({ id: "HarnessEventItem" });
|
|
16872
|
+
var HarnessEventsResponse = external_exports.object({
|
|
16873
|
+
counts: external_exports.object({
|
|
16874
|
+
block: external_exports.number().int().nonnegative(),
|
|
16875
|
+
redact: external_exports.number().int().nonnegative(),
|
|
16876
|
+
warn: external_exports.number().int().nonnegative()
|
|
16877
|
+
}),
|
|
16878
|
+
items: external_exports.array(HarnessEventItem)
|
|
16879
|
+
}).meta({ id: "HarnessEventsResponse" });
|
|
16880
|
+
var RescanResponse = external_exports.object({
|
|
16881
|
+
jobId: external_exports.string(),
|
|
16882
|
+
startedAt: external_exports.iso.datetime()
|
|
16883
|
+
}).meta({ id: "RescanResponse" });
|
|
16884
|
+
var ConnectProjectBody = external_exports.object({ repo: external_exports.string() }).meta({ id: "ConnectProjectBody" });
|
|
16885
|
+
var ListAssetsQuery = external_exports.object({
|
|
16886
|
+
/** Filter by one or more AssetType values; absent means all types. */
|
|
16887
|
+
type: external_exports.array(AssetType).optional(),
|
|
16888
|
+
/** Free-text search term. */
|
|
16889
|
+
q: external_exports.string().optional()
|
|
16890
|
+
});
|
|
16891
|
+
var GetProjectTreeQuery = external_exports.object({
|
|
16892
|
+
/** Subtree root path; defaults to repository root when absent. */
|
|
16893
|
+
path: external_exports.string().optional(),
|
|
16894
|
+
/** Free-text filter applied to file paths. */
|
|
16895
|
+
q: external_exports.string().optional(),
|
|
16896
|
+
/**
|
|
16897
|
+
* Special listing mode. `blocked` returns every effectively-blocked, auto-blocked
|
|
16898
|
+
* file across the whole repo (folders omitted, most-recent first), ignoring
|
|
16899
|
+
* `path`/`q` — powers the project-wide "recently blocked" strip.
|
|
16900
|
+
*/
|
|
16901
|
+
filter: external_exports.enum(["blocked"]).optional()
|
|
16902
|
+
});
|
|
16903
|
+
var GetProjectFileQuery = external_exports.object({
|
|
16904
|
+
/** Repository-relative file path; absent or empty → 400. */
|
|
16905
|
+
path: external_exports.string()
|
|
16906
|
+
});
|
|
16907
|
+
var GetHarnessEventsQuery = external_exports.object({
|
|
16908
|
+
/** Maximum number of events to return. Range: 1–50; default: 7. */
|
|
16909
|
+
limit: external_exports.coerce.number().int().min(1).max(50).default(7)
|
|
16910
|
+
});
|
|
16911
|
+
|
|
17155
16912
|
// ../../packages/schema/src/zod/shares.ts
|
|
17156
16913
|
var DestinationKind = external_exports.enum(["provider", "internal", "external", "ip"]).meta({ id: "DestinationKind" });
|
|
17157
16914
|
var Transport = external_exports.enum(["https", "http", "sftp", "grpc", "smtp", "ws", "wss"]).meta({ id: "Transport" });
|
|
@@ -17358,6 +17115,127 @@ var EgressWriteSummary = external_exports.object({
|
|
|
17358
17115
|
droppedFiles: external_exports.array(external_exports.string()).default([])
|
|
17359
17116
|
}).meta({ id: "EgressWriteSummary" });
|
|
17360
17117
|
|
|
17118
|
+
// ../../packages/schema/src/zod/event.ts
|
|
17119
|
+
var EventKind = external_exports.enum(["prompt", "response", "code_change", "tool_use"]).meta({ id: "EventKind" });
|
|
17120
|
+
var CAPTURE_EVENT_TYPES_SQL = EventKind.options.map((k) => `'${k}'`).join(",");
|
|
17121
|
+
var EventMetadata = external_exports.object({
|
|
17122
|
+
sessionId: external_exports.string().optional(),
|
|
17123
|
+
repo: external_exports.string().optional(),
|
|
17124
|
+
filePath: external_exports.string().optional(),
|
|
17125
|
+
// The host tool whose input/output was scanned (e.g. 'Bash', 'WebFetch'),
|
|
17126
|
+
// set by the tool-scanning hooks. The tool NAME only — never the tool's
|
|
17127
|
+
// arguments or output, which can carry the very value a finding masked
|
|
17128
|
+
// (metadata is stored unredacted). Gives findings on non-file captures a
|
|
17129
|
+
// display location ("via Bash") when no filePath exists.
|
|
17130
|
+
toolName: external_exports.string().optional(),
|
|
17131
|
+
// Set (true) by the worktree scanner when the file is excluded by the
|
|
17132
|
+
// repo's .gitignore. Gitignored files ARE still scanned — local scratch and
|
|
17133
|
+
// generated code can leak real secrets — but the provenance is recorded so
|
|
17134
|
+
// policy/dashboards can treat those findings as informational rather than
|
|
17135
|
+
// blocking. Omitted (not false) for tracked files and non-scan events.
|
|
17136
|
+
gitignored: external_exports.boolean().optional(),
|
|
17137
|
+
// Set (true) ONLY when the event's `content` is the COMPLETE file at
|
|
17138
|
+
// capture time (a worktree scan reading from disk). Hook-captured edits
|
|
17139
|
+
// (e.g. an Edit tool's new_string) are partial fragments and MUST NOT set
|
|
17140
|
+
// this. The resolver-on-ingest keys its fixed-at-source dropout
|
|
17141
|
+
// diff on this marker: only a whole-file snapshot can prove a previously
|
|
17142
|
+
// open finding is gone; a fragment's absence proves nothing (the secret
|
|
17143
|
+
// may live outside the hunk). Omitted (not false) for fragments and
|
|
17144
|
+
// non-scan events, so pre-marker clients safely default to the
|
|
17145
|
+
// non-authoritative path.
|
|
17146
|
+
wholeFile: external_exports.boolean().optional(),
|
|
17147
|
+
model: external_exports.string().optional(),
|
|
17148
|
+
turnIndex: external_exports.number().int().nonnegative().optional(),
|
|
17149
|
+
// Distributed-tracing correlation. `correlationId` ties a recorded event back
|
|
17150
|
+
// to the request that captured/ingested it (a UUID, generated independently of
|
|
17151
|
+
// the trace id); `traceId` is the W3C trace id (32 lowercase hex chars) of the
|
|
17152
|
+
// originating span when telemetry is enabled. Both optional + backward
|
|
17153
|
+
// compatible — populated by the plugin (see @akasecurity/plugin-sdk).
|
|
17154
|
+
correlationId: external_exports.uuid().optional(),
|
|
17155
|
+
traceId: external_exports.string().regex(/^[0-9a-f]{32}$/).optional(),
|
|
17156
|
+
// Ids of the detection exceptions that downgraded findings in this capture
|
|
17157
|
+
// to 'allow' — the enforcement audit trail's link back to the grant that
|
|
17158
|
+
// authorized the bypass. Absent on captures where no exception applied.
|
|
17159
|
+
exceptionIds: external_exports.array(external_exports.guid()).optional()
|
|
17160
|
+
}).meta({ id: "EventMetadata" });
|
|
17161
|
+
var Event = external_exports.object({
|
|
17162
|
+
id: external_exports.guid(),
|
|
17163
|
+
sourceTool: SourceTool,
|
|
17164
|
+
kind: EventKind,
|
|
17165
|
+
occurredAt: external_exports.iso.datetime(),
|
|
17166
|
+
contentHash: external_exports.string(),
|
|
17167
|
+
content: external_exports.string(),
|
|
17168
|
+
metadata: EventMetadata.optional()
|
|
17169
|
+
}).meta({ id: "Event" });
|
|
17170
|
+
var IngestEvent = Event.meta({ id: "IngestEvent" });
|
|
17171
|
+
var IngestBatch = external_exports.object({
|
|
17172
|
+
events: external_exports.array(IngestEvent).min(1).max(100),
|
|
17173
|
+
// Dedup policy for this batch. Id-dedup ALWAYS applies. 'content-hash'
|
|
17174
|
+
// additionally rejects any event whose contentHash the store has already
|
|
17175
|
+
// recorded — for re-runnable bulk ingest (worktree scan, transcript
|
|
17176
|
+
// backfill), where a re-run mints fresh event ids for identical content and
|
|
17177
|
+
// would otherwise accumulate duplicates. Live hook traffic must NOT set it:
|
|
17178
|
+
// two genuinely separate prompts can be byte-identical and both belong on
|
|
17179
|
+
// the timeline.
|
|
17180
|
+
dedupe: external_exports.literal("content-hash").optional()
|
|
17181
|
+
}).meta({ id: "IngestBatch" });
|
|
17182
|
+
|
|
17183
|
+
// ../../packages/schema/src/zod/exception.ts
|
|
17184
|
+
var ExceptionScope = external_exports.enum(["once", "temporary", "permanent"]);
|
|
17185
|
+
var ExceptionConditions = external_exports.object({
|
|
17186
|
+
repo: external_exports.string().optional(),
|
|
17187
|
+
sourceTool: external_exports.string().optional(),
|
|
17188
|
+
provider: external_exports.string().optional()
|
|
17189
|
+
}).strict();
|
|
17190
|
+
var ExceptionCapability = external_exports.enum(["suppress", "reveal_to_model"]);
|
|
17191
|
+
var DetectionException = external_exports.object({
|
|
17192
|
+
id: external_exports.guid(),
|
|
17193
|
+
ruleId: external_exports.string(),
|
|
17194
|
+
// Denormalized from the rule, for reporting — never matched on.
|
|
17195
|
+
category: DetectionCategory,
|
|
17196
|
+
// HMAC-SHA256 hex of the raw match under a machine-local key: a KEYED
|
|
17197
|
+
// fingerprint, never the raw value, and never reversible. Matching recomputes
|
|
17198
|
+
// the fingerprint from a fresh capture; the value itself is never stored.
|
|
17199
|
+
// Shape-constrained so a malformed — or accidentally raw — value is rejected
|
|
17200
|
+
// at the boundary rather than persisted.
|
|
17201
|
+
valueFingerprint: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
17202
|
+
// Version of the fingerprint key the grant was written under; a rotated key
|
|
17203
|
+
// invalidates old grants rather than silently mismatching them.
|
|
17204
|
+
keyVersion: external_exports.number().int().positive(),
|
|
17205
|
+
// maskMatch() preview of the approved value — never the raw value.
|
|
17206
|
+
maskedValue: external_exports.string(),
|
|
17207
|
+
capability: ExceptionCapability.default("suppress"),
|
|
17208
|
+
scope: ExceptionScope,
|
|
17209
|
+
expiresAt: external_exports.iso.datetime().nullable(),
|
|
17210
|
+
maxUses: external_exports.number().int().positive().nullable(),
|
|
17211
|
+
useCount: external_exports.number().int().nonnegative(),
|
|
17212
|
+
lastUsedAt: external_exports.iso.datetime().nullable(),
|
|
17213
|
+
// Mandatory: every grant carries the human reason it exists.
|
|
17214
|
+
justification: external_exports.string().min(1),
|
|
17215
|
+
conditions: ExceptionConditions.nullable(),
|
|
17216
|
+
createdBy: external_exports.string(),
|
|
17217
|
+
createdVia: external_exports.enum(["cli-approve", "cli-add", "web-approve", "web-add", "api", "setup-triage"]),
|
|
17218
|
+
createdAt: external_exports.iso.datetime(),
|
|
17219
|
+
updatedAt: external_exports.iso.datetime(),
|
|
17220
|
+
// Revocation is terminal and retained — consumed/expired/revoked rows are
|
|
17221
|
+
// audit evidence; nothing in the exception lifecycle hard-deletes.
|
|
17222
|
+
revokedAt: external_exports.iso.datetime().nullable(),
|
|
17223
|
+
revokedBy: external_exports.string().nullable(),
|
|
17224
|
+
revokeReason: external_exports.string().nullable()
|
|
17225
|
+
});
|
|
17226
|
+
var ExceptionBundleEntry = DetectionException.pick({
|
|
17227
|
+
id: true,
|
|
17228
|
+
ruleId: true,
|
|
17229
|
+
valueFingerprint: true,
|
|
17230
|
+
keyVersion: true,
|
|
17231
|
+
capability: true,
|
|
17232
|
+
expiresAt: true,
|
|
17233
|
+
maxUses: true,
|
|
17234
|
+
useCount: true,
|
|
17235
|
+
conditions: true
|
|
17236
|
+
});
|
|
17237
|
+
var ExceptionDescriptor = DetectionException.omit({ valueFingerprint: true });
|
|
17238
|
+
|
|
17361
17239
|
// ../../packages/schema/src/zod/exception-action.ts
|
|
17362
17240
|
var confirmation = external_exports.string().optional();
|
|
17363
17241
|
var ApproveBlockedInput = external_exports.object({
|
|
@@ -17400,10 +17278,11 @@ function toApiAction(dbVal) {
|
|
|
17400
17278
|
}
|
|
17401
17279
|
function toApiCategory(dbVal) {
|
|
17402
17280
|
if (dbVal === "code_context") return "source_code";
|
|
17403
|
-
|
|
17281
|
+
const parsed = FindingCategory.safeParse(dbVal);
|
|
17282
|
+
return parsed.success ? parsed.data : "custom";
|
|
17404
17283
|
}
|
|
17405
17284
|
function toApiProvider(sourceTool) {
|
|
17406
|
-
return TOOL_TO_HARNESS[sourceTool] ??
|
|
17285
|
+
return TOOL_TO_HARNESS[sourceTool] ?? HARNESS.Api;
|
|
17407
17286
|
}
|
|
17408
17287
|
var STATUS_PRECEDENCE = ["open", "handled", "dismissed", "resolved"];
|
|
17409
17288
|
function foldGroupStatus(instanceStatuses) {
|
|
@@ -17975,6 +17854,7 @@ var ListVaultDerefsResponse = external_exports.object({
|
|
|
17975
17854
|
});
|
|
17976
17855
|
var VaultKeyCustody = external_exports.string();
|
|
17977
17856
|
var VaultInlineReveal = external_exports.enum(["masked", "full", "off"]);
|
|
17857
|
+
var VAULT_CONSENT_VERSION = 1;
|
|
17978
17858
|
var VaultConsent = external_exports.object({
|
|
17979
17859
|
acknowledgedAt: external_exports.iso.datetime(),
|
|
17980
17860
|
version: external_exports.number().int().positive()
|
|
@@ -17982,7 +17862,14 @@ var VaultConsent = external_exports.object({
|
|
|
17982
17862
|
|
|
17983
17863
|
// ../../packages/schema/src/zod/local.ts
|
|
17984
17864
|
var WORKSPACE_SETTINGS_SPEC_VERSION = 5;
|
|
17985
|
-
var
|
|
17865
|
+
var MODEL_JUDGE_PAYLOAD_VERSION = 1;
|
|
17866
|
+
var RunMode = external_exports.enum(["standalone", "attached"]);
|
|
17867
|
+
var ControlPlaneConnection = external_exports.object({
|
|
17868
|
+
endpoint: external_exports.string().min(1),
|
|
17869
|
+
// Display name for the deployment, shown instead of the raw endpoint.
|
|
17870
|
+
label: external_exports.string().min(1).optional(),
|
|
17871
|
+
attachedAt: external_exports.iso.datetime()
|
|
17872
|
+
}).meta({ id: "ControlPlaneConnection" });
|
|
17986
17873
|
var SimpleDetectionPolicy = external_exports.enum(["redact", "warn"]);
|
|
17987
17874
|
var HistoricalAccess = external_exports.enum(["full", "session-only"]);
|
|
17988
17875
|
var ModelJudgeConsent = external_exports.object({
|
|
@@ -17991,12 +17878,10 @@ var ModelJudgeConsent = external_exports.object({
|
|
|
17991
17878
|
});
|
|
17992
17879
|
var WorkspaceSettings = external_exports.object({
|
|
17993
17880
|
specVersion: external_exports.number().int().positive().default(WORKSPACE_SETTINGS_SPEC_VERSION),
|
|
17994
|
-
|
|
17995
|
-
//
|
|
17996
|
-
runMode:
|
|
17997
|
-
|
|
17998
|
-
RunMode.default("standalone")
|
|
17999
|
-
),
|
|
17881
|
+
runMode: RunMode.default("standalone"),
|
|
17882
|
+
// Present only while attached; a detach clears it. Its presence is what makes
|
|
17883
|
+
// `runMode: 'attached'` mean anything — see isAttached.
|
|
17884
|
+
controlPlane: ControlPlaneConnection.optional(),
|
|
18000
17885
|
policy: SimpleDetectionPolicy.default("redact"),
|
|
18001
17886
|
// Consent for scanning pre-install surfaces; opt-in (see HistoricalAccess).
|
|
18002
17887
|
historicalAccess: HistoricalAccess.default("session-only"),
|
|
@@ -18098,39 +17983,244 @@ function toInspectionFindingRow(input) {
|
|
|
18098
17983
|
firstDetectedAt: input.firstDetectedAt ? isoToEpochMillis(input.firstDetectedAt) : null
|
|
18099
17984
|
};
|
|
18100
17985
|
}
|
|
18101
|
-
function toCaptureAttributes(event) {
|
|
18102
|
-
const metadata = event.metadata;
|
|
18103
|
-
return {
|
|
18104
|
-
source_tool: event.sourceTool,
|
|
18105
|
-
...metadata?.repo !== void 0 ? { repo: metadata.repo } : {},
|
|
18106
|
-
...metadata?.filePath !== void 0 ? { file_path: metadata.filePath } : {},
|
|
18107
|
-
...metadata?.toolName !== void 0 ? { tool_name: metadata.toolName } : {},
|
|
18108
|
-
...metadata?.gitignored !== void 0 ? { gitignored: metadata.gitignored } : {},
|
|
18109
|
-
...metadata?.wholeFile !== void 0 ? { whole_file: metadata.wholeFile } : {},
|
|
18110
|
-
...metadata?.correlationId !== void 0 ? { correlation_id: metadata.correlationId } : {},
|
|
18111
|
-
...metadata?.traceId !== void 0 ? { trace_id: metadata.traceId } : {},
|
|
18112
|
-
...metadata?.exceptionIds !== void 0 ? { exception_ids: metadata.exceptionIds } : {},
|
|
18113
|
-
// `model`/`turnIndex` have no dedicated CaptureAttributes field (no writer
|
|
18114
|
-
// has ever populated either), but every legacy metadata key still rides
|
|
18115
|
-
// the bag rather than being silently dropped — CaptureAttributes'
|
|
18116
|
-
// `.catchall(z.unknown())` carries the long tail.
|
|
18117
|
-
...metadata?.model !== void 0 ? { model: metadata.model } : {},
|
|
18118
|
-
...metadata?.turnIndex !== void 0 ? { turn_index: metadata.turnIndex } : {}
|
|
18119
|
-
};
|
|
17986
|
+
function toCaptureAttributes(event) {
|
|
17987
|
+
const metadata = event.metadata;
|
|
17988
|
+
return {
|
|
17989
|
+
source_tool: event.sourceTool,
|
|
17990
|
+
...metadata?.repo !== void 0 ? { repo: metadata.repo } : {},
|
|
17991
|
+
...metadata?.filePath !== void 0 ? { file_path: metadata.filePath } : {},
|
|
17992
|
+
...metadata?.toolName !== void 0 ? { tool_name: metadata.toolName } : {},
|
|
17993
|
+
...metadata?.gitignored !== void 0 ? { gitignored: metadata.gitignored } : {},
|
|
17994
|
+
...metadata?.wholeFile !== void 0 ? { whole_file: metadata.wholeFile } : {},
|
|
17995
|
+
...metadata?.correlationId !== void 0 ? { correlation_id: metadata.correlationId } : {},
|
|
17996
|
+
...metadata?.traceId !== void 0 ? { trace_id: metadata.traceId } : {},
|
|
17997
|
+
...metadata?.exceptionIds !== void 0 ? { exception_ids: metadata.exceptionIds } : {},
|
|
17998
|
+
// `model`/`turnIndex` have no dedicated CaptureAttributes field (no writer
|
|
17999
|
+
// has ever populated either), but every legacy metadata key still rides
|
|
18000
|
+
// the bag rather than being silently dropped — CaptureAttributes'
|
|
18001
|
+
// `.catchall(z.unknown())` carries the long tail.
|
|
18002
|
+
...metadata?.model !== void 0 ? { model: metadata.model } : {},
|
|
18003
|
+
...metadata?.turnIndex !== void 0 ? { turn_index: metadata.turnIndex } : {}
|
|
18004
|
+
};
|
|
18005
|
+
}
|
|
18006
|
+
function captureDefinitionVersion(finding2) {
|
|
18007
|
+
return `capture/${finding2.category}/${finding2.severity}`;
|
|
18008
|
+
}
|
|
18009
|
+
function toCaptureDefinitionInput(finding2) {
|
|
18010
|
+
return {
|
|
18011
|
+
ruleId: finding2.ruleId,
|
|
18012
|
+
version: captureDefinitionVersion(finding2),
|
|
18013
|
+
name: finding2.ruleId,
|
|
18014
|
+
category: finding2.category,
|
|
18015
|
+
severity: finding2.severity,
|
|
18016
|
+
definition: JSON.stringify({ ruleId: finding2.ruleId })
|
|
18017
|
+
};
|
|
18018
|
+
}
|
|
18019
|
+
|
|
18020
|
+
// ../../packages/schema/src/zod/managed.ts
|
|
18021
|
+
var MANAGED_SETTINGS_FILENAME = "managed-settings.json";
|
|
18022
|
+
var MANAGED_SETTINGS_SPEC_VERSION = 1;
|
|
18023
|
+
var ManagedSettingKey = external_exports.enum([
|
|
18024
|
+
"runMode",
|
|
18025
|
+
"historicalAccess",
|
|
18026
|
+
"vaultConsent",
|
|
18027
|
+
"vaultKeyCustody",
|
|
18028
|
+
"vaultInlineReveal",
|
|
18029
|
+
"modelJudgeConsent",
|
|
18030
|
+
"dataSharesInPlace"
|
|
18031
|
+
]).meta({ id: "ManagedSettingKey" });
|
|
18032
|
+
var ManagedSettingsValues = external_exports.object({
|
|
18033
|
+
runMode: external_exports.enum(["standalone", "attached"]).optional(),
|
|
18034
|
+
controlPlane: external_exports.object({
|
|
18035
|
+
endpoint: external_exports.string().min(1),
|
|
18036
|
+
label: external_exports.string().min(1).optional()
|
|
18037
|
+
}).optional(),
|
|
18038
|
+
historicalAccess: external_exports.enum(["full", "session-only"]).optional(),
|
|
18039
|
+
vaultConsent: external_exports.boolean().optional(),
|
|
18040
|
+
vaultKeyCustody: external_exports.enum(["file", "keychain"]).optional(),
|
|
18041
|
+
vaultInlineReveal: external_exports.enum(["masked", "full", "off"]).optional(),
|
|
18042
|
+
modelJudgeConsent: external_exports.boolean().optional(),
|
|
18043
|
+
dataSharesInPlace: external_exports.boolean().optional()
|
|
18044
|
+
}).meta({ id: "ManagedSettingsValues" });
|
|
18045
|
+
var ManagedSettings = external_exports.object({
|
|
18046
|
+
specVersion: external_exports.number().int().positive().default(MANAGED_SETTINGS_SPEC_VERSION),
|
|
18047
|
+
// Shown on every locked control, so the user can tell an administrative
|
|
18048
|
+
// decision from a bug. Absent renders as a generic "your organization".
|
|
18049
|
+
organization: external_exports.string().min(1).optional(),
|
|
18050
|
+
// What the administrator pinned.
|
|
18051
|
+
values: ManagedSettingsValues.default({}),
|
|
18052
|
+
// Which of those the user may not change. A key here with no matching value
|
|
18053
|
+
// freezes whatever the user last chose; a value with no lock is a DEFAULT
|
|
18054
|
+
// the user may still override. The two are separable on purpose.
|
|
18055
|
+
lockedFields: external_exports.array(ManagedSettingKey).default([])
|
|
18056
|
+
}).meta({ id: "ManagedSettings" });
|
|
18057
|
+
|
|
18058
|
+
// ../../packages/schema/src/zod/policy.ts
|
|
18059
|
+
var PolicyScope = external_exports.enum(["global", "repo", "user"]).meta({ id: "PolicyScope" });
|
|
18060
|
+
var PolicyTarget = external_exports.union([external_exports.object({ ruleId: external_exports.string() }), external_exports.object({ category: DetectionCategory })]).meta({ id: "PolicyTarget" });
|
|
18061
|
+
var Policy = external_exports.object({
|
|
18062
|
+
id: external_exports.guid(),
|
|
18063
|
+
scope: PolicyScope,
|
|
18064
|
+
target: PolicyTarget,
|
|
18065
|
+
action: ActionTaken,
|
|
18066
|
+
enabled: external_exports.boolean().default(true),
|
|
18067
|
+
customKeywords: external_exports.array(external_exports.string()).optional(),
|
|
18068
|
+
// Display name — optional so older policy rows without name still parse.
|
|
18069
|
+
// Added for the findings API (policy.name column migration).
|
|
18070
|
+
name: external_exports.string().optional()
|
|
18071
|
+
}).meta({ id: "Policy" });
|
|
18072
|
+
var PolicyBundle = external_exports.object({
|
|
18073
|
+
version: external_exports.string(),
|
|
18074
|
+
policies: external_exports.array(Policy),
|
|
18075
|
+
// Rules from the installed marketplace packs (snapshotted by the
|
|
18076
|
+
// control plane). The plugin registers these in addition to its bundled
|
|
18077
|
+
// packs. Optional so older backends — and older on-disk caches — that omit
|
|
18078
|
+
// the field still parse; consumers read `bundle.rules ?? []`.
|
|
18079
|
+
rules: external_exports.array(Rule).optional(),
|
|
18080
|
+
// When true, `rules` IS the complete effective ruleset and the runtime must
|
|
18081
|
+
// NOT merge its compiled-in bundled packs — the standalone gateway sets this
|
|
18082
|
+
// after reading the user's installed snapshot (installed_packs, enabled
|
|
18083
|
+
// packs only), which is how detection updates stay manual: new bundled
|
|
18084
|
+
// rules run only after the user applies the pack update. Absent/false keeps
|
|
18085
|
+
// the historical composition (bundled packs + rules) — older caches.
|
|
18086
|
+
rulesComplete: external_exports.boolean().optional(),
|
|
18087
|
+
// Active detection exceptions, evaluation subset only (see
|
|
18088
|
+
// ExceptionBundleEntry). Optional so older bundle producers — and older
|
|
18089
|
+
// on-disk caches — that omit the field still parse; consumers read
|
|
18090
|
+
// `bundle.exceptions ?? []`.
|
|
18091
|
+
exceptions: external_exports.array(ExceptionBundleEntry).optional(),
|
|
18092
|
+
// Rule ids whose pack is assigned a REVERSIBLE archetype (Redact & Vault).
|
|
18093
|
+
// A second axis over the same `redact` action, carried beside the policies
|
|
18094
|
+
// rather than on them: nothing writes ruleId-targeted policies to disk, so
|
|
18095
|
+
// widening Policy itself would change a persisted shape to express something
|
|
18096
|
+
// only the in-memory bundle needs. Optional so an older producer — or an
|
|
18097
|
+
// older on-disk cache — still parses; consumers read `?? []` and get the
|
|
18098
|
+
// pre-existing one-way behaviour, which is the safe direction to default.
|
|
18099
|
+
reversibleRuleIds: external_exports.array(external_exports.string()).optional(),
|
|
18100
|
+
// Installed pack version, keyed by ruleId, for rules in `rules` that came
|
|
18101
|
+
// from a versioned installed pack. Optional so older backends — and older
|
|
18102
|
+
// on-disk caches — that omit the field still parse; consumers fall back to
|
|
18103
|
+
// the rule's own spec version. NOT the bundle version above — see
|
|
18104
|
+
// installedRuleset's ruleVersions for the source of truth.
|
|
18105
|
+
ruleVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
18106
|
+
customKeywords: external_exports.array(external_exports.string()),
|
|
18107
|
+
fetchedAt: external_exports.iso.datetime()
|
|
18108
|
+
}).meta({ id: "PolicyBundle" });
|
|
18109
|
+
var OBSERVE_ONLY_CATEGORIES = ["config"];
|
|
18110
|
+
var ENFORCEABLE_CATEGORIES = DetectionCategory.options.filter((c) => !OBSERVE_ONLY_CATEGORIES.includes(c));
|
|
18111
|
+
var CATEGORY_PEAK_SEVERITY = {
|
|
18112
|
+
secret: "critical",
|
|
18113
|
+
financial: "critical",
|
|
18114
|
+
// core-financial/credit-card
|
|
18115
|
+
code_flaw: "critical",
|
|
18116
|
+
pii: "high",
|
|
18117
|
+
phi: "high",
|
|
18118
|
+
custom: "high",
|
|
18119
|
+
// user-defined; conservative
|
|
18120
|
+
code_context: "low",
|
|
18121
|
+
config: "low"
|
|
18122
|
+
// observe-only; floors to monitor regardless
|
|
18123
|
+
};
|
|
18124
|
+
function severityFloorPolicy(category) {
|
|
18125
|
+
if (OBSERVE_ONLY_CATEGORIES.includes(category)) return "monitor";
|
|
18126
|
+
const peak = CATEGORY_PEAK_SEVERITY[category];
|
|
18127
|
+
return peak === "critical" || peak === "high" ? "warn" : "monitor";
|
|
18128
|
+
}
|
|
18129
|
+
var PolicyKind = external_exports.enum(["builtin", "custom"]).meta({ id: "PolicyKind" });
|
|
18130
|
+
var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "vault", "block"];
|
|
18131
|
+
var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
|
|
18132
|
+
var BUILTIN_ORDER = KNOWN_BUILTIN_IDS;
|
|
18133
|
+
var BUILTIN_POLICY_SPECS = {
|
|
18134
|
+
monitor: {
|
|
18135
|
+
name: "Monitor",
|
|
18136
|
+
action: "log",
|
|
18137
|
+
reversible: false,
|
|
18138
|
+
description: "Log every match for audit. The request is allowed through untouched."
|
|
18139
|
+
},
|
|
18140
|
+
warn: {
|
|
18141
|
+
name: "Warn",
|
|
18142
|
+
action: "warn",
|
|
18143
|
+
reversible: false,
|
|
18144
|
+
description: "Allow the request, but warn the user inline before it is sent."
|
|
18145
|
+
},
|
|
18146
|
+
redact: {
|
|
18147
|
+
name: "Redact",
|
|
18148
|
+
action: "redact",
|
|
18149
|
+
reversible: false,
|
|
18150
|
+
description: "Strip the matched value from the request and destroy it, then continue. What was removed cannot be recovered."
|
|
18151
|
+
},
|
|
18152
|
+
vault: {
|
|
18153
|
+
name: "Redact & Vault",
|
|
18154
|
+
action: "redact",
|
|
18155
|
+
reversible: true,
|
|
18156
|
+
description: "Strip the matched value from the request and keep an encrypted, recoverable copy in the local vault, leaving a pointer in its place. Needs the vault consent granted under Settings; without it this behaves as Redact."
|
|
18157
|
+
},
|
|
18158
|
+
block: {
|
|
18159
|
+
name: "Block",
|
|
18160
|
+
action: "block",
|
|
18161
|
+
reversible: false,
|
|
18162
|
+
description: "Refuse the request entirely whenever any rule in this detection matches."
|
|
18163
|
+
}
|
|
18164
|
+
};
|
|
18165
|
+
function builtinPolicyToAction(id) {
|
|
18166
|
+
return BUILTIN_POLICY_SPECS[id].action;
|
|
18167
|
+
}
|
|
18168
|
+
var CATEGORY_EXPRESSIBLE_IDS = KNOWN_BUILTIN_IDS.filter(
|
|
18169
|
+
(id) => !BUILTIN_POLICY_SPECS[id].reversible
|
|
18170
|
+
);
|
|
18171
|
+
var CATEGORY_INEXPRESSIBLE_IDS = KNOWN_BUILTIN_IDS.filter(
|
|
18172
|
+
(id) => BUILTIN_POLICY_SPECS[id].reversible
|
|
18173
|
+
);
|
|
18174
|
+
var CategoryPolicyId = external_exports.enum(CATEGORY_EXPRESSIBLE_IDS).meta({ id: "CategoryPolicyId" });
|
|
18175
|
+
function builtinPolicyIsReversible(id) {
|
|
18176
|
+
return BUILTIN_POLICY_SPECS[id].reversible;
|
|
18120
18177
|
}
|
|
18121
|
-
function
|
|
18122
|
-
|
|
18178
|
+
function policyIdIsReversible(policyId) {
|
|
18179
|
+
const parsed = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
|
|
18180
|
+
const id = parsed.success ? parsed.data : DEFAULT_PACK_POLICY_ID;
|
|
18181
|
+
return builtinPolicyIsReversible(id);
|
|
18123
18182
|
}
|
|
18124
|
-
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18183
|
+
var DEFAULT_ACTIONS = Object.fromEntries(
|
|
18184
|
+
DetectionCategory.options.map((c) => [c, builtinPolicyToAction(severityFloorPolicy(c))])
|
|
18185
|
+
);
|
|
18186
|
+
var BUILTIN_POLICIES = Object.fromEntries(
|
|
18187
|
+
KNOWN_BUILTIN_IDS.map((id) => [id, { id, ...BUILTIN_POLICY_SPECS[id] }])
|
|
18188
|
+
);
|
|
18189
|
+
var DEFAULT_PACK_POLICY_ID = "monitor";
|
|
18190
|
+
function policyIdToAction(policyId) {
|
|
18191
|
+
const parsed = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
|
|
18192
|
+
const id = parsed.success ? parsed.data : DEFAULT_PACK_POLICY_ID;
|
|
18193
|
+
return BUILTIN_POLICIES[id].action;
|
|
18133
18194
|
}
|
|
18195
|
+
var UsedByItem = external_exports.object({
|
|
18196
|
+
id: external_exports.string(),
|
|
18197
|
+
name: external_exports.string(),
|
|
18198
|
+
ruleCount: external_exports.number().int().nonnegative(),
|
|
18199
|
+
enabled: external_exports.boolean()
|
|
18200
|
+
}).meta({ id: "UsedByItem" });
|
|
18201
|
+
var PolicyListItem = external_exports.object({
|
|
18202
|
+
id: external_exports.string(),
|
|
18203
|
+
kind: PolicyKind,
|
|
18204
|
+
name: external_exports.string(),
|
|
18205
|
+
enabled: external_exports.boolean(),
|
|
18206
|
+
usedByCount: external_exports.number().int().nonnegative()
|
|
18207
|
+
}).meta({ id: "PolicyListItem" });
|
|
18208
|
+
var ListPoliciesResponse = external_exports.object({ items: external_exports.array(PolicyListItem) }).meta({ id: "ListPoliciesResponse" });
|
|
18209
|
+
var PolicyDetail = external_exports.object({
|
|
18210
|
+
specVersion: external_exports.literal(1),
|
|
18211
|
+
id: external_exports.string(),
|
|
18212
|
+
kind: PolicyKind,
|
|
18213
|
+
name: external_exports.string(),
|
|
18214
|
+
enabled: external_exports.boolean(),
|
|
18215
|
+
description: external_exports.string(),
|
|
18216
|
+
usedBy: external_exports.array(UsedByItem)
|
|
18217
|
+
}).meta({ id: "PolicyDetail" });
|
|
18218
|
+
var PolicyStatsResponse = external_exports.object({
|
|
18219
|
+
policies: external_exports.number().int().nonnegative(),
|
|
18220
|
+
builtin: external_exports.number().int().nonnegative(),
|
|
18221
|
+
custom: external_exports.number().int().nonnegative(),
|
|
18222
|
+
detectionsGoverned: external_exports.number().int().nonnegative()
|
|
18223
|
+
}).meta({ id: "PolicyStatsResponse" });
|
|
18134
18224
|
|
|
18135
18225
|
// ../../packages/schema/src/zod/project-files.ts
|
|
18136
18226
|
var ProjectFileInput = external_exports.object({
|
|
@@ -18210,44 +18300,6 @@ var BatchedRemediation = external_exports.discriminatedUnion("kind", [
|
|
|
18210
18300
|
NoRemediationDecision
|
|
18211
18301
|
]);
|
|
18212
18302
|
|
|
18213
|
-
// ../../packages/schema/src/zod/rule-test.ts
|
|
18214
|
-
var TestRulesRequest = external_exports.object({
|
|
18215
|
-
rules: external_exports.array(Rule).min(1).max(100),
|
|
18216
|
-
text: external_exports.string().max(5e4).optional(),
|
|
18217
|
-
fixtures: external_exports.array(RuleFixture).max(200).optional()
|
|
18218
|
-
}).refine((v) => v.text !== void 0 || (v.fixtures?.length ?? 0) > 0, {
|
|
18219
|
-
message: "Provide `text`, `fixtures`, or both \u2014 there must be something to test"
|
|
18220
|
-
}).meta({ id: "TestRulesRequest" });
|
|
18221
|
-
var RuleTestMatch = external_exports.object({
|
|
18222
|
-
ruleId: external_exports.string(),
|
|
18223
|
-
category: DetectionCategory,
|
|
18224
|
-
severity: Severity,
|
|
18225
|
-
span: Span,
|
|
18226
|
-
confidence: external_exports.number().min(0).max(1),
|
|
18227
|
-
match: external_exports.string()
|
|
18228
|
-
}).meta({ id: "RuleTestMatch" });
|
|
18229
|
-
var FixtureResult = external_exports.object({
|
|
18230
|
-
label: external_exports.string(),
|
|
18231
|
-
shouldMatch: external_exports.boolean(),
|
|
18232
|
-
didMatch: external_exports.boolean(),
|
|
18233
|
-
passed: external_exports.boolean(),
|
|
18234
|
-
matches: external_exports.array(RuleTestMatch)
|
|
18235
|
-
}).meta({ id: "FixtureResult" });
|
|
18236
|
-
var TestRulesResponse = external_exports.object({
|
|
18237
|
-
// Present only when the request supplied `text`.
|
|
18238
|
-
adhoc: external_exports.object({ matches: external_exports.array(RuleTestMatch) }).optional(),
|
|
18239
|
-
fixtures: external_exports.array(FixtureResult),
|
|
18240
|
-
summary: external_exports.object({
|
|
18241
|
-
total: external_exports.number().int().nonnegative(),
|
|
18242
|
-
passed: external_exports.number().int().nonnegative(),
|
|
18243
|
-
failed: external_exports.number().int().nonnegative()
|
|
18244
|
-
}),
|
|
18245
|
-
// Ids of rules whose matcher type the engine cannot evaluate today (e.g.
|
|
18246
|
-
// `validator`), so they silently never match. Surfaced so an author is not
|
|
18247
|
-
// misled by a green run that actually skipped a rule.
|
|
18248
|
-
unsupportedRuleIds: external_exports.array(external_exports.string())
|
|
18249
|
-
}).meta({ id: "TestRulesResponse" });
|
|
18250
|
-
|
|
18251
18303
|
// ../../packages/schema/src/zod/security.ts
|
|
18252
18304
|
var SeveritySummaryItem = external_exports.object({
|
|
18253
18305
|
severity: Severity,
|
|
@@ -18345,10 +18397,22 @@ var TopSourcesQuery = external_exports.object({
|
|
|
18345
18397
|
// Omit for both kinds.
|
|
18346
18398
|
kind: external_exports.enum(SOURCE_KINDS).optional()
|
|
18347
18399
|
});
|
|
18348
|
-
var Provider =
|
|
18400
|
+
var Provider = Harness.extract([
|
|
18401
|
+
"ClaudeCode",
|
|
18402
|
+
"Cursor",
|
|
18403
|
+
"Codex",
|
|
18404
|
+
"Antigravity",
|
|
18405
|
+
"ClaudeAi",
|
|
18406
|
+
"ChatGpt",
|
|
18407
|
+
"Copilot",
|
|
18408
|
+
"Api"
|
|
18409
|
+
]).meta({ id: "Provider" });
|
|
18349
18410
|
var ScanCoverageProvider = external_exports.object({
|
|
18350
18411
|
provider: Provider,
|
|
18351
|
-
// Percent of that provider's traffic
|
|
18412
|
+
// Percent of that provider's traffic the shipped capture surface reaches.
|
|
18413
|
+
// A curated business fact, constant across every `range` — not a measured
|
|
18414
|
+
// per-window metric. 0 exactly when `supported` is false. See the comment
|
|
18415
|
+
// above the block for where these numbers are decided.
|
|
18352
18416
|
coverage: external_exports.number().int().min(0).max(100),
|
|
18353
18417
|
supported: external_exports.boolean()
|
|
18354
18418
|
}).meta({ id: "ScanCoverageProvider" });
|
|
@@ -18402,6 +18466,18 @@ var ApplyRecommendedActionResponse = external_exports.object({
|
|
|
18402
18466
|
var DismissRecommendedActionResponse = external_exports.object({ id: external_exports.string(), status: external_exports.literal("dismissed") }).meta({ id: "DismissRecommendedActionResponse" });
|
|
18403
18467
|
var RecommendedActionIdParam = external_exports.object({ id: external_exports.string() });
|
|
18404
18468
|
|
|
18469
|
+
// ../../packages/schema/src/zod/settings-action.ts
|
|
18470
|
+
var SaveSettingsInput = external_exports.object({
|
|
18471
|
+
historicalAccess: external_exports.string(),
|
|
18472
|
+
modelJudgeConsent: external_exports.boolean(),
|
|
18473
|
+
vaultConsent: external_exports.string(),
|
|
18474
|
+
vaultInlineReveal: external_exports.string()
|
|
18475
|
+
});
|
|
18476
|
+
var AttachInput = external_exports.object({
|
|
18477
|
+
endpoint: external_exports.string(),
|
|
18478
|
+
label: external_exports.string().optional()
|
|
18479
|
+
});
|
|
18480
|
+
|
|
18405
18481
|
// ../../packages/schema/src/zod/triage.ts
|
|
18406
18482
|
var TriageHit = external_exports.object({
|
|
18407
18483
|
ruleId: external_exports.string(),
|
|
@@ -18416,7 +18492,7 @@ var TriageHit = external_exports.object({
|
|
|
18416
18492
|
valueFingerprint: external_exports.string().optional(),
|
|
18417
18493
|
keyVersion: external_exports.number().int().nonnegative().optional()
|
|
18418
18494
|
});
|
|
18419
|
-
var TriagePolicy =
|
|
18495
|
+
var TriagePolicy = CategoryPolicyId;
|
|
18420
18496
|
var TriageCategoryRec = external_exports.object({
|
|
18421
18497
|
category: DetectionCategory,
|
|
18422
18498
|
action: TriagePolicy,
|
|
@@ -18634,8 +18710,11 @@ function chmodBestEffort(path, mode) {
|
|
|
18634
18710
|
function tightenDir(dir) {
|
|
18635
18711
|
chmodBestEffort(dir, DATA_DIR_MODE);
|
|
18636
18712
|
}
|
|
18713
|
+
function mkdirOwnerOnlySync(dir, recursive = false) {
|
|
18714
|
+
mkdirSync(dir, { recursive, mode: DATA_DIR_MODE });
|
|
18715
|
+
}
|
|
18637
18716
|
function ensureDataDirSync(dir) {
|
|
18638
|
-
|
|
18717
|
+
mkdirOwnerOnlySync(dir, true);
|
|
18639
18718
|
tightenDir(dir);
|
|
18640
18719
|
}
|
|
18641
18720
|
function dbSidecars(file2) {
|
|
@@ -18647,6 +18726,9 @@ function tightenFile(file2) {
|
|
|
18647
18726
|
function tightenPerms(file2) {
|
|
18648
18727
|
for (const path of [file2, ...dbSidecars(file2)]) chmodBestEffort(path, DATA_FILE_MODE);
|
|
18649
18728
|
}
|
|
18729
|
+
function writeExclusiveOwnerOnlySync(file2, data) {
|
|
18730
|
+
writeFileSync(file2, data, { mode: DATA_FILE_MODE, flag: "wx" });
|
|
18731
|
+
}
|
|
18650
18732
|
function classifyOccupant(file2) {
|
|
18651
18733
|
try {
|
|
18652
18734
|
if (lstatSync(file2).isSymbolicLink()) return { kind: "symlink" };
|
|
@@ -18675,7 +18757,7 @@ function createOwnerOnlyFileSync(file2, data) {
|
|
|
18675
18757
|
}
|
|
18676
18758
|
let created;
|
|
18677
18759
|
try {
|
|
18678
|
-
|
|
18760
|
+
writeExclusiveOwnerOnlySync(tmp, data);
|
|
18679
18761
|
created = publishByLink(tmp, file2, data);
|
|
18680
18762
|
} finally {
|
|
18681
18763
|
try {
|
|
@@ -18697,7 +18779,7 @@ function publishByLink(tmp, file2, data) {
|
|
|
18697
18779
|
if (!LINK_UNSUPPORTED.has(code ?? "")) throw err;
|
|
18698
18780
|
}
|
|
18699
18781
|
try {
|
|
18700
|
-
|
|
18782
|
+
writeExclusiveOwnerOnlySync(file2, data);
|
|
18701
18783
|
return true;
|
|
18702
18784
|
} catch (err) {
|
|
18703
18785
|
if (err.code === "EEXIST") return false;
|
|
@@ -18710,6 +18792,25 @@ function backupPath(file2, tag) {
|
|
|
18710
18792
|
return `${file2}.${tag}.${String(Date.now())}.${randomUUID().slice(0, 8)}.bak`;
|
|
18711
18793
|
}
|
|
18712
18794
|
var STALE_PARTIAL_MS = 5 * 6e4;
|
|
18795
|
+
var SNAPSHOT_STAGING_SUFFIX = ".partial";
|
|
18796
|
+
var STAGED_NAME_SUFFIX = `.bak${SNAPSHOT_STAGING_SUFFIX}`;
|
|
18797
|
+
var SNAPSHOT_STAGING_COPY = "copy";
|
|
18798
|
+
function createSnapshotStaging(backup) {
|
|
18799
|
+
const stage = `${backup}${SNAPSHOT_STAGING_SUFFIX}`;
|
|
18800
|
+
rmSync2(stage, { recursive: true, force: true });
|
|
18801
|
+
mkdirOwnerOnlySync(stage);
|
|
18802
|
+
tightenDir(stage);
|
|
18803
|
+
return { stage, copy: join(stage, SNAPSHOT_STAGING_COPY) };
|
|
18804
|
+
}
|
|
18805
|
+
function idleMs(entry) {
|
|
18806
|
+
for (const candidate of [join(entry, SNAPSHOT_STAGING_COPY), entry]) {
|
|
18807
|
+
try {
|
|
18808
|
+
return Date.now() - statSync(candidate).mtimeMs;
|
|
18809
|
+
} catch {
|
|
18810
|
+
}
|
|
18811
|
+
}
|
|
18812
|
+
return null;
|
|
18813
|
+
}
|
|
18713
18814
|
function reapStalePartials(file2) {
|
|
18714
18815
|
const dir = dirname(file2);
|
|
18715
18816
|
const prefix = `${basename(file2)}.`;
|
|
@@ -18720,30 +18821,34 @@ function reapStalePartials(file2) {
|
|
|
18720
18821
|
return;
|
|
18721
18822
|
}
|
|
18722
18823
|
for (const name of entries) {
|
|
18723
|
-
if (!name.startsWith(prefix) || !name.endsWith(
|
|
18724
|
-
const
|
|
18824
|
+
if (!name.startsWith(prefix) || !name.endsWith(STAGED_NAME_SUFFIX)) continue;
|
|
18825
|
+
const staging = join(dir, name);
|
|
18725
18826
|
try {
|
|
18726
|
-
|
|
18727
|
-
|
|
18827
|
+
const idle = idleMs(staging);
|
|
18828
|
+
if (idle !== null && idle > STALE_PARTIAL_MS) {
|
|
18829
|
+
rmSync2(staging, { recursive: true, force: true });
|
|
18728
18830
|
}
|
|
18729
18831
|
} catch {
|
|
18730
18832
|
}
|
|
18731
18833
|
}
|
|
18732
18834
|
}
|
|
18733
18835
|
function snapshotStore(db, backup) {
|
|
18734
|
-
const
|
|
18836
|
+
const { stage, copy } = createSnapshotStaging(backup);
|
|
18735
18837
|
try {
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
18739
|
-
renameSync2(partial2, backup);
|
|
18838
|
+
db.prepare("VACUUM INTO ?").run(copy);
|
|
18839
|
+
tightenFile(copy);
|
|
18840
|
+
renameSync2(copy, backup);
|
|
18740
18841
|
} catch (error51) {
|
|
18741
18842
|
try {
|
|
18742
|
-
rmSync2(
|
|
18843
|
+
rmSync2(stage, { recursive: true, force: true });
|
|
18743
18844
|
} catch {
|
|
18744
18845
|
}
|
|
18745
18846
|
throw error51;
|
|
18746
18847
|
}
|
|
18848
|
+
try {
|
|
18849
|
+
rmSync2(stage, { recursive: true, force: true });
|
|
18850
|
+
} catch {
|
|
18851
|
+
}
|
|
18747
18852
|
}
|
|
18748
18853
|
function moveStoreAside(file2, backup) {
|
|
18749
18854
|
const undo = [];
|
|
@@ -19471,9 +19576,10 @@ function safeParseStringArray(raw) {
|
|
|
19471
19576
|
const parsed = safeJson(raw, null);
|
|
19472
19577
|
return Array.isArray(parsed) ? parsed : [];
|
|
19473
19578
|
}
|
|
19579
|
+
var DEFAULT_HARNESS = HARNESS.ClaudeCode;
|
|
19474
19580
|
function toHarness(raw) {
|
|
19475
19581
|
const parsed = Harness.safeParse(raw);
|
|
19476
|
-
return parsed.success ? parsed.data :
|
|
19582
|
+
return parsed.success ? parsed.data : DEFAULT_HARNESS;
|
|
19477
19583
|
}
|
|
19478
19584
|
function resolveLifecycle(row, lastActivityMs, nowMs) {
|
|
19479
19585
|
if (row.status) {
|
|
@@ -19604,7 +19710,7 @@ var SqliteActivityRepository = class {
|
|
|
19604
19710
|
const params = [];
|
|
19605
19711
|
if (query.harness && query.harness.length > 0) {
|
|
19606
19712
|
conditions.push(
|
|
19607
|
-
`coalesce(json_extract(attributes, '$.harness'), '
|
|
19713
|
+
`coalesce(json_extract(attributes, '$.harness'), '${DEFAULT_HARNESS}') IN (${placeholders(query.harness.length)})`
|
|
19608
19714
|
);
|
|
19609
19715
|
params.push(...query.harness);
|
|
19610
19716
|
}
|
|
@@ -19811,13 +19917,13 @@ var SqliteActivityRepository = class {
|
|
|
19811
19917
|
* The DISTINCT harnesses that actually have sessions (optionally within a
|
|
19812
19918
|
* `started_at >= fromMs` window), so the filter can offer only the harnesses
|
|
19813
19919
|
* present rather than the full enum. Each stored value is normalized through
|
|
19814
|
-
* the SAME `toHarness` default the list uses (missing →
|
|
19815
|
-
* store of bare (harness-less) roots surfaces exactly
|
|
19920
|
+
* the SAME `toHarness` default the list uses (missing → DEFAULT_HARNESS), so
|
|
19921
|
+
* a store of bare (harness-less) roots surfaces exactly that one harness.
|
|
19816
19922
|
*/
|
|
19817
19923
|
harnessFacets(fromMs) {
|
|
19818
19924
|
const where = fromMs === void 0 ? "" : " AND started_at >= ?";
|
|
19819
19925
|
const stmt = this.db.prepare(
|
|
19820
|
-
`SELECT DISTINCT coalesce(json_extract(attributes, '$.harness'), '
|
|
19926
|
+
`SELECT DISTINCT coalesce(json_extract(attributes, '$.harness'), '${DEFAULT_HARNESS}') AS harness
|
|
19821
19927
|
FROM audit_events WHERE ${SESSION_ROOT}${where}`
|
|
19822
19928
|
);
|
|
19823
19929
|
const rows = allRows(
|
|
@@ -20031,8 +20137,8 @@ var SqliteAuditEventsRepository = class {
|
|
|
20031
20137
|
}
|
|
20032
20138
|
// Insert one transcript-derived `llm_call` leaf. Unlike `insertAuditEvent`
|
|
20033
20139
|
// (which takes a caller-supplied random id), the id here is MINTED internally
|
|
20034
|
-
// from the natural key — `llmCallId(sessionId, messageId)` —
|
|
20035
|
-
//
|
|
20140
|
+
// from the natural key — `llmCallId(sessionId, messageId)` — derived from the
|
|
20141
|
+
// session and message alone, like the sibling local-store ids. The deterministic
|
|
20036
20142
|
// id + the UPSERT-take-MAX(output_tokens) statement make every re-read idempotent
|
|
20037
20143
|
// AND converge a streaming partial/final split across two incremental passes:
|
|
20038
20144
|
// a whole-file re-read no-ops (equal output), a lagging final replaces a
|
|
@@ -20997,6 +21103,42 @@ var SqliteFindingsRepository = class {
|
|
|
20997
21103
|
this.db = db;
|
|
20998
21104
|
}
|
|
20999
21105
|
db;
|
|
21106
|
+
/**
|
|
21107
|
+
* The newest `limit` findings, newest first.
|
|
21108
|
+
*
|
|
21109
|
+
* THE PLAN IS THE POINT HERE, and two things in the SQL below exist only to
|
|
21110
|
+
* pin it. The natural spelling — drive from `inspection_findings`, order by the
|
|
21111
|
+
* JOINED `e.started_at` — cannot push the LIMIT down, because the sort key is
|
|
21112
|
+
* not on the driving table: SQLite sorts every finding in the store through a
|
|
21113
|
+
* temp B-tree to return 500 rows. Measured at 35.0 ms on a 40,000-event corpus
|
|
21114
|
+
* against 0.9 ms for the form below, and the gap is a ratio of the store size
|
|
21115
|
+
* rather than a constant.
|
|
21116
|
+
*
|
|
21117
|
+
* What it takes to make `started_at` order come out of an index instead:
|
|
21118
|
+
*
|
|
21119
|
+
* - **`+e.event_type`** — the unary plus makes that term non-indexable, so the
|
|
21120
|
+
* planner stops choosing `idx_audit_type_t` (`event_type, started_at`). That
|
|
21121
|
+
* index cannot serve the ORDER BY: the predicate spans four event types, so
|
|
21122
|
+
* satisfying a global `started_at` order across them needs a range merge
|
|
21123
|
+
* SQLite will not do, and it sorts instead. Freed of it, the planner scans
|
|
21124
|
+
* `idx_audit_started_at` — a bare `started_at` index — in DESC order and
|
|
21125
|
+
* filters the type per row, which lets the LIMIT stop the scan early.
|
|
21126
|
+
* - **`CROSS JOIN`** — semantically identical to JOIN in SQLite, and there
|
|
21127
|
+
* purely to stop the tables being reordered. With plain JOINs the planner
|
|
21128
|
+
* drives from `f` and sorts everything again: measured at 23.6 ms, i.e. the
|
|
21129
|
+
* unary plus ALONE recovers almost none of the win. Both are needed.
|
|
21130
|
+
*
|
|
21131
|
+
* Neither is a micro-optimisation that a later reader should tidy away, and
|
|
21132
|
+
* `packages/persistence/test/performance/hot-read-query-plans.test.ts` fails if
|
|
21133
|
+
* the temp B-tree comes back.
|
|
21134
|
+
*
|
|
21135
|
+
* Degrading gracefully was the reason for `+` over `INDEXED BY`, which measured
|
|
21136
|
+
* identically (0.9 ms): `INDEXED BY` is a hard requirement, so dropping or
|
|
21137
|
+
* renaming the index turns this read into an ERROR, where `+` turns it into a
|
|
21138
|
+
* scan-and-sort — slower, still correct. The worst case for the chosen form is
|
|
21139
|
+
* a store whose recent captures carry no findings at all, where the scan walks
|
|
21140
|
+
* the whole index; that is still no worse than the full sort it replaced.
|
|
21141
|
+
*/
|
|
21000
21142
|
recentFindings(opts) {
|
|
21001
21143
|
const limit = opts?.limit ?? 50;
|
|
21002
21144
|
const rows = allRows(
|
|
@@ -21005,10 +21147,10 @@ var SqliteFindingsRepository = class {
|
|
|
21005
21147
|
f.masked_match, f.action_taken, f.confidence, e.started_at AS occurred_at,
|
|
21006
21148
|
json_extract(e.attributes, '$.source_tool') AS source_tool,
|
|
21007
21149
|
e.event_type AS kind
|
|
21008
|
-
FROM
|
|
21009
|
-
JOIN
|
|
21010
|
-
JOIN inspection_definitions d ON d.id = f.inspection_definition_id
|
|
21011
|
-
WHERE e.event_type IN (${CAPTURE_EVENT_TYPES_SQL})
|
|
21150
|
+
FROM audit_events e
|
|
21151
|
+
CROSS JOIN inspection_findings f ON f.audit_event_id = e.id
|
|
21152
|
+
CROSS JOIN inspection_definitions d ON d.id = f.inspection_definition_id
|
|
21153
|
+
WHERE +e.event_type IN (${CAPTURE_EVENT_TYPES_SQL})
|
|
21012
21154
|
ORDER BY e.started_at DESC, f.rowid DESC
|
|
21013
21155
|
LIMIT :limit`
|
|
21014
21156
|
),
|
|
@@ -21652,7 +21794,8 @@ var SqliteInspectionDefinitionsRepository = class {
|
|
|
21652
21794
|
}
|
|
21653
21795
|
db;
|
|
21654
21796
|
insertStmt;
|
|
21655
|
-
//
|
|
21797
|
+
// Insert-if-absent; returns the content-addressed definition id. An id already
|
|
21798
|
+
// present keeps the stored row untouched — see the class doc.
|
|
21656
21799
|
upsert(input) {
|
|
21657
21800
|
const id = inspectionDefinitionId(input.ruleId, input.version);
|
|
21658
21801
|
const row = toInspectionDefinitionRow(input, id);
|
|
@@ -21796,11 +21939,23 @@ function isParseableBinaryVersion(version2) {
|
|
|
21796
21939
|
|
|
21797
21940
|
// ../../packages/persistence/src/repositories/installed-packs.ts
|
|
21798
21941
|
var DEFAULT_POLICY_ID = DEFAULT_PACK_POLICY_ID;
|
|
21942
|
+
function printableRuleId(entry) {
|
|
21943
|
+
if (typeof entry !== "object" || entry === null) return null;
|
|
21944
|
+
const candidate = entry.id;
|
|
21945
|
+
return Rule.shape.id.safeParse(candidate).success ? candidate : null;
|
|
21946
|
+
}
|
|
21947
|
+
function firstIssueReason(error51) {
|
|
21948
|
+
const issue2 = error51.issues[0];
|
|
21949
|
+
if (!issue2) return "unknown";
|
|
21950
|
+
const path = issue2.path.map((segment) => String(segment)).join(".");
|
|
21951
|
+
return path ? `${path}: ${issue2.code}` : issue2.code;
|
|
21952
|
+
}
|
|
21953
|
+
var REJECTED_RULE_DETAIL_CAP = 10;
|
|
21799
21954
|
function inventorySignature(packs2) {
|
|
21800
21955
|
return packs2.map((p) => `${p.namespace}/${p.packId}@${p.version}#${hashRules(p.rulesJson)}`).sort().join(",");
|
|
21801
21956
|
}
|
|
21802
21957
|
function hashRules(rulesJson) {
|
|
21803
|
-
return createHash2("
|
|
21958
|
+
return createHash2("sha256").update(rulesJson).digest("hex");
|
|
21804
21959
|
}
|
|
21805
21960
|
function parseVersion(v) {
|
|
21806
21961
|
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v);
|
|
@@ -22012,10 +22167,21 @@ var SqliteInstalledPacksRepository = class {
|
|
|
22012
22167
|
* (all detection off) instead of falling back to the bundled packs. Every
|
|
22013
22168
|
* JSON-level failure therefore counts as invalid.
|
|
22014
22169
|
*/
|
|
22170
|
+
/**
|
|
22171
|
+
* ORDERED, because a rule id is unique only WITHIN a pack — the sole unique
|
|
22172
|
+
* index is (namespace, pack_id) — so two enabled packs may contribute the same
|
|
22173
|
+
* id, and the per-rule maps below are last-write-wins. Without an ORDER BY the
|
|
22174
|
+
* winner is whatever order SQLite happens to return, which makes a collision
|
|
22175
|
+
* resolve differently on two machines holding identical stores. Ordering by
|
|
22176
|
+
* (namespace, pack_id) makes the loser deterministic and therefore testable.
|
|
22177
|
+
*/
|
|
22015
22178
|
installedRuleset() {
|
|
22016
22179
|
const rows = allRows(
|
|
22017
22180
|
this.db.prepare(
|
|
22018
|
-
`SELECT enabled, policy_id AS policyId, rules_json AS rulesJson, version
|
|
22181
|
+
`SELECT enabled, policy_id AS policyId, rules_json AS rulesJson, version,
|
|
22182
|
+
namespace, pack_id AS packId
|
|
22183
|
+
FROM installed_packs
|
|
22184
|
+
ORDER BY namespace, pack_id`
|
|
22019
22185
|
)
|
|
22020
22186
|
);
|
|
22021
22187
|
const out = {
|
|
@@ -22023,22 +22189,32 @@ var SqliteInstalledPacksRepository = class {
|
|
|
22023
22189
|
enabledPacks: 0,
|
|
22024
22190
|
rules: [],
|
|
22025
22191
|
invalidRules: 0,
|
|
22192
|
+
rejectedRules: [],
|
|
22026
22193
|
ruleActions: /* @__PURE__ */ new Map(),
|
|
22027
|
-
ruleVersions: /* @__PURE__ */ new Map()
|
|
22194
|
+
ruleVersions: /* @__PURE__ */ new Map(),
|
|
22195
|
+
reversibleRules: /* @__PURE__ */ new Set()
|
|
22196
|
+
};
|
|
22197
|
+
const reject = (pack, ruleId, reason) => {
|
|
22198
|
+
if (out.rejectedRules.length >= REJECTED_RULE_DETAIL_CAP) return;
|
|
22199
|
+
out.rejectedRules.push({ pack, ruleId, reason });
|
|
22028
22200
|
};
|
|
22029
22201
|
for (const row of rows) {
|
|
22030
22202
|
if (!intToBool(row.enabled)) continue;
|
|
22031
22203
|
out.enabledPacks += 1;
|
|
22032
22204
|
const action = policyIdToAction(row.policyId);
|
|
22205
|
+
const reversible = policyIdIsReversible(row.policyId);
|
|
22206
|
+
const pack = `${row.namespace}/${row.packId}`;
|
|
22033
22207
|
let raw;
|
|
22034
22208
|
try {
|
|
22035
22209
|
raw = JSON.parse(row.rulesJson);
|
|
22036
22210
|
} catch {
|
|
22037
22211
|
out.invalidRules += 1;
|
|
22212
|
+
reject(pack, null, "rules_json: malformed JSON");
|
|
22038
22213
|
continue;
|
|
22039
22214
|
}
|
|
22040
22215
|
if (!Array.isArray(raw)) {
|
|
22041
22216
|
out.invalidRules += 1;
|
|
22217
|
+
reject(pack, null, "rules_json: not an array");
|
|
22042
22218
|
continue;
|
|
22043
22219
|
}
|
|
22044
22220
|
for (const entry of raw) {
|
|
@@ -22047,7 +22223,12 @@ var SqliteInstalledPacksRepository = class {
|
|
|
22047
22223
|
out.rules.push(parsed.data);
|
|
22048
22224
|
out.ruleActions.set(parsed.data.id, action);
|
|
22049
22225
|
out.ruleVersions.set(parsed.data.id, row.version);
|
|
22050
|
-
|
|
22226
|
+
if (reversible) out.reversibleRules.add(parsed.data.id);
|
|
22227
|
+
else out.reversibleRules.delete(parsed.data.id);
|
|
22228
|
+
} else {
|
|
22229
|
+
out.invalidRules += 1;
|
|
22230
|
+
reject(pack, printableRuleId(entry), firstIssueReason(parsed.error));
|
|
22231
|
+
}
|
|
22051
22232
|
}
|
|
22052
22233
|
}
|
|
22053
22234
|
return out;
|
|
@@ -22241,31 +22422,38 @@ var CATEGORY_ORDER = ["config", "skill", "mcp", "hook"];
|
|
|
22241
22422
|
var VALID_HARNESS_IDS = new Set(HarnessId.options);
|
|
22242
22423
|
var WORKTREE_CHECKOUT_FILTER = "(url IS NULL OR (url NOT LIKE '%/.claude/worktrees/%' AND url NOT LIKE '%\\.claude\\worktrees\\%'))";
|
|
22243
22424
|
var HARNESS_LABELS = {
|
|
22244
|
-
|
|
22245
|
-
|
|
22246
|
-
|
|
22247
|
-
|
|
22425
|
+
[HARNESS.ClaudeCode]: "Claude Code",
|
|
22426
|
+
[HARNESS.Cursor]: "Cursor",
|
|
22427
|
+
[HARNESS.Codex]: "Codex",
|
|
22428
|
+
[HARNESS.Antigravity]: "Antigravity"
|
|
22248
22429
|
};
|
|
22249
22430
|
var HARNESS_LIVENESS_WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
22250
22431
|
var EMPTY_PROJECT_AGG = {
|
|
22251
22432
|
accessCounts: { open: 0, approved: 0, blocked: 0, total: 0 },
|
|
22252
22433
|
findingsCount: 0
|
|
22253
22434
|
};
|
|
22435
|
+
var stripSeparators = (value) => value.toLowerCase().replace(/[\s-]/g, "");
|
|
22436
|
+
var TITLE_NEEDLES = {
|
|
22437
|
+
ClaudeCode: stripSeparators(SOURCE_TOOL.ClaudeCode),
|
|
22438
|
+
Cursor: stripSeparators(SOURCE_TOOL.Cursor),
|
|
22439
|
+
Codex: stripSeparators(SOURCE_TOOL.Codex),
|
|
22440
|
+
Antigravity: stripSeparators(SOURCE_TOOL.Antigravity)
|
|
22441
|
+
};
|
|
22254
22442
|
function resolveHarnessId(attrs, row) {
|
|
22255
22443
|
if (attrs.provider && VALID_HARNESS_IDS.has(attrs.provider)) {
|
|
22256
22444
|
return attrs.provider;
|
|
22257
22445
|
}
|
|
22258
|
-
const t = (row.title ?? "")
|
|
22259
|
-
if (t.includes(
|
|
22260
|
-
if (t.includes(
|
|
22261
|
-
if (t.includes(
|
|
22262
|
-
if (t.includes(
|
|
22446
|
+
const t = stripSeparators(row.title ?? "");
|
|
22447
|
+
if (t.includes(TITLE_NEEDLES.ClaudeCode) || t === "claude") return HARNESS.ClaudeCode;
|
|
22448
|
+
if (t.includes(TITLE_NEEDLES.Cursor)) return HARNESS.Cursor;
|
|
22449
|
+
if (t.includes(TITLE_NEEDLES.Codex)) return HARNESS.Codex;
|
|
22450
|
+
if (t.includes(TITLE_NEEDLES.Antigravity)) return HARNESS.Antigravity;
|
|
22263
22451
|
return null;
|
|
22264
22452
|
}
|
|
22265
22453
|
function isLiveRealClaudeCode(rows) {
|
|
22266
22454
|
return rows.some((r) => {
|
|
22267
22455
|
const attrs = safeJson(r.attributes, {});
|
|
22268
|
-
return attrs.provenance !== "sample" && resolveHarnessId(attrs, r) ===
|
|
22456
|
+
return attrs.provenance !== "sample" && resolveHarnessId(attrs, r) === HARNESS.ClaudeCode;
|
|
22269
22457
|
});
|
|
22270
22458
|
}
|
|
22271
22459
|
function toAssetSummary(row) {
|
|
@@ -22533,7 +22721,7 @@ var SqliteInventoryAssetsRepository = class {
|
|
|
22533
22721
|
const isRealHarness = rows.some(
|
|
22534
22722
|
(r) => safeJson(r.attributes, {}).provenance !== "sample"
|
|
22535
22723
|
);
|
|
22536
|
-
const attachConfig = isRealHarness && harnessId ===
|
|
22724
|
+
const attachConfig = isRealHarness && harnessId === HARNESS.ClaudeCode && configAssets.length > 0;
|
|
22537
22725
|
const assets = attachConfig ? [...harnessAssets, ...configAssets].sort((a, b) => a.name.localeCompare(b.name)) : harnessAssets;
|
|
22538
22726
|
if (q && assets.length === 0) continue;
|
|
22539
22727
|
const firstRow = rows[0];
|
|
@@ -23207,9 +23395,10 @@ var SqliteProjectFilesRepository = class {
|
|
|
23207
23395
|
// ../../packages/persistence/src/repositories/resolutions.ts
|
|
23208
23396
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
23209
23397
|
var SqliteResolutionsRepository = class {
|
|
23210
|
-
constructor(db, now = () => Date.now()) {
|
|
23398
|
+
constructor(db, now = () => Date.now(), newId = () => randomUUID7()) {
|
|
23211
23399
|
this.db = db;
|
|
23212
23400
|
this.now = now;
|
|
23401
|
+
this.newId = newId;
|
|
23213
23402
|
this.insertStmt = db.prepare(
|
|
23214
23403
|
`INSERT INTO finding_resolution (id, finding_key, status, method, resolved_at, evidence, created_at)
|
|
23215
23404
|
VALUES (:id, :findingKey, :status, :method, :resolvedAt, :evidence, :createdAt)`
|
|
@@ -23242,12 +23431,14 @@ var SqliteResolutionsRepository = class {
|
|
|
23242
23431
|
}
|
|
23243
23432
|
db;
|
|
23244
23433
|
now;
|
|
23434
|
+
newId;
|
|
23245
23435
|
insertStmt;
|
|
23246
23436
|
latestStmt;
|
|
23247
23437
|
openAtRestStmt;
|
|
23248
23438
|
resolvedAtRestStmt;
|
|
23249
23439
|
/**
|
|
23250
|
-
* Insert one disposition row. The repo mints the id and stamps created_at
|
|
23440
|
+
* Insert one disposition row. The repo mints the id and stamps created_at,
|
|
23441
|
+
* both through the constructor's injectable seams.
|
|
23251
23442
|
* `status`/`method` are typed AND re-parsed here against @akasecurity/schema's
|
|
23252
23443
|
* FindingStatus/ResolutionMethod, so the persisted vocabulary can never drift
|
|
23253
23444
|
* from the schema enums. NOTE for future manual-resolution writers: this is
|
|
@@ -23259,7 +23450,7 @@ var SqliteResolutionsRepository = class {
|
|
|
23259
23450
|
*/
|
|
23260
23451
|
insertResolution(r) {
|
|
23261
23452
|
this.insertStmt.run({
|
|
23262
|
-
id:
|
|
23453
|
+
id: this.newId(),
|
|
23263
23454
|
findingKey: r.findingKey,
|
|
23264
23455
|
status: FindingStatus.parse(r.status),
|
|
23265
23456
|
method: ResolutionMethod.parse(r.method),
|
|
@@ -23838,16 +24029,16 @@ var ACTION_TO_KIND = {
|
|
|
23838
24029
|
warn: "warned"
|
|
23839
24030
|
};
|
|
23840
24031
|
var ENFORCEMENT_KINDS = ["blocked", "redacted", "warned"];
|
|
23841
|
-
var SCAN_COVERAGE =
|
|
23842
|
-
|
|
23843
|
-
|
|
23844
|
-
|
|
23845
|
-
|
|
23846
|
-
|
|
23847
|
-
|
|
23848
|
-
|
|
23849
|
-
|
|
23850
|
-
|
|
24032
|
+
var SCAN_COVERAGE = {
|
|
24033
|
+
[HARNESS.Antigravity]: { coverage: 60, supported: true },
|
|
24034
|
+
[HARNESS.Api]: { coverage: 0, supported: false },
|
|
24035
|
+
[HARNESS.ChatGpt]: { coverage: 40, supported: true },
|
|
24036
|
+
[HARNESS.ClaudeAi]: { coverage: 40, supported: true },
|
|
24037
|
+
[HARNESS.ClaudeCode]: { coverage: 100, supported: true },
|
|
24038
|
+
[HARNESS.Codex]: { coverage: 80, supported: true },
|
|
24039
|
+
[HARNESS.Copilot]: { coverage: 0, supported: false },
|
|
24040
|
+
[HARNESS.Cursor]: { coverage: 0, supported: false }
|
|
24041
|
+
};
|
|
23851
24042
|
var GRANULARITY = {
|
|
23852
24043
|
"7d": "day",
|
|
23853
24044
|
"30d": "day",
|
|
@@ -23946,9 +24137,22 @@ var SqliteSecurityRepository = class {
|
|
|
23946
24137
|
return Promise.resolve({ total, needsRemediation, bySeverity });
|
|
23947
24138
|
}
|
|
23948
24139
|
// Range is echoed but does not change the result today — coverage is a constant
|
|
23949
|
-
// business fact (see SCAN_COVERAGE), not a measured per-window metric.
|
|
24140
|
+
// business fact (see SCAN_COVERAGE), not a measured per-window metric. Order
|
|
24141
|
+
// comes from Provider.options (the enum's declaration order), not from
|
|
24142
|
+
// SCAN_COVERAGE's own key order — deliberately, not because object literals
|
|
24143
|
+
// leave key order unspecified (ES2015 guarantees insertion order for these
|
|
24144
|
+
// non-integer string keys, so iterating SCAN_COVERAGE directly would be
|
|
24145
|
+
// reliable too). The reason is the schema comment's promise: the returned
|
|
24146
|
+
// order must mirror the generated OpenAPI enum list, which is Provider's
|
|
24147
|
+
// contract, not this table's.
|
|
23950
24148
|
scanCoverage(range) {
|
|
23951
|
-
return Promise.resolve({
|
|
24149
|
+
return Promise.resolve({
|
|
24150
|
+
range,
|
|
24151
|
+
providers: Provider.options.map((provider) => ({
|
|
24152
|
+
provider,
|
|
24153
|
+
...SCAN_COVERAGE[provider]
|
|
24154
|
+
}))
|
|
24155
|
+
});
|
|
23952
24156
|
}
|
|
23953
24157
|
enforcementActions(range) {
|
|
23954
24158
|
const lenMs = RANGE_DAYS[range] * DAY_MS4;
|
|
@@ -24006,10 +24210,10 @@ var SqliteSecurityRepository = class {
|
|
|
24006
24210
|
// count; a superseding open/redetected row means the finding is not
|
|
24007
24211
|
// remediated and is excluded, same invariant as severitySummary. Legacy
|
|
24008
24212
|
// at-rest findings with finding_key IS NULL can never have a resolution row
|
|
24009
|
-
// (the lifecycle is keyed by finding_key), so
|
|
24010
|
-
//
|
|
24011
|
-
//
|
|
24012
|
-
// mirroring this file's other methods.
|
|
24213
|
+
// (the lifecycle is keyed by finding_key), so they cannot reach the driving
|
|
24214
|
+
// set below. One raw-row query (fetch the findings with resolution activity in
|
|
24215
|
+
// the window + each one's latest resolution status/method/resolved_at) +
|
|
24216
|
+
// pure-JS filter/bucket/mean, mirroring this file's other methods.
|
|
24013
24217
|
mttrTrend(range) {
|
|
24014
24218
|
const granularity = granularityFor(range);
|
|
24015
24219
|
const bucketMs = (granularity === "day" ? 1 : 7) * DAY_MS4;
|
|
@@ -24025,29 +24229,80 @@ var SqliteSecurityRepository = class {
|
|
|
24025
24229
|
// started_at the upsert overwrites onto inspection_findings.audit_event_id.
|
|
24026
24230
|
// COALESCE onto the parent event's started_at defends against any
|
|
24027
24231
|
// legacy/edge row the backfill left null.
|
|
24028
|
-
`SELECT
|
|
24232
|
+
`SELECT DISTINCT f.finding_key AS finding_key,
|
|
24233
|
+
COALESCE(f.first_detected_at, e.started_at) AS first_detected_at, d.severity AS severity,
|
|
24029
24234
|
latest.status AS latest_status,
|
|
24030
24235
|
latest.method AS latest_method,
|
|
24031
24236
|
latest.resolved_at AS latest_resolved_at
|
|
24032
|
-
FROM
|
|
24033
|
-
JOIN
|
|
24034
|
-
JOIN
|
|
24237
|
+
FROM finding_resolution fr
|
|
24238
|
+
CROSS JOIN inspection_findings f ON f.finding_key = fr.finding_key
|
|
24239
|
+
CROSS JOIN audit_events e ON e.id = f.audit_event_id
|
|
24240
|
+
CROSS JOIN inspection_definitions d ON d.id = f.inspection_definition_id
|
|
24035
24241
|
LEFT JOIN ${LATEST_RESOLUTION_BY_KEY_SQL} latest
|
|
24036
24242
|
ON latest.finding_key = f.finding_key
|
|
24037
|
-
WHERE
|
|
24038
|
-
AND e.event_type IN (${CAPTURE_EVENT_TYPES_SQL})
|
|
24039
|
-
|
|
24040
|
-
SELECT 1 FROM finding_resolution fr
|
|
24041
|
-
WHERE fr.finding_key = f.finding_key
|
|
24042
|
-
AND fr.resolved_at >= :windowStart
|
|
24043
|
-
)`
|
|
24044
|
-
// The EXISTS is a SUPERSET prefilter that bounds the scan to keys with
|
|
24045
|
-
// any resolution activity at/after the window start — a row this method
|
|
24243
|
+
WHERE fr.resolved_at >= :windowStart
|
|
24244
|
+
AND e.event_type IN (${CAPTURE_EVENT_TYPES_SQL})`
|
|
24245
|
+
// `fr` is a SUPERSET prefilter, not the answer: a finding this method
|
|
24046
24246
|
// ultimately counts has its LATEST resolution inside the window, which
|
|
24047
|
-
// implies
|
|
24048
|
-
// latest-wins + status/method + window gate
|
|
24049
|
-
// dialect-agnostic.
|
|
24050
|
-
//
|
|
24247
|
+
// implies a resolution row at/after the window start exists, so nothing
|
|
24248
|
+
// wanted is dropped. The exact latest-wins + status/method + window gate
|
|
24249
|
+
// stays in JS below, dialect-agnostic. `f.finding_key IS NOT NULL` is
|
|
24250
|
+
// implied rather than dropped — the join key comes from
|
|
24251
|
+
// finding_resolution, whose finding_key is NOT NULL.
|
|
24252
|
+
//
|
|
24253
|
+
// IT IS THE DRIVING TABLE THAT MAKES THAT PREFILTER A BOUND, which is
|
|
24254
|
+
// the correction this replaced. Spelled as an `EXISTS` in the WHERE it
|
|
24255
|
+
// READ as a bound and was not one: SQLite drove from `audit_events` on
|
|
24256
|
+
// event_type, joined every capture event to its findings, and evaluated
|
|
24257
|
+
// the EXISTS last — bounding the RESULT and not the scan, so a 7d request
|
|
24258
|
+
// still cost the store's whole trackable history. Measured at 44.6 ms on
|
|
24259
|
+
// 50,000 events and 171.3 ms on 150,000 — linear in the STORE, and in
|
|
24260
|
+
// both cases returning rows for a window holding a fraction of it.
|
|
24261
|
+
//
|
|
24262
|
+
// Two things carry it, and they answer DIFFERENT halves — which is worth
|
|
24263
|
+
// stating precisely, because the obvious reading (both are needed for the
|
|
24264
|
+
// speed) is wrong and was measured to be wrong:
|
|
24265
|
+
//
|
|
24266
|
+
// - **`CROSS JOIN`** is the whole of the store-size fix. In SQLite the
|
|
24267
|
+
// keyword is semantically identical to JOIN and exists only to stop the
|
|
24268
|
+
// tables being reordered; with plain JOINs the planner puts `e` back on
|
|
24269
|
+
// the outside, because with no ANALYZE statistics it prices
|
|
24270
|
+
// `event_type IN (...)` as a selective probe. Reverting it alone takes
|
|
24271
|
+
// the 2k->20k flatness ratio from 1.32 to 16.87.
|
|
24272
|
+
// - **`idx_finding_resolution_resolved_at`** (migration 0021) makes
|
|
24273
|
+
// `resolved_at >= :windowStart` a range SEARCH instead of a bare
|
|
24274
|
+
// `SCAN fr` — finding_key was this table's only index before it, so the
|
|
24275
|
+
// range had none. It buys NO flatness in store size: remove it and the
|
|
24276
|
+
// ratio above does not move, because the latest-resolution derived
|
|
24277
|
+
// table already passes over the whole of finding_resolution, so this
|
|
24278
|
+
// read is O(resolutions) either way and resolutions are not the store.
|
|
24279
|
+
// What it buys is the criterion `hot-read-query-plans.test.ts` enforces
|
|
24280
|
+
// — no hot read may pass over a table with no index — and that is the
|
|
24281
|
+
// guard that goes red when it is dropped. Neither test catches the
|
|
24282
|
+
// other's defect.
|
|
24283
|
+
//
|
|
24284
|
+
// SELECT DISTINCT is a CORRECTNESS requirement of driving from `fr`, not a
|
|
24285
|
+
// tidy-up. finding_resolution is append-only, so a key that was fixed,
|
|
24286
|
+
// redetected and fixed again carries several rows inside one window and
|
|
24287
|
+
// matches once per row — and the value below is a MEAN, so a key matched
|
|
24288
|
+
// three times is a key weighted three times.
|
|
24289
|
+
//
|
|
24290
|
+
// The skew is easy to argue away and the argument is wrong, so it is worth
|
|
24291
|
+
// recording. Duplicate rows for ONE key are identical (every projected
|
|
24292
|
+
// column is per-key: `latest.*` is latest-wins, `first_detected_at` is
|
|
24293
|
+
// preserved), so sums and counts scale together and that key's own mean
|
|
24294
|
+
// does not move. What moves is a bucket holding TWO findings that duplicate
|
|
24295
|
+
// UNEQUALLY: three rows for a 5.9-day fix and one for a 1.9-day fix average
|
|
24296
|
+
// 4.9 days weighted against 3.9 unweighted. Measured, and pinned by
|
|
24297
|
+
// `security.test.ts`'s "weights a finding ONCE however many resolution rows
|
|
24298
|
+
// it has inside the window" — which needed a fixture built for it, since no
|
|
24299
|
+
// single-key case can show it.
|
|
24300
|
+
//
|
|
24301
|
+
// `finding_key` is selected to make the DISTINCT dedup by KEY rather than
|
|
24302
|
+
// by value tuple. On the other columns alone, two genuinely different
|
|
24303
|
+
// findings sharing a severity, a first-detection event and a resolution
|
|
24304
|
+
// instant — one commit fixing two secrets in one file — are one tuple, and
|
|
24305
|
+
// collapsing them would under-count in the other direction.
|
|
24051
24306
|
),
|
|
24052
24307
|
{ windowStart }
|
|
24053
24308
|
);
|
|
@@ -24105,16 +24360,47 @@ var SqliteSecurityRepository = class {
|
|
|
24105
24360
|
}
|
|
24106
24361
|
// Recently-resolved activity feed: findings whose finding_key's LATEST
|
|
24107
24362
|
// finding_resolution row is status:'resolved'/method:'fixed-at-source' —
|
|
24108
|
-
// same latest-resolution-wins
|
|
24109
|
-
//
|
|
24110
|
-
//
|
|
24111
|
-
//
|
|
24112
|
-
//
|
|
24113
|
-
//
|
|
24114
|
-
//
|
|
24115
|
-
//
|
|
24116
|
-
//
|
|
24117
|
-
//
|
|
24363
|
+
// same latest-resolution-wins derived table as severitySummary / mttrTrend
|
|
24364
|
+
// (NOT a plain JOIN, which would surface every historical resolution row for
|
|
24365
|
+
// a key rather than just its current disposition). A key whose latest row is
|
|
24366
|
+
// a superseding 'open'/'redetected' row (the same secret came back) is
|
|
24367
|
+
// excluded — it is not currently resolved. Legacy at-rest findings with
|
|
24368
|
+
// finding_key IS NULL are excluded outright (the resolution lifecycle can
|
|
24369
|
+
// never attach to them). Path comes from the finding's parent event
|
|
24370
|
+
// (event_type 'code_change', attributes.file_path) — mirrors resolutions.ts's
|
|
24371
|
+
// openAtRestStmt accessor. Ordered by resolved_at DESC, capped at `limit`.
|
|
24372
|
+
//
|
|
24373
|
+
// THE RESOLUTION SET DRIVES THIS QUERY, and that is a correctness property of
|
|
24374
|
+
// the plan rather than a preference. Written the other way round — driving
|
|
24375
|
+
// from inspection_findings/audit_events with `latest` LEFT JOINed on — SQLite
|
|
24376
|
+
// cannot use the join key: `f` is reached FROM `latest` by finding_key, so
|
|
24377
|
+
// `latest` gets probed on (rn, status, method) instead and the plan enumerates
|
|
24378
|
+
// every (code_change event x resolved key) pair before `f` can reject it. That
|
|
24379
|
+
// is a cross product, and it is quadratic in the store: measured at 10,966 ms
|
|
24380
|
+
// on a corpus of 50,000 events carrying 2,051 resolutions, against 20 rows
|
|
24381
|
+
// returned. It was invisible for as long as it was, and reported at 8 ms,
|
|
24382
|
+
// because an empty finding_resolution table makes the inner side empty and the
|
|
24383
|
+
// cross product collapses to nothing — so the shape is only observable on a
|
|
24384
|
+
// corpus that seeds resolutions.
|
|
24385
|
+
//
|
|
24386
|
+
// Driving from `latest` instead makes every step below it a unique-index or
|
|
24387
|
+
// primary-key lookup (uq_inspection_findings_key, then audit_events' own PK),
|
|
24388
|
+
// so the cost is the derived table's own — linear in resolutions, which is
|
|
24389
|
+
// what this feed is legitimately about.
|
|
24390
|
+
//
|
|
24391
|
+
// CROSS JOIN is what actually pins that, and it is load-bearing rather than
|
|
24392
|
+
// decorative: in SQLite the keyword is semantically identical to JOIN and
|
|
24393
|
+
// exists only to stop the optimizer reordering the tables. Written as plain
|
|
24394
|
+
// JOINs in this order the planner puts `e` back on the outside — it has no
|
|
24395
|
+
// ANALYZE statistics to price the alternatives with, so it takes
|
|
24396
|
+
// `event_type = 'code_change'` for a selective index probe and rebuilds the
|
|
24397
|
+
// cross product. The FROM order alone was measured to change the plan not at
|
|
24398
|
+
// all.
|
|
24399
|
+
//
|
|
24400
|
+
// The LEFT JOIN it replaced was already an inner join in effect: three
|
|
24401
|
+
// `latest.*` predicates sit in the WHERE, and each of them is false for a
|
|
24402
|
+
// null-extended row. Spelling it JOIN changes no row and stops the plan
|
|
24403
|
+
// reading as though the findings side could drive.
|
|
24118
24404
|
recentlyResolved(limit = 20) {
|
|
24119
24405
|
const rows = allRows(
|
|
24120
24406
|
this.db.prepare(
|
|
@@ -24124,17 +24410,15 @@ var SqliteSecurityRepository = class {
|
|
|
24124
24410
|
json_extract(e.attributes, '$.file_path') AS path,
|
|
24125
24411
|
COALESCE(f.first_detected_at, e.started_at) AS first_detected_at,
|
|
24126
24412
|
latest.resolved_at AS latest_resolved_at
|
|
24127
|
-
FROM
|
|
24128
|
-
JOIN
|
|
24129
|
-
JOIN
|
|
24130
|
-
|
|
24131
|
-
|
|
24132
|
-
WHERE e.event_type = 'code_change'
|
|
24133
|
-
AND f.finding_key IS NOT NULL
|
|
24134
|
-
AND latest.status = 'resolved'
|
|
24413
|
+
FROM ${LATEST_RESOLUTION_BY_KEY_SQL} latest
|
|
24414
|
+
CROSS JOIN inspection_findings f ON f.finding_key = latest.finding_key
|
|
24415
|
+
CROSS JOIN audit_events e ON e.id = f.audit_event_id
|
|
24416
|
+
CROSS JOIN inspection_definitions d ON d.id = f.inspection_definition_id
|
|
24417
|
+
WHERE latest.status = 'resolved'
|
|
24135
24418
|
AND latest.method = 'fixed-at-source'
|
|
24136
24419
|
AND latest.resolved_at IS NOT NULL
|
|
24137
|
-
|
|
24420
|
+
AND e.event_type = 'code_change'
|
|
24421
|
+
ORDER BY latest.resolved_at DESC
|
|
24138
24422
|
LIMIT :limit`
|
|
24139
24423
|
),
|
|
24140
24424
|
{ limit }
|
|
@@ -25071,6 +25355,7 @@ function openAndInitialize(file2) {
|
|
|
25071
25355
|
function openLocalDatabase(dir) {
|
|
25072
25356
|
ensureDataDirSync(dir);
|
|
25073
25357
|
const file2 = join2(dir, DB_FILENAME);
|
|
25358
|
+
reapStalePartials(file2);
|
|
25074
25359
|
const {
|
|
25075
25360
|
db,
|
|
25076
25361
|
events,
|
|
@@ -25482,11 +25767,79 @@ function migrateLegacyLayout(base = defaultDataDir()) {
|
|
|
25482
25767
|
}
|
|
25483
25768
|
}
|
|
25484
25769
|
|
|
25485
|
-
// ../../packages/persistence/src/settings.ts
|
|
25770
|
+
// ../../packages/persistence/src/managed-settings.ts
|
|
25486
25771
|
import { readFileSync as readFileSync3 } from "fs";
|
|
25772
|
+
import { posix, win32 } from "path";
|
|
25773
|
+
function managedSettingsPaths(platform2 = process.platform) {
|
|
25774
|
+
if (platform2 === "darwin") {
|
|
25775
|
+
return [
|
|
25776
|
+
posix.join("/Library", "Application Support", "AKASecurity", MANAGED_SETTINGS_FILENAME),
|
|
25777
|
+
posix.join("/Library", "Managed Preferences", MANAGED_SETTINGS_FILENAME)
|
|
25778
|
+
];
|
|
25779
|
+
}
|
|
25780
|
+
if (platform2 === "win32") {
|
|
25781
|
+
return [win32.join("C:\\", "ProgramData", "AKASecurity", MANAGED_SETTINGS_FILENAME)];
|
|
25782
|
+
}
|
|
25783
|
+
return [posix.join("/etc", "aka", MANAGED_SETTINGS_FILENAME)];
|
|
25784
|
+
}
|
|
25785
|
+
function readManagedSettings(paths = managedSettingsPaths()) {
|
|
25786
|
+
for (const path of paths) {
|
|
25787
|
+
let text;
|
|
25788
|
+
try {
|
|
25789
|
+
text = readFileSync3(path, "utf8");
|
|
25790
|
+
} catch {
|
|
25791
|
+
continue;
|
|
25792
|
+
}
|
|
25793
|
+
const record2 = parseJsonObject(text);
|
|
25794
|
+
if (!record2) continue;
|
|
25795
|
+
const parsed = ManagedSettings.safeParse(record2);
|
|
25796
|
+
if (parsed.success) return parsed.data;
|
|
25797
|
+
}
|
|
25798
|
+
return null;
|
|
25799
|
+
}
|
|
25800
|
+
function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ new Date()) {
|
|
25801
|
+
if (!managed) return settings;
|
|
25802
|
+
const { values } = managed;
|
|
25803
|
+
const merged = { ...settings };
|
|
25804
|
+
if (values.runMode !== void 0) merged.runMode = values.runMode;
|
|
25805
|
+
if (values.controlPlane !== void 0) {
|
|
25806
|
+
merged.controlPlane = {
|
|
25807
|
+
...values.controlPlane,
|
|
25808
|
+
// The administrator pinned WHICH deployment, not WHEN this machine
|
|
25809
|
+
// joined it. Keep the user's own attach time when the endpoint is
|
|
25810
|
+
// unchanged, so a managed machine does not appear to re-attach on every
|
|
25811
|
+
// read; stamp a fresh one when the administrator moved it.
|
|
25812
|
+
attachedAt: settings.controlPlane?.endpoint === values.controlPlane.endpoint ? settings.controlPlane.attachedAt : now().toISOString()
|
|
25813
|
+
};
|
|
25814
|
+
}
|
|
25815
|
+
if (values.historicalAccess !== void 0) merged.historicalAccess = values.historicalAccess;
|
|
25816
|
+
if (values.vaultKeyCustody !== void 0) merged.vaultKeyCustody = values.vaultKeyCustody;
|
|
25817
|
+
if (values.vaultInlineReveal !== void 0) merged.vaultInlineReveal = values.vaultInlineReveal;
|
|
25818
|
+
if (values.dataSharesInPlace !== void 0) merged.dataSharesInPlace = values.dataSharesInPlace;
|
|
25819
|
+
if (values.vaultConsent !== void 0) {
|
|
25820
|
+
merged.vaultConsent = values.vaultConsent ? (
|
|
25821
|
+
// Keep an existing valid grant so its acknowledgedAt survives; mint one
|
|
25822
|
+
// at the current version otherwise.
|
|
25823
|
+
settings.vaultConsent?.version === VAULT_CONSENT_VERSION ? settings.vaultConsent : { acknowledgedAt: now().toISOString(), version: VAULT_CONSENT_VERSION }
|
|
25824
|
+
) : void 0;
|
|
25825
|
+
}
|
|
25826
|
+
if (values.modelJudgeConsent !== void 0) {
|
|
25827
|
+
merged.modelJudgeConsent = values.modelJudgeConsent ? settings.modelJudgeConsent?.payloadVersion === MODEL_JUDGE_PAYLOAD_VERSION ? settings.modelJudgeConsent : {
|
|
25828
|
+
acknowledgedAt: now().toISOString(),
|
|
25829
|
+
payloadVersion: MODEL_JUDGE_PAYLOAD_VERSION
|
|
25830
|
+
} : void 0;
|
|
25831
|
+
}
|
|
25832
|
+
return merged;
|
|
25833
|
+
}
|
|
25834
|
+
|
|
25835
|
+
// ../../packages/persistence/src/settings.ts
|
|
25836
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
25487
25837
|
import { join as join5 } from "path";
|
|
25488
25838
|
var SETTINGS_FILENAME = "settings.json";
|
|
25489
25839
|
function readWorkspaceSettings(base = defaultDataDir()) {
|
|
25840
|
+
return overlayManagedSettings(readUserSettings(base), readManagedSettings());
|
|
25841
|
+
}
|
|
25842
|
+
function readUserSettings(base) {
|
|
25490
25843
|
const record2 = readJson(join5(settingsDir(base), SETTINGS_FILENAME));
|
|
25491
25844
|
if (!record2) return defaultWorkspaceSettings();
|
|
25492
25845
|
try {
|
|
@@ -25498,7 +25851,7 @@ function readWorkspaceSettings(base = defaultDataDir()) {
|
|
|
25498
25851
|
function readJson(file2) {
|
|
25499
25852
|
let text;
|
|
25500
25853
|
try {
|
|
25501
|
-
text =
|
|
25854
|
+
text = readFileSync4(file2, "utf8");
|
|
25502
25855
|
} catch {
|
|
25503
25856
|
return null;
|
|
25504
25857
|
}
|
|
@@ -25517,15 +25870,7 @@ import {
|
|
|
25517
25870
|
// ../../packages/persistence/src/vault/key-provider.ts
|
|
25518
25871
|
import { execFileSync } from "child_process";
|
|
25519
25872
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
25520
|
-
import {
|
|
25521
|
-
chmodSync as chmodSync2,
|
|
25522
|
-
mkdirSync as mkdirSync2,
|
|
25523
|
-
readFileSync as readFileSync4,
|
|
25524
|
-
renameSync as renameSync4,
|
|
25525
|
-
rmSync as rmSync4,
|
|
25526
|
-
statSync as statSync3,
|
|
25527
|
-
writeFileSync as writeFileSync3
|
|
25528
|
-
} from "fs";
|
|
25873
|
+
import { chmodSync as chmodSync2, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
25529
25874
|
import { join as join6 } from "path";
|
|
25530
25875
|
|
|
25531
25876
|
// ../../packages/persistence/src/vault/vault.ts
|
|
@@ -25621,7 +25966,7 @@ function resolveProviderSafe(resolveProviderFn) {
|
|
|
25621
25966
|
}
|
|
25622
25967
|
|
|
25623
25968
|
// ../../packages/plugin-sdk/src/config-inventory.ts
|
|
25624
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
25969
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync7, realpathSync, statSync as statSync5 } from "fs";
|
|
25625
25970
|
import { homedir as homedir2 } from "os";
|
|
25626
25971
|
import { basename as basename4, join as join10 } from "path";
|
|
25627
25972
|
|
|
@@ -26197,6 +26542,40 @@ function escapeRegExp2(value) {
|
|
|
26197
26542
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26198
26543
|
}
|
|
26199
26544
|
|
|
26545
|
+
// ../../packages/detections/src/regex-cache.ts
|
|
26546
|
+
var singles = /* @__PURE__ */ new WeakMap();
|
|
26547
|
+
var keywordLists = /* @__PURE__ */ new WeakMap();
|
|
26548
|
+
var labelLists = /* @__PURE__ */ new WeakMap();
|
|
26549
|
+
function listCache(kind) {
|
|
26550
|
+
return kind === "keyword" ? keywordLists : labelLists;
|
|
26551
|
+
}
|
|
26552
|
+
function memoizedRegExp(owner, build) {
|
|
26553
|
+
const cached2 = singles.get(owner);
|
|
26554
|
+
if (cached2 !== void 0) {
|
|
26555
|
+
cached2.lastIndex = 0;
|
|
26556
|
+
return cached2;
|
|
26557
|
+
}
|
|
26558
|
+
const compiled = build();
|
|
26559
|
+
singles.set(owner, compiled);
|
|
26560
|
+
return compiled;
|
|
26561
|
+
}
|
|
26562
|
+
function memoizedRegExpList(kind, owner, build) {
|
|
26563
|
+
const cache = listCache(kind);
|
|
26564
|
+
const cached2 = cache.get(owner);
|
|
26565
|
+
if (cached2 !== void 0) {
|
|
26566
|
+
if (cached2.stateful) {
|
|
26567
|
+
for (const re of cached2.entries) if (re !== void 0) re.lastIndex = 0;
|
|
26568
|
+
}
|
|
26569
|
+
return cached2.entries;
|
|
26570
|
+
}
|
|
26571
|
+
const entries = build();
|
|
26572
|
+
cache.set(owner, {
|
|
26573
|
+
entries,
|
|
26574
|
+
stateful: entries.some((re) => re !== void 0 && (re.global || re.sticky))
|
|
26575
|
+
});
|
|
26576
|
+
return entries;
|
|
26577
|
+
}
|
|
26578
|
+
|
|
26200
26579
|
// ../../packages/detections/src/matchers/limits.ts
|
|
26201
26580
|
var MAX_MATCHES_PER_RULE = 1e4;
|
|
26202
26581
|
var MAX_REGEX_INPUT_LENGTH = 2e5;
|
|
@@ -26207,10 +26586,17 @@ var KeywordMatcher2 = class {
|
|
|
26207
26586
|
if (rule.matcher.type !== "keyword") return [];
|
|
26208
26587
|
const { keywords, caseSensitive } = rule.matcher;
|
|
26209
26588
|
const spans = [];
|
|
26210
|
-
|
|
26211
|
-
|
|
26589
|
+
const compiled = memoizedRegExpList(
|
|
26590
|
+
"keyword",
|
|
26591
|
+
rule.matcher,
|
|
26592
|
+
() => keywords.map((kw) => {
|
|
26593
|
+
if (kw.length === 0) return void 0;
|
|
26594
|
+
return new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
26595
|
+
})
|
|
26596
|
+
);
|
|
26597
|
+
for (const re of compiled) {
|
|
26598
|
+
if (re === void 0) continue;
|
|
26212
26599
|
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
26213
|
-
const re = new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
26214
26600
|
let m;
|
|
26215
26601
|
while ((m = re.exec(text)) !== null) {
|
|
26216
26602
|
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
@@ -26226,7 +26612,10 @@ var RegexMatcher2 = class {
|
|
|
26226
26612
|
match(text, rule) {
|
|
26227
26613
|
if (rule.matcher.type !== "regex") return [];
|
|
26228
26614
|
const { pattern, flags, captureGroup } = rule.matcher;
|
|
26229
|
-
const re =
|
|
26615
|
+
const re = memoizedRegExp(
|
|
26616
|
+
rule.matcher,
|
|
26617
|
+
() => new RegExp(pattern, flags.includes("d") ? flags : `${flags}d`)
|
|
26618
|
+
);
|
|
26230
26619
|
const scanText2 = text.length > MAX_REGEX_INPUT_LENGTH ? text.slice(0, MAX_REGEX_INPUT_LENGTH) : text;
|
|
26231
26620
|
const spans = [];
|
|
26232
26621
|
let m;
|
|
@@ -26285,6 +26674,10 @@ function luhnCheck(digits) {
|
|
|
26285
26674
|
// ../../packages/detections/src/engine.ts
|
|
26286
26675
|
var keywordMatcher = new KeywordMatcher2();
|
|
26287
26676
|
var regexMatcher = new RegexMatcher2();
|
|
26677
|
+
var MATCHERS = {
|
|
26678
|
+
keyword: (text, rule) => keywordMatcher.match(text, rule),
|
|
26679
|
+
regex: (text, rule) => regexMatcher.match(text, rule)
|
|
26680
|
+
};
|
|
26288
26681
|
var packs = /* @__PURE__ */ new Map();
|
|
26289
26682
|
var POST_VALIDATORS = {
|
|
26290
26683
|
entropy: (value, config2) => isHighEntropy(value, numberOption(config2, "threshold"), numberOption(config2, "minLength")),
|
|
@@ -26300,8 +26693,7 @@ function passesPostValidators(rule, value) {
|
|
|
26300
26693
|
for (const ref of validators) {
|
|
26301
26694
|
const name = typeof ref === "string" ? ref : ref.name;
|
|
26302
26695
|
const config2 = typeof ref === "string" ? void 0 : ref.config;
|
|
26303
|
-
|
|
26304
|
-
if (validate && !validate(value, config2)) return false;
|
|
26696
|
+
if (!POST_VALIDATORS[name](value, config2)) return false;
|
|
26305
26697
|
}
|
|
26306
26698
|
return true;
|
|
26307
26699
|
}
|
|
@@ -26334,11 +26726,15 @@ function isCorroborated(candidate, candidates, text) {
|
|
|
26334
26726
|
const labels = req.labels;
|
|
26335
26727
|
if (labels && labels.length > 0) {
|
|
26336
26728
|
const haystack = text.slice(Math.max(0, winStart), winEnd);
|
|
26337
|
-
for (const
|
|
26338
|
-
|
|
26339
|
-
|
|
26340
|
-
|
|
26341
|
-
|
|
26729
|
+
for (const re of memoizedRegExpList(
|
|
26730
|
+
"label",
|
|
26731
|
+
req,
|
|
26732
|
+
() => labels.map((label) => {
|
|
26733
|
+
const trimmed = label.trim();
|
|
26734
|
+
return trimmed.length === 0 ? void 0 : new RegExp(`(?<![A-Za-z0-9])${escapeRegExp2(trimmed)}(?![A-Za-z0-9])`, "i");
|
|
26735
|
+
})
|
|
26736
|
+
)) {
|
|
26737
|
+
if (re?.test(haystack)) return true;
|
|
26342
26738
|
}
|
|
26343
26739
|
}
|
|
26344
26740
|
return false;
|
|
@@ -26358,14 +26754,7 @@ function scan(text, rules, context) {
|
|
|
26358
26754
|
const candidates = [];
|
|
26359
26755
|
for (const rule of ruleset) {
|
|
26360
26756
|
if (!ruleApplies(rule, extension)) continue;
|
|
26361
|
-
|
|
26362
|
-
if (rule.matcher.type === "keyword") {
|
|
26363
|
-
spans = keywordMatcher.match(text, rule);
|
|
26364
|
-
} else if (rule.matcher.type === "regex") {
|
|
26365
|
-
spans = regexMatcher.match(text, rule);
|
|
26366
|
-
} else {
|
|
26367
|
-
continue;
|
|
26368
|
-
}
|
|
26757
|
+
const spans = MATCHERS[rule.matcher.type](text, rule);
|
|
26369
26758
|
for (const span of spans) {
|
|
26370
26759
|
const rawMatch = text.slice(span.start, span.end);
|
|
26371
26760
|
if (!passesPostValidators(rule, rawMatch)) continue;
|
|
@@ -26688,24 +27077,33 @@ function probesFor(rule) {
|
|
|
26688
27077
|
const derived = rule.matcher.type === "regex" ? derivedProbes(rule.matcher.pattern) : [];
|
|
26689
27078
|
return [...derived, ...EXPONENTIAL_PROBES, ...POLYNOMIAL_PROBES];
|
|
26690
27079
|
}
|
|
26691
|
-
|
|
27080
|
+
var wallClock = () => performance.now();
|
|
27081
|
+
function worstProbeMs(rule, now = wallClock, corroborate) {
|
|
26692
27082
|
let ms = 0;
|
|
26693
27083
|
let probe = "";
|
|
27084
|
+
let corroboratedMs;
|
|
26694
27085
|
for (const text of probesFor(rule)) {
|
|
26695
|
-
const start =
|
|
27086
|
+
const start = now();
|
|
27087
|
+
const corroborateStart = corroborate?.();
|
|
26696
27088
|
scan(text, [rule]);
|
|
26697
|
-
const elapsed =
|
|
27089
|
+
const elapsed = now() - start;
|
|
27090
|
+
const corroborateEnd = corroborate?.();
|
|
26698
27091
|
if (elapsed > ms) {
|
|
26699
27092
|
ms = elapsed;
|
|
26700
27093
|
probe = text;
|
|
27094
|
+
corroboratedMs = corroborateStart === void 0 || corroborateEnd === void 0 ? void 0 : corroborateEnd - corroborateStart;
|
|
26701
27095
|
}
|
|
26702
27096
|
if (ms >= BUDGET_MS) break;
|
|
26703
27097
|
}
|
|
26704
|
-
return { ms, probe };
|
|
27098
|
+
return { ms, probe, corroboratedMs };
|
|
26705
27099
|
}
|
|
26706
|
-
|
|
26707
|
-
|
|
26708
|
-
|
|
27100
|
+
var CPU_CORROBORATION_SHARE = 0.2;
|
|
27101
|
+
var CORROBORATION_FLOOR_MS = BUDGET_MS * CPU_CORROBORATION_SHARE;
|
|
27102
|
+
function checkRuleTiming(rule, corroborate) {
|
|
27103
|
+
const { ms, probe, corroboratedMs } = worstProbeMs(rule, wallClock, corroborate);
|
|
27104
|
+
const work = corroboratedMs ?? 0;
|
|
27105
|
+
const verdict = ms < BUDGET_MS ? "safe" : work >= CORROBORATION_FLOOR_MS ? "over-budget" : "uncorroborated";
|
|
27106
|
+
return { verdict, worstMs: ms, corroboratedMs: work, probe };
|
|
26709
27107
|
}
|
|
26710
27108
|
|
|
26711
27109
|
// ../../rules/code-flaws/auth-jwt-no-verify.json
|
|
@@ -28786,7 +29184,7 @@ function maskText(text) {
|
|
|
28786
29184
|
}
|
|
28787
29185
|
|
|
28788
29186
|
// ../../packages/plugin-sdk/src/repo.ts
|
|
28789
|
-
import { existsSync as existsSync6, readFileSync as
|
|
29187
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
28790
29188
|
import { basename as basename3, dirname as dirname2, isAbsolute, join as join9, sep as sep2 } from "path";
|
|
28791
29189
|
function resolveRepoIdentity(cwd) {
|
|
28792
29190
|
try {
|
|
@@ -28889,7 +29287,7 @@ function resolveGitContext(root) {
|
|
|
28889
29287
|
}
|
|
28890
29288
|
function safeRead(path) {
|
|
28891
29289
|
try {
|
|
28892
|
-
return
|
|
29290
|
+
return readFileSync6(path, "utf8");
|
|
28893
29291
|
} catch {
|
|
28894
29292
|
return void 0;
|
|
28895
29293
|
}
|
|
@@ -29252,10 +29650,10 @@ function parseFrontmatter(raw) {
|
|
|
29252
29650
|
if (lines[0]?.trim() !== "---") return out;
|
|
29253
29651
|
for (const line of lines.slice(1)) {
|
|
29254
29652
|
if (line.trim() === "---") break;
|
|
29255
|
-
const
|
|
29256
|
-
if (
|
|
29257
|
-
const key = line.slice(0,
|
|
29258
|
-
const value = line.slice(
|
|
29653
|
+
const sep4 = line.indexOf(":");
|
|
29654
|
+
if (sep4 === -1) continue;
|
|
29655
|
+
const key = line.slice(0, sep4).trim();
|
|
29656
|
+
const value = line.slice(sep4 + 1).trim().replace(/^['"]|['"]$/g, "");
|
|
29259
29657
|
if (value === "") continue;
|
|
29260
29658
|
if (key === "name") out.name = value;
|
|
29261
29659
|
else if (key === "description") out.description = value;
|
|
@@ -29389,7 +29787,7 @@ function dedupeMcpServers(servers) {
|
|
|
29389
29787
|
}
|
|
29390
29788
|
function readOptional(path) {
|
|
29391
29789
|
try {
|
|
29392
|
-
return
|
|
29790
|
+
return readFileSync7(path, "utf8");
|
|
29393
29791
|
} catch {
|
|
29394
29792
|
return void 0;
|
|
29395
29793
|
}
|
|
@@ -29408,6 +29806,11 @@ function str2(value) {
|
|
|
29408
29806
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
29409
29807
|
}
|
|
29410
29808
|
|
|
29809
|
+
// ../../packages/plugin-sdk/src/data-gateway.ts
|
|
29810
|
+
function offersMaintenance(gateway, member) {
|
|
29811
|
+
return typeof gateway[member] === "function";
|
|
29812
|
+
}
|
|
29813
|
+
|
|
29411
29814
|
// ../../packages/plugin-sdk/src/events.ts
|
|
29412
29815
|
import { createHash as createHash4, randomUUID as randomUUID13 } from "crypto";
|
|
29413
29816
|
function contentHashOf(text) {
|
|
@@ -29672,7 +30075,12 @@ function createIsolatedScanner(data, opts = {}) {
|
|
|
29672
30075
|
build: (id) => ({ kind: "probe", id, rule }),
|
|
29673
30076
|
reply: (message2) => {
|
|
29674
30077
|
if (message2.kind !== "probed") return false;
|
|
29675
|
-
resolve({
|
|
30078
|
+
resolve({
|
|
30079
|
+
status: "ok",
|
|
30080
|
+
verdict: message2.verdict,
|
|
30081
|
+
worstMs: message2.worstMs,
|
|
30082
|
+
corroboratedMs: message2.corroboratedMs
|
|
30083
|
+
});
|
|
29676
30084
|
return true;
|
|
29677
30085
|
}
|
|
29678
30086
|
},
|
|
@@ -29692,6 +30100,12 @@ function createIsolatedScanner(data, opts = {}) {
|
|
|
29692
30100
|
};
|
|
29693
30101
|
}
|
|
29694
30102
|
|
|
30103
|
+
// ../../packages/plugin-sdk/src/work-clock.ts
|
|
30104
|
+
function workClockMs() {
|
|
30105
|
+
const usage = typeof process.threadCpuUsage === "function" ? process.threadCpuUsage() : process.cpuUsage();
|
|
30106
|
+
return (usage.user + usage.system) / 1e3;
|
|
30107
|
+
}
|
|
30108
|
+
|
|
29695
30109
|
// ../../packages/plugin-sdk/src/rule-quarantine.ts
|
|
29696
30110
|
var PASS_BUDGET_MS = 2e3;
|
|
29697
30111
|
var UNQUARANTINE_HINT = "clear it with `aka detections unquarantine`";
|
|
@@ -29720,6 +30134,14 @@ function warnUnmeasured(rule) {
|
|
|
29720
30134
|
false
|
|
29721
30135
|
);
|
|
29722
30136
|
}
|
|
30137
|
+
function warnUncorroborated(rule, worstMs, corroboratedMs) {
|
|
30138
|
+
warn(
|
|
30139
|
+
rule,
|
|
30140
|
+
"deferred",
|
|
30141
|
+
`its regex matcher ran past the ReDoS timing budget (${worstMs.toFixed(1)}ms) but spent only ${corroboratedMs.toFixed(1)}ms of CPU doing it, which is a busy machine rather than a slow pattern; excluded from this run and measured again next time, with nothing recorded against it.`,
|
|
30142
|
+
false
|
|
30143
|
+
);
|
|
30144
|
+
}
|
|
29723
30145
|
function warnUnmeasurable(reason, count) {
|
|
29724
30146
|
process.stderr.write(
|
|
29725
30147
|
`[aka] ${String(count)} pulled/custom-pack rule(s) could not be time-checked: ${reason}. That is a problem with this install, not with the rules \u2014 until it is fixed they are excluded from every scan on this machine. Nothing was quarantined, so reinstalling AKA brings them straight back.
|
|
@@ -29766,24 +30188,31 @@ async function filterUnsafeRules(rules, gateway, opts) {
|
|
|
29766
30188
|
warnUnmeasured(rule);
|
|
29767
30189
|
continue;
|
|
29768
30190
|
}
|
|
29769
|
-
let
|
|
30191
|
+
let verdict;
|
|
29770
30192
|
let worstMs;
|
|
30193
|
+
let corroboratedMs = 0;
|
|
29771
30194
|
if (prober) {
|
|
29772
30195
|
const outcome = await prober.probe(rule);
|
|
29773
30196
|
if (outcome.status === "unavailable") {
|
|
29774
30197
|
unmeasurable.set(outcome.reason, (unmeasurable.get(outcome.reason) ?? 0) + 1);
|
|
29775
30198
|
continue;
|
|
29776
30199
|
}
|
|
29777
|
-
|
|
30200
|
+
verdict = outcome.status === "ok" ? outcome.verdict : "over-budget";
|
|
29778
30201
|
worstMs = outcome.status === "ok" ? outcome.worstMs : outcome.elapsedMs;
|
|
30202
|
+
if (outcome.status === "ok") corroboratedMs = outcome.corroboratedMs;
|
|
29779
30203
|
} else {
|
|
29780
30204
|
try {
|
|
29781
|
-
({
|
|
30205
|
+
({ verdict, worstMs, corroboratedMs } = checkRuleTiming(rule, workClockMs));
|
|
29782
30206
|
} catch {
|
|
29783
|
-
|
|
30207
|
+
verdict = "over-budget";
|
|
29784
30208
|
worstMs = Number.POSITIVE_INFINITY;
|
|
29785
30209
|
}
|
|
29786
30210
|
}
|
|
30211
|
+
if (verdict === "uncorroborated") {
|
|
30212
|
+
warnUncorroborated(rule, worstMs, corroboratedMs);
|
|
30213
|
+
continue;
|
|
30214
|
+
}
|
|
30215
|
+
const isSafe = verdict === "safe";
|
|
29787
30216
|
let persisted = false;
|
|
29788
30217
|
try {
|
|
29789
30218
|
await gateway.setRuleProbeVerdict(key, isSafe ? "safe" : "quarantined", worstMs);
|
|
@@ -29883,6 +30312,39 @@ function createGuardedScanner(partition, gateway, opts) {
|
|
|
29883
30312
|
};
|
|
29884
30313
|
}
|
|
29885
30314
|
|
|
30315
|
+
// ../../packages/plugin-sdk/src/ignore-layers.ts
|
|
30316
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
30317
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
30318
|
+
import { join as join11 } from "path";
|
|
30319
|
+
function readIgnoreLayer(dir, filename, anchorLen) {
|
|
30320
|
+
try {
|
|
30321
|
+
return { matcher: (0, import_ignore.default)().add(readFileSync8(join11(dir, filename), "utf8")), anchorLen };
|
|
30322
|
+
} catch {
|
|
30323
|
+
return void 0;
|
|
30324
|
+
}
|
|
30325
|
+
}
|
|
30326
|
+
function relToAnchor(dirRel, anchorLen, name) {
|
|
30327
|
+
if (anchorLen === dirRel.length) return name;
|
|
30328
|
+
return `${dirRel.slice(anchorLen === 0 ? 0 : anchorLen + 1)}/${name}`;
|
|
30329
|
+
}
|
|
30330
|
+
function evaluateIgnore(layers, dirRel, name, isDir) {
|
|
30331
|
+
const suffix = isDir ? "/" : "";
|
|
30332
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
30333
|
+
const layer = layers[i];
|
|
30334
|
+
if (layer === void 0) continue;
|
|
30335
|
+
const verdict = layer.matcher.test(relToAnchor(dirRel, layer.anchorLen, name) + suffix);
|
|
30336
|
+
if (verdict.ignored) return "ignored";
|
|
30337
|
+
if (verdict.unignored) return "unignored";
|
|
30338
|
+
}
|
|
30339
|
+
return "unmatched";
|
|
30340
|
+
}
|
|
30341
|
+
function childRel(dirRel, name) {
|
|
30342
|
+
return dirRel === "" ? name : `${dirRel}/${name}`;
|
|
30343
|
+
}
|
|
30344
|
+
function withLayer(layers, layer) {
|
|
30345
|
+
return layer ? [...layers, layer] : layers;
|
|
30346
|
+
}
|
|
30347
|
+
|
|
29886
30348
|
// ../../packages/plugin-sdk/src/inventory-resolver.ts
|
|
29887
30349
|
import { arch, hostname as hostname4, platform, release } from "os";
|
|
29888
30350
|
function resolveInventoryContext(input) {
|
|
@@ -29913,21 +30375,21 @@ function resolveInventoryContext(input) {
|
|
|
29913
30375
|
}
|
|
29914
30376
|
|
|
29915
30377
|
// ../../packages/plugin-sdk/src/nudge.ts
|
|
29916
|
-
import { mkdirSync as
|
|
29917
|
-
import { join as
|
|
30378
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
30379
|
+
import { join as join12 } from "path";
|
|
29918
30380
|
var SESSION_START_MARKER = "session-start-last";
|
|
29919
30381
|
function claimSessionStart(dataDir2, sessionId) {
|
|
29920
30382
|
return claimOncePerSession(dataDir2, SESSION_START_MARKER, sessionId);
|
|
29921
30383
|
}
|
|
29922
30384
|
function claimOncePerSession(dataDir2, marker, sessionId) {
|
|
29923
30385
|
if (!sessionId) return true;
|
|
29924
|
-
const path =
|
|
30386
|
+
const path = join12(dataDir2, marker);
|
|
29925
30387
|
try {
|
|
29926
|
-
if (
|
|
30388
|
+
if (readFileSync9(path, "utf8") === sessionId) return false;
|
|
29927
30389
|
} catch {
|
|
29928
30390
|
}
|
|
29929
30391
|
try {
|
|
29930
|
-
|
|
30392
|
+
mkdirSync2(dataDir2, { recursive: true, mode: DATA_DIR_MODE });
|
|
29931
30393
|
writeFileSync5(path, sessionId, { mode: DATA_FILE_MODE });
|
|
29932
30394
|
} catch {
|
|
29933
30395
|
}
|
|
@@ -29939,9 +30401,8 @@ import { readdirSync as readdirSync3, realpathSync as realpathSync2 } from "fs";
|
|
|
29939
30401
|
import { basename as basename5, dirname as dirname3, sep as sep3 } from "path";
|
|
29940
30402
|
|
|
29941
30403
|
// ../../packages/plugin-sdk/src/project-files.ts
|
|
29942
|
-
|
|
29943
|
-
import {
|
|
29944
|
-
import { basename as basename6, join as join12, relative, sep as sep4 } from "path";
|
|
30404
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4 } from "fs";
|
|
30405
|
+
import { basename as basename6, join as join13 } from "path";
|
|
29945
30406
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
29946
30407
|
".git",
|
|
29947
30408
|
"node_modules",
|
|
@@ -29959,23 +30420,10 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
29959
30420
|
".cache"
|
|
29960
30421
|
]);
|
|
29961
30422
|
var MAX_FILES = 2e4;
|
|
29962
|
-
|
|
29963
|
-
|
|
29964
|
-
|
|
29965
|
-
|
|
29966
|
-
} catch {
|
|
29967
|
-
return void 0;
|
|
29968
|
-
}
|
|
29969
|
-
}
|
|
29970
|
-
function isIgnored(layers, absPath, isDir) {
|
|
29971
|
-
let ignored = false;
|
|
29972
|
-
for (const layer of layers) {
|
|
29973
|
-
const rel = relative(layer.base, absPath).split(sep4).join("/") + (isDir ? "/" : "");
|
|
29974
|
-
const verdict = layer.matcher.test(rel);
|
|
29975
|
-
if (verdict.ignored) ignored = true;
|
|
29976
|
-
else if (verdict.unignored) ignored = false;
|
|
29977
|
-
}
|
|
29978
|
-
return ignored;
|
|
30423
|
+
var PROJECT_WALK_BOUNDS = { maxDepth: 64, budgetMs: 4e3 };
|
|
30424
|
+
var DEADLINE_CHECK_INTERVAL = 512;
|
|
30425
|
+
function isIgnored(layers, dirRel, name, isDir) {
|
|
30426
|
+
return evaluateIgnore(layers, dirRel, name, isDir) === "ignored";
|
|
29979
30427
|
}
|
|
29980
30428
|
var GENERATED_FILES = /* @__PURE__ */ new Set([
|
|
29981
30429
|
"pnpm-lock.yaml",
|
|
@@ -30026,9 +30474,11 @@ function classifyOrigin(relPath, name) {
|
|
|
30026
30474
|
}
|
|
30027
30475
|
return "source";
|
|
30028
30476
|
}
|
|
30029
|
-
function resolveProjectFiles(cwd) {
|
|
30477
|
+
function resolveProjectFiles(cwd, opts = {}) {
|
|
30478
|
+
const bounds = opts.bounds ?? PROJECT_WALK_BOUNDS;
|
|
30479
|
+
const now = opts.now ?? (() => performance.now());
|
|
30030
30480
|
try {
|
|
30031
|
-
let visit2 = function(dir, layers) {
|
|
30481
|
+
let visit2 = function(dir, dirRel, layers, depth) {
|
|
30032
30482
|
let dirents;
|
|
30033
30483
|
try {
|
|
30034
30484
|
dirents = readdirSync4(dir, { withFileTypes: true, encoding: "utf8" });
|
|
@@ -30036,21 +30486,33 @@ function resolveProjectFiles(cwd) {
|
|
|
30036
30486
|
walk.lostSubtree = true;
|
|
30037
30487
|
return false;
|
|
30038
30488
|
}
|
|
30039
|
-
|
|
30040
|
-
|
|
30489
|
+
if (now() > deadline) {
|
|
30490
|
+
walk.omitted = true;
|
|
30491
|
+
return true;
|
|
30492
|
+
}
|
|
30493
|
+
const dirLayers = withLayer(layers, readIgnoreLayer(dir, ".gitignore", dirRel.length));
|
|
30041
30494
|
for (const entry of dirents) {
|
|
30042
|
-
|
|
30495
|
+
walk.seen++;
|
|
30496
|
+
if (walk.seen % DEADLINE_CHECK_INTERVAL === 0 && now() > deadline) {
|
|
30497
|
+
walk.omitted = true;
|
|
30498
|
+
return true;
|
|
30499
|
+
}
|
|
30043
30500
|
if (entry.isDirectory()) {
|
|
30044
|
-
if (SKIP_DIRS.has(entry.name) || isIgnored(dirLayers,
|
|
30045
|
-
|
|
30046
|
-
if (
|
|
30501
|
+
if (SKIP_DIRS.has(entry.name) || isIgnored(dirLayers, dirRel, entry.name, true)) continue;
|
|
30502
|
+
const fullPath = join13(dir, entry.name);
|
|
30503
|
+
if (existsSync8(join13(fullPath, ".git"))) continue;
|
|
30504
|
+
if (depth >= bounds.maxDepth) {
|
|
30505
|
+
walk.omitted = true;
|
|
30506
|
+
continue;
|
|
30507
|
+
}
|
|
30508
|
+
if (visit2(fullPath, childRel(dirRel, entry.name), dirLayers, depth + 1)) return true;
|
|
30047
30509
|
continue;
|
|
30048
30510
|
}
|
|
30049
30511
|
if (!entry.isFile()) continue;
|
|
30050
30512
|
if (entry.name === ".git") continue;
|
|
30051
|
-
if (isIgnored(dirLayers,
|
|
30513
|
+
if (isIgnored(dirLayers, dirRel, entry.name, false)) continue;
|
|
30052
30514
|
if (files.length >= MAX_FILES) return true;
|
|
30053
|
-
const relPath =
|
|
30515
|
+
const relPath = childRel(dirRel, entry.name);
|
|
30054
30516
|
files.push({
|
|
30055
30517
|
path: relPath,
|
|
30056
30518
|
name: basename6(entry.name),
|
|
@@ -30066,8 +30528,9 @@ function resolveProjectFiles(cwd) {
|
|
|
30066
30528
|
const root = worktree;
|
|
30067
30529
|
const isLinkedCheckout = resolveHeadRoot(cwd) !== worktree;
|
|
30068
30530
|
const files = [];
|
|
30069
|
-
const walk = { lostSubtree: false };
|
|
30070
|
-
const
|
|
30531
|
+
const walk = { lostSubtree: false, omitted: false, seen: 0 };
|
|
30532
|
+
const deadline = now() + bounds.budgetMs;
|
|
30533
|
+
const truncated = visit2(root, "", [], 0) || walk.lostSubtree || walk.omitted || isLinkedCheckout;
|
|
30071
30534
|
if (files.length === 0) return void 0;
|
|
30072
30535
|
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
30073
30536
|
return { files, truncated, scannedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -30133,6 +30596,7 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
30133
30596
|
let initialized = false;
|
|
30134
30597
|
const ruleActionIndex = /* @__PURE__ */ new Map();
|
|
30135
30598
|
const categoryActionIndex = /* @__PURE__ */ new Map();
|
|
30599
|
+
let reversibleRuleIndex = /* @__PURE__ */ new Set();
|
|
30136
30600
|
async function ensureInitialized() {
|
|
30137
30601
|
if (initialized) return;
|
|
30138
30602
|
const bundle = await gateway.getPolicyBundle();
|
|
@@ -30145,6 +30609,7 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
30145
30609
|
categoryActionIndex.set(p.target.category, p.action);
|
|
30146
30610
|
}
|
|
30147
30611
|
}
|
|
30612
|
+
reversibleRuleIndex = new Set(bundle.reversibleRuleIds ?? []);
|
|
30148
30613
|
const bundledProbeKeys = new Set(
|
|
30149
30614
|
getLoadedRules().map(ruleProbeKey).filter((key) => key !== void 0)
|
|
30150
30615
|
);
|
|
@@ -30223,11 +30688,13 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
30223
30688
|
if (worst === "block") return { action: "block", text: null, findings };
|
|
30224
30689
|
if (worst === "redact") {
|
|
30225
30690
|
const redactFindings = findings.filter((f) => actionFor(f) === "redact");
|
|
30691
|
+
const reversibleFindings = redactFindings.filter((f) => reversibleRuleIndex.has(f.ruleId));
|
|
30226
30692
|
return {
|
|
30227
30693
|
action: "redact",
|
|
30228
30694
|
text: redact(text, redactFindings),
|
|
30229
30695
|
findings,
|
|
30230
|
-
enforcedFindings: redactFindings
|
|
30696
|
+
enforcedFindings: redactFindings,
|
|
30697
|
+
reversibleFindings
|
|
30231
30698
|
};
|
|
30232
30699
|
}
|
|
30233
30700
|
return { action: worst, text, findings };
|
|
@@ -30441,8 +30908,8 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
30441
30908
|
var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
30442
30909
|
|
|
30443
30910
|
// ../../packages/plugin-sdk/src/throttle.ts
|
|
30444
|
-
import { mkdirSync as
|
|
30445
|
-
import { join as
|
|
30911
|
+
import { mkdirSync as mkdirSync3, statSync as statSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
30912
|
+
import { join as join14 } from "path";
|
|
30446
30913
|
|
|
30447
30914
|
// ../../packages/plugin-runtime/src/standalone-gateway.ts
|
|
30448
30915
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
@@ -30458,6 +30925,8 @@ var StandaloneDataGateway = class {
|
|
|
30458
30925
|
db;
|
|
30459
30926
|
// Kept for the fingerprint key lookup (exception.key lives beside the store).
|
|
30460
30927
|
dataDir;
|
|
30928
|
+
// One notice per gateway — see warnRulesetDiscarded.
|
|
30929
|
+
warnedRulesetDiscarded = false;
|
|
30461
30930
|
constructor(dataDir2, detections = [], meta3) {
|
|
30462
30931
|
this.db = openLocalDatabase(dataDir2);
|
|
30463
30932
|
this.dataDir = dataDir2;
|
|
@@ -30577,28 +31046,69 @@ var StandaloneDataGateway = class {
|
|
|
30577
31046
|
// - ANY invalid rule among enabled packs (all-invalid, partial corruption,
|
|
30578
31047
|
// or a single malformed entry) → undefined → bundled fallback. Serving a
|
|
30579
31048
|
// reduced "complete" set would silently drop exactly the corrupted rules
|
|
30580
|
-
// with no fallback
|
|
30581
|
-
// never loses coverage
|
|
30582
|
-
//
|
|
30583
|
-
//
|
|
31049
|
+
// with no fallback. The bundled packs are a superset of AKA's OWN packs,
|
|
31050
|
+
// so falling back never loses coverage there — but they contain no
|
|
31051
|
+
// pulled or custom pack, so for those this trades a partial ruleset for
|
|
31052
|
+
// none of them plus the loss of every pack's per-detection enforcement
|
|
31053
|
+
// action. That is deliberate (a store this machine cannot fully validate
|
|
31054
|
+
// is not authoritative), and it is why the cost of REJECTING a rule
|
|
31055
|
+
// matters: `Rule` is strict, so one unrecognized key in one custom rule
|
|
31056
|
+
// reaches this branch, not just a genuinely malformed or foreign store.
|
|
31057
|
+
// `installed-packs.test.ts` pins that per-rule counting;
|
|
30584
31058
|
// - enabled packs that produce ZERO rules with no invalids (e.g. every
|
|
30585
31059
|
// enabled pack's rules_json is `[]`) → undefined → bundled fallback: an
|
|
30586
31060
|
// enabled pack contributing nothing is untrustworthy, not a real
|
|
30587
31061
|
// "detect nothing" (that is expressed by disabling packs, handled above);
|
|
30588
31062
|
// - otherwise → the enabled packs' validated rules, marked complete.
|
|
31063
|
+
/**
|
|
31064
|
+
* The discard above is the one ruleset decision this gateway reaches on its
|
|
31065
|
+
* own, and it is the most expensive one here: ONE rejected entry costs the
|
|
31066
|
+
* user every custom rule and every per-detection enforcement action, replaced
|
|
31067
|
+
* by bundled packs that contain neither. Nothing else reports it — a hook is a
|
|
31068
|
+
* short-lived process whose stderr is the only channel it has — so name what
|
|
31069
|
+
* was rejected and where the rest of the list lives.
|
|
31070
|
+
*
|
|
31071
|
+
* Unlike a quarantine verdict this caches nothing: the rejection is re-derived
|
|
31072
|
+
* from the store on every run, so the recovery is to fix or reinstall the pack,
|
|
31073
|
+
* and no line here may offer a command that clears a stored verdict.
|
|
31074
|
+
*
|
|
31075
|
+
* Written at most once per gateway — a second getPolicyBundle() in the same
|
|
31076
|
+
* process would re-report the same finding.
|
|
31077
|
+
*/
|
|
31078
|
+
warnRulesetDiscarded(snapshot) {
|
|
31079
|
+
if (this.warnedRulesetDiscarded) return;
|
|
31080
|
+
this.warnedRulesetDiscarded = true;
|
|
31081
|
+
const listed = snapshot.rejectedRules.map((r) => `${r.pack}${r.ruleId === null ? "" : ` "${r.ruleId}"`} (${r.reason})`).join(", ");
|
|
31082
|
+
const undisclosed = snapshot.invalidRules - snapshot.rejectedRules.length;
|
|
31083
|
+
const more = undisclosed > 0 ? `, and ${String(undisclosed)} more` : "";
|
|
31084
|
+
process.stderr.write(
|
|
31085
|
+
`[aka] installed ruleset not used: ${String(snapshot.invalidRules)} rule(s) under enabled packs failed validation, so scanning fell back to the bundled packs and no custom rule or per-detection action is enforced \u2014 rejected: ${listed}${more}; review them with \`aka detections\`
|
|
31086
|
+
`
|
|
31087
|
+
);
|
|
31088
|
+
}
|
|
30589
31089
|
installedScanRules() {
|
|
30590
31090
|
try {
|
|
30591
31091
|
const snapshot = this.db.installedPacks.installedRuleset();
|
|
30592
31092
|
if (snapshot.installedPacks === 0) return void 0;
|
|
30593
31093
|
if (snapshot.enabledPacks === 0) {
|
|
30594
|
-
return {
|
|
31094
|
+
return {
|
|
31095
|
+
rules: [],
|
|
31096
|
+
ruleActions: /* @__PURE__ */ new Map(),
|
|
31097
|
+
ruleVersions: /* @__PURE__ */ new Map(),
|
|
31098
|
+
reversibleRules: /* @__PURE__ */ new Set(),
|
|
31099
|
+
complete: true
|
|
31100
|
+
};
|
|
31101
|
+
}
|
|
31102
|
+
if (snapshot.invalidRules > 0) {
|
|
31103
|
+
this.warnRulesetDiscarded(snapshot);
|
|
31104
|
+
return void 0;
|
|
30595
31105
|
}
|
|
30596
|
-
if (snapshot.invalidRules > 0) return void 0;
|
|
30597
31106
|
if (snapshot.rules.length === 0) return void 0;
|
|
30598
31107
|
return {
|
|
30599
31108
|
rules: snapshot.rules,
|
|
30600
31109
|
ruleActions: snapshot.ruleActions,
|
|
30601
31110
|
ruleVersions: snapshot.ruleVersions,
|
|
31111
|
+
reversibleRules: snapshot.reversibleRules,
|
|
30602
31112
|
complete: true
|
|
30603
31113
|
};
|
|
30604
31114
|
} catch {
|
|
@@ -30626,6 +31136,11 @@ var StandaloneDataGateway = class {
|
|
|
30626
31136
|
return {
|
|
30627
31137
|
version: "local",
|
|
30628
31138
|
policies: [...policies, ...rulePolicies],
|
|
31139
|
+
// The reversibility half of each pack's assignment. Emitted only under the
|
|
31140
|
+
// authoritative installed snapshot, exactly like rulePolicies above: the
|
|
31141
|
+
// bundled-packs fallback carries no per-pack assignment, so it carries no
|
|
31142
|
+
// reversibility either and every redaction there stays one-way.
|
|
31143
|
+
reversibleRuleIds: installed ? [...installed.reversibleRules] : [],
|
|
30629
31144
|
rules: installed ? installed.rules : [],
|
|
30630
31145
|
...installed ? { rulesComplete: true } : {},
|
|
30631
31146
|
...installed ? { ruleVersions: Object.fromEntries(installed.ruleVersions) } : {},
|
|
@@ -30644,29 +31159,32 @@ var StandaloneDataGateway = class {
|
|
|
30644
31159
|
return this.db.exceptions.recordBlocked(entry);
|
|
30645
31160
|
}
|
|
30646
31161
|
// Retention sweep over TERMINAL exception rows (revoked / expired / budget
|
|
30647
|
-
// exhausted) —
|
|
30648
|
-
//
|
|
31162
|
+
// exhausted) — local-store maintenance, invoked from SessionStart through the
|
|
31163
|
+
// LocalStoreMaintenance capability rather than the DataGateway port. Active
|
|
31164
|
+
// grants are never touched.
|
|
30649
31165
|
sweepTerminalExceptions(retentionMs) {
|
|
30650
31166
|
return this.db.exceptions.sweepTerminal(retentionMs);
|
|
30651
31167
|
}
|
|
30652
|
-
// The warn-era enforcement cap
|
|
30653
|
-
//
|
|
30654
|
-
// of block/redact rows capped to
|
|
30655
|
-
// already-capped one).
|
|
31168
|
+
// The warn-era enforcement cap — local-store maintenance, invoked from
|
|
31169
|
+
// SessionStart through the LocalStoreMaintenance capability rather than
|
|
31170
|
+
// the DataGateway port. Returns the number of block/redact rows capped to
|
|
31171
|
+
// warn (0 for a redact-policy store or an already-capped one).
|
|
30656
31172
|
capWarnEraEnforcement(policyMode) {
|
|
30657
31173
|
const { capped } = capWarnEraEnforcementOnce(this.db, policyMode, this.dataDir);
|
|
30658
31174
|
return { capped };
|
|
30659
31175
|
}
|
|
30660
31176
|
// One project-file scan → the local project_file tree (one transaction inside
|
|
30661
|
-
// the LocalDatabase, fail-open there). Like the sweep above, this is
|
|
30662
|
-
//
|
|
31177
|
+
// the LocalDatabase, fail-open there). Like the sweep above, this is reached
|
|
31178
|
+
// through the LocalStoreMaintenance capability rather than the DataGateway
|
|
31179
|
+
// port: the file tree is a local-store read model.
|
|
30663
31180
|
recordProjectFiles(projectId, scan2) {
|
|
30664
31181
|
this.db.recordProjectFiles(projectId, scan2);
|
|
30665
31182
|
return Promise.resolve();
|
|
30666
31183
|
}
|
|
30667
31184
|
// Fold ghost source_project rows minted by the pre-worktree-fix resolver
|
|
30668
|
-
// (checkout-path identities) into the repo's canonical row.
|
|
30669
|
-
//
|
|
31185
|
+
// (checkout-path identities) into the repo's canonical row. Local-store
|
|
31186
|
+
// maintenance, invoked from SessionStart through the LocalStoreMaintenance
|
|
31187
|
+
// capability. Fail-open in the store.
|
|
30670
31188
|
reconcileWorktreeProjects(canonicalId, headRoot, worktreeRoot) {
|
|
30671
31189
|
this.db.reconcileWorktreeProjects(canonicalId, headRoot, worktreeRoot);
|
|
30672
31190
|
return Promise.resolve();
|
|
@@ -30677,10 +31195,10 @@ var StandaloneDataGateway = class {
|
|
|
30677
31195
|
* executing the plugin generation they started with (Claude Code caches
|
|
30678
31196
|
* plugin versions), and the write gate makes their installed-pack writes
|
|
30679
31197
|
* silent no-ops — this is the one-line nudge telling the user WHY, and that
|
|
30680
|
-
* a restart picks the newer plugin up.
|
|
30681
|
-
* SessionStart
|
|
30682
|
-
* null (no notice), and
|
|
30683
|
-
* never fire it.
|
|
31198
|
+
* a restart picks the newer plugin up. Local-store maintenance, invoked
|
|
31199
|
+
* from SessionStart through the LocalStoreMaintenance capability rather
|
|
31200
|
+
* than the DataGateway port. Fail-open: any error → null (no notice), and
|
|
31201
|
+
* unparseable versions compare equal so garbage can never fire it.
|
|
30684
31202
|
*/
|
|
30685
31203
|
staleBinaryNotice(currentVersion) {
|
|
30686
31204
|
try {
|
|
@@ -30758,7 +31276,8 @@ var StandaloneDataGateway = class {
|
|
|
30758
31276
|
|
|
30759
31277
|
// ../../packages/plugin-runtime/src/resolve.ts
|
|
30760
31278
|
var standaloneGatewayFactory = (config2, meta3) => new StandaloneDataGateway(config2.dataDir, bundledDetections(), meta3);
|
|
30761
|
-
|
|
31279
|
+
var defaultGatewayFactory = standaloneGatewayFactory;
|
|
31280
|
+
function resolveDataGateway(config2, meta3, gatewayFactory = defaultGatewayFactory) {
|
|
30762
31281
|
return gatewayFactory(config2, meta3);
|
|
30763
31282
|
}
|
|
30764
31283
|
|
|
@@ -30804,11 +31323,13 @@ async function handleSessionStart(input, config2 = loadConfig()) {
|
|
|
30804
31323
|
buildSessionRoot(input.sessionId, input, ctx, resolved, config2.provider, branch)
|
|
30805
31324
|
);
|
|
30806
31325
|
await recordConfigInventory(gateway, input.sessionId, input.cwd, input.homeDir);
|
|
30807
|
-
if (gateway
|
|
31326
|
+
if (offersMaintenance(gateway, "sweepTerminalExceptions")) {
|
|
30808
31327
|
try {
|
|
30809
31328
|
await gateway.sweepTerminalExceptions(EXCEPTION_RETENTION_MS);
|
|
30810
31329
|
} catch {
|
|
30811
31330
|
}
|
|
31331
|
+
}
|
|
31332
|
+
if (offersMaintenance(gateway, "capWarnEraEnforcement")) {
|
|
30812
31333
|
try {
|
|
30813
31334
|
const { capped } = gateway.capWarnEraEnforcement(config2.settings.policy);
|
|
30814
31335
|
if (capped > 0) {
|
|
@@ -30818,6 +31339,8 @@ async function handleSessionStart(input, config2 = loadConfig()) {
|
|
|
30818
31339
|
}
|
|
30819
31340
|
} catch {
|
|
30820
31341
|
}
|
|
31342
|
+
}
|
|
31343
|
+
if (offersMaintenance(gateway, "recordProjectFiles")) {
|
|
30821
31344
|
try {
|
|
30822
31345
|
if (resolved.sourceProjectId) {
|
|
30823
31346
|
const filesScan = resolveProjectFiles(input.cwd);
|
|
@@ -30825,6 +31348,8 @@ async function handleSessionStart(input, config2 = loadConfig()) {
|
|
|
30825
31348
|
}
|
|
30826
31349
|
} catch {
|
|
30827
31350
|
}
|
|
31351
|
+
}
|
|
31352
|
+
if (offersMaintenance(gateway, "reconcileWorktreeProjects")) {
|
|
30828
31353
|
try {
|
|
30829
31354
|
const headRoot = resolveHeadRoot(input.cwd);
|
|
30830
31355
|
const worktreeRoot = resolveWorktreeRoot(input.cwd);
|
|
@@ -30837,9 +31362,9 @@ async function handleSessionStart(input, config2 = loadConfig()) {
|
|
|
30837
31362
|
}
|
|
30838
31363
|
} catch {
|
|
30839
31364
|
}
|
|
30840
|
-
|
|
30841
|
-
|
|
30842
|
-
}
|
|
31365
|
+
}
|
|
31366
|
+
if (input.harnessVersion !== void 0 && offersMaintenance(gateway, "staleBinaryNotice")) {
|
|
31367
|
+
return { staleBinaryNotice: gateway.staleBinaryNotice(input.harnessVersion) };
|
|
30843
31368
|
}
|
|
30844
31369
|
} finally {
|
|
30845
31370
|
await gateway.close();
|
|
@@ -30912,8 +31437,9 @@ function buildSessionRoot(sessionId, input, ctx, resolved, provider, branch) {
|
|
|
30912
31437
|
}
|
|
30913
31438
|
|
|
30914
31439
|
// src/native-host/protocol.ts
|
|
31440
|
+
var WEB_SOURCE_TOOLS = [SOURCE_TOOL.ChatGpt, SOURCE_TOOL.ClaudeAi];
|
|
30915
31441
|
function isWebSourceTool(value) {
|
|
30916
|
-
return value
|
|
31442
|
+
return WEB_SOURCE_TOOLS.includes(value);
|
|
30917
31443
|
}
|
|
30918
31444
|
function isEventKind(value) {
|
|
30919
31445
|
return typeof value === "string" && EventKind.options.includes(value);
|
|
@@ -30970,8 +31496,8 @@ function writeMessage(stdout, message2) {
|
|
|
30970
31496
|
|
|
30971
31497
|
// src/native-host/host.ts
|
|
30972
31498
|
var WEB_TOOL_TO_SOURCE = {
|
|
30973
|
-
|
|
30974
|
-
|
|
31499
|
+
[SOURCE_TOOL.ChatGpt]: SOURCE_TOOL.ChatGpt,
|
|
31500
|
+
[SOURCE_TOOL.ClaudeAi]: SOURCE_TOOL.ClaudeAi
|
|
30975
31501
|
};
|
|
30976
31502
|
function resolveWebProvider(tool) {
|
|
30977
31503
|
return () => tool === "chatgpt" ? { provider: "openai" } : { provider: "anthropic" };
|
|
@@ -30995,7 +31521,12 @@ async function handleRequest(request, configForTool = defaultConfigForTool) {
|
|
|
30995
31521
|
{
|
|
30996
31522
|
sessionId: request.sessionId,
|
|
30997
31523
|
cwd: homedir3(),
|
|
30998
|
-
|
|
31524
|
+
// Mapped, exactly as the capture branch below maps it. The two ids are
|
|
31525
|
+
// identical today, so passing `request.tool` raw here worked — but the
|
|
31526
|
+
// session root's `harness` is derived from THIS value and its captures'
|
|
31527
|
+
// `source_tool` from that one, so the first web provider whose web id
|
|
31528
|
+
// differs from its wire id would split a session from its own events.
|
|
31529
|
+
tool: WEB_TOOL_TO_SOURCE[request.tool],
|
|
30999
31530
|
harnessInterface: request.hostname
|
|
31000
31531
|
},
|
|
31001
31532
|
config2
|