0sec-cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/0sec.js +40 -35
- package/README.md +9 -0
- package/chunks/{adapt-loop-ECQG7454.js → adapt-loop-SMH6V4PD.js} +4 -4
- package/chunks/{artifact-scraper-GJEZMOHF.js → artifact-scraper-HQ7HLP6V.js} +2 -2
- package/chunks/{assumption-mining-BVMMUZHB.js → assumption-mining-5SNIVVDN.js} +13 -13
- package/chunks/{chunk-SZJCPG2I.js → chunk-242TMK6G.js} +1 -1
- package/chunks/{chunk-HE7LCA7G.js → chunk-2JCCA2JL.js} +1 -1
- package/chunks/{chunk-SNKTC4BP.js → chunk-3KPWWJCI.js} +1 -1
- package/chunks/{chunk-IORC6MQX.js → chunk-5JI7L7KV.js} +1557 -145
- package/chunks/{chunk-KKGE5RQE.js → chunk-6L26OBWI.js} +1 -1
- package/chunks/{chunk-HT6P7RY3.js → chunk-72CISA2D.js} +1 -1
- package/chunks/{chunk-VGRDNSHA.js → chunk-AD7WXDH6.js} +3 -2
- package/chunks/{chunk-QOKTUOU2.js → chunk-ADOLI6DT.js} +1 -1
- package/chunks/{chunk-HDWV7PGI.js → chunk-AHTBZC3E.js} +2 -2
- package/chunks/{chunk-D6S3IIPG.js → chunk-ASUR522M.js} +3 -3
- package/chunks/{chunk-CLHCDHP4.js → chunk-ATATQACO.js} +1 -1
- package/chunks/{chunk-KTQDLNSR.js → chunk-BATRQBOR.js} +1 -1
- package/chunks/{chunk-K26SZ37E.js → chunk-BFR2CDV5.js} +7 -7
- package/chunks/{chunk-A6CLR72I.js → chunk-BFRB6HB2.js} +1 -1
- package/chunks/{chunk-H44E2CRN.js → chunk-BVAZO4WA.js} +1 -1
- package/chunks/{chunk-O462Y7P2.js → chunk-BZNEY2ZS.js} +334 -128
- package/chunks/{chunk-DN25OQQA.js → chunk-C2WXWFBB.js} +1 -1
- package/chunks/{chunk-QJQKHO7G.js → chunk-CMKXP5RR.js} +1 -1
- package/chunks/{chunk-2CJ776PV.js → chunk-GMT2AZKM.js} +23 -14
- package/chunks/{chunk-47TQJWDH.js → chunk-JQHOLLTD.js} +3 -3
- package/chunks/{chunk-MMLDQR4H.js → chunk-N7BOUYEV.js} +3 -3
- package/chunks/{chunk-QKICO43A.js → chunk-SVJEDVYK.js} +1 -1
- package/chunks/{chunk-3QFDYBZQ.js → chunk-TSK2AG6J.js} +18 -18
- package/chunks/{chunk-UJ4IK5PO.js → chunk-U5FLXGHT.js} +1 -1
- package/chunks/{chunk-SOG2U7B3.js → chunk-UCYRA73C.js} +1 -1
- package/chunks/{chunk-2SANI5RH.js → chunk-UR4ELX2Y.js} +61 -5
- package/chunks/{chunk-UM3ZNQIM.js → chunk-WEBMRWEG.js} +17 -9
- package/chunks/{chunk-RDZYQQLW.js → chunk-WXQ6BJ6A.js} +1 -1
- package/chunks/{chunk-4Y4KQJXE.js → chunk-XM5NLHYU.js} +6 -6
- package/chunks/{chunk-LOHTE223.js → chunk-YYRBQVFE.js} +1 -1
- package/chunks/{chunk-WKNNZVJS.js → chunk-Z5FA2XOX.js} +1 -1
- package/chunks/{commands-U3AMV5ZU.js → commands-TBC2F5CE.js} +635 -431
- package/chunks/{cost-ledger-ZCKMBJEN.js → cost-ledger-NU63MYZM.js} +2 -2
- package/chunks/{db-26NGQFKO.js → db-KFWOAUUB.js} +3 -3
- package/chunks/{disclose-A6AEIEDA.js → disclose-EKTWSCGW.js} +2 -2
- package/chunks/{dist-GL66KMUX.js → dist-4MAW5X6L.js} +2 -2
- package/chunks/{dist-FDKALV4R.js → dist-4YICS2J2.js} +29 -25
- package/chunks/{dist-JR67XKYO.js → dist-FMGSR3DW.js} +1 -1
- package/chunks/{eval-runner-DDLE5RQ3.js → eval-runner-7ZF472KV.js} +8 -8
- package/chunks/{exploit-agent-XP23ISN7.js → exploit-agent-45YQOHPJ.js} +1 -1
- package/chunks/{exploit-autoclimb-E6T7RRSC.js → exploit-autoclimb-UZGEMGYT.js} +1 -1
- package/chunks/{exploit-climb-2FAUP6XU.js → exploit-climb-SG23KB2G.js} +2 -2
- package/chunks/{harness-HWOYFKFY.js → harness-7ODOLOWU.js} +3 -3
- package/chunks/{hunt-scan-XPELSPQQ.js → hunt-scan-MMKUOETU.js} +11 -11
- package/chunks/{kernel-primitive-TENE3R7T.js → kernel-primitive-7U6CWHXD.js} +2 -2
- package/chunks/{kernel-vm-runner-4F6QSNFY.js → kernel-vm-runner-3JAU4O6J.js} +2 -2
- package/chunks/{native-loop-NTONUDP7.js → native-loop-RJCJPOUS.js} +7 -7
- package/chunks/{orchestrate-ZUWAUWBC.js → orchestrate-OC2VZN2X.js} +26 -26
- package/chunks/{pipeline-FCARFZU3.js → pipeline-BZK5BLJR.js} +2 -2
- package/chunks/{process-3Q7QJIOZ.js → process-LQRCS5OY.js} +3 -3
- package/chunks/{replay-runner-RRR4E2A7.js → replay-runner-45G3VU7X.js} +2 -2
- package/chunks/{run-ESNN4V5W.js → run-D56MPDKY.js} +324 -240
- package/chunks/{runtime-62ZQAH7H.js → runtime-G7YWIO3B.js} +5 -5
- package/chunks/{session-store-BCFQYDCE.js → session-store-GZ4A4KYT.js} +2 -2
- package/chunks/{variant-candidates-6KM6F6MD.js → variant-candidates-YERCYMPD.js} +3 -3
- package/chunks/{web-recon-prepass-DPVCBRZA.js → web-recon-prepass-JJGPEOLE.js} +3 -3
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
searchPublicReports,
|
|
16
16
|
searchSimilar,
|
|
17
17
|
searchTargetHistory
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-YYRBQVFE.js";
|
|
19
19
|
import {
|
|
20
20
|
runWpFingerprint,
|
|
21
21
|
summarizeWpFingerprint
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
loadJournal,
|
|
35
35
|
rehydrateContext,
|
|
36
36
|
renderSeedMessages
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-UCYRA73C.js";
|
|
38
38
|
import {
|
|
39
39
|
applyPatchOps,
|
|
40
40
|
parsePatch,
|
|
@@ -49,9 +49,10 @@ import {
|
|
|
49
49
|
} from "./chunk-RRMJC3ZE.js";
|
|
50
50
|
import {
|
|
51
51
|
hasKnownMarkerText,
|
|
52
|
+
redactAuthHeaders,
|
|
52
53
|
redactSensitiveHeaders,
|
|
53
54
|
require_dist
|
|
54
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-WEBMRWEG.js";
|
|
55
56
|
import {
|
|
56
57
|
ScopePolicy,
|
|
57
58
|
extractUrls,
|
|
@@ -62,11 +63,11 @@ import {
|
|
|
62
63
|
diag,
|
|
63
64
|
features,
|
|
64
65
|
loadCloudCredentials
|
|
65
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-UR4ELX2Y.js";
|
|
66
67
|
import {
|
|
67
68
|
eventBus,
|
|
68
69
|
isCloudEventSinkActive
|
|
69
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-ADOLI6DT.js";
|
|
70
71
|
import {
|
|
71
72
|
DEFAULT_ALLOW_MODEL_SELF_EXTENSION,
|
|
72
73
|
DEFAULT_AUTONOMY_MODE,
|
|
@@ -77,7 +78,7 @@ import {
|
|
|
77
78
|
getRates,
|
|
78
79
|
homeStateDir,
|
|
79
80
|
resolveIdentities
|
|
80
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-6L26OBWI.js";
|
|
81
82
|
import {
|
|
82
83
|
external_exports
|
|
83
84
|
} from "./chunk-YLMN3N25.js";
|
|
@@ -6631,7 +6632,7 @@ function redactAuthValues(value, secrets) {
|
|
|
6631
6632
|
}
|
|
6632
6633
|
return redacted;
|
|
6633
6634
|
}
|
|
6634
|
-
function
|
|
6635
|
+
function redactAuthHeaders2(headers, secrets) {
|
|
6635
6636
|
const secretSet = new Set(secrets);
|
|
6636
6637
|
return Object.fromEntries(Object.entries(headers).map(([name, value]) => [
|
|
6637
6638
|
name,
|
|
@@ -13403,9 +13404,9 @@ async function executeDeepSourceReview(ctx, args) {
|
|
|
13403
13404
|
const { statSync: statSync6 } = await import("node:fs");
|
|
13404
13405
|
const { prepare } = await import("./prepare-MYY743TK.js");
|
|
13405
13406
|
const { collectScopeFiles, countScopeFilesUpTo } = await import("./source-files-PWRQR6LY.js");
|
|
13406
|
-
const { runHuntScan, makeMultiLensVerifier } = await import("./hunt-scan-
|
|
13407
|
+
const { runHuntScan, makeMultiLensVerifier } = await import("./hunt-scan-MMKUOETU.js");
|
|
13407
13408
|
const { loadAppsecFinderLenses } = await import("./appsec-catalog-CBWHGTEL.js");
|
|
13408
|
-
const { ScanCostLedger } = await import("./cost-ledger-
|
|
13409
|
+
const { ScanCostLedger } = await import("./cost-ledger-NU63MYZM.js");
|
|
13409
13410
|
let resolvedTarget;
|
|
13410
13411
|
try {
|
|
13411
13412
|
resolvedTarget = scopedPath(ctx, target);
|
|
@@ -13511,8 +13512,8 @@ async function executeFileSecurityReview(ctx, args) {
|
|
|
13511
13512
|
if (!target)
|
|
13512
13513
|
return errResult("`target` is required (a repo root path)");
|
|
13513
13514
|
const { resolve: resolve15 } = await import("node:path");
|
|
13514
|
-
const { createRuntime } = await import("./runtime-
|
|
13515
|
-
const { runFileReviewPipeline } = await import("./pipeline-
|
|
13515
|
+
const { createRuntime } = await import("./runtime-G7YWIO3B.js");
|
|
13516
|
+
const { runFileReviewPipeline } = await import("./pipeline-BZK5BLJR.js");
|
|
13516
13517
|
let rootPath;
|
|
13517
13518
|
try {
|
|
13518
13519
|
rootPath = resolve15(scopedPath(ctx, target));
|
|
@@ -13547,8 +13548,8 @@ async function executeFileSecurityReview(ctx, args) {
|
|
|
13547
13548
|
};
|
|
13548
13549
|
}
|
|
13549
13550
|
async function executeAssembleAdvisory(_ctx, args) {
|
|
13550
|
-
const { osecDB } = await import("./dist-
|
|
13551
|
-
const { renderAdvisoryMarkdown, assembleEvidencePack, decideFilingState, renderVendorNotificationMarkdown, EmptyPocError, UnreproducedFindingError } = await import("./disclose-
|
|
13551
|
+
const { osecDB } = await import("./dist-4MAW5X6L.js");
|
|
13552
|
+
const { renderAdvisoryMarkdown, assembleEvidencePack, decideFilingState, renderVendorNotificationMarkdown, EmptyPocError, UnreproducedFindingError } = await import("./disclose-EKTWSCGW.js");
|
|
13552
13553
|
const dbPath = typeof args.db_path === "string" && args.db_path.trim() ? args.db_path.trim() : void 0;
|
|
13553
13554
|
const scanId = typeof args.scan_id === "string" && args.scan_id.trim() ? args.scan_id.trim() : void 0;
|
|
13554
13555
|
const findingId = typeof args.finding_id === "string" && args.finding_id.trim() ? args.finding_id.trim() : void 0;
|
|
@@ -13654,7 +13655,7 @@ function rowToAdvisoryFinding(row) {
|
|
|
13654
13655
|
return finding;
|
|
13655
13656
|
}
|
|
13656
13657
|
async function executeCveLookup(_ctx, args) {
|
|
13657
|
-
const { findCveArtifacts, normaliseCveId } = await import("./artifact-scraper-
|
|
13658
|
+
const { findCveArtifacts, normaliseCveId } = await import("./artifact-scraper-HQ7HLP6V.js");
|
|
13658
13659
|
const rawCve = String(args.cve ?? args.cve_id ?? "").trim();
|
|
13659
13660
|
if (!rawCve)
|
|
13660
13661
|
return errResult("`cve` is required, e.g. CVE-2024-1086");
|
|
@@ -13861,8 +13862,8 @@ function refuseOutOfScope(ctx, url) {
|
|
|
13861
13862
|
return null;
|
|
13862
13863
|
}
|
|
13863
13864
|
async function loadPersistedFinding(findingId, dbPathArg) {
|
|
13864
|
-
const { osecDB, resolveOsecDbPath, listOsecRunDatabasePaths } = await import("./dist-
|
|
13865
|
-
const { findingSchema, formatZodError } = await import("./dist-
|
|
13865
|
+
const { osecDB, resolveOsecDbPath, listOsecRunDatabasePaths } = await import("./dist-4MAW5X6L.js");
|
|
13866
|
+
const { findingSchema, formatZodError } = await import("./dist-FMGSR3DW.js");
|
|
13866
13867
|
const { resolve: resolve15 } = await import("node:path");
|
|
13867
13868
|
const { existsSync: existsSync9 } = await import("node:fs");
|
|
13868
13869
|
const requestedId = findingId.trim();
|
|
@@ -13987,8 +13988,8 @@ async function executeVariantHunt(ctx, args) {
|
|
|
13987
13988
|
return errResult2("`source` is required (a source tree path or git URL)");
|
|
13988
13989
|
const { resolve: resolve15, join: join20 } = await import("node:path");
|
|
13989
13990
|
const { prepare } = await import("./prepare-MYY743TK.js");
|
|
13990
|
-
const { generateVariantCandidates } = await import("./variant-candidates-
|
|
13991
|
-
const { runHuntScan, makeSkepticVerifier } = await import("./hunt-scan-
|
|
13991
|
+
const { generateVariantCandidates } = await import("./variant-candidates-YERCYMPD.js");
|
|
13992
|
+
const { runHuntScan, makeSkepticVerifier } = await import("./hunt-scan-MMKUOETU.js");
|
|
13992
13993
|
let resolvedTarget;
|
|
13993
13994
|
try {
|
|
13994
13995
|
resolvedTarget = scopedPath2(ctx, target);
|
|
@@ -14054,8 +14055,8 @@ async function executeAssumptionHunt(ctx, args) {
|
|
|
14054
14055
|
const { tmpdir: tmpdir5 } = await import("node:os");
|
|
14055
14056
|
const { prepare } = await import("./prepare-MYY743TK.js");
|
|
14056
14057
|
const { collectScopeFiles } = await import("./source-files-PWRQR6LY.js");
|
|
14057
|
-
const { runAssumptionHunt } = await import("./assumption-mining-
|
|
14058
|
-
const { makeSkepticVerifier } = await import("./hunt-scan-
|
|
14058
|
+
const { runAssumptionHunt } = await import("./assumption-mining-5SNIVVDN.js");
|
|
14059
|
+
const { makeSkepticVerifier } = await import("./hunt-scan-MMKUOETU.js");
|
|
14059
14060
|
let resolvedTarget;
|
|
14060
14061
|
try {
|
|
14061
14062
|
resolvedTarget = scopedPath2(ctx, target);
|
|
@@ -14135,7 +14136,7 @@ async function executeGenerateFix(ctx, args) {
|
|
|
14135
14136
|
return errResult2("`repo` is required (the repo root the patch applies to) \u2014 no scoped source path is set to default to.");
|
|
14136
14137
|
const { resolve: resolve15 } = await import("node:path");
|
|
14137
14138
|
const { runSourceFix } = await import("./fix-IG7LYXH3.js");
|
|
14138
|
-
const { LlmApiRuntime: LlmApiRuntime2 } = await import("./runtime-
|
|
14139
|
+
const { LlmApiRuntime: LlmApiRuntime2 } = await import("./runtime-G7YWIO3B.js");
|
|
14139
14140
|
const loaded = await loadPersistedFinding(findingId, typeof args.db_path === "string" ? args.db_path : void 0);
|
|
14140
14141
|
if ("error" in loaded)
|
|
14141
14142
|
return errResult2(loaded.error);
|
|
@@ -14192,8 +14193,8 @@ async function executeVerifyFinding(ctx, args) {
|
|
|
14192
14193
|
const loaded = await loadPersistedFinding(findingId, typeof args.db_path === "string" ? args.db_path : void 0);
|
|
14193
14194
|
if ("error" in loaded)
|
|
14194
14195
|
return errResult2(loaded.error);
|
|
14195
|
-
const { runDeterministicReplay, LocalShellRunner } = await import("./replay-runner-
|
|
14196
|
-
const { VERSION: VERSION2 } = await import("./dist-
|
|
14196
|
+
const { runDeterministicReplay, LocalShellRunner } = await import("./replay-runner-45G3VU7X.js");
|
|
14197
|
+
const { VERSION: VERSION2 } = await import("./dist-FMGSR3DW.js");
|
|
14197
14198
|
let outcome;
|
|
14198
14199
|
try {
|
|
14199
14200
|
outcome = await runDeterministicReplay(loaded.finding, {
|
|
@@ -14239,7 +14240,7 @@ async function executeProtocolConformance(ctx, args) {
|
|
|
14239
14240
|
return errResult2(denial);
|
|
14240
14241
|
const { runHttpConformanceCheck } = await import("./http-conformance-DU66MZIU.js");
|
|
14241
14242
|
const { createLiveHttpSender } = await import("./http-sender-GWH2IYEA.js");
|
|
14242
|
-
const { LlmApiRuntime: LlmApiRuntime2 } = await import("./runtime-
|
|
14243
|
+
const { LlmApiRuntime: LlmApiRuntime2 } = await import("./runtime-G7YWIO3B.js");
|
|
14243
14244
|
const llm = new LlmApiRuntime2({ type: "api", timeout: 6e4 });
|
|
14244
14245
|
const send = createLiveHttpSender();
|
|
14245
14246
|
const protocol = {
|
|
@@ -14378,7 +14379,7 @@ async function executeSafetyEval(ctx, args) {
|
|
|
14378
14379
|
const denial = refuseOutOfScope(ctx, target);
|
|
14379
14380
|
if (denial)
|
|
14380
14381
|
return errResult2(denial);
|
|
14381
|
-
const { runEval } = await import("./eval-runner-
|
|
14382
|
+
const { runEval } = await import("./eval-runner-7ZF472KV.js");
|
|
14382
14383
|
const categories = Array.isArray(args.categories) ? args.categories.map((c) => String(c)).filter(Boolean) : void 0;
|
|
14383
14384
|
const timeout = typeof args.timeout_ms === "number" && args.timeout_ms > 0 ? args.timeout_ms : void 0;
|
|
14384
14385
|
let scorecard;
|
|
@@ -14557,14 +14558,14 @@ async function executeWeaponizeKernel(ctx, args) {
|
|
|
14557
14558
|
if (!hasEngagementScope(ctx)) {
|
|
14558
14559
|
return errResult2("weaponize_kernel requires an active engagement scope. It is not available for a no-scope session.");
|
|
14559
14560
|
}
|
|
14560
|
-
const { runWeaponization, kernelVmArtifactsReady } = await import("./harness-
|
|
14561
|
+
const { runWeaponization, kernelVmArtifactsReady } = await import("./harness-7ODOLOWU.js");
|
|
14561
14562
|
if (!kernelVmArtifactsReady()) {
|
|
14562
14563
|
return errResult2("weaponize_kernel is denied: kernel-VM artifacts are not present. It only ever runs inside a DISPOSABLE kernel VM \u2014 set 0SEC_KERNEL_QEMU_KERNEL and 0SEC_KERNEL_QEMU_DISK to existing image paths. Refusing to run without the VM.");
|
|
14563
14564
|
}
|
|
14564
14565
|
const dmesg = typeof args.dmesg === "string" ? args.dmesg : "";
|
|
14565
14566
|
if (!dmesg.trim())
|
|
14566
14567
|
return errResult2("`dmesg` is required (the kernel crash log / KASAN splat to weaponize).");
|
|
14567
|
-
const { classifyPrimitiveFromDmesg } = await import("./kernel-primitive-
|
|
14568
|
+
const { classifyPrimitiveFromDmesg } = await import("./kernel-primitive-7U6CWHXD.js");
|
|
14568
14569
|
const crashType = typeof args.crash_type === "string" && args.crash_type.trim() ? args.crash_type.trim() : void 0;
|
|
14569
14570
|
const primitive = classifyPrimitiveFromDmesg(dmesg, crashType);
|
|
14570
14571
|
const reproducer = typeof args.reproducer === "string" && args.reproducer.trim() ? args.reproducer : void 0;
|
|
@@ -14599,12 +14600,12 @@ async function executeCveAdapt(ctx, args) {
|
|
|
14599
14600
|
if (!hasEngagementScope(ctx)) {
|
|
14600
14601
|
return errResult2("cve_adapt requires an active engagement scope. It is not available for a no-scope session.");
|
|
14601
14602
|
}
|
|
14602
|
-
const { kernelVmArtifactsReady } = await import("./harness-
|
|
14603
|
+
const { kernelVmArtifactsReady } = await import("./harness-7ODOLOWU.js");
|
|
14603
14604
|
if (!kernelVmArtifactsReady()) {
|
|
14604
14605
|
return errResult2("cve_adapt is denied: its default verification boots a kernel VM and kernel-VM artifacts are not present. Set 0SEC_KERNEL_QEMU_KERNEL and 0SEC_KERNEL_QEMU_DISK to existing image paths. Refusing to run without the VM.");
|
|
14605
14606
|
}
|
|
14606
|
-
const { adaptAndVerify } = await import("./adapt-loop-
|
|
14607
|
-
const { findCveArtifacts, normaliseCveId } = await import("./artifact-scraper-
|
|
14607
|
+
const { adaptAndVerify } = await import("./adapt-loop-SMH6V4PD.js");
|
|
14608
|
+
const { findCveArtifacts, normaliseCveId } = await import("./artifact-scraper-HQ7HLP6V.js");
|
|
14608
14609
|
const rawCve = String(args.cve ?? "").trim();
|
|
14609
14610
|
if (!rawCve)
|
|
14610
14611
|
return errResult2("`cve` is required, e.g. CVE-2024-1086.");
|
|
@@ -19682,10 +19683,10 @@ var ToolExecutor = class _ToolExecutor {
|
|
|
19682
19683
|
const responseHeaders = Object.fromEntries(chosen.res.headers.entries());
|
|
19683
19684
|
const safeResponseBody = redactAuthValues(chosen.body, sensitiveValues);
|
|
19684
19685
|
const safeRequestBody = body ? redactAuthValues(body, sensitiveValues) : void 0;
|
|
19685
|
-
const safeSentHeaders =
|
|
19686
|
+
const safeSentHeaders = redactAuthHeaders2(chosen.sentHeaders, sensitiveValues);
|
|
19686
19687
|
const output = {
|
|
19687
19688
|
status: chosen.res.status,
|
|
19688
|
-
headers:
|
|
19689
|
+
headers: redactAuthHeaders2(responseHeaders, sensitiveValues),
|
|
19689
19690
|
body: safeResponseBody.slice(0, 1e4)
|
|
19690
19691
|
// cap response size
|
|
19691
19692
|
};
|
|
@@ -20091,11 +20092,11 @@ var ToolExecutor = class _ToolExecutor {
|
|
|
20091
20092
|
const safeBody = redactAuthValues(text2, sensitiveValues);
|
|
20092
20093
|
const output = {
|
|
20093
20094
|
status: res.status,
|
|
20094
|
-
headers:
|
|
20095
|
+
headers: redactAuthHeaders2(responseHeaders, sensitiveValues),
|
|
20095
20096
|
body: safeBody.slice(0, 1e4)
|
|
20096
20097
|
};
|
|
20097
20098
|
this.persistToolArtifact("submit_form", {
|
|
20098
|
-
request: { url: fetchUrl, method, headers:
|
|
20099
|
+
request: { url: fetchUrl, method, headers: redactAuthHeaders2(sentHeaders, sensitiveValues), fields },
|
|
20099
20100
|
response: { status: output.status, body: output.body.slice(0, 5e3) }
|
|
20100
20101
|
});
|
|
20101
20102
|
return { success: true, output };
|
|
@@ -21433,7 +21434,7 @@ var ToolExecutor = class _ToolExecutor {
|
|
|
21433
21434
|
* inside `runNativeAgentLoop`), so this is effectively free.
|
|
21434
21435
|
*/
|
|
21435
21436
|
async loadSubagentDeps() {
|
|
21436
|
-
const { runNativeAgentLoop: runNativeAgentLoop2 } = await import("./native-loop-
|
|
21437
|
+
const { runNativeAgentLoop: runNativeAgentLoop2 } = await import("./native-loop-RJCJPOUS.js");
|
|
21437
21438
|
return { runNativeAgentLoop: runNativeAgentLoop2 };
|
|
21438
21439
|
}
|
|
21439
21440
|
async runOneSubagent(task, maxTurns, base, deps, messagingOverride, selection, admittedLease, sharedContext) {
|
|
@@ -24912,7 +24913,7 @@ import { randomUUID as randomUUID14 } from "node:crypto";
|
|
|
24912
24913
|
import { closeSync as closeSync7, fsyncSync as fsyncSync6, lstatSync as lstatSync5, openSync as openSync7, readFileSync as readFileSync13, renameSync as renameSync4, unlinkSync as unlinkSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24913
24914
|
import { chmod as chmod2, mkdir as mkdir4, mkdtemp as mkdtemp4, realpath as realpath2, rm as rm4, writeFile as writeFile3 } from "node:fs/promises";
|
|
24914
24915
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
24915
|
-
import { dirname as dirname5, join as join15, resolve as resolve12 } from "node:path";
|
|
24916
|
+
import { dirname as dirname5, extname as extname2, join as join15, resolve as resolve12 } from "node:path";
|
|
24916
24917
|
|
|
24917
24918
|
// packages/core/dist/improvement/loop.js
|
|
24918
24919
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
@@ -26952,7 +26953,7 @@ function resolveAnalyticsLevel(env = process.env) {
|
|
|
26952
26953
|
}
|
|
26953
26954
|
const raw = env[ANALYTICS_LEVEL_ENV];
|
|
26954
26955
|
if (typeof raw !== "string")
|
|
26955
|
-
return "
|
|
26956
|
+
return "full";
|
|
26956
26957
|
const normalized = raw.trim().toLowerCase();
|
|
26957
26958
|
return isAnalyticsLevel(normalized) ? normalized : "off";
|
|
26958
26959
|
}
|
|
@@ -26993,46 +26994,145 @@ var REDACTED_SLACK = "<REDACTED-SLACK>";
|
|
|
26993
26994
|
var REDACTED_JWT = "<REDACTED-JWT>";
|
|
26994
26995
|
var REDACTED_PEM = "<REDACTED-PEM>";
|
|
26995
26996
|
var REDACTED_SECRET = "<REDACTED-SECRET>";
|
|
26996
|
-
var REDACTED_EMAIL = "<REDACTED-EMAIL>";
|
|
26997
26997
|
var DEFAULT_REDACTION_CAP = 4e3;
|
|
26998
|
+
var MAX_CONTENT_BYTES = 262144;
|
|
26998
26999
|
var PEM_RE = /-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9 ]+ )?PRIVATE KEY-----/g;
|
|
26999
27000
|
var OPENAI_RE = /\bsk-[A-Za-z0-9_-]{16,}/g;
|
|
27000
|
-
var GH_RE = /\
|
|
27001
|
+
var GH_RE = /\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})/g;
|
|
27001
27002
|
var AWS_RE = /\b(?:AKIA|ASIA|ABIA|ACCA)[0-9A-Z]{16}\b/g;
|
|
27002
27003
|
var GCP_RE = /\bAIza[0-9A-Za-z_-]{35}\b/g;
|
|
27003
27004
|
var SLACK_RE = /\bxox[abprs]-[A-Za-z0-9-]{10,}/g;
|
|
27004
|
-
var JWT_RE = /\beyJ[A-Za-z0-9_-]
|
|
27005
|
-
var CONN_STRING_RE = /\b([a-z][a-z0-9+.-]
|
|
27006
|
-
var
|
|
27007
|
-
var
|
|
27008
|
-
var
|
|
27009
|
-
var
|
|
27005
|
+
var JWT_RE = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
|
|
27006
|
+
var CONN_STRING_RE = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s:/?#"'`]+:[^\s/?#"'`]*@/gi;
|
|
27007
|
+
var CREDENTIAL_NAME = "password|passwd|pwd|secret|token|credentials?|api[_-]?key|access[_-]?key(?:[_-]?id)?|private[_-]?key|client[_-]?secret|(?:access|refresh|auth|session|bearer|api|csrf|xsrf)[_-]?token|session[_-]?cookie|authorization|proxy[_-]?authorization|cookie|set[_-]?cookie";
|
|
27008
|
+
var CREDENTIAL_KEY_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${CREDENTIAL_NAME})$`, "i");
|
|
27009
|
+
var HEADER_RE = /^(?:authorization|proxy-authorization|cookie|set-cookie|x-auth-token|x-api-key|x-csrf-token|x-xsrf-token)$/i;
|
|
27010
|
+
var ASSIGNMENT_RE = /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\b[A-Za-z_][A-Za-z0-9_-]*)(\s*[:=]\s*)("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s"'\x60,;{}[\]&#\\]+)/g;
|
|
27011
|
+
var QUOTED_RE = /"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g;
|
|
27012
|
+
function credentialKey(name) {
|
|
27013
|
+
return CREDENTIAL_KEY_RE.test(name.replace(/([a-z0-9])([A-Z])/g, "$1_$2"));
|
|
27014
|
+
}
|
|
27010
27015
|
function truncate3(s, max) {
|
|
27011
|
-
return s.length <= max ? s : `${s.slice(0, max)}
|
|
27016
|
+
return s.length <= max ? s : `${s.slice(0, Math.max(0, max - 3))}${".".repeat(Math.min(3, max))}`;
|
|
27017
|
+
}
|
|
27018
|
+
function jsonValueEnd(text2, start) {
|
|
27019
|
+
let depth = 0;
|
|
27020
|
+
let quoted = false;
|
|
27021
|
+
for (let i = start; i < text2.length; i++) {
|
|
27022
|
+
const char = text2[i];
|
|
27023
|
+
if (quoted) {
|
|
27024
|
+
if (char === "\\")
|
|
27025
|
+
i++;
|
|
27026
|
+
else if (char === '"') {
|
|
27027
|
+
quoted = false;
|
|
27028
|
+
if (depth === 0)
|
|
27029
|
+
return i + 1;
|
|
27030
|
+
}
|
|
27031
|
+
} else if (char === '"')
|
|
27032
|
+
quoted = true;
|
|
27033
|
+
else if (char === "{" || char === "[")
|
|
27034
|
+
depth++;
|
|
27035
|
+
else if (char === "}" || char === "]") {
|
|
27036
|
+
if (depth === 0)
|
|
27037
|
+
return i;
|
|
27038
|
+
if (--depth === 0)
|
|
27039
|
+
return i + 1;
|
|
27040
|
+
} else if (depth === 0 && (char === "," || /\s/.test(char)))
|
|
27041
|
+
return i;
|
|
27042
|
+
}
|
|
27043
|
+
return text2.length;
|
|
27044
|
+
}
|
|
27045
|
+
function redactPlain(text2, ctx) {
|
|
27046
|
+
const secrets = ctx.authSecretValues ?? [];
|
|
27047
|
+
let out = secrets.length > 0 ? redactAuthValues(text2, secrets) : text2;
|
|
27048
|
+
out = redactAuthHeaders(out);
|
|
27049
|
+
out = out.replace(OPENAI_RE, REDACTED_OPENAI);
|
|
27050
|
+
out = out.replace(GH_RE, REDACTED_GH);
|
|
27051
|
+
out = out.replace(AWS_RE, REDACTED_AWS);
|
|
27052
|
+
out = out.replace(GCP_RE, REDACTED_GCP);
|
|
27053
|
+
out = out.replace(SLACK_RE, REDACTED_SLACK);
|
|
27054
|
+
out = out.replace(JWT_RE, REDACTED_JWT);
|
|
27055
|
+
return out.replace(CONN_STRING_RE, `$1${REDACTED_SECRET}@`);
|
|
27012
27056
|
}
|
|
27013
27057
|
function redactContent(text2, ctx = {}) {
|
|
27014
27058
|
try {
|
|
27015
27059
|
if (typeof text2 !== "string" || text2.length === 0)
|
|
27016
27060
|
return "";
|
|
27017
|
-
let out = text2;
|
|
27018
|
-
const secrets = ctx.authSecretValues ?? [];
|
|
27019
|
-
if (secrets.length > 0)
|
|
27020
|
-
out = redactAuthValues(out, secrets);
|
|
27021
|
-
out = redactSensitiveHeaders(out);
|
|
27022
|
-
out = out.replace(PEM_RE, REDACTED_PEM);
|
|
27023
|
-
out = out.replace(OPENAI_RE, REDACTED_OPENAI);
|
|
27024
|
-
out = out.replace(GH_RE, REDACTED_GH);
|
|
27025
|
-
out = out.replace(AWS_RE, REDACTED_AWS);
|
|
27026
|
-
out = out.replace(GCP_RE, REDACTED_GCP);
|
|
27027
|
-
out = out.replace(SLACK_RE, REDACTED_SLACK);
|
|
27028
|
-
out = out.replace(JWT_RE, REDACTED_JWT);
|
|
27029
|
-
out = out.replace(CONN_STRING_RE, `$1://${REDACTED_SECRET}@`);
|
|
27030
|
-
out = out.replace(ASSIGNMENT_RE, `$1$2${REDACTED_SECRET}`);
|
|
27031
|
-
out = out.replace(ENV_SECRET_LINE_RE, `$1$2${REDACTED_SECRET}`);
|
|
27032
|
-
out = out.replace(EMAIL_RE, REDACTED_EMAIL);
|
|
27033
|
-
out = out.replace(ENTROPY_RE, REDACTED_SECRET);
|
|
27034
27061
|
const cap = ctx.maxChars ?? DEFAULT_REDACTION_CAP;
|
|
27035
|
-
|
|
27062
|
+
const contentContext = ctx.maxChars === Number.POSITIVE_INFINITY ? ctx : { ...ctx, maxChars: Number.POSITIVE_INFINITY };
|
|
27063
|
+
if (/^\s*[[{]/.test(text2)) {
|
|
27064
|
+
let validJson = false;
|
|
27065
|
+
try {
|
|
27066
|
+
JSON.parse(text2);
|
|
27067
|
+
validJson = true;
|
|
27068
|
+
} catch (error) {
|
|
27069
|
+
if (!(error instanceof SyntaxError))
|
|
27070
|
+
throw error;
|
|
27071
|
+
}
|
|
27072
|
+
if (validJson) {
|
|
27073
|
+
let out2 = "";
|
|
27074
|
+
let cursor2 = 0;
|
|
27075
|
+
for (const match of text2.matchAll(QUOTED_RE)) {
|
|
27076
|
+
if (match.index < cursor2)
|
|
27077
|
+
continue;
|
|
27078
|
+
const token = match[0];
|
|
27079
|
+
const decoded = JSON.parse(token);
|
|
27080
|
+
const clean = redactContent(decoded, contentContext);
|
|
27081
|
+
const end = match.index + token.length;
|
|
27082
|
+
if (clean !== decoded) {
|
|
27083
|
+
out2 += text2.slice(cursor2, match.index) + JSON.stringify(clean);
|
|
27084
|
+
cursor2 = end;
|
|
27085
|
+
}
|
|
27086
|
+
let next = end;
|
|
27087
|
+
while (/\s/.test(text2[next] ?? ""))
|
|
27088
|
+
next++;
|
|
27089
|
+
if (text2[next] !== ":" || !credentialKey(decoded))
|
|
27090
|
+
continue;
|
|
27091
|
+
next++;
|
|
27092
|
+
while (/\s/.test(text2[next] ?? ""))
|
|
27093
|
+
next++;
|
|
27094
|
+
out2 += text2.slice(cursor2, next) + JSON.stringify(REDACTED_SECRET);
|
|
27095
|
+
cursor2 = jsonValueEnd(text2, next);
|
|
27096
|
+
}
|
|
27097
|
+
return truncate3(out2 + text2.slice(cursor2), cap);
|
|
27098
|
+
}
|
|
27099
|
+
}
|
|
27100
|
+
const assigned = text2.replace(PEM_RE, REDACTED_PEM).replace(ASSIGNMENT_RE, (match, key, separator, value) => {
|
|
27101
|
+
let name = key.startsWith('"') || key.startsWith("'") ? key.slice(1, -1) : key;
|
|
27102
|
+
if (key.startsWith('"')) {
|
|
27103
|
+
try {
|
|
27104
|
+
name = JSON.parse(key);
|
|
27105
|
+
} catch (error) {
|
|
27106
|
+
if (!(error instanceof SyntaxError))
|
|
27107
|
+
throw error;
|
|
27108
|
+
}
|
|
27109
|
+
}
|
|
27110
|
+
if (!credentialKey(name))
|
|
27111
|
+
return match;
|
|
27112
|
+
const quote = value[0] === '"' || value[0] === "'" ? value[0] : "";
|
|
27113
|
+
if (!quote && separator.includes(":") && HEADER_RE.test(name))
|
|
27114
|
+
return match;
|
|
27115
|
+
return `${key}${separator}${quote}${REDACTED_SECRET}${quote}`;
|
|
27116
|
+
});
|
|
27117
|
+
let out = "";
|
|
27118
|
+
let cursor = 0;
|
|
27119
|
+
for (const match of assigned.matchAll(QUOTED_RE)) {
|
|
27120
|
+
out += redactPlain(assigned.slice(cursor, match.index), ctx);
|
|
27121
|
+
const token = match[0];
|
|
27122
|
+
let decoded = token.slice(1, -1);
|
|
27123
|
+
if (token[0] === '"') {
|
|
27124
|
+
try {
|
|
27125
|
+
decoded = JSON.parse(token);
|
|
27126
|
+
} catch (error) {
|
|
27127
|
+
if (!(error instanceof SyntaxError))
|
|
27128
|
+
throw error;
|
|
27129
|
+
}
|
|
27130
|
+
}
|
|
27131
|
+
const clean = redactContent(decoded, contentContext);
|
|
27132
|
+
out += clean === decoded ? token : token[0] === '"' ? JSON.stringify(clean) : `'${clean}'`;
|
|
27133
|
+
cursor = match.index + token.length;
|
|
27134
|
+
}
|
|
27135
|
+
return truncate3(out + redactPlain(assigned.slice(cursor), ctx), cap);
|
|
27036
27136
|
} catch {
|
|
27037
27137
|
return "";
|
|
27038
27138
|
}
|
|
@@ -27045,6 +27145,8 @@ var ANALYTICS_SENT_LOG_FILENAME = "analytics-sent.log";
|
|
|
27045
27145
|
var TRANSMIT_TIMEOUT_MS = 4e3;
|
|
27046
27146
|
var USAGE_FLUSH_DEBOUNCE_MS = 2e3;
|
|
27047
27147
|
var TRANSMIT_DEBOUNCE_MS = 500;
|
|
27148
|
+
var MAX_RECORDS_PER_BATCH = 100;
|
|
27149
|
+
var MAX_BODY_BYTES = 1048576;
|
|
27048
27150
|
var FINITE_PLATFORMS = /* @__PURE__ */ new Set([
|
|
27049
27151
|
"darwin",
|
|
27050
27152
|
"linux",
|
|
@@ -27106,6 +27208,10 @@ function classifyFailureText(text2) {
|
|
|
27106
27208
|
return "stream-incomplete";
|
|
27107
27209
|
return null;
|
|
27108
27210
|
}
|
|
27211
|
+
var CONTENT_FIELDS = ["argsRedacted", "outputRedacted", "sourceRedacted"];
|
|
27212
|
+
var BODY_PREFIX = '{"records":[';
|
|
27213
|
+
var BODY_SUFFIX = "]}";
|
|
27214
|
+
var BODY_OVERHEAD_BYTES = BODY_PREFIX.length + BODY_SUFFIX.length;
|
|
27109
27215
|
function redactRecordStrings(value) {
|
|
27110
27216
|
try {
|
|
27111
27217
|
if (typeof value === "string")
|
|
@@ -27113,16 +27219,16 @@ function redactRecordStrings(value) {
|
|
|
27113
27219
|
if (Array.isArray(value))
|
|
27114
27220
|
return value.map((v) => redactRecordStrings(v));
|
|
27115
27221
|
if (value && typeof value === "object") {
|
|
27116
|
-
const out =
|
|
27222
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
27117
27223
|
for (const [k, v] of Object.entries(value)) {
|
|
27118
27224
|
const rk = redactContent(k) || "<redacted-key>";
|
|
27119
|
-
out[rk] = redactRecordStrings(v);
|
|
27225
|
+
out[rk] = typeof v === "string" && CONTENT_FIELDS.includes(k) ? redactContent(v, { maxChars: Number.POSITIVE_INFINITY }) : redactRecordStrings(v);
|
|
27120
27226
|
}
|
|
27121
27227
|
return out;
|
|
27122
27228
|
}
|
|
27123
27229
|
return value;
|
|
27124
27230
|
} catch {
|
|
27125
|
-
return
|
|
27231
|
+
return void 0;
|
|
27126
27232
|
}
|
|
27127
27233
|
}
|
|
27128
27234
|
function toText(value) {
|
|
@@ -27162,12 +27268,19 @@ function bump(map, key) {
|
|
|
27162
27268
|
}
|
|
27163
27269
|
var AnalyticsPipeline = class {
|
|
27164
27270
|
level = "off";
|
|
27271
|
+
observedLevel = "off";
|
|
27272
|
+
transmitting = null;
|
|
27165
27273
|
homeDir;
|
|
27166
27274
|
fetchImpl;
|
|
27167
27275
|
installId = null;
|
|
27168
27276
|
sessionId = newSessionId();
|
|
27169
27277
|
acc = emptyAccumulator();
|
|
27170
27278
|
accDirty = false;
|
|
27279
|
+
/**
|
|
27280
|
+
* Queued payload + the tier it was enqueued at. The tier is kept so on
|
|
27281
|
+
* downgrade we can purge records that are no longer permitted, and so
|
|
27282
|
+
* transmit can re-check each record against the live level.
|
|
27283
|
+
*/
|
|
27171
27284
|
batch = [];
|
|
27172
27285
|
usageFlushTimer = null;
|
|
27173
27286
|
transmitTimer = null;
|
|
@@ -27183,15 +27296,59 @@ var AnalyticsPipeline = class {
|
|
|
27183
27296
|
if (opts.fetchImpl !== void 0)
|
|
27184
27297
|
this.fetchImpl = opts.fetchImpl;
|
|
27185
27298
|
}
|
|
27186
|
-
/**
|
|
27299
|
+
/**
|
|
27300
|
+
* Update the cached consent tier live (e.g. a /settings change).
|
|
27301
|
+
*
|
|
27302
|
+
* Downgrading the level purges any queued records that are no longer
|
|
27303
|
+
* permitted. Switching to "off" also unsubscribes the bus sink and resets
|
|
27304
|
+
* the usage accumulator so events emitted while off are never queued.
|
|
27305
|
+
* Switching from "off" to a non-off level subscribes the sink with a fresh
|
|
27306
|
+
* accumulator.
|
|
27307
|
+
*/
|
|
27187
27308
|
setLevel(level) {
|
|
27309
|
+
const wasOff = this.level === "off";
|
|
27310
|
+
if (!levelAtLeast(level, this.level)) {
|
|
27311
|
+
this.batch = this.batch.filter((entry) => levelAtLeast(level, entry.requiredTier));
|
|
27312
|
+
}
|
|
27188
27313
|
this.level = level;
|
|
27189
|
-
|
|
27314
|
+
this.effectiveLevel();
|
|
27315
|
+
if (level === "off") {
|
|
27316
|
+
this.unsubscribe?.();
|
|
27317
|
+
this.unsubscribe = null;
|
|
27318
|
+
this.acc = emptyAccumulator();
|
|
27319
|
+
this.accDirty = false;
|
|
27320
|
+
this.batch = [];
|
|
27321
|
+
} else {
|
|
27322
|
+
if (wasOff) {
|
|
27323
|
+
this.acc = emptyAccumulator();
|
|
27324
|
+
this.accDirty = false;
|
|
27325
|
+
}
|
|
27190
27326
|
this.ensureSubscribed();
|
|
27327
|
+
}
|
|
27191
27328
|
}
|
|
27192
|
-
/** Current
|
|
27329
|
+
/** Current tier after live environment restrictions. */
|
|
27193
27330
|
getLevel() {
|
|
27194
|
-
return this.
|
|
27331
|
+
return this.effectiveLevel();
|
|
27332
|
+
}
|
|
27333
|
+
/**
|
|
27334
|
+
* The effective consent tier: minimum of the stored (saved/configured) tier
|
|
27335
|
+
* and the environment-resolved tier. This ensures an explicit env override
|
|
27336
|
+
* (e.g. `0SEC_ANALYTICS_LEVEL=off` in the parent shell) can never be
|
|
27337
|
+
* bypassed by a cached "full" pipeline. Also re-checks opt-out env vars
|
|
27338
|
+
* at every call, so a late-set `0SEC_OFFLINE` still takes effect.
|
|
27339
|
+
*/
|
|
27340
|
+
effectiveLevel() {
|
|
27341
|
+
const envLevel = resolveAnalyticsLevel();
|
|
27342
|
+
const level = levelAtLeast(this.level, envLevel) ? envLevel : this.level;
|
|
27343
|
+
if (!levelAtLeast(level, this.observedLevel)) {
|
|
27344
|
+
this.batch = this.batch.filter((entry) => levelAtLeast(level, entry.requiredTier));
|
|
27345
|
+
if (level === "off") {
|
|
27346
|
+
this.acc = emptyAccumulator();
|
|
27347
|
+
this.accDirty = false;
|
|
27348
|
+
}
|
|
27349
|
+
}
|
|
27350
|
+
this.observedLevel = level;
|
|
27351
|
+
return level;
|
|
27195
27352
|
}
|
|
27196
27353
|
/** True iff the bus sink is currently subscribed. */
|
|
27197
27354
|
isActive() {
|
|
@@ -27209,6 +27366,8 @@ var AnalyticsPipeline = class {
|
|
|
27209
27366
|
// ── Bus-derived usage counters ────────────────────────────────────────
|
|
27210
27367
|
onBusEvent(type, payload) {
|
|
27211
27368
|
try {
|
|
27369
|
+
if (!levelAtLeast(this.effectiveLevel(), "usage"))
|
|
27370
|
+
return;
|
|
27212
27371
|
switch (type) {
|
|
27213
27372
|
case "tool_call_started": {
|
|
27214
27373
|
const tool = typeof payload["tool"] === "string" ? payload["tool"] : "unknown";
|
|
@@ -27300,7 +27459,7 @@ var AnalyticsPipeline = class {
|
|
|
27300
27459
|
*/
|
|
27301
27460
|
recordCommand(input) {
|
|
27302
27461
|
try {
|
|
27303
|
-
if (!levelAtLeast(this.
|
|
27462
|
+
if (!levelAtLeast(this.effectiveLevel(), "commands"))
|
|
27304
27463
|
return;
|
|
27305
27464
|
const record = {
|
|
27306
27465
|
tool: label(input.tool),
|
|
@@ -27320,7 +27479,7 @@ var AnalyticsPipeline = class {
|
|
|
27320
27479
|
*/
|
|
27321
27480
|
recordCode(input) {
|
|
27322
27481
|
try {
|
|
27323
|
-
if (!levelAtLeast(this.
|
|
27482
|
+
if (!levelAtLeast(this.effectiveLevel(), "commands"))
|
|
27324
27483
|
return;
|
|
27325
27484
|
const record = {
|
|
27326
27485
|
lang: label(input.lang),
|
|
@@ -27337,7 +27496,7 @@ var AnalyticsPipeline = class {
|
|
|
27337
27496
|
*/
|
|
27338
27497
|
recordScope(input) {
|
|
27339
27498
|
try {
|
|
27340
|
-
if (!levelAtLeast(this.
|
|
27499
|
+
if (!levelAtLeast(this.effectiveLevel(), "full"))
|
|
27341
27500
|
return;
|
|
27342
27501
|
const record = {
|
|
27343
27502
|
targetRedacted: toText(input.target),
|
|
@@ -27353,7 +27512,7 @@ var AnalyticsPipeline = class {
|
|
|
27353
27512
|
*/
|
|
27354
27513
|
recordFinding(input) {
|
|
27355
27514
|
try {
|
|
27356
|
-
if (!levelAtLeast(this.
|
|
27515
|
+
if (!levelAtLeast(this.effectiveLevel(), "full"))
|
|
27357
27516
|
return;
|
|
27358
27517
|
const record = {
|
|
27359
27518
|
severity: label(input.severity),
|
|
@@ -27368,22 +27527,51 @@ var AnalyticsPipeline = class {
|
|
|
27368
27527
|
}
|
|
27369
27528
|
}
|
|
27370
27529
|
// ── The choke point ───────────────────────────────────────────────────
|
|
27371
|
-
/**
|
|
27372
|
-
* The ONLY path toward transmission. Gate → redact → envelope → batch →
|
|
27373
|
-
* transmit. Never throws; a below-tier record is silently dropped.
|
|
27374
|
-
*/
|
|
27530
|
+
/** The only path to transmission: consent, redaction, byte limits, envelope. */
|
|
27375
27531
|
enqueue(record, requiredTier) {
|
|
27376
27532
|
try {
|
|
27377
|
-
|
|
27533
|
+
const level = this.effectiveLevel();
|
|
27534
|
+
if (level === "off" || !levelAtLeast(level, requiredTier))
|
|
27378
27535
|
return;
|
|
27379
27536
|
const redacted = redactRecordStrings(record);
|
|
27380
|
-
|
|
27381
|
-
|
|
27382
|
-
|
|
27537
|
+
if (!redacted)
|
|
27538
|
+
return;
|
|
27539
|
+
for (const field of CONTENT_FIELDS) {
|
|
27540
|
+
const content = redacted[field];
|
|
27541
|
+
if (typeof content !== "string")
|
|
27542
|
+
continue;
|
|
27543
|
+
const bytes2 = Buffer.byteLength(content, "utf8");
|
|
27544
|
+
if (bytes2 > MAX_CONTENT_BYTES) {
|
|
27545
|
+
this.reportOversize(field, bytes2, MAX_CONTENT_BYTES);
|
|
27546
|
+
return;
|
|
27547
|
+
}
|
|
27548
|
+
}
|
|
27549
|
+
const json = JSON.stringify({ ...this.buildEnvelope(), ...redacted });
|
|
27550
|
+
const bytes = Buffer.byteLength(json, "utf8");
|
|
27551
|
+
if (bytes + BODY_OVERHEAD_BYTES > MAX_BODY_BYTES) {
|
|
27552
|
+
this.reportOversize("record", bytes + BODY_OVERHEAD_BYTES, MAX_BODY_BYTES);
|
|
27553
|
+
return;
|
|
27554
|
+
}
|
|
27555
|
+
this.batch.push({ json, bytes, requiredTier });
|
|
27383
27556
|
this.scheduleTransmit();
|
|
27384
27557
|
} catch {
|
|
27385
27558
|
}
|
|
27386
27559
|
}
|
|
27560
|
+
reportOversize(field, bytes, maxBytes) {
|
|
27561
|
+
const filename = "analytics-outcomes.log";
|
|
27562
|
+
try {
|
|
27563
|
+
const dir = homeStateDir(this.homeDir);
|
|
27564
|
+
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
27565
|
+
appendFileSync(join14(dir, filename), `${JSON.stringify({ ts: Date.now(), outcome: "oversize", field, bytes, maxBytes })}
|
|
27566
|
+
`, { mode: 384 });
|
|
27567
|
+
} catch {
|
|
27568
|
+
}
|
|
27569
|
+
try {
|
|
27570
|
+
process.stderr.write(`[0sec analytics] Skipped oversized ${field}: ${bytes} UTF-8 bytes exceeds ${maxBytes}; not truncated or uploaded. Details: ${filename}.
|
|
27571
|
+
`);
|
|
27572
|
+
} catch {
|
|
27573
|
+
}
|
|
27574
|
+
}
|
|
27387
27575
|
buildEnvelope() {
|
|
27388
27576
|
if (this.installId === null) {
|
|
27389
27577
|
try {
|
|
@@ -27396,7 +27584,7 @@ var AnalyticsPipeline = class {
|
|
|
27396
27584
|
schemaVersion: ANALYTICS_SCHEMA_VERSION,
|
|
27397
27585
|
installId: this.installId,
|
|
27398
27586
|
sessionId: this.sessionId,
|
|
27399
|
-
tier: this.
|
|
27587
|
+
tier: this.effectiveLevel(),
|
|
27400
27588
|
ts: Date.now(),
|
|
27401
27589
|
cliVersion: typeof VERSION === "string" ? VERSION : "unknown",
|
|
27402
27590
|
platform: finitePlatform(),
|
|
@@ -27416,60 +27604,72 @@ var AnalyticsPipeline = class {
|
|
|
27416
27604
|
} catch {
|
|
27417
27605
|
}
|
|
27418
27606
|
}
|
|
27419
|
-
/**
|
|
27420
|
-
|
|
27421
|
-
|
|
27422
|
-
|
|
27423
|
-
|
|
27424
|
-
|
|
27425
|
-
|
|
27426
|
-
|
|
27427
|
-
|
|
27607
|
+
/** Serialize drains so consent changes can purge every still-pending record. */
|
|
27608
|
+
transmit() {
|
|
27609
|
+
if (!this.transmitting) {
|
|
27610
|
+
this.transmitting = Promise.resolve().then(() => this.drain()).finally(() => {
|
|
27611
|
+
this.transmitting = null;
|
|
27612
|
+
});
|
|
27613
|
+
}
|
|
27614
|
+
return this.transmitting;
|
|
27615
|
+
}
|
|
27616
|
+
async drain() {
|
|
27617
|
+
this.effectiveLevel();
|
|
27618
|
+
if (this.batch.length === 0)
|
|
27428
27619
|
return;
|
|
27429
27620
|
let creds;
|
|
27430
27621
|
try {
|
|
27431
27622
|
creds = loadCloudCredentials(this.homeDir ? { homeDir: this.homeDir } : {});
|
|
27432
27623
|
} catch {
|
|
27624
|
+
this.batch = [];
|
|
27433
27625
|
return;
|
|
27434
27626
|
}
|
|
27435
|
-
|
|
27436
|
-
this.
|
|
27437
|
-
|
|
27438
|
-
|
|
27439
|
-
|
|
27440
|
-
|
|
27627
|
+
while (this.batch.length > 0) {
|
|
27628
|
+
const level = this.effectiveLevel();
|
|
27629
|
+
this.batch = this.batch.filter((entry) => levelAtLeast(level, entry.requiredTier));
|
|
27630
|
+
if (this.batch.length === 0)
|
|
27631
|
+
return;
|
|
27632
|
+
let bytes = BODY_OVERHEAD_BYTES;
|
|
27633
|
+
let count = 0;
|
|
27634
|
+
for (const entry of this.batch) {
|
|
27635
|
+
const nextBytes = bytes + entry.bytes + (count === 0 ? 0 : 1);
|
|
27636
|
+
if (count === MAX_RECORDS_PER_BATCH || nextBytes > MAX_BODY_BYTES)
|
|
27637
|
+
break;
|
|
27638
|
+
bytes = nextBytes;
|
|
27639
|
+
count++;
|
|
27640
|
+
}
|
|
27641
|
+
const chunk = this.batch.splice(0, count);
|
|
27642
|
+
const body = BODY_PREFIX + chunk.map((entry) => entry.json).join(",") + BODY_SUFFIX;
|
|
27643
|
+
for (const entry of chunk)
|
|
27644
|
+
this.appendTransparencyLog(entry.json);
|
|
27645
|
+
const controller = new AbortController();
|
|
27646
|
+
const timer = setTimeout(() => controller.abort(), TRANSMIT_TIMEOUT_MS);
|
|
27441
27647
|
timer.unref?.();
|
|
27442
|
-
|
|
27443
|
-
|
|
27444
|
-
|
|
27445
|
-
|
|
27446
|
-
|
|
27447
|
-
|
|
27448
|
-
|
|
27449
|
-
|
|
27450
|
-
|
|
27451
|
-
|
|
27452
|
-
|
|
27453
|
-
|
|
27454
|
-
|
|
27455
|
-
|
|
27456
|
-
}
|
|
27457
|
-
|
|
27458
|
-
} finally {
|
|
27459
|
-
if (timer) {
|
|
27460
|
-
try {
|
|
27461
|
-
clearTimeout(timer);
|
|
27462
|
-
} catch {
|
|
27463
|
-
}
|
|
27648
|
+
try {
|
|
27649
|
+
const doFetch = this.fetchImpl ?? fetch;
|
|
27650
|
+
await doFetch(`${creds.host}${ANALYTICS_ENDPOINT}`, {
|
|
27651
|
+
method: "POST",
|
|
27652
|
+
headers: {
|
|
27653
|
+
Authorization: `Bearer ${creds.token}`,
|
|
27654
|
+
"Content-Type": "application/json",
|
|
27655
|
+
Accept: "application/json",
|
|
27656
|
+
"User-Agent": `0sec-cli/${typeof VERSION === "string" ? VERSION : "unknown"}`
|
|
27657
|
+
},
|
|
27658
|
+
body,
|
|
27659
|
+
signal: controller.signal
|
|
27660
|
+
});
|
|
27661
|
+
} catch {
|
|
27662
|
+
} finally {
|
|
27663
|
+
clearTimeout(timer);
|
|
27464
27664
|
}
|
|
27465
27665
|
}
|
|
27466
27666
|
}
|
|
27467
|
-
appendTransparencyLog(
|
|
27667
|
+
appendTransparencyLog(json) {
|
|
27468
27668
|
try {
|
|
27469
27669
|
const dir = homeStateDir(this.homeDir);
|
|
27470
27670
|
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
27471
27671
|
const path = join14(dir, ANALYTICS_SENT_LOG_FILENAME);
|
|
27472
|
-
appendFileSync(path, `${
|
|
27672
|
+
appendFileSync(path, `${json}
|
|
27473
27673
|
`, { mode: 384 });
|
|
27474
27674
|
} catch {
|
|
27475
27675
|
}
|
|
@@ -27517,6 +27717,7 @@ var AnalyticsPipeline = class {
|
|
|
27517
27717
|
this.usageFlushTimer = null;
|
|
27518
27718
|
this.transmitTimer = null;
|
|
27519
27719
|
this.level = "off";
|
|
27720
|
+
this.observedLevel = "off";
|
|
27520
27721
|
this.homeDir = void 0;
|
|
27521
27722
|
this.fetchImpl = void 0;
|
|
27522
27723
|
this.installId = null;
|
|
@@ -27793,11 +27994,16 @@ var ExecutablePluginManager = class {
|
|
|
27793
27994
|
throw new Error("Executable source exceeds size limit");
|
|
27794
27995
|
}
|
|
27795
27996
|
try {
|
|
27796
|
-
analyticsPipeline.
|
|
27797
|
-
|
|
27798
|
-
|
|
27799
|
-
|
|
27800
|
-
|
|
27997
|
+
const level = analyticsPipeline.getLevel();
|
|
27998
|
+
if (level === "commands" || level === "full") {
|
|
27999
|
+
for (const name of names) {
|
|
28000
|
+
analyticsPipeline.recordCode({
|
|
28001
|
+
lang: extname2(name).slice(1) || "text",
|
|
28002
|
+
source: submission.files[name],
|
|
28003
|
+
origin: "executable-plugin"
|
|
28004
|
+
});
|
|
28005
|
+
}
|
|
28006
|
+
}
|
|
27801
28007
|
} catch {
|
|
27802
28008
|
}
|
|
27803
28009
|
const before = this.readRegistry().plugins[manifest.id];
|