failproofai 1.0.4-beta.6 → 1.0.4-beta.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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +15 -4
- package/.next/standalone/.next/server/app/settings/page.js +2 -2
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +10 -10
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-4ja6q._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cr3xu._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04px77e._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egr5s1._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0i0l1di._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0r3c1_0._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ui5ur8._.js → [root-of-the-server]__12hbpha._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17xnxlx._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ckpmkk._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_04ng_6x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_07t3jol._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_02b3i98._.js → _0a0zlpr._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +33 -22
- package/.next/standalone/.next/static/chunks/{20xkiqzvfkuvm.js → 083fk73jtv9a0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1xgq22tri86an.js → 0divvxng208xo.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1gn08w2pgqh09.js → 0f1pznnc7zlub.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3jxd133cw2vm3.js → 0ntdfr2552x-h.js} +1 -1
- package/.next/standalone/.next/static/chunks/{32m2ryfankf_2.js → 0t6ea7d3bkmdv.js} +1 -1
- package/.next/standalone/.next/static/chunks/{07c6l1lq5_69b.js → 15uon66hpwbgg.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2a84ug32tzik2.js → 1csubx9gwhsf6.js} +1 -1
- package/.next/standalone/.next/static/chunks/27du9n7ssja7l.js +1 -0
- package/.next/standalone/.next/static/chunks/2h_pcb1y8_jde.js +1 -0
- package/.next/standalone/.next/static/chunks/{12bsgz8czvcnn.js → 2pwfrn6_mw-1u.js} +1 -1
- package/.next/standalone/app/actions/get-scheduled-audit.ts +5 -0
- package/.next/standalone/app/actions/update-scheduled-audit.ts +14 -1
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +1 -1
- package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
- package/.next/standalone/app/audit/_components/leak-section.tsx +1 -1
- package/.next/standalone/app/settings/settings-client.tsx +42 -11
- package/.next/standalone/package.json +9 -9
- package/.next/standalone/server.js +1 -1
- package/dist/cli.mjs +69 -68
- package/dist/worker.mjs +3 -3
- package/package.json +9 -9
- package/src/audit/index.ts +1 -1
- package/src/audit/leak-record.ts +24 -12
- package/src/audit/macos-notifier.ts +54 -66
- package/src/hooks/builtin-policies.ts +2 -2
- package/src/hooks/configure-wizard.ts +8 -1
- package/src/hooks/uninstall-cli.ts +3 -3
- package/.next/standalone/.next/static/chunks/3ioub_lpen-sq.js +0 -1
- package/.next/standalone/.next/static/chunks/44ncu88eq6z71.js +0 -1
- /package/.next/standalone/.next/static/{aeM365dNTtUZOZvNkX8ba → YiPsVpjrc-pEQoN7XvhZ0}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{aeM365dNTtUZOZvNkX8ba → YiPsVpjrc-pEQoN7XvhZ0}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{aeM365dNTtUZOZvNkX8ba → YiPsVpjrc-pEQoN7XvhZ0}/_ssgManifest.js +0 -0
|
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
|
|
|
9
9
|
const hostname = process.env.HOSTNAME || '0.0.0.0'
|
|
10
10
|
|
|
11
11
|
let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
|
|
12
|
-
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.4-beta.
|
|
12
|
+
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.4-beta.7"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"instrumentationClientInject":[],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","enablePrerenderSourceMaps":true,"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":true,"coldCacheBadge":false,"devValidationWorker":true,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"dynamicOnHover":false,"useOffline":false,"varyParams":true,"optimisticRouting":true,"instrumentationClientRouterTransitionEvents":false,"prefetchInlining":{"maxSize":2048,"maxBundleSize":10240},"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptOperationCache":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"devMemoryThresholdRestart":true,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"requestInsights":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"useTypeScriptCli":true,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":true,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"serverComponentsHmrCancellation":false,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":true,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","turbopackMemoryEvictionMode":"auto","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"useCacheTimeout":54,"instantInsights":{"validationLevel":"warning"},"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"repoRoot":"/home/runner/work/failproofai/failproofai","distDirRoot":".next"}
|
|
13
13
|
|
|
14
14
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
|
|
15
15
|
|
package/dist/cli.mjs
CHANGED
|
@@ -29,7 +29,7 @@ var __esm = (fn, res, err) => () => {
|
|
|
29
29
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
30
|
|
|
31
31
|
// package.json
|
|
32
|
-
var version2 = "1.0.4-beta.
|
|
32
|
+
var version2 = "1.0.4-beta.7", package_default;
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "failproofai",
|
|
@@ -154,16 +154,16 @@ var init_package = __esm(() => {
|
|
|
154
154
|
browserslist: "4.28.8"
|
|
155
155
|
},
|
|
156
156
|
optionalDependencies: {
|
|
157
|
-
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.
|
|
158
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.
|
|
159
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.
|
|
160
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.
|
|
157
|
+
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.7",
|
|
158
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.7",
|
|
159
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.7",
|
|
160
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.7"
|
|
161
161
|
},
|
|
162
162
|
failproofaidBinaries: {
|
|
163
|
-
"linux-x64": "
|
|
164
|
-
"linux-arm64": "
|
|
165
|
-
"darwin-x64": "
|
|
166
|
-
"darwin-arm64": "
|
|
163
|
+
"linux-x64": "e59735a8f94cd8ac697b2bd67aafdd8d76a8394d53db229876980cc13a18f07e",
|
|
164
|
+
"linux-arm64": "b9ce50dd2f79b55f4f7112add265a776a4a6d002c2a56f971e666fbb796f3906",
|
|
165
|
+
"darwin-x64": "b46efc8ec33945a5cc26b7bb288fb87cea65b5983bd83094b5e607d53b8eda4c",
|
|
166
|
+
"darwin-arm64": "a8cc6112cee5ca8a7d517900e9ce32118855135980f22979fa0ff7aa6f68d954"
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
});
|
|
@@ -3874,8 +3874,8 @@ var init_builtin_policies = __esm(() => {
|
|
|
3874
3874
|
[/sk-ant-oat01-[A-Za-z0-9\-_]{20,}/, "Anthropic OAuth token"],
|
|
3875
3875
|
[/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"],
|
|
3876
3876
|
[/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"],
|
|
3877
|
-
[/sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
|
|
3878
|
-
[/sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
|
|
3877
|
+
[/(?<!\w)sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
|
|
3878
|
+
[/(?<!\w)sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
|
|
3879
3879
|
[/sk-or-v1-[A-Za-z0-9\-_]{20,}/, "OpenRouter API key"],
|
|
3880
3880
|
[/sk-[A-Za-z0-9]{20,}/, "OpenAI-compatible key (issuer unknown)"],
|
|
3881
3881
|
[/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"],
|
|
@@ -25190,12 +25190,15 @@ var init_leak_fingerprint = __esm(() => {
|
|
|
25190
25190
|
|
|
25191
25191
|
// src/audit/macos-notifier.ts
|
|
25192
25192
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
25193
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync17, readdirSync as readdirSync16, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
|
|
25193
|
+
import { chmodSync as chmodSync5, existsSync as existsSync26, mkdirSync as mkdirSync17, readdirSync as readdirSync16, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
|
|
25194
25194
|
import { homedir as homedir24 } from "node:os";
|
|
25195
25195
|
import { resolve as resolve22 } from "node:path";
|
|
25196
25196
|
function macNotifierAppPath(home) {
|
|
25197
25197
|
return resolve22(runDir(home), "..", "bin", "FailproofAI Notifier.app");
|
|
25198
25198
|
}
|
|
25199
|
+
function macNotifierRunnerPath(home) {
|
|
25200
|
+
return resolve22(runDir(home), "..", "bin", "failproofai-notifier.zsh");
|
|
25201
|
+
}
|
|
25199
25202
|
function macNotifierPlistPath() {
|
|
25200
25203
|
return resolve22(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
|
|
25201
25204
|
}
|
|
@@ -25204,35 +25207,28 @@ function escapeXml2(s) {
|
|
|
25204
25207
|
}
|
|
25205
25208
|
function notifierScript(home) {
|
|
25206
25209
|
const dir = macNotifyDir(home);
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
|
|
25210
|
-
|
|
25211
|
-
|
|
25212
|
-
|
|
25213
|
-
|
|
25214
|
-
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
|
|
25219
|
-
|
|
25220
|
-
|
|
25221
|
-
|
|
25222
|
-
|
|
25223
|
-
repeat with i from 2 to (count of lines_)
|
|
25224
|
-
if noteBody is not "" then set noteBody to noteBody & " "
|
|
25225
|
-
set noteBody to noteBody & (item i of lines_)
|
|
25226
|
-
end repeat
|
|
25227
|
-
display notification noteBody with title noteTitle
|
|
25228
|
-
end if
|
|
25229
|
-
end try
|
|
25230
|
-
end if
|
|
25231
|
-
end repeat
|
|
25210
|
+
const quotedDir = `'${dir.replace(/'/g, `'\\''`)}'`;
|
|
25211
|
+
return `#!/bin/zsh
|
|
25212
|
+
set -u
|
|
25213
|
+
setopt NULL_GLOB
|
|
25214
|
+
|
|
25215
|
+
drop_dir=${quotedDir}
|
|
25216
|
+
|
|
25217
|
+
for entry_path in "$drop_dir"/*; do
|
|
25218
|
+
[ -f "$entry_path" ] || continue
|
|
25219
|
+
note_title=$(/usr/bin/sed -n '1p' "$entry_path")
|
|
25220
|
+
note_body=$(/usr/bin/sed -n '2,$p' "$entry_path" | /usr/bin/tr '\\n' ' ')
|
|
25221
|
+
/bin/rm -f "$entry_path"
|
|
25222
|
+
[ -n "$note_title" ] || continue
|
|
25223
|
+
/usr/bin/osascript - "$note_title" "$note_body" <<'APPLESCRIPT'
|
|
25224
|
+
on run argv
|
|
25225
|
+
display notification (item 2 of argv) with title (item 1 of argv)
|
|
25232
25226
|
end run
|
|
25227
|
+
APPLESCRIPT
|
|
25228
|
+
done
|
|
25233
25229
|
`;
|
|
25234
25230
|
}
|
|
25235
|
-
function notifierPlistContents(
|
|
25231
|
+
function notifierPlistContents(runnerPath, watchDir) {
|
|
25236
25232
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
25237
25233
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
25238
25234
|
<plist version="1.0">
|
|
@@ -25241,7 +25237,7 @@ function notifierPlistContents(appPath, watchDir) {
|
|
|
25241
25237
|
<string>${escapeXml2(MAC_NOTIFIER_LABEL)}</string>
|
|
25242
25238
|
<key>ProgramArguments</key>
|
|
25243
25239
|
<array>
|
|
25244
|
-
<string>${escapeXml2(
|
|
25240
|
+
<string>${escapeXml2(runnerPath)}</string>
|
|
25245
25241
|
</array>
|
|
25246
25242
|
<!-- Started only when something is queued, and it exits when the queue is
|
|
25247
25243
|
empty. RunAtLoad would fire it once at login with nothing to say. -->
|
|
@@ -25268,20 +25264,15 @@ function installMacNotifier(home) {
|
|
|
25268
25264
|
if (process.platform !== "darwin")
|
|
25269
25265
|
return { installed: false, reason: "not macOS" };
|
|
25270
25266
|
try {
|
|
25271
|
-
const
|
|
25267
|
+
const runner = macNotifierRunnerPath(home);
|
|
25272
25268
|
const watch = macNotifyDir(home);
|
|
25273
25269
|
mkdirSync17(watch, { recursive: true, mode: 448 });
|
|
25274
|
-
mkdirSync17(resolve22(
|
|
25275
|
-
|
|
25276
|
-
|
|
25277
|
-
rmSync9(
|
|
25278
|
-
run("osacompile", ["-o", app, scriptPath]);
|
|
25279
|
-
rmSync9(scriptPath, { force: true });
|
|
25280
|
-
const plist = resolve22(app, "Contents", "Info.plist");
|
|
25281
|
-
run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
|
|
25282
|
-
run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
|
|
25270
|
+
mkdirSync17(resolve22(runner, ".."), { recursive: true });
|
|
25271
|
+
writeFileSync15(runner, notifierScript(home), { mode: 448 });
|
|
25272
|
+
chmodSync5(runner, 448);
|
|
25273
|
+
rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
|
|
25283
25274
|
mkdirSync17(resolve22(macNotifierPlistPath(), ".."), { recursive: true });
|
|
25284
|
-
writeFileSync15(macNotifierPlistPath(), notifierPlistContents(
|
|
25275
|
+
writeFileSync15(macNotifierPlistPath(), notifierPlistContents(runner, watch), { mode: 420 });
|
|
25285
25276
|
const target = `gui/${process.getuid?.() ?? 0}`;
|
|
25286
25277
|
try {
|
|
25287
25278
|
run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
|
|
@@ -25300,6 +25291,7 @@ function uninstallMacNotifier(home) {
|
|
|
25300
25291
|
} catch {}
|
|
25301
25292
|
rmSync9(macNotifierPlistPath(), { force: true });
|
|
25302
25293
|
rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
|
|
25294
|
+
rmSync9(macNotifierRunnerPath(home), { force: true });
|
|
25303
25295
|
rmSync9(macNotifyDir(home), { recursive: true, force: true });
|
|
25304
25296
|
}
|
|
25305
25297
|
function queueMacNotification(id, title, body, home) {
|
|
@@ -25323,7 +25315,7 @@ ${body.replace(/\s+/g, " ")}
|
|
|
25323
25315
|
}
|
|
25324
25316
|
}
|
|
25325
25317
|
function macNotifierInstalled(home) {
|
|
25326
|
-
return existsSync26(macNotifierPlistPath()) && existsSync26(
|
|
25318
|
+
return existsSync26(macNotifierPlistPath()) && existsSync26(macNotifierRunnerPath(home));
|
|
25327
25319
|
}
|
|
25328
25320
|
function pruneMacNotifyQueue(home, maxAgeMs = 7 * 86400000) {
|
|
25329
25321
|
try {
|
|
@@ -27431,24 +27423,24 @@ function upsertFinding(record, incoming) {
|
|
|
27431
27423
|
});
|
|
27432
27424
|
return { record, isNew: true };
|
|
27433
27425
|
}
|
|
27426
|
+
const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at && s.mechanism.direction === sighting.mechanism.direction && s.mechanism.summary === sighting.mechanism.summary);
|
|
27427
|
+
if (seen)
|
|
27428
|
+
return { record, isNew: false };
|
|
27434
27429
|
existing.occurrences += 1;
|
|
27435
27430
|
if (sighting.at > existing.lastSeen)
|
|
27436
27431
|
existing.lastSeen = sighting.at;
|
|
27437
27432
|
if (sighting.at < existing.firstSeen)
|
|
27438
27433
|
existing.firstSeen = sighting.at;
|
|
27439
|
-
|
|
27440
|
-
|
|
27441
|
-
|
|
27442
|
-
existing.sightings.
|
|
27443
|
-
if (existing.sightings.length > MAX_SIGHTINGS) {
|
|
27444
|
-
existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
|
|
27445
|
-
}
|
|
27434
|
+
existing.sightings.push(sighting);
|
|
27435
|
+
existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
|
|
27436
|
+
if (existing.sightings.length > MAX_SIGHTINGS) {
|
|
27437
|
+
existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
|
|
27446
27438
|
}
|
|
27447
27439
|
return { record, isNew: false };
|
|
27448
27440
|
}
|
|
27449
27441
|
function pruneRecord(record, nowMs) {
|
|
27450
27442
|
const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
|
|
27451
|
-
const live = record.findings.filter((f) => f.lastSeen >= cutoff);
|
|
27443
|
+
const live = record.findings.filter((f) => !f.lastSeen || !Number.isFinite(Date.parse(f.lastSeen)) || f.lastSeen >= cutoff);
|
|
27452
27444
|
live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
|
|
27453
27445
|
record.findings = live.slice(0, MAX_FINDINGS);
|
|
27454
27446
|
return record;
|
|
@@ -27730,7 +27722,7 @@ var init_redact_example = __esm(() => {
|
|
|
27730
27722
|
|
|
27731
27723
|
// src/audit/cache.ts
|
|
27732
27724
|
import { createHash as createHash8 } from "node:crypto";
|
|
27733
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync27, writeFileSync as writeFileSync18, chmodSync as
|
|
27725
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync27, writeFileSync as writeFileSync18, chmodSync as chmodSync6, openSync, readSync, closeSync } from "node:fs";
|
|
27734
27726
|
import { join as join33 } from "node:path";
|
|
27735
27727
|
function getEngineVersion() {
|
|
27736
27728
|
if (cachedEngineVersion)
|
|
@@ -27856,7 +27848,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
|
|
|
27856
27848
|
}
|
|
27857
27849
|
writeFileSync18(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
|
|
27858
27850
|
try {
|
|
27859
|
-
|
|
27851
|
+
chmodSync6(cachePath, 384);
|
|
27860
27852
|
} catch {}
|
|
27861
27853
|
} catch {}
|
|
27862
27854
|
}
|
|
@@ -30210,7 +30202,15 @@ Hooks keep enforcing; scheduled audits stay off until it is.
|
|
|
30210
30202
|
} catch {}
|
|
30211
30203
|
}
|
|
30212
30204
|
pruneOldDaemonBinaries();
|
|
30213
|
-
installMacNotifier();
|
|
30205
|
+
const notifier = installMacNotifier();
|
|
30206
|
+
if (process.platform === "darwin" && !notifier.installed) {
|
|
30207
|
+
hookLogWarn(`macOS notification helper was not installed: ${notifier.reason ?? "unknown error"}`);
|
|
30208
|
+
stdout.write(`
|
|
30209
|
+
System notifications could not be installed. Scheduled scans and email alerts
|
|
30210
|
+
still work; re-run \`failproofai config\` after checking the local LaunchAgent.
|
|
30211
|
+
|
|
30212
|
+
`);
|
|
30213
|
+
}
|
|
30214
30214
|
}
|
|
30215
30215
|
const applied = emit("configure_applied", {
|
|
30216
30216
|
target,
|
|
@@ -30789,7 +30789,7 @@ var init_harness_cli = __esm(() => {
|
|
|
30789
30789
|
});
|
|
30790
30790
|
|
|
30791
30791
|
// src/hooks/fp-config.ts
|
|
30792
|
-
import { chmodSync as
|
|
30792
|
+
import { chmodSync as chmodSync7, existsSync as existsSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync33, statSync as statSync24, writeFileSync as writeFileSync23 } from "node:fs";
|
|
30793
30793
|
function detectLayout2() {
|
|
30794
30794
|
const raw = readVersionFile2();
|
|
30795
30795
|
if (raw) {
|
|
@@ -30859,7 +30859,7 @@ var init_fp_home2 = () => {};
|
|
|
30859
30859
|
|
|
30860
30860
|
// src/hooks/migrations.ts
|
|
30861
30861
|
import {
|
|
30862
|
-
chmodSync as
|
|
30862
|
+
chmodSync as chmodSync8,
|
|
30863
30863
|
copyFileSync as copyFileSync3,
|
|
30864
30864
|
existsSync as existsSync40,
|
|
30865
30865
|
mkdirSync as mkdirSync27,
|
|
@@ -30910,7 +30910,7 @@ function migrateToLayout42() {
|
|
|
30910
30910
|
if (!existsSync40(secret))
|
|
30911
30911
|
continue;
|
|
30912
30912
|
try {
|
|
30913
|
-
|
|
30913
|
+
chmodSync8(secret, 384);
|
|
30914
30914
|
} catch {}
|
|
30915
30915
|
}
|
|
30916
30916
|
writeVersionFile({ layout: 4 });
|
|
@@ -31645,6 +31645,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
31645
31645
|
if (found.daemonConfigured) {
|
|
31646
31646
|
plan.push(` • stop requiring the daemon (policies go back to evaluating in-process)`);
|
|
31647
31647
|
}
|
|
31648
|
+
let removeDaemon = opts.purge === true;
|
|
31648
31649
|
if (found.serviceInstalled) {
|
|
31649
31650
|
plan.push(opts.purge || opts.yes ? ` • stop, disable and delete the service at ${found.servicePath} — needs sudo` : ` • ask whether to remove the service at ${found.servicePath} (kept unless you say so)`);
|
|
31650
31651
|
}
|
|
@@ -31704,7 +31705,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
31704
31705
|
}
|
|
31705
31706
|
}
|
|
31706
31707
|
if (found.serviceInstalled) {
|
|
31707
|
-
|
|
31708
|
+
removeDaemon = opts.purge || opts.yes ? true : await opts.confirmDaemon?.() ?? false;
|
|
31708
31709
|
if (!removeDaemon) {
|
|
31709
31710
|
lines.push(`• kept the daemon service at ${found.servicePath}`, ` Remove it later with: failproofai uninstall --purge`);
|
|
31710
31711
|
} else {
|
|
@@ -31724,7 +31725,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
31724
31725
|
}
|
|
31725
31726
|
}
|
|
31726
31727
|
}
|
|
31727
|
-
if (opts.purge ||
|
|
31728
|
+
if (opts.purge || removeDaemon) {
|
|
31728
31729
|
uninstallMacNotifier();
|
|
31729
31730
|
}
|
|
31730
31731
|
if (opts.purge && found.homeExists) {
|
|
@@ -35886,7 +35887,7 @@ import { realpathSync as realpathSync7 } from "fs";
|
|
|
35886
35887
|
import { dirname as dirname25, resolve as resolve35 } from "path";
|
|
35887
35888
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
35888
35889
|
// package.json
|
|
35889
|
-
var version = "1.0.4-beta.
|
|
35890
|
+
var version = "1.0.4-beta.7";
|
|
35890
35891
|
|
|
35891
35892
|
// bin/failproofai.mjs
|
|
35892
35893
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
package/dist/worker.mjs
CHANGED
|
@@ -2809,8 +2809,8 @@ var init_builtin_policies = __esm(() => {
|
|
|
2809
2809
|
[/sk-ant-oat01-[A-Za-z0-9\-_]{20,}/, "Anthropic OAuth token"],
|
|
2810
2810
|
[/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"],
|
|
2811
2811
|
[/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"],
|
|
2812
|
-
[/sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
|
|
2813
|
-
[/sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
|
|
2812
|
+
[/(?<!\w)sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
|
|
2813
|
+
[/(?<!\w)sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
|
|
2814
2814
|
[/sk-or-v1-[A-Za-z0-9\-_]{20,}/, "OpenRouter API key"],
|
|
2815
2815
|
[/sk-[A-Za-z0-9]{20,}/, "OpenAI-compatible key (issuer unknown)"],
|
|
2816
2816
|
[/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"],
|
|
@@ -3507,7 +3507,7 @@ function parsePackPolicyName(canonicalName) {
|
|
|
3507
3507
|
}
|
|
3508
3508
|
|
|
3509
3509
|
// package.json
|
|
3510
|
-
var version = "1.0.4-beta.
|
|
3510
|
+
var version = "1.0.4-beta.7";
|
|
3511
3511
|
var init_package = () => {};
|
|
3512
3512
|
|
|
3513
3513
|
// src/posthog-key.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "1.0.4-beta.
|
|
3
|
+
"version": "1.0.4-beta.7",
|
|
4
4
|
"description": "Observability and enforcement for AI agent harnesses. 39 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs",
|
|
@@ -121,15 +121,15 @@
|
|
|
121
121
|
"browserslist": "4.28.8"
|
|
122
122
|
},
|
|
123
123
|
"optionalDependencies": {
|
|
124
|
-
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.
|
|
125
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.
|
|
126
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.
|
|
127
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.
|
|
124
|
+
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.7",
|
|
125
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.7",
|
|
126
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.7",
|
|
127
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.7"
|
|
128
128
|
},
|
|
129
129
|
"failproofaidBinaries": {
|
|
130
|
-
"linux-x64": "
|
|
131
|
-
"linux-arm64": "
|
|
132
|
-
"darwin-x64": "
|
|
133
|
-
"darwin-arm64": "
|
|
130
|
+
"linux-x64": "e59735a8f94cd8ac697b2bd67aafdd8d76a8394d53db229876980cc13a18f07e",
|
|
131
|
+
"linux-arm64": "b9ce50dd2f79b55f4f7112add265a776a4a6d002c2a56f971e666fbb796f3906",
|
|
132
|
+
"darwin-x64": "b46efc8ec33945a5cc26b7bb288fb87cea65b5983bd83094b5e607d53b8eda4c",
|
|
133
|
+
"darwin-arm64": "a8cc6112cee5ca8a7d517900e9ce32118855135980f22979fa0ff7aa6f68d954"
|
|
134
134
|
}
|
|
135
135
|
}
|
package/src/audit/index.ts
CHANGED
|
@@ -70,7 +70,7 @@ const TRANSCRIPT_BYTE_BUDGET = 48 * 1024 * 1024;
|
|
|
70
70
|
* otherwise the largest transcript on the machine could never be scanned, which
|
|
71
71
|
* is precisely the one most likely to hold something.
|
|
72
72
|
*/
|
|
73
|
-
class ByteGate {
|
|
73
|
+
export class ByteGate {
|
|
74
74
|
private inFlight = 0;
|
|
75
75
|
private waiting: Array<() => void> = [];
|
|
76
76
|
|
package/src/audit/leak-record.ts
CHANGED
|
@@ -152,23 +152,30 @@ export function upsertFinding(
|
|
|
152
152
|
return { record, isNew: true };
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
existing.occurrences += 1;
|
|
156
|
-
if (sighting.at > existing.lastSeen) existing.lastSeen = sighting.at;
|
|
157
|
-
if (sighting.at < existing.firstSeen) existing.firstSeen = sighting.at;
|
|
158
|
-
|
|
159
155
|
// Keep the earliest sighting AND the most recent evidence. The report/email
|
|
160
156
|
// promises the CLI and timestamp of the latest exposure; keeping only the
|
|
161
157
|
// first five made those fields stale forever after a busy credential crossed
|
|
162
158
|
// the cap. Middle sightings are the expendable ones.
|
|
163
159
|
const seen = existing.sightings.some(
|
|
164
|
-
(s) =>
|
|
160
|
+
(s) =>
|
|
161
|
+
s.sessionId === sighting.sessionId &&
|
|
162
|
+
s.at === sighting.at &&
|
|
163
|
+
s.mechanism.direction === sighting.mechanism.direction &&
|
|
164
|
+
s.mechanism.summary === sighting.mechanism.summary,
|
|
165
165
|
);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
166
|
+
// Cached transcript results are folded through this function again. An
|
|
167
|
+
// identical sighting is therefore not a new exposure and must not inflate
|
|
168
|
+
// the count each time the same cache entry is reused.
|
|
169
|
+
if (seen) return { record, isNew: false };
|
|
170
|
+
|
|
171
|
+
existing.occurrences += 1;
|
|
172
|
+
if (sighting.at > existing.lastSeen) existing.lastSeen = sighting.at;
|
|
173
|
+
if (sighting.at < existing.firstSeen) existing.firstSeen = sighting.at;
|
|
174
|
+
|
|
175
|
+
existing.sightings.push(sighting);
|
|
176
|
+
existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
|
|
177
|
+
if (existing.sightings.length > MAX_SIGHTINGS) {
|
|
178
|
+
existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
|
|
172
179
|
}
|
|
173
180
|
return { record, isNew: false };
|
|
174
181
|
}
|
|
@@ -181,7 +188,12 @@ export function upsertFinding(
|
|
|
181
188
|
*/
|
|
182
189
|
export function pruneRecord(record: LeakRecord, nowMs: number): LeakRecord {
|
|
183
190
|
const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86_400_000).toISOString();
|
|
184
|
-
|
|
191
|
+
// A missing or malformed timestamp cannot be aged out safely. Keep it until
|
|
192
|
+
// the bounded-cap pass below rather than silently deleting a finding that the
|
|
193
|
+
// reporting path deliberately surfaces as having an unknown date.
|
|
194
|
+
const live = record.findings.filter(
|
|
195
|
+
(f) => !f.lastSeen || !Number.isFinite(Date.parse(f.lastSeen)) || f.lastSeen >= cutoff,
|
|
196
|
+
);
|
|
185
197
|
live.sort((a, b) => (a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0));
|
|
186
198
|
record.findings = live.slice(0, MAX_FINDINGS);
|
|
187
199
|
return record;
|