diff --git a/package-lock.json b/package-lock.json index 5e3f2d284..050379b14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@repomix/strip-comments": "^2.4.2", "@repomix/tree-sitter-wasms": "^0.1.16", "@secretlint/core": "^11.5.0", + "@secretlint/profiler": "^11.5.0", "@secretlint/secretlint-rule-preset-recommend": "^11.4.1", "commander": "^14.0.3", "fast-xml-builder": "^1.1.4", @@ -229,9 +230,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -249,9 +247,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -269,9 +264,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -289,9 +281,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -1051,9 +1040,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1071,9 +1057,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1091,9 +1074,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1111,9 +1091,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1131,9 +1108,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1151,9 +1125,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1171,9 +1142,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1191,9 +1159,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1677,6 +1642,13 @@ "node": ">=20.0.0" } }, + "node_modules/@secretlint/config-loader/node_modules/@secretlint/profiler": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-11.4.1.tgz", + "integrity": "sha512-mMzPUnZ2+arX8PYCwKU1ouCHzVUIZiNWPtzyyguL0Oc7dokyk8u7QA4IwAl8DMm04GN3jntL2E+1CBVN7z3crg==", + "dev": true, + "license": "MIT" + }, "node_modules/@secretlint/config-loader/node_modules/@secretlint/types": { "version": "11.4.1", "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-11.4.1.tgz", @@ -1702,12 +1674,6 @@ "node": ">=20.0.0" } }, - "node_modules/@secretlint/core/node_modules/@secretlint/profiler": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-11.5.0.tgz", - "integrity": "sha512-o7lZEA4NTJWzNoO3evTZ0luanV0EQlEbjzREIijM1/O1Bfpuy4P+mgAY3+S7CXlrC4I8RApCV2sP2qPiHQtNMA==", - "license": "MIT" - }, "node_modules/@secretlint/formatter": { "version": "11.4.1", "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-11.4.1.tgz", @@ -1777,6 +1743,13 @@ "node": ">=20.0.0" } }, + "node_modules/@secretlint/node/node_modules/@secretlint/profiler": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-11.4.1.tgz", + "integrity": "sha512-mMzPUnZ2+arX8PYCwKU1ouCHzVUIZiNWPtzyyguL0Oc7dokyk8u7QA4IwAl8DMm04GN3jntL2E+1CBVN7z3crg==", + "dev": true, + "license": "MIT" + }, "node_modules/@secretlint/node/node_modules/@secretlint/types": { "version": "11.4.1", "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-11.4.1.tgz", @@ -1788,10 +1761,9 @@ } }, "node_modules/@secretlint/profiler": { - "version": "11.4.1", - "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-11.4.1.tgz", - "integrity": "sha512-mMzPUnZ2+arX8PYCwKU1ouCHzVUIZiNWPtzyyguL0Oc7dokyk8u7QA4IwAl8DMm04GN3jntL2E+1CBVN7z3crg==", - "dev": true, + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-11.5.0.tgz", + "integrity": "sha512-o7lZEA4NTJWzNoO3evTZ0luanV0EQlEbjzREIijM1/O1Bfpuy4P+mgAY3+S7CXlrC4I8RApCV2sP2qPiHQtNMA==", "license": "MIT" }, "node_modules/@secretlint/resolver": { @@ -1902,22 +1874,6 @@ "node": ">=8" } }, - "node_modules/@textlint/linter-formatter/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@textlint/linter-formatter/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2378,6 +2334,22 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2572,6 +2544,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2583,7 +2556,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { "version": "14.0.3", @@ -3429,6 +3403,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4485,6 +4460,13 @@ "node": ">=20.0.0" } }, + "node_modules/secretlint/node_modules/@secretlint/profiler": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-11.4.1.tgz", + "integrity": "sha512-mMzPUnZ2+arX8PYCwKU1ouCHzVUIZiNWPtzyyguL0Oc7dokyk8u7QA4IwAl8DMm04GN3jntL2E+1CBVN7z3crg==", + "dev": true, + "license": "MIT" + }, "node_modules/secretlint/node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -4689,6 +4671,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4884,40 +4884,6 @@ "node": ">=8" } }, - "node_modules/table/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/table/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", diff --git a/package.json b/package.json index e07cadc13..853e859fa 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "@repomix/strip-comments": "^2.4.2", "@repomix/tree-sitter-wasms": "^0.1.16", "@secretlint/core": "^11.5.0", + "@secretlint/profiler": "^11.5.0", "@secretlint/secretlint-rule-preset-recommend": "^11.4.1", "commander": "^14.0.3", "fast-xml-builder": "^1.1.4", diff --git a/src/core/security/workers/securityCheckWorker.ts b/src/core/security/workers/securityCheckWorker.ts index 656278460..597d2a2fa 100644 --- a/src/core/security/workers/securityCheckWorker.ts +++ b/src/core/security/workers/securityCheckWorker.ts @@ -1,4 +1,5 @@ import { lintSource } from '@secretlint/core'; +import { secretLintProfiler } from '@secretlint/profiler'; import { creator } from '@secretlint/secretlint-rule-preset-recommend'; import type { SecretLintCoreConfig } from '@secretlint/types'; import { logger, setLogLevelByWorkerData } from '../../../shared/logger.js'; @@ -7,6 +8,38 @@ import { logger, setLogLevelByWorkerData } from '../../../shared/logger.js'; // This must be called before any logging operations in the worker setLogLevelByWorkerData(); +// Disable @secretlint/profiler inside this worker. +// +// secretLintProfiler is a module-level singleton that installs a global +// PerformanceObserver on import and, for every `lintSource` call, pushes one +// entry per mark into an unbounded `entries` array. Each incoming mark then +// runs an O(n) `entries.find()` scan against all prior entries, making the +// total profiler cost across a single worker's lifetime O(n^2) in the number +// of files processed. For a typical ~1000-file repo this adds ~500-900ms of +// pure profiler bookkeeping per worker with zero functional benefit — +// secretlint core only *writes* marks via `profiler.mark()` and never reads +// back `getEntries()` / `getMeasures()` during linting. +// +// Replacing `mark` with a no-op prevents any `performance.mark()` calls from +// firing, so the observer callback never runs and `entries` stays empty. +// +// Use `Object.defineProperty` + try/catch so the worker still boots even if +// a future @secretlint/profiler version makes `mark` a getter-only or +// non-configurable property — the optimization would silently regress in +// that case, but the security check itself keeps working. +try { + Object.defineProperty(secretLintProfiler, 'mark', { + value: () => {}, + writable: true, + configurable: true, + }); +} catch (error) { + // Property may be non-configurable in a future secretlint version. + // Security linting still works correctly — only this performance + // optimization is skipped. + logger.trace('Could not override secretLintProfiler.mark; leaving profiler enabled', error); +} + // Security check type to distinguish between regular files, git diffs, and git logs export type SecurityCheckType = 'file' | 'gitDiff' | 'gitLog';