Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 63 additions & 97 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
33 changes: 33 additions & 0 deletions src/core/security/workers/securityCheckWorker.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';

Expand Down
Loading