failproofai 1.0.4-beta.2 → 1.0.4-beta.4
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 +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 +4 -4
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1lh7m5d._.js → [externals]__0v1hz15._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1rqkg_y._.js → [externals]__1nb206a._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0--lkk6._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_08w6xzm._.js → _0otft92._.js} +2 -2
- 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 +3 -3
- package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +1 -1
- 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]__013jr2b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.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]__0p-5p8u._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yl9wb5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0guxnh-._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/_0oq1dh6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +13 -0
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- 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/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 +22 -22
- package/.next/standalone/.next/static/chunks/{04r6ch8uf_n8m.js → 04o5zfl7p5lhx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0o-hh5_turzlz.css → 0jpd8dv2vk930.css} +1 -1
- package/.next/standalone/.next/static/chunks/{2ej3b8gk5ittu.js → 0po8n4tyotjf2.js} +1 -1
- package/.next/standalone/.next/static/chunks/0qx7gav1c2_vu.js +1 -0
- package/.next/standalone/.next/static/chunks/{2aquitk72k2op.js → 17tfki9x5rd_7.js} +1 -1
- package/.next/standalone/.next/static/chunks/{010bv1w6j171t.js → 1i-i0pxg9q_8y.js} +1 -1
- package/.next/standalone/.next/static/chunks/{32spub4wqjem-.js → 2bxr2_2h4kaqq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0wz8yftk18ts2.js → 323cyb3a2s06y.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1pb1oztsbwcss.js → 364cqbpeg1y5i.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3m4upvybtrexd.js → 38dqur43qthrl.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2bi_1y0a_smt7.js → 42gwu2bsz4ske.js} +2 -2
- package/.next/standalone/app/actions/get-leaks.ts +10 -1
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +29 -2
- package/.next/standalone/app/audit/_components/leak-section.tsx +15 -2
- package/.next/standalone/app/audit/audit-styles.css +18 -0
- package/.next/standalone/lib/sqlite-reader.ts +78 -1
- package/.next/standalone/package.json +10 -10
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +1 -1
- package/dist/cli.mjs +397 -225
- package/dist/worker.mjs +81 -35
- package/lib/sqlite-reader.ts +78 -1
- package/package.json +10 -10
- package/pi-extension/index.ts +19 -4
- package/src/audit/cache.ts +6 -0
- package/src/audit/cli-adapters/claude.ts +13 -0
- package/src/audit/cli-login.ts +4 -1
- package/src/audit/cli.ts +84 -59
- package/src/audit/index.ts +149 -8
- package/src/audit/leak-notice.ts +99 -1
- package/src/audit/leak-scan.ts +20 -44
- package/src/audit/leak-store.ts +49 -1
- package/src/audit/redact-example.ts +60 -5
- package/src/audit/types.ts +6 -0
- package/src/hooks/handler.ts +30 -10
- package/src/hooks/integrations.ts +14 -0
- package/src/hooks/notice.ts +45 -9
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rgu2r3._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0-oij9d._.js +0 -23
- package/.next/standalone/.next/static/chunks/0zebh1n9jkfbt.js +0 -1
- /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → P6icI2V2PvVuePJrqjHCr}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → P6icI2V2PvVuePJrqjHCr}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → P6icI2V2PvVuePJrqjHCr}/_ssgManifest.js +0 -0
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.4", package_default;
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "failproofai",
|
|
@@ -150,20 +150,20 @@ var init_package = __esm(() => {
|
|
|
150
150
|
vite: "8.0.16",
|
|
151
151
|
undici: "7.29.0",
|
|
152
152
|
"brace-expansion": "5.0.9",
|
|
153
|
-
sharp: "0.35.
|
|
153
|
+
sharp: "0.35.4",
|
|
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.4",
|
|
158
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.4",
|
|
159
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.4",
|
|
160
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.4"
|
|
161
161
|
},
|
|
162
162
|
failproofaidBinaries: {
|
|
163
|
-
"linux-x64": "
|
|
164
|
-
"linux-arm64": "
|
|
165
|
-
"darwin-x64": "
|
|
166
|
-
"darwin-arm64": "
|
|
163
|
+
"linux-x64": "4487790ed9b881da2914b5985a23b5adca1f20e226d71c635d8170064e6b2340",
|
|
164
|
+
"linux-arm64": "c903c5e201198213ccd8295fdab741c7d08d22c8dd5c276e52aa766595bedcc2",
|
|
165
|
+
"darwin-x64": "f0933584abbf0f9ff95cd153f8c6c704e467af1d6ffc8f42f9c426bd44b1142a",
|
|
166
|
+
"darwin-arm64": "387a3acbf13f667a557c8ac632fe67dee350cda078e3266e71edfcfacb9ecae6"
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
});
|
|
@@ -11810,6 +11810,19 @@ async function applyDecision(result, ctx, eventName) {
|
|
|
11810
11810
|
if (out && out.decision && out.decision.behavior === "deny") {
|
|
11811
11811
|
throw new Error((out.decision.message) || "Blocked by failproofai");
|
|
11812
11812
|
}
|
|
11813
|
+
const notice = parsed.failproofaiNotice;
|
|
11814
|
+
if (typeof notice === "string" && notice && ctx && ctx.client && ctx.client.tui) {
|
|
11815
|
+
try {
|
|
11816
|
+
await ctx.client.tui.showToast({
|
|
11817
|
+
body: {
|
|
11818
|
+
title: "failproofai audit",
|
|
11819
|
+
message: notice,
|
|
11820
|
+
variant: "warning",
|
|
11821
|
+
duration: 12_000,
|
|
11822
|
+
},
|
|
11823
|
+
});
|
|
11824
|
+
} catch { /* a courtesy notice must never break the host hook */ }
|
|
11825
|
+
}
|
|
11813
11826
|
// Forward additional context as a prompt to the session. For Stop /
|
|
11814
11827
|
// SubagentStop the prompt is the only force-retry channel (session.idle
|
|
11815
11828
|
// already fired), so AWAIT to ensure the SDK round-trip completes before
|
|
@@ -16510,6 +16523,20 @@ function shapeNotice(cli, notice, existingStdout = "") {
|
|
|
16510
16523
|
return empty;
|
|
16511
16524
|
return { stdout: text + `
|
|
16512
16525
|
`, stderr: "" };
|
|
16526
|
+
case "shim": {
|
|
16527
|
+
if (existingStdout.trim().startsWith("{")) {
|
|
16528
|
+
try {
|
|
16529
|
+
const parsed = JSON.parse(existingStdout);
|
|
16530
|
+
parsed.failproofaiNotice = text;
|
|
16531
|
+
return { stdout: JSON.stringify(parsed), stderr: "" };
|
|
16532
|
+
} catch {
|
|
16533
|
+
return empty;
|
|
16534
|
+
}
|
|
16535
|
+
}
|
|
16536
|
+
if (existingStdout.trim())
|
|
16537
|
+
return empty;
|
|
16538
|
+
return { stdout: JSON.stringify({ failproofaiNotice: text }), stderr: "" };
|
|
16539
|
+
}
|
|
16513
16540
|
default:
|
|
16514
16541
|
return empty;
|
|
16515
16542
|
}
|
|
@@ -16518,9 +16545,15 @@ function canDeliverNotice(cli) {
|
|
|
16518
16545
|
return !!cli && (NOTICE_CHANNEL[cli] ?? "none") !== "none";
|
|
16519
16546
|
}
|
|
16520
16547
|
function leakNoticeText(newFindings) {
|
|
16521
|
-
const n = newFindings === 1 ? "a credential" : `${newFindings}
|
|
16548
|
+
const n = newFindings === 1 ? "a possible credential exposure" : `${newFindings} possible credential exposures`;
|
|
16522
16549
|
return `failproofai found ${n} in this project's agent transcripts.
|
|
16523
|
-
` + "Run `failproofai audit` to
|
|
16550
|
+
` + "Run `failproofai audit` to review the matches and rotate anything real.";
|
|
16551
|
+
}
|
|
16552
|
+
function desktopLeakNotice() {
|
|
16553
|
+
return {
|
|
16554
|
+
title: "failproofai audit needs review",
|
|
16555
|
+
body: "Possible credential exposure was found in your agent transcripts. " + "Run failproofai audit to verify the matches and rotate anything real."
|
|
16556
|
+
};
|
|
16524
16557
|
}
|
|
16525
16558
|
var NOTICE_CHANNEL, MAX_NOTICE_CHARS = 900;
|
|
16526
16559
|
var init_notice = __esm(() => {
|
|
@@ -16528,7 +16561,9 @@ var init_notice = __esm(() => {
|
|
|
16528
16561
|
claude: "systemMessage",
|
|
16529
16562
|
codex: "systemMessage",
|
|
16530
16563
|
copilot: "stderr",
|
|
16531
|
-
factory: "stdout"
|
|
16564
|
+
factory: "stdout",
|
|
16565
|
+
opencode: "shim",
|
|
16566
|
+
pi: "shim"
|
|
16532
16567
|
};
|
|
16533
16568
|
});
|
|
16534
16569
|
|
|
@@ -16732,7 +16767,11 @@ function readJson(path) {
|
|
|
16732
16767
|
function readLeakIdentity(home) {
|
|
16733
16768
|
const existing = readJson(auditLeakIdentityFile(home));
|
|
16734
16769
|
if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
|
|
16735
|
-
return {
|
|
16770
|
+
return {
|
|
16771
|
+
salt: existing.salt,
|
|
16772
|
+
dismissed: existing.dismissed ?? [],
|
|
16773
|
+
reportViewedAt: typeof existing.reportViewedAt === "number" && Number.isFinite(existing.reportViewedAt) ? existing.reportViewedAt : undefined
|
|
16774
|
+
};
|
|
16736
16775
|
}
|
|
16737
16776
|
const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
|
|
16738
16777
|
writeLeakIdentity(minted, home);
|
|
@@ -16814,16 +16853,6 @@ var init_leak_store = __esm(() => {
|
|
|
16814
16853
|
// src/audit/leak-notice.ts
|
|
16815
16854
|
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync5, statSync as statSync8, writeFileSync as writeFileSync7, rmSync as rmSync4 } from "node:fs";
|
|
16816
16855
|
import { resolve as resolve11 } from "node:path";
|
|
16817
|
-
function pendingLeakNotice(home, channel = "cli") {
|
|
16818
|
-
try {
|
|
16819
|
-
const dir = NOTICE_DIR(home, channel);
|
|
16820
|
-
const claimed = new Set(existsSync13(dir) ? readdirSync5(dir) : []);
|
|
16821
|
-
const ids = activeFindings(readLeakRecord(home), home).map((f) => f.id).filter((id) => !claimed.has(id));
|
|
16822
|
-
return { ids, count: ids.length };
|
|
16823
|
-
} catch {
|
|
16824
|
-
return { ids: [], count: 0 };
|
|
16825
|
-
}
|
|
16826
|
-
}
|
|
16827
16856
|
function markLeakNoticeDelivered(ids, home, channel = "cli") {
|
|
16828
16857
|
const won = [];
|
|
16829
16858
|
try {
|
|
@@ -16840,6 +16869,48 @@ function markLeakNoticeDelivered(ids, home, channel = "cli") {
|
|
|
16840
16869
|
} catch {}
|
|
16841
16870
|
return won;
|
|
16842
16871
|
}
|
|
16872
|
+
function releaseLeakNoticeClaims(ids, home, channel = "cli") {
|
|
16873
|
+
try {
|
|
16874
|
+
const dir = NOTICE_DIR(home, channel);
|
|
16875
|
+
for (const id of ids) {
|
|
16876
|
+
if (!isFindingId(id))
|
|
16877
|
+
continue;
|
|
16878
|
+
rmSync4(resolve11(dir, id), { force: true });
|
|
16879
|
+
}
|
|
16880
|
+
} catch {}
|
|
16881
|
+
}
|
|
16882
|
+
function sessionNoticePending(sessionId, home) {
|
|
16883
|
+
try {
|
|
16884
|
+
if (!sessionId || !/^[\w.:-]{1,200}$/.test(sessionId))
|
|
16885
|
+
return { ids: [], count: 0 };
|
|
16886
|
+
const dir = resolve11(auditDir(home), "notified-sessions");
|
|
16887
|
+
if (existsSync13(resolve11(dir, sessionId)))
|
|
16888
|
+
return { ids: [], count: 0 };
|
|
16889
|
+
const findings = activeFindings(readLeakRecord(home), home);
|
|
16890
|
+
if (findings.length === 0)
|
|
16891
|
+
return { ids: [], count: 0 };
|
|
16892
|
+
const viewedAt = readLeakIdentity(home).reportViewedAt ?? 0;
|
|
16893
|
+
const unviewed = findings.filter((f) => {
|
|
16894
|
+
const seen = Date.parse(f.firstSeen);
|
|
16895
|
+
return !Number.isFinite(seen) || seen > viewedAt;
|
|
16896
|
+
});
|
|
16897
|
+
return { ids: unviewed.map((f) => f.id), count: unviewed.length };
|
|
16898
|
+
} catch {
|
|
16899
|
+
return { ids: [], count: 0 };
|
|
16900
|
+
}
|
|
16901
|
+
}
|
|
16902
|
+
function markSessionNoticed(sessionId, home) {
|
|
16903
|
+
try {
|
|
16904
|
+
if (!sessionId || !/^[\w.:-]{1,200}$/.test(sessionId))
|
|
16905
|
+
return false;
|
|
16906
|
+
const dir = resolve11(auditDir(home), "notified-sessions");
|
|
16907
|
+
mkdirSync9(dir, { recursive: true });
|
|
16908
|
+
writeFileSync7(resolve11(dir, sessionId), "", { flag: "wx", mode: 384 });
|
|
16909
|
+
return true;
|
|
16910
|
+
} catch {
|
|
16911
|
+
return false;
|
|
16912
|
+
}
|
|
16913
|
+
}
|
|
16843
16914
|
var NOTICE_DIR = (home, channel = "cli") => resolve11(auditDir(home), channel === "cli" ? "notified" : `notified-${channel}`), MARKER_TTL_MS;
|
|
16844
16915
|
var init_leak_notice = __esm(() => {
|
|
16845
16916
|
init_fp_home();
|
|
@@ -17542,8 +17613,21 @@ var init_cursor_projects = __esm(() => {
|
|
|
17542
17613
|
// lib/sqlite-reader.ts
|
|
17543
17614
|
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
|
|
17544
17615
|
import initSqlJs from "sql.js/dist/sql-asm.js";
|
|
17616
|
+
function silenceSqliteExperimentalWarning() {
|
|
17617
|
+
if (warningPatched)
|
|
17618
|
+
return;
|
|
17619
|
+
warningPatched = true;
|
|
17620
|
+
const original = process.emitWarning.bind(process);
|
|
17621
|
+
process.emitWarning = (warning, ...rest) => {
|
|
17622
|
+
const text = typeof warning === "string" ? warning : String(warning?.message ?? "");
|
|
17623
|
+
if (text.includes("SQLite is an experimental feature"))
|
|
17624
|
+
return;
|
|
17625
|
+
return original(warning, ...rest);
|
|
17626
|
+
};
|
|
17627
|
+
}
|
|
17545
17628
|
async function tryNodeSqlite(dbPath) {
|
|
17546
17629
|
try {
|
|
17630
|
+
silenceSqliteExperimentalWarning();
|
|
17547
17631
|
const mod = await import("node:sqlite");
|
|
17548
17632
|
const db = new mod.DatabaseSync(dbPath, { readOnly: true });
|
|
17549
17633
|
return {
|
|
@@ -17564,10 +17648,21 @@ function loadSqlJs() {
|
|
|
17564
17648
|
sqlPromise = initSqlJs();
|
|
17565
17649
|
return sqlPromise;
|
|
17566
17650
|
}
|
|
17651
|
+
function clearWalFlag(bytes) {
|
|
17652
|
+
if (bytes.length < 20)
|
|
17653
|
+
return bytes;
|
|
17654
|
+
if (bytes.toString("latin1", 0, 16) !== SQLITE_MAGIC)
|
|
17655
|
+
return bytes;
|
|
17656
|
+
if (bytes[18] === 1 && bytes[19] === 1)
|
|
17657
|
+
return bytes;
|
|
17658
|
+
bytes[18] = 1;
|
|
17659
|
+
bytes[19] = 1;
|
|
17660
|
+
return bytes;
|
|
17661
|
+
}
|
|
17567
17662
|
async function trySqlJs(dbPath) {
|
|
17568
17663
|
try {
|
|
17569
17664
|
const SQL = await loadSqlJs();
|
|
17570
|
-
const db = new SQL.Database(readFileSync9(dbPath));
|
|
17665
|
+
const db = new SQL.Database(clearWalFlag(readFileSync9(dbPath)));
|
|
17571
17666
|
return {
|
|
17572
17667
|
query(sql, params) {
|
|
17573
17668
|
const stmt = db.prepare(sql);
|
|
@@ -17595,7 +17690,7 @@ async function openSqliteReadonly(dbPath) {
|
|
|
17595
17690
|
return null;
|
|
17596
17691
|
return await tryNodeSqlite(dbPath) ?? await trySqlJs(dbPath);
|
|
17597
17692
|
}
|
|
17598
|
-
var sqlPromise = null;
|
|
17693
|
+
var warningPatched = false, sqlPromise = null, SQLITE_MAGIC = "SQLite format 3\x00";
|
|
17599
17694
|
var init_sqlite_reader = () => {};
|
|
17600
17695
|
|
|
17601
17696
|
// lib/opencode-db.ts
|
|
@@ -23012,22 +23107,22 @@ function canonicalizeEventType(raw, cli) {
|
|
|
23012
23107
|
}
|
|
23013
23108
|
return raw;
|
|
23014
23109
|
}
|
|
23015
|
-
function attachLeakNotice(eventType, cli, outcome) {
|
|
23110
|
+
function attachLeakNotice(eventType, cli, outcome, sessionId) {
|
|
23016
23111
|
try {
|
|
23017
23112
|
if (!canDeliverNotice(cli))
|
|
23018
23113
|
return outcome;
|
|
23019
23114
|
if (!cli)
|
|
23020
23115
|
return outcome;
|
|
23021
23116
|
const canonical = canonicalizeEventType(eventType, cli);
|
|
23022
|
-
if (canonical !== "Stop"
|
|
23117
|
+
if (canonical !== "Stop")
|
|
23023
23118
|
return outcome;
|
|
23024
|
-
const pending =
|
|
23119
|
+
const pending = sessionNoticePending(sessionId ?? "");
|
|
23025
23120
|
if (pending.count === 0)
|
|
23026
23121
|
return outcome;
|
|
23027
23122
|
const shaped = shapeNotice(cli, leakNoticeText(pending.count), outcome.stdout);
|
|
23028
23123
|
if (shaped.stdout === outcome.stdout && !shaped.stderr)
|
|
23029
23124
|
return outcome;
|
|
23030
|
-
|
|
23125
|
+
markSessionNoticed(sessionId ?? "");
|
|
23031
23126
|
return {
|
|
23032
23127
|
exitCode: outcome.exitCode,
|
|
23033
23128
|
stdout: shaped.stdout,
|
|
@@ -23339,11 +23434,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
23339
23434
|
}
|
|
23340
23435
|
} catch {}
|
|
23341
23436
|
}
|
|
23342
|
-
const withNotice = attachLeakNotice(eventType, cli, {
|
|
23343
|
-
exitCode: result.exitCode,
|
|
23344
|
-
stdout: result.stdout,
|
|
23345
|
-
stderr: result.stderr
|
|
23346
|
-
});
|
|
23437
|
+
const withNotice = attachLeakNotice(eventType, cli, { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr }, sessionId);
|
|
23347
23438
|
return withNotice;
|
|
23348
23439
|
} finally {
|
|
23349
23440
|
if (opts?.awaitTelemetryFlush ?? true) {
|
|
@@ -26241,6 +26332,7 @@ var init_shared = __esm(() => {
|
|
|
26241
26332
|
|
|
26242
26333
|
// src/audit/cli-adapters/claude.ts
|
|
26243
26334
|
import { readFile as readFile15, open as open2 } from "node:fs/promises";
|
|
26335
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
26244
26336
|
async function listClaudeTranscriptMetadata(opts = {}) {
|
|
26245
26337
|
const projectFilter = opts.projects ? new Set(opts.projects) : null;
|
|
26246
26338
|
const sinceMs = opts.sinceMs ?? 0;
|
|
@@ -26257,13 +26349,22 @@ async function listClaudeTranscriptMetadata(opts = {}) {
|
|
|
26257
26349
|
for (const t of transcripts) {
|
|
26258
26350
|
if (t.mtimeMs < sinceMs)
|
|
26259
26351
|
continue;
|
|
26352
|
+
let sessionDescription;
|
|
26353
|
+
if (t.isSubagent) {
|
|
26354
|
+
try {
|
|
26355
|
+
const meta = JSON.parse(readFileSync26(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
|
|
26356
|
+
if (typeof meta.description === "string")
|
|
26357
|
+
sessionDescription = meta.description;
|
|
26358
|
+
} catch {}
|
|
26359
|
+
}
|
|
26260
26360
|
out.push({
|
|
26261
26361
|
cli: "claude",
|
|
26262
26362
|
projectName: project.name,
|
|
26263
26363
|
sessionId: t.sessionId,
|
|
26264
26364
|
transcriptPath: t.transcriptPath,
|
|
26265
26365
|
mtimeMs: t.mtimeMs,
|
|
26266
|
-
sizeBytes: t.sizeBytes
|
|
26366
|
+
sizeBytes: t.sizeBytes,
|
|
26367
|
+
sessionDescription
|
|
26267
26368
|
});
|
|
26268
26369
|
}
|
|
26269
26370
|
}
|
|
@@ -27493,6 +27594,106 @@ var init_features = __esm(() => {
|
|
|
27493
27594
|
})();
|
|
27494
27595
|
});
|
|
27495
27596
|
|
|
27597
|
+
// src/audit/leak-scan.ts
|
|
27598
|
+
function unquote(v) {
|
|
27599
|
+
return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
|
|
27600
|
+
}
|
|
27601
|
+
function isDocsLiteral(value) {
|
|
27602
|
+
const { createHash } = __require("node:crypto");
|
|
27603
|
+
return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
|
|
27604
|
+
}
|
|
27605
|
+
function isSelfOutput(text) {
|
|
27606
|
+
return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
|
|
27607
|
+
}
|
|
27608
|
+
function literalPrefixOf(source) {
|
|
27609
|
+
let out = "";
|
|
27610
|
+
for (let i = 0;i < source.length; i++) {
|
|
27611
|
+
const c = source[i];
|
|
27612
|
+
if (c === "\\") {
|
|
27613
|
+
const next = source[i + 1];
|
|
27614
|
+
if (next === undefined)
|
|
27615
|
+
break;
|
|
27616
|
+
if (/[dwsSDWbB]/.test(next))
|
|
27617
|
+
break;
|
|
27618
|
+
out += next;
|
|
27619
|
+
i++;
|
|
27620
|
+
continue;
|
|
27621
|
+
}
|
|
27622
|
+
if ("[](){}|?*+^$.".includes(c))
|
|
27623
|
+
break;
|
|
27624
|
+
out += c;
|
|
27625
|
+
}
|
|
27626
|
+
return out.length >= 2 ? out : null;
|
|
27627
|
+
}
|
|
27628
|
+
function applicablePatterns(text) {
|
|
27629
|
+
return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
|
|
27630
|
+
}
|
|
27631
|
+
function findSecrets(text) {
|
|
27632
|
+
if (!text)
|
|
27633
|
+
return [];
|
|
27634
|
+
if (isSelfOutput(text))
|
|
27635
|
+
return [];
|
|
27636
|
+
const byValue = new Map;
|
|
27637
|
+
for (const [pattern, label] of applicablePatterns(text)) {
|
|
27638
|
+
const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
|
|
27639
|
+
for (const m of text.matchAll(re)) {
|
|
27640
|
+
const value = m[0];
|
|
27641
|
+
if (isDocsLiteral(value))
|
|
27642
|
+
continue;
|
|
27643
|
+
if (!byValue.has(value))
|
|
27644
|
+
byValue.set(value, { value, name: null, rule: label, shaped: true });
|
|
27645
|
+
}
|
|
27646
|
+
}
|
|
27647
|
+
for (const m of text.matchAll(ASSIGNMENT_RE)) {
|
|
27648
|
+
const name = m[2];
|
|
27649
|
+
const value = unquote(m[4]);
|
|
27650
|
+
const existing = byValue.get(value);
|
|
27651
|
+
if (existing)
|
|
27652
|
+
existing.name ??= name;
|
|
27653
|
+
}
|
|
27654
|
+
return [...byValue.values()];
|
|
27655
|
+
}
|
|
27656
|
+
function flattenToolInput(input, depth = 0) {
|
|
27657
|
+
if (depth > 6 || input == null)
|
|
27658
|
+
return "";
|
|
27659
|
+
if (typeof input === "string")
|
|
27660
|
+
return input;
|
|
27661
|
+
if (typeof input === "number" || typeof input === "boolean")
|
|
27662
|
+
return String(input);
|
|
27663
|
+
if (Array.isArray(input))
|
|
27664
|
+
return input.map((v) => flattenToolInput(v, depth + 1)).join(`
|
|
27665
|
+
`);
|
|
27666
|
+
if (typeof input === "object") {
|
|
27667
|
+
return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
|
|
27668
|
+
`);
|
|
27669
|
+
}
|
|
27670
|
+
return "";
|
|
27671
|
+
}
|
|
27672
|
+
var LEAK_SCAN_VERSION = 5, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
|
|
27673
|
+
var init_leak_scan = __esm(() => {
|
|
27674
|
+
init_builtin_policies();
|
|
27675
|
+
ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
27676
|
+
DOCS_LITERALS = new Set([
|
|
27677
|
+
"1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
|
|
27678
|
+
"78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
|
|
27679
|
+
"cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
|
|
27680
|
+
"3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
|
|
27681
|
+
"1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
|
|
27682
|
+
"23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
|
|
27683
|
+
"872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
|
|
27684
|
+
"78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
|
|
27685
|
+
"2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
|
|
27686
|
+
"b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
|
|
27687
|
+
]);
|
|
27688
|
+
SELF_OUTPUT_MARKERS = [
|
|
27689
|
+
"[REDACTED:",
|
|
27690
|
+
"[redacted:",
|
|
27691
|
+
"failproofai audit",
|
|
27692
|
+
"assigned secret]"
|
|
27693
|
+
];
|
|
27694
|
+
GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
|
|
27695
|
+
});
|
|
27696
|
+
|
|
27496
27697
|
// src/audit/redact-example.ts
|
|
27497
27698
|
import { homedir as homedir27 } from "node:os";
|
|
27498
27699
|
function maskTruncatedSecret(input) {
|
|
@@ -27529,7 +27730,7 @@ function isSecretName(name) {
|
|
|
27529
27730
|
return components.length > 1 && components.some((part) => COMPOUND_ONLY_COMPONENTS.includes(part));
|
|
27530
27731
|
}
|
|
27531
27732
|
function maskAssignedSecrets(input) {
|
|
27532
|
-
let out = input.replace(
|
|
27733
|
+
let out = input.replace(ASSIGNMENT_RE2, (match, quote, name, separator, value) => {
|
|
27533
27734
|
if (!isSecretName(name))
|
|
27534
27735
|
return match;
|
|
27535
27736
|
if (value.startsWith("[REDACTED"))
|
|
@@ -27588,7 +27789,7 @@ function redactExample(input, home = homedir27()) {
|
|
|
27588
27789
|
const collapsed = shortened.replace(/\s+/g, " ").trim();
|
|
27589
27790
|
return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
|
|
27590
27791
|
}
|
|
27591
|
-
var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS,
|
|
27792
|
+
var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS, ASSIGNMENT_RE2, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE, CLIENT_BUNDLE_PREFIXES, PUBLISHED_MARKERS;
|
|
27592
27793
|
var init_redact_example = __esm(() => {
|
|
27593
27794
|
init_builtin_policies();
|
|
27594
27795
|
ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
|
|
@@ -27616,9 +27817,9 @@ var init_redact_example = __esm(() => {
|
|
|
27616
27817
|
"APIKEY",
|
|
27617
27818
|
"PRIVATEKEY"
|
|
27618
27819
|
];
|
|
27619
|
-
SECRET_NAME_COMPONENTS = ["
|
|
27620
|
-
COMPOUND_ONLY_COMPONENTS = ["PWD"];
|
|
27621
|
-
|
|
27820
|
+
SECRET_NAME_COMPONENTS = ["PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "COOKIE"];
|
|
27821
|
+
COMPOUND_ONLY_COMPONENTS = ["PWD", "KEY"];
|
|
27822
|
+
ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
27622
27823
|
URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]{0,31}:\/\/)[^\s/:@]{1,256}:[^\s/@]{1,256}@/gi;
|
|
27623
27824
|
BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
|
|
27624
27825
|
CLIENT_BUNDLE_PREFIXES = [
|
|
@@ -27634,136 +27835,9 @@ var init_redact_example = __esm(() => {
|
|
|
27634
27835
|
PUBLISHED_MARKERS = /PUBLISHABLE|(^|_)PUBLIC_KEY$|(^|_)ANON_KEY$/;
|
|
27635
27836
|
});
|
|
27636
27837
|
|
|
27637
|
-
// src/audit/leak-scan.ts
|
|
27638
|
-
function isNotACredential(value) {
|
|
27639
|
-
if (value.length < MIN_VALUE_LEN)
|
|
27640
|
-
return true;
|
|
27641
|
-
if (/^[$<{(`%]/.test(value))
|
|
27642
|
-
return true;
|
|
27643
|
-
if (value.includes("${") || value.includes("{{") || value.includes("%("))
|
|
27644
|
-
return true;
|
|
27645
|
-
if (/^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)+$/.test(value))
|
|
27646
|
-
return true;
|
|
27647
|
-
if (value.includes("[REDACTED") || /^[•*#.]+$/.test(value))
|
|
27648
|
-
return true;
|
|
27649
|
-
if (/(.)\1{5,}/.test(value))
|
|
27650
|
-
return true;
|
|
27651
|
-
if (/^(true|false|null|undefined|none)$/i.test(value))
|
|
27652
|
-
return true;
|
|
27653
|
-
if (/^-?\d+(\.\d+)?$/.test(value))
|
|
27654
|
-
return true;
|
|
27655
|
-
if (/^\/|^~\/|^\.\.?\//.test(value))
|
|
27656
|
-
return true;
|
|
27657
|
-
return false;
|
|
27658
|
-
}
|
|
27659
|
-
function unquote(v) {
|
|
27660
|
-
return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
|
|
27661
|
-
}
|
|
27662
|
-
function isDocsLiteral(value) {
|
|
27663
|
-
const { createHash } = __require("node:crypto");
|
|
27664
|
-
return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
|
|
27665
|
-
}
|
|
27666
|
-
function isSelfOutput(text) {
|
|
27667
|
-
return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
|
|
27668
|
-
}
|
|
27669
|
-
function literalPrefixOf(source) {
|
|
27670
|
-
let out = "";
|
|
27671
|
-
for (let i = 0;i < source.length; i++) {
|
|
27672
|
-
const c = source[i];
|
|
27673
|
-
if (c === "\\") {
|
|
27674
|
-
const next = source[i + 1];
|
|
27675
|
-
if (next === undefined)
|
|
27676
|
-
break;
|
|
27677
|
-
if (/[dwsSDWbB]/.test(next))
|
|
27678
|
-
break;
|
|
27679
|
-
out += next;
|
|
27680
|
-
i++;
|
|
27681
|
-
continue;
|
|
27682
|
-
}
|
|
27683
|
-
if ("[](){}|?*+^$.".includes(c))
|
|
27684
|
-
break;
|
|
27685
|
-
out += c;
|
|
27686
|
-
}
|
|
27687
|
-
return out.length >= 2 ? out : null;
|
|
27688
|
-
}
|
|
27689
|
-
function applicablePatterns(text) {
|
|
27690
|
-
return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
|
|
27691
|
-
}
|
|
27692
|
-
function findSecrets(text) {
|
|
27693
|
-
if (!text)
|
|
27694
|
-
return [];
|
|
27695
|
-
if (isSelfOutput(text))
|
|
27696
|
-
return [];
|
|
27697
|
-
const byValue = new Map;
|
|
27698
|
-
for (const [pattern, label] of applicablePatterns(text)) {
|
|
27699
|
-
const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
|
|
27700
|
-
for (const m of text.matchAll(re)) {
|
|
27701
|
-
const value = m[0];
|
|
27702
|
-
if (isDocsLiteral(value))
|
|
27703
|
-
continue;
|
|
27704
|
-
if (!byValue.has(value))
|
|
27705
|
-
byValue.set(value, { value, name: null, rule: label, shaped: true });
|
|
27706
|
-
}
|
|
27707
|
-
}
|
|
27708
|
-
for (const m of text.matchAll(ASSIGNMENT_RE2)) {
|
|
27709
|
-
const name = m[2];
|
|
27710
|
-
const value = unquote(m[4]);
|
|
27711
|
-
if (!isSecretName(name) || isNotACredential(value) || isDocsLiteral(value))
|
|
27712
|
-
continue;
|
|
27713
|
-
const existing = byValue.get(value);
|
|
27714
|
-
if (existing) {
|
|
27715
|
-
existing.name ??= name;
|
|
27716
|
-
continue;
|
|
27717
|
-
}
|
|
27718
|
-
byValue.set(value, { value, name, rule: "assigned secret", shaped: false });
|
|
27719
|
-
}
|
|
27720
|
-
return [...byValue.values()];
|
|
27721
|
-
}
|
|
27722
|
-
function flattenToolInput(input, depth = 0) {
|
|
27723
|
-
if (depth > 6 || input == null)
|
|
27724
|
-
return "";
|
|
27725
|
-
if (typeof input === "string")
|
|
27726
|
-
return input;
|
|
27727
|
-
if (typeof input === "number" || typeof input === "boolean")
|
|
27728
|
-
return String(input);
|
|
27729
|
-
if (Array.isArray(input))
|
|
27730
|
-
return input.map((v) => flattenToolInput(v, depth + 1)).join(`
|
|
27731
|
-
`);
|
|
27732
|
-
if (typeof input === "object") {
|
|
27733
|
-
return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
|
|
27734
|
-
`);
|
|
27735
|
-
}
|
|
27736
|
-
return "";
|
|
27737
|
-
}
|
|
27738
|
-
var ASSIGNMENT_RE2, MIN_VALUE_LEN = 8, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
|
|
27739
|
-
var init_leak_scan = __esm(() => {
|
|
27740
|
-
init_builtin_policies();
|
|
27741
|
-
init_redact_example();
|
|
27742
|
-
ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
27743
|
-
DOCS_LITERALS = new Set([
|
|
27744
|
-
"1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
|
|
27745
|
-
"78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
|
|
27746
|
-
"cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
|
|
27747
|
-
"3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
|
|
27748
|
-
"1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
|
|
27749
|
-
"23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
|
|
27750
|
-
"872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
|
|
27751
|
-
"78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
|
|
27752
|
-
"2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
|
|
27753
|
-
"b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
|
|
27754
|
-
]);
|
|
27755
|
-
SELF_OUTPUT_MARKERS = [
|
|
27756
|
-
"[REDACTED:",
|
|
27757
|
-
"[redacted:",
|
|
27758
|
-
"failproofai audit",
|
|
27759
|
-
"assigned secret]"
|
|
27760
|
-
];
|
|
27761
|
-
GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
|
|
27762
|
-
});
|
|
27763
|
-
|
|
27764
27838
|
// src/audit/cache.ts
|
|
27765
27839
|
import { createHash as createHash8 } from "node:crypto";
|
|
27766
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as
|
|
27840
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync27, writeFileSync as writeFileSync19, chmodSync as chmodSync5, openSync, readSync, closeSync } from "node:fs";
|
|
27767
27841
|
import { join as join33 } from "node:path";
|
|
27768
27842
|
function getEngineVersion() {
|
|
27769
27843
|
if (cachedEngineVersion)
|
|
@@ -27827,7 +27901,7 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
|
|
|
27827
27901
|
if (!existsSync33(cachePath))
|
|
27828
27902
|
return null;
|
|
27829
27903
|
try {
|
|
27830
|
-
const raw =
|
|
27904
|
+
const raw = readFileSync27(cachePath, "utf-8");
|
|
27831
27905
|
const entry = JSON.parse(raw);
|
|
27832
27906
|
if (entry.schemaVersion !== CACHE_SCHEMA_VERSION)
|
|
27833
27907
|
return null;
|
|
@@ -27835,6 +27909,8 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
|
|
|
27835
27909
|
return null;
|
|
27836
27910
|
if (entry.detectorVersion !== getDetectorVersion())
|
|
27837
27911
|
return null;
|
|
27912
|
+
if (entry.leakScanVersion !== LEAK_SCAN_VERSION)
|
|
27913
|
+
return null;
|
|
27838
27914
|
if (!Number.isFinite(entry.cachedAt) || Date.now() - entry.cachedAt > CACHE_TTL_MS)
|
|
27839
27915
|
return null;
|
|
27840
27916
|
if (!entry.result)
|
|
@@ -27874,6 +27950,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
|
|
|
27874
27950
|
sizeBytes,
|
|
27875
27951
|
engineVersion: getEngineVersion(),
|
|
27876
27952
|
detectorVersion: getDetectorVersion(),
|
|
27953
|
+
leakScanVersion: LEAK_SCAN_VERSION,
|
|
27877
27954
|
result
|
|
27878
27955
|
};
|
|
27879
27956
|
if (resume && resume.bytesScanned > 0) {
|
|
@@ -27894,6 +27971,7 @@ var cachedEngineVersion = null, cachedDetectorVersion = null, CACHE_SCHEMA_VERSI
|
|
|
27894
27971
|
var init_cache = __esm(() => {
|
|
27895
27972
|
init_builtin_policies();
|
|
27896
27973
|
init_detectors();
|
|
27974
|
+
init_leak_scan();
|
|
27897
27975
|
init_fp_home();
|
|
27898
27976
|
CACHE_TTL_MS = 30 * 24 * 60 * 60000;
|
|
27899
27977
|
});
|
|
@@ -27962,6 +28040,30 @@ var init_replay = __esm(() => {
|
|
|
27962
28040
|
});
|
|
27963
28041
|
|
|
27964
28042
|
// src/audit/index.ts
|
|
28043
|
+
class ByteGate {
|
|
28044
|
+
budget;
|
|
28045
|
+
inFlight = 0;
|
|
28046
|
+
waiting = [];
|
|
28047
|
+
constructor(budget) {
|
|
28048
|
+
this.budget = budget;
|
|
28049
|
+
}
|
|
28050
|
+
async acquire(bytes) {
|
|
28051
|
+
const want = Math.max(0, bytes);
|
|
28052
|
+
while (this.inFlight > 0 && this.inFlight + want > this.budget) {
|
|
28053
|
+
await new Promise((resolve) => this.waiting.push(resolve));
|
|
28054
|
+
}
|
|
28055
|
+
this.inFlight += want;
|
|
28056
|
+
}
|
|
28057
|
+
release(bytes) {
|
|
28058
|
+
this.inFlight -= Math.max(0, bytes);
|
|
28059
|
+
if (this.inFlight < 0)
|
|
28060
|
+
this.inFlight = 0;
|
|
28061
|
+
const waiters = this.waiting;
|
|
28062
|
+
this.waiting = [];
|
|
28063
|
+
for (const wake of waiters)
|
|
28064
|
+
wake();
|
|
28065
|
+
}
|
|
28066
|
+
}
|
|
27965
28067
|
function shortPolicyName(name) {
|
|
27966
28068
|
const slash = name.indexOf("/");
|
|
27967
28069
|
return slash >= 0 ? name.slice(slash + 1) : name;
|
|
@@ -28003,6 +28105,27 @@ function parseSinceOpt(since) {
|
|
|
28003
28105
|
return t;
|
|
28004
28106
|
throw new Error(`Invalid --since value: "${since}" (expected e.g. "7d", "30d", or "2026-04-01")`);
|
|
28005
28107
|
}
|
|
28108
|
+
function isCredentialResearchSession(events, sessionDescription) {
|
|
28109
|
+
if (sessionDescription && CREDENTIAL_RESEARCH_PURPOSE.test(sessionDescription))
|
|
28110
|
+
return true;
|
|
28111
|
+
const matched = new Set;
|
|
28112
|
+
let evidenceEvents = 0;
|
|
28113
|
+
for (const event of events) {
|
|
28114
|
+
const intent = flattenToolInput(event.toolInput);
|
|
28115
|
+
let eventMatched = false;
|
|
28116
|
+
for (let i = 0;i < CREDENTIAL_RESEARCH_MARKERS.length; i++) {
|
|
28117
|
+
if (CREDENTIAL_RESEARCH_MARKERS[i].test(intent)) {
|
|
28118
|
+
matched.add(i);
|
|
28119
|
+
eventMatched = true;
|
|
28120
|
+
}
|
|
28121
|
+
}
|
|
28122
|
+
if (eventMatched)
|
|
28123
|
+
evidenceEvents++;
|
|
28124
|
+
if (matched.size >= 2 || evidenceEvents >= 3)
|
|
28125
|
+
return true;
|
|
28126
|
+
}
|
|
28127
|
+
return false;
|
|
28128
|
+
}
|
|
28006
28129
|
async function scanOneTranscript(meta, resume) {
|
|
28007
28130
|
const empty = {
|
|
28008
28131
|
transcriptPath: meta.transcriptPath,
|
|
@@ -28043,6 +28166,9 @@ async function scanOneTranscript(meta, resume) {
|
|
|
28043
28166
|
const result = empty;
|
|
28044
28167
|
result.eventsScanned = events.length;
|
|
28045
28168
|
result.cwd = result.cwd || events[0].cwd || "";
|
|
28169
|
+
const suppressLeakScan = isCredentialResearchSession(events, meta.sessionDescription);
|
|
28170
|
+
if (suppressLeakScan)
|
|
28171
|
+
result.leakScanSuppressed = "credential-research";
|
|
28046
28172
|
for (const event of events) {
|
|
28047
28173
|
let replayHits;
|
|
28048
28174
|
try {
|
|
@@ -28054,7 +28180,8 @@ async function scanOneTranscript(meta, resume) {
|
|
|
28054
28180
|
const example = formatPolicyExample(hit.policyName, event);
|
|
28055
28181
|
recordHit(result, hit.policyName, event.timestamp, event.cwd, truncateExample(example));
|
|
28056
28182
|
}
|
|
28057
|
-
|
|
28183
|
+
if (!suppressLeakScan)
|
|
28184
|
+
recordLeaks(result, event);
|
|
28058
28185
|
}
|
|
28059
28186
|
return { result, bytesScanned, detectorState: sessionState, resumed };
|
|
28060
28187
|
}
|
|
@@ -28094,10 +28221,12 @@ function leakSalt() {
|
|
|
28094
28221
|
}
|
|
28095
28222
|
return cachedSalt;
|
|
28096
28223
|
}
|
|
28097
|
-
function persistLeaks(perTranscript) {
|
|
28224
|
+
function persistLeaks(perTranscript, replaceExisting) {
|
|
28098
28225
|
const fresh = [];
|
|
28099
28226
|
try {
|
|
28100
|
-
const
|
|
28227
|
+
const previous = readLeakRecord();
|
|
28228
|
+
const previousIds = new Set(previous.findings.map((f) => f.id));
|
|
28229
|
+
const record = replaceExisting ? emptyRecord(previous.salt, new Date().toISOString()) : previous;
|
|
28101
28230
|
for (const t of perTranscript) {
|
|
28102
28231
|
for (const leak of t.leaks ?? []) {
|
|
28103
28232
|
const { isNew } = upsertFinding(record, {
|
|
@@ -28114,7 +28243,7 @@ function persistLeaks(perTranscript) {
|
|
|
28114
28243
|
mechanism: describeMechanism(leak.toolName, leak.direction, leak.path)
|
|
28115
28244
|
}
|
|
28116
28245
|
});
|
|
28117
|
-
if (isNew)
|
|
28246
|
+
if (isNew && !previousIds.has(leak.id))
|
|
28118
28247
|
fresh.push(leak.id);
|
|
28119
28248
|
}
|
|
28120
28249
|
}
|
|
@@ -28144,6 +28273,12 @@ function mergeIncremental(cached, tail) {
|
|
|
28144
28273
|
examplesByName: {},
|
|
28145
28274
|
rangeByName: { ...cached.rangeByName }
|
|
28146
28275
|
};
|
|
28276
|
+
if (cached.leakScanSuppressed || tail.leakScanSuppressed) {
|
|
28277
|
+
out.leakScanSuppressed = "credential-research";
|
|
28278
|
+
out.leaks = [];
|
|
28279
|
+
} else {
|
|
28280
|
+
out.leaks = [...cached.leaks ?? [], ...tail.leaks ?? []];
|
|
28281
|
+
}
|
|
28147
28282
|
for (const [name, list] of Object.entries(cached.examplesByName)) {
|
|
28148
28283
|
out.examplesByName[name] = [...list];
|
|
28149
28284
|
}
|
|
@@ -28267,16 +28402,19 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28267
28402
|
}
|
|
28268
28403
|
} catch {}
|
|
28269
28404
|
const allTranscripts = [];
|
|
28405
|
+
let discoveryErrors = 0;
|
|
28270
28406
|
for (const cli of clis) {
|
|
28271
28407
|
const adapter = ADAPTERS[cli];
|
|
28272
28408
|
let list;
|
|
28273
28409
|
try {
|
|
28274
28410
|
list = await adapter.listTranscripts({ projects: opts.projects, sinceMs });
|
|
28275
28411
|
} catch {
|
|
28412
|
+
discoveryErrors++;
|
|
28276
28413
|
continue;
|
|
28277
28414
|
}
|
|
28278
28415
|
allTranscripts.push(...list);
|
|
28279
28416
|
}
|
|
28417
|
+
const gate = new ByteGate(TRANSCRIPT_BYTE_BUDGET);
|
|
28280
28418
|
let skipped = 0;
|
|
28281
28419
|
let errors = 0;
|
|
28282
28420
|
const tasks = allTranscripts.map((meta) => async () => {
|
|
@@ -28289,6 +28427,7 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28289
28427
|
resume = found?.kind === "resume" ? { fromByte: found.fromByte, detectorState: found.detectorState } : undefined;
|
|
28290
28428
|
cachedPrefix = found?.kind === "resume" ? found.result : null;
|
|
28291
28429
|
}
|
|
28430
|
+
await gate.acquire(meta.sizeBytes);
|
|
28292
28431
|
try {
|
|
28293
28432
|
const scan = await scanOneTranscript(meta, resume);
|
|
28294
28433
|
const fresh = cachedPrefix && scan.resumed ? mergeIncremental(cachedPrefix, scan.result) : scan.result;
|
|
@@ -28311,6 +28450,8 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28311
28450
|
examplesByName: {},
|
|
28312
28451
|
rangeByName: {}
|
|
28313
28452
|
};
|
|
28453
|
+
} finally {
|
|
28454
|
+
gate.release(meta.sizeBytes);
|
|
28314
28455
|
}
|
|
28315
28456
|
});
|
|
28316
28457
|
const settled = await batchAll(tasks, TRANSCRIPT_CONCURRENCY);
|
|
@@ -28337,7 +28478,8 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28337
28478
|
projectsScannedSet.add(t.cwd);
|
|
28338
28479
|
eventsScanned += t.eventsScanned ?? 0;
|
|
28339
28480
|
}
|
|
28340
|
-
const
|
|
28481
|
+
const coversAllHistory = opts.clis === undefined && opts.projects === undefined && opts.since === undefined && discoveryErrors === 0 && errors === 0 && skipped === 0;
|
|
28482
|
+
const newFindingIds = persistLeaks(perTranscript, coversAllHistory);
|
|
28341
28483
|
const auditResult = {
|
|
28342
28484
|
version: 2,
|
|
28343
28485
|
newLeakIds: newFindingIds,
|
|
@@ -28364,7 +28506,7 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28364
28506
|
};
|
|
28365
28507
|
return auditResult;
|
|
28366
28508
|
}
|
|
28367
|
-
var TRANSCRIPT_CONCURRENCY = 8, cachedSalt;
|
|
28509
|
+
var TRANSCRIPT_CONCURRENCY = 8, TRANSCRIPT_BYTE_BUDGET, CREDENTIAL_RESEARCH_MARKERS, CREDENTIAL_RESEARCH_PURPOSE, cachedSalt;
|
|
28368
28510
|
var init_audit = __esm(() => {
|
|
28369
28511
|
init_builtin_policies();
|
|
28370
28512
|
init_hooks_config();
|
|
@@ -28380,6 +28522,15 @@ var init_audit = __esm(() => {
|
|
|
28380
28522
|
init_cache();
|
|
28381
28523
|
init_replay();
|
|
28382
28524
|
init_types2();
|
|
28525
|
+
TRANSCRIPT_BYTE_BUDGET = 48 * 1024 * 1024;
|
|
28526
|
+
CREDENTIAL_RESEARCH_MARKERS = [
|
|
28527
|
+
/\b(?:secret|credential)[-_ ](?:scanner|detection|detector|pattern|regex|corpus)\b/i,
|
|
28528
|
+
/\b(?:trufflehog|trufflesecurity|gitleaks|detect-secrets|secret-detection-rules)\b/i,
|
|
28529
|
+
/\b(?:SECRET_PATTERNS|findSecrets|isDocsLiteral|leak-scan)\b/,
|
|
28530
|
+
/\b(?:fixture|placeholder|synthetic|sample) (?:api )?(?:key|token|secret|credential)s?\b/i,
|
|
28531
|
+
/\b(?:grep|rg|ripgrep|scan|hunt|search)\b[^\n]{0,240}\b(?:secret|credential|token)s?\b/i
|
|
28532
|
+
];
|
|
28533
|
+
CREDENTIAL_RESEARCH_PURPOSE = /\b(?:hunt|scan|search|research|test)(?:ing)?\b[^\n]{0,80}\b(?:secret|credential|token)s?\b|\b(?:secret|credential|token)s?\b[^\n]{0,80}\b(?:scanner|detector|detection|research|fixtures?|corpus)\b/i;
|
|
28383
28534
|
});
|
|
28384
28535
|
|
|
28385
28536
|
// src/audit/audit-lock.ts
|
|
@@ -28388,7 +28539,7 @@ import {
|
|
|
28388
28539
|
linkSync,
|
|
28389
28540
|
mkdirSync as mkdirSync23,
|
|
28390
28541
|
openSync as openSync2,
|
|
28391
|
-
readFileSync as
|
|
28542
|
+
readFileSync as readFileSync28,
|
|
28392
28543
|
unlinkSync as unlinkSync4,
|
|
28393
28544
|
writeFileSync as writeFileSync20,
|
|
28394
28545
|
writeSync
|
|
@@ -28449,7 +28600,7 @@ function handleFor(path, info) {
|
|
|
28449
28600
|
}
|
|
28450
28601
|
function readLock2(path) {
|
|
28451
28602
|
try {
|
|
28452
|
-
const parsed = JSON.parse(
|
|
28603
|
+
const parsed = JSON.parse(readFileSync28(path, "utf8"));
|
|
28453
28604
|
if (typeof parsed?.pid !== "number" || typeof parsed?.startedAt !== "number")
|
|
28454
28605
|
return null;
|
|
28455
28606
|
return {
|
|
@@ -28509,7 +28660,7 @@ var init_audit_lock = __esm(() => {
|
|
|
28509
28660
|
});
|
|
28510
28661
|
|
|
28511
28662
|
// src/audit/dashboard-cache.ts
|
|
28512
|
-
import { existsSync as existsSync34, readFileSync as
|
|
28663
|
+
import { existsSync as existsSync34, readFileSync as readFileSync29 } from "node:fs";
|
|
28513
28664
|
function getCachePath() {
|
|
28514
28665
|
return auditDashboardFile();
|
|
28515
28666
|
}
|
|
@@ -28532,7 +28683,7 @@ function readDashboardCacheMeta() {
|
|
|
28532
28683
|
if (!existsSync34(cachePath))
|
|
28533
28684
|
return null;
|
|
28534
28685
|
try {
|
|
28535
|
-
const raw =
|
|
28686
|
+
const raw = readFileSync29(cachePath, "utf-8");
|
|
28536
28687
|
const entry = JSON.parse(raw);
|
|
28537
28688
|
if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
|
|
28538
28689
|
return null;
|
|
@@ -28756,7 +28907,7 @@ var init_api_server_client = __esm(() => {
|
|
|
28756
28907
|
});
|
|
28757
28908
|
|
|
28758
28909
|
// lib/auth/auth-store.ts
|
|
28759
|
-
import { existsSync as existsSync35, readFileSync as
|
|
28910
|
+
import { existsSync as existsSync35, readFileSync as readFileSync30, readdirSync as readdirSync19, rmSync as rmSync14 } from "node:fs";
|
|
28760
28911
|
import { join as join34, resolve as resolve25 } from "node:path";
|
|
28761
28912
|
function getAuthFilePath() {
|
|
28762
28913
|
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
@@ -28767,7 +28918,7 @@ function readAuth() {
|
|
|
28767
28918
|
if (!existsSync35(p))
|
|
28768
28919
|
return null;
|
|
28769
28920
|
try {
|
|
28770
|
-
const raw =
|
|
28921
|
+
const raw = readFileSync30(p, "utf-8");
|
|
28771
28922
|
const parsed = JSON.parse(raw);
|
|
28772
28923
|
if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
|
|
28773
28924
|
return null;
|
|
@@ -28977,7 +29128,7 @@ var init_harm_report = __esm(() => {
|
|
|
28977
29128
|
});
|
|
28978
29129
|
|
|
28979
29130
|
// src/audit/machine-store.ts
|
|
28980
|
-
import { existsSync as existsSync36, readFileSync as
|
|
29131
|
+
import { existsSync as existsSync36, readFileSync as readFileSync31, rmSync as rmSync15 } from "node:fs";
|
|
28981
29132
|
import { hostname as hostname5 } from "node:os";
|
|
28982
29133
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
28983
29134
|
function readMachineIdentity(home) {
|
|
@@ -28985,7 +29136,7 @@ function readMachineIdentity(home) {
|
|
|
28985
29136
|
if (!existsSync36(path))
|
|
28986
29137
|
return null;
|
|
28987
29138
|
try {
|
|
28988
|
-
const parsed = JSON.parse(
|
|
29139
|
+
const parsed = JSON.parse(readFileSync31(path, "utf8"));
|
|
28989
29140
|
if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
|
|
28990
29141
|
return null;
|
|
28991
29142
|
return {
|
|
@@ -29556,6 +29707,8 @@ var init_cli = __esm(() => {
|
|
|
29556
29707
|
init_desktop_notify();
|
|
29557
29708
|
init_macos_notifier();
|
|
29558
29709
|
init_leak_notice();
|
|
29710
|
+
init_notice();
|
|
29711
|
+
init_leak_store();
|
|
29559
29712
|
init_fp_config();
|
|
29560
29713
|
init_tui();
|
|
29561
29714
|
init_package();
|
|
@@ -29575,7 +29728,7 @@ var init_cli = __esm(() => {
|
|
|
29575
29728
|
});
|
|
29576
29729
|
|
|
29577
29730
|
// src/hooks/configure-wizard.ts
|
|
29578
|
-
import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readFileSync as
|
|
29731
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readFileSync as readFileSync32 } from "node:fs";
|
|
29579
29732
|
import { homedir as homedir28 } from "node:os";
|
|
29580
29733
|
import { dirname as dirname17, resolve as resolve26, sep as sep5 } from "node:path";
|
|
29581
29734
|
async function emit(event, props) {
|
|
@@ -29601,7 +29754,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
|
|
|
29601
29754
|
let config = {};
|
|
29602
29755
|
try {
|
|
29603
29756
|
if (existsSync37(path))
|
|
29604
|
-
config = JSON.parse(
|
|
29757
|
+
config = JSON.parse(readFileSync32(path, "utf8"));
|
|
29605
29758
|
} catch {
|
|
29606
29759
|
return;
|
|
29607
29760
|
}
|
|
@@ -30725,7 +30878,7 @@ var init_harness_cli = __esm(() => {
|
|
|
30725
30878
|
});
|
|
30726
30879
|
|
|
30727
30880
|
// src/hooks/fp-config.ts
|
|
30728
|
-
import { chmodSync as chmodSync6, existsSync as existsSync40, mkdirSync as mkdirSync27, readFileSync as
|
|
30881
|
+
import { chmodSync as chmodSync6, existsSync as existsSync40, mkdirSync as mkdirSync27, readFileSync as readFileSync33, statSync as statSync25, writeFileSync as writeFileSync24 } from "node:fs";
|
|
30729
30882
|
function detectLayout2() {
|
|
30730
30883
|
const raw = readVersionFile2();
|
|
30731
30884
|
if (raw) {
|
|
@@ -30766,7 +30919,7 @@ function readLegacyTomlVersion2(text) {
|
|
|
30766
30919
|
function readVersionFile2() {
|
|
30767
30920
|
let text;
|
|
30768
30921
|
try {
|
|
30769
|
-
text =
|
|
30922
|
+
text = readFileSync33(versionFile(), "utf8");
|
|
30770
30923
|
} catch {
|
|
30771
30924
|
return null;
|
|
30772
30925
|
}
|
|
@@ -30799,7 +30952,7 @@ import {
|
|
|
30799
30952
|
copyFileSync as copyFileSync3,
|
|
30800
30953
|
existsSync as existsSync41,
|
|
30801
30954
|
mkdirSync as mkdirSync28,
|
|
30802
|
-
readFileSync as
|
|
30955
|
+
readFileSync as readFileSync34,
|
|
30803
30956
|
renameSync as renameSync9,
|
|
30804
30957
|
rmSync as rmSync16,
|
|
30805
30958
|
writeFileSync as writeFileSync25
|
|
@@ -30869,7 +31022,7 @@ function planMigration2(from, registry = MIGRATIONS2) {
|
|
|
30869
31022
|
}
|
|
30870
31023
|
function readLedger2() {
|
|
30871
31024
|
try {
|
|
30872
|
-
const parsed = JSON.parse(
|
|
31025
|
+
const parsed = JSON.parse(readFileSync34(migrationLedgerFile(), "utf8"));
|
|
30873
31026
|
return Array.isArray(parsed) ? parsed : [];
|
|
30874
31027
|
} catch {
|
|
30875
31028
|
return [];
|
|
@@ -31064,7 +31217,7 @@ import {
|
|
|
31064
31217
|
existsSync as existsSync42,
|
|
31065
31218
|
mkdirSync as mkdirSync29,
|
|
31066
31219
|
mkdtempSync as mkdtempSync2,
|
|
31067
|
-
readFileSync as
|
|
31220
|
+
readFileSync as readFileSync35,
|
|
31068
31221
|
writeFileSync as writeFileSync26,
|
|
31069
31222
|
unlinkSync as unlinkSync5,
|
|
31070
31223
|
rmSync as rmSync17
|
|
@@ -31711,7 +31864,7 @@ var init_uninstall_cli = __esm(() => {
|
|
|
31711
31864
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
31712
31865
|
import { homedir as homedir31, tmpdir as tmpdir4 } from "node:os";
|
|
31713
31866
|
import { createHash as createHash9 } from "node:crypto";
|
|
31714
|
-
import { copyFileSync as copyFileSync4, existsSync as existsSync44, mkdirSync as mkdirSync30, mkdtempSync as mkdtempSync3, readFileSync as
|
|
31867
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync44, mkdirSync as mkdirSync30, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, readdirSync as readdirSync22, realpathSync as realpathSync3, rmSync as rmSync19, statSync as statSync26, writeFileSync as writeFileSync27 } from "node:fs";
|
|
31715
31868
|
import { basename as basename8, dirname as dirname21, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as resolve30, sep as sep6 } from "node:path";
|
|
31716
31869
|
function parseList(rest, flag) {
|
|
31717
31870
|
const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
|
|
@@ -31828,7 +31981,7 @@ async function build(rest) {
|
|
|
31828
31981
|
const entryPath = resolve30(entry);
|
|
31829
31982
|
if (!existsSync44(entryPath))
|
|
31830
31983
|
return fail2([`No such file: ${entryPath}`]);
|
|
31831
|
-
const source =
|
|
31984
|
+
const source = readFileSync36(entryPath, "utf8");
|
|
31832
31985
|
const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
|
|
31833
31986
|
if (localImport) {
|
|
31834
31987
|
return fail2([
|
|
@@ -31891,7 +32044,7 @@ async function build(rest) {
|
|
|
31891
32044
|
copyFileSync4(entryPath, entryOut);
|
|
31892
32045
|
const sha = (bytes) => createHash9("sha256").update(bytes).digest("hex");
|
|
31893
32046
|
writeFileSync27(resolve30(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
|
|
31894
|
-
${sha(
|
|
32047
|
+
${sha(readFileSync36(entryOut))} ${PACK_ENTRY_ASSET}
|
|
31895
32048
|
`, "utf8");
|
|
31896
32049
|
const on = policies.filter((p) => p.defaultEnabled).length;
|
|
31897
32050
|
return ok2([
|
|
@@ -32217,7 +32370,7 @@ function findEntry(dir) {
|
|
|
32217
32370
|
try {
|
|
32218
32371
|
if (statSync26(full).size > 512 * 1024)
|
|
32219
32372
|
continue;
|
|
32220
|
-
const text =
|
|
32373
|
+
const text = readFileSync36(full, "utf8");
|
|
32221
32374
|
if (/from\s+["']failproofai["']/.test(text) && /customPolicies\s*\.\s*add\s*\(/.test(text)) {
|
|
32222
32375
|
found.push(full);
|
|
32223
32376
|
}
|
|
@@ -32236,7 +32389,7 @@ function withLocalImports(sources) {
|
|
|
32236
32389
|
try {
|
|
32237
32390
|
if (statSync26(file).size > 512 * 1024)
|
|
32238
32391
|
continue;
|
|
32239
|
-
text =
|
|
32392
|
+
text = readFileSync36(file, "utf8");
|
|
32240
32393
|
} catch {
|
|
32241
32394
|
continue;
|
|
32242
32395
|
}
|
|
@@ -32759,7 +32912,7 @@ async function publish(rest) {
|
|
|
32759
32912
|
}
|
|
32760
32913
|
const tag = flag("tag") ?? version;
|
|
32761
32914
|
let entryToBuild = entry;
|
|
32762
|
-
const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(
|
|
32915
|
+
const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(readFileSync36(entry, "utf8"));
|
|
32763
32916
|
if (needsBundle) {
|
|
32764
32917
|
const sources = discovered.length > 1 ? discovered : [entry];
|
|
32765
32918
|
const bundled = bundleEntry(sources, outDirEarly);
|
|
@@ -32838,7 +32991,7 @@ async function publish(rest) {
|
|
|
32838
32991
|
if (prior) {
|
|
32839
32992
|
await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
|
|
32840
32993
|
}
|
|
32841
|
-
const bytes =
|
|
32994
|
+
const bytes = readFileSync36(resolve30(outDir, asset));
|
|
32842
32995
|
const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
|
|
32843
32996
|
method: "POST",
|
|
32844
32997
|
contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
|
|
@@ -34242,11 +34395,11 @@ var init_manager2 = __esm(() => {
|
|
|
34242
34395
|
});
|
|
34243
34396
|
|
|
34244
34397
|
// src/audit/audit-schedule.ts
|
|
34245
|
-
import { readFileSync as
|
|
34398
|
+
import { readFileSync as readFileSync37 } from "node:fs";
|
|
34246
34399
|
function readAuditSchedule(home) {
|
|
34247
34400
|
let raw;
|
|
34248
34401
|
try {
|
|
34249
|
-
raw =
|
|
34402
|
+
raw = readFileSync37(auditScheduleFile(home), "utf8");
|
|
34250
34403
|
} catch {
|
|
34251
34404
|
return null;
|
|
34252
34405
|
}
|
|
@@ -34310,7 +34463,9 @@ async function ensureSignedIn(preset) {
|
|
|
34310
34463
|
}
|
|
34311
34464
|
if (!canPrompt()) {
|
|
34312
34465
|
throw new LoginError(`Signing in needs an interactive terminal, and this one is not.
|
|
34313
|
-
` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" +
|
|
34466
|
+
` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + `or sign in from the dashboard — both write the same session file.
|
|
34467
|
+
` + `
|
|
34468
|
+
` + "`--email` does not avoid this: it fills in the address so you are not\n" + "asked for it, but a one-time code is still sent there for you to paste.");
|
|
34314
34469
|
}
|
|
34315
34470
|
return { user: await runLogin(preset), prompted: true };
|
|
34316
34471
|
}
|
|
@@ -34692,7 +34847,7 @@ function parseScriptArgs(argv) {
|
|
|
34692
34847
|
var init_parse_script_args = () => {};
|
|
34693
34848
|
|
|
34694
34849
|
// scripts/install-diagnosis.mjs
|
|
34695
|
-
import { existsSync as existsSync46, readFileSync as
|
|
34850
|
+
import { existsSync as existsSync46, readFileSync as readFileSync38, realpathSync as realpathSync4 } from "node:fs";
|
|
34696
34851
|
import { dirname as dirname22, resolve as resolve33 } from "node:path";
|
|
34697
34852
|
import { homedir as homedir32, platform as platform5 } from "node:os";
|
|
34698
34853
|
import { spawnSync } from "node:child_process";
|
|
@@ -34706,7 +34861,7 @@ function findPackageRoot(start) {
|
|
|
34706
34861
|
const pkgPath = resolve33(dir, "package.json");
|
|
34707
34862
|
if (existsSync46(pkgPath)) {
|
|
34708
34863
|
try {
|
|
34709
|
-
const pkg = JSON.parse(
|
|
34864
|
+
const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
|
|
34710
34865
|
if (pkg.name === PKG_NAME)
|
|
34711
34866
|
return dir;
|
|
34712
34867
|
} catch {}
|
|
@@ -34724,7 +34879,7 @@ function readPackageVersion(packageRoot) {
|
|
|
34724
34879
|
if (!packageRoot)
|
|
34725
34880
|
return null;
|
|
34726
34881
|
try {
|
|
34727
|
-
const pkg = JSON.parse(
|
|
34882
|
+
const pkg = JSON.parse(readFileSync38(resolve33(packageRoot, "package.json"), "utf8"));
|
|
34728
34883
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
34729
34884
|
} catch {
|
|
34730
34885
|
return null;
|
|
@@ -34972,14 +35127,14 @@ function helpText() {
|
|
|
34972
35127
|
const lines = helpScreen({
|
|
34973
35128
|
command: "audit",
|
|
34974
35129
|
version: version2,
|
|
34975
|
-
tagline: "
|
|
35130
|
+
tagline: "find credentials your agents leaked into their own transcripts",
|
|
34976
35131
|
sections: [
|
|
34977
35132
|
{
|
|
34978
35133
|
label: "usage",
|
|
34979
35134
|
entries: [
|
|
34980
|
-
["(bare)", `Scan your session history, then open http://localhost:${DASHBOARD_PORT}/audit`],
|
|
34981
|
-
["--schedule [days]", "Scan on a timer and email the findings. Default 7 days, range 1-90. Signs you in the first time."],
|
|
34982
|
-
["--email <address>", "With --schedule,
|
|
35135
|
+
["(bare)", `Scan your session history for leaked keys, then open http://localhost:${DASHBOARD_PORT}/audit`],
|
|
35136
|
+
["--schedule [days]", "Scan on a timer, notify you on this machine, and email the findings. Default 7 days, range 1-90. Signs you in the first time."],
|
|
35137
|
+
["--email <address>", "With --schedule, fills in your address. A sign-in code is still emailed to you to paste."],
|
|
34983
35138
|
["--no-schedule", "Stop the timer. Leaves you signed in."],
|
|
34984
35139
|
["--notify", "Show a desktop notification when a scan finds a credential. On by default."],
|
|
34985
35140
|
["--no-notify", "Stop those notifications. Scans and the digest are unaffected."],
|
|
@@ -34988,7 +35143,11 @@ function helpText() {
|
|
|
34988
35143
|
]
|
|
34989
35144
|
}
|
|
34990
35145
|
],
|
|
34991
|
-
footer: [
|
|
35146
|
+
footer: [
|
|
35147
|
+
"Everything runs on this machine. A scan tells you three ways: a desktop",
|
|
35148
|
+
"notification, two lines in your agent session, and the emailed digest —",
|
|
35149
|
+
"and only that digest ever leaves."
|
|
35150
|
+
]
|
|
34992
35151
|
}, helpOptsFor(process.stdout));
|
|
34993
35152
|
return ["", ...lines, ""].join(`
|
|
34994
35153
|
`) + `
|
|
@@ -35154,24 +35313,35 @@ async function announceLeaksOrThrow(result) {
|
|
|
35154
35313
|
const claimed = markLeakNoticeDelivered(ids, undefined, "desktop");
|
|
35155
35314
|
if (claimed.length === 0)
|
|
35156
35315
|
return;
|
|
35157
|
-
const
|
|
35158
|
-
const
|
|
35159
|
-
const
|
|
35160
|
-
|
|
35161
|
-
|
|
35162
|
-
|
|
35163
|
-
|
|
35316
|
+
const live = new Set(activeFindings(readLeakRecord()).map((f) => f.id));
|
|
35317
|
+
const shown = claimed.filter((id) => live.has(id)).length || claimed.length;
|
|
35318
|
+
const n = shown === 1 ? "a possible credential exposure" : `${shown} possible credential exposures`;
|
|
35319
|
+
const { title, body } = desktopLeakNotice();
|
|
35320
|
+
let delivered = false;
|
|
35321
|
+
try {
|
|
35322
|
+
if (process.platform === "darwin") {
|
|
35323
|
+
pruneMacNotifyQueue();
|
|
35324
|
+
if (!queueMacNotification(claimed[0], title, body)) {
|
|
35325
|
+
process.stderr.write(`failproofai: found ${n} but could not queue a notification
|
|
35164
35326
|
`);
|
|
35165
|
-
|
|
35166
|
-
|
|
35327
|
+
} else {
|
|
35328
|
+
delivered = true;
|
|
35329
|
+
}
|
|
35330
|
+
if (delivered && !macNotifierInstalled()) {
|
|
35331
|
+
process.stderr.write(`failproofai: found ${n}; the notifier is not installed, so nothing will show it ` + `(run \`failproofai config\`)
|
|
35167
35332
|
`);
|
|
35333
|
+
}
|
|
35334
|
+
return;
|
|
35168
35335
|
}
|
|
35169
|
-
|
|
35170
|
-
|
|
35171
|
-
|
|
35172
|
-
|
|
35173
|
-
process.stderr.write(`failproofai: found ${n} but could not raise a desktop notification (${outcome.reason})
|
|
35336
|
+
const outcome = await notifyDesktop(title, body, 0);
|
|
35337
|
+
delivered = outcome.ok;
|
|
35338
|
+
if (!outcome.ok) {
|
|
35339
|
+
process.stderr.write(`failproofai: found ${n} but could not raise a desktop notification (${outcome.reason})
|
|
35174
35340
|
`);
|
|
35341
|
+
}
|
|
35342
|
+
} finally {
|
|
35343
|
+
if (!delivered)
|
|
35344
|
+
releaseLeakNoticeClaims(claimed, undefined, "desktop");
|
|
35175
35345
|
}
|
|
35176
35346
|
}
|
|
35177
35347
|
async function runScheduledAudit() {
|
|
@@ -35365,6 +35535,8 @@ var init_cli2 = __esm(() => {
|
|
|
35365
35535
|
init_desktop_notify();
|
|
35366
35536
|
init_macos_notifier();
|
|
35367
35537
|
init_leak_notice();
|
|
35538
|
+
init_notice();
|
|
35539
|
+
init_leak_store();
|
|
35368
35540
|
init_fp_config();
|
|
35369
35541
|
init_tui();
|
|
35370
35542
|
init_package();
|
|
@@ -35825,7 +35997,7 @@ import { realpathSync as realpathSync7 } from "fs";
|
|
|
35825
35997
|
import { dirname as dirname25, resolve as resolve36 } from "path";
|
|
35826
35998
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
35827
35999
|
// package.json
|
|
35828
|
-
var version = "1.0.4-beta.
|
|
36000
|
+
var version = "1.0.4-beta.4";
|
|
35829
36001
|
|
|
35830
36002
|
// bin/failproofai.mjs
|
|
35831
36003
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
@@ -36070,7 +36242,7 @@ Run \`failproofai help\` for usage.`);
|
|
|
36070
36242
|
label: "see what it caught",
|
|
36071
36243
|
entries: [
|
|
36072
36244
|
["(no args)", "Open the policy dashboard on localhost:8020"],
|
|
36073
|
-
["audit", "
|
|
36245
|
+
["audit", "Find credentials your agents leaked, and get told about it"],
|
|
36074
36246
|
["config --status", "Cloud connection, daemon version, pause state"]
|
|
36075
36247
|
]
|
|
36076
36248
|
},
|