From 4a50f00a9e705133a34b0e86dc4f689005179ce6 Mon Sep 17 00:00:00 2001 From: RAJVEER42 Date: Fri, 22 May 2026 02:22:04 +0530 Subject: [PATCH] fix: $global scanner config correctly inherited by per-repo entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit semgrep, trufflehog, claude, and piAgent blocks were merged from DEFAULT_CONFIG + per-repo overrides only — globalConfig was extracted but never spread into the scanner merges. trigger and comment handled this correctly; scanner blocks did not. Adds two tests covering global inheritance and per-repo override precedence for semgrep. --- .changeset/vast-pandas-trade.md | 5 +++++ src/__tests__/config.test.ts | 19 +++++++++++++++++++ src/config.ts | 8 ++++---- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 .changeset/vast-pandas-trade.md diff --git a/.changeset/vast-pandas-trade.md b/.changeset/vast-pandas-trade.md new file mode 100644 index 0000000..1405937 --- /dev/null +++ b/.changeset/vast-pandas-trade.md @@ -0,0 +1,5 @@ +--- +"layne": patch +--- + +fix: $global scanner config (semgrep, trufflehog, claude, piAgent) is now correctly inherited by per-repo entries diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index c801950..54be422 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -409,6 +409,24 @@ describe('loadScanConfig()', () => { // --- piAgent defaults --- + it('inherits $global semgrep config when the repo has no semgrep block', async () => { + vi.mocked(readFile).mockResolvedValueOnce(JSON.stringify({ + '$global': { semgrep: { extraArgs: ['--config', 'p/owasp-top-ten'] } }, + 'acme/frontend': { mode: 'diff_only' }, + })); + const config = await loadScanConfig({ owner: 'acme', repo: 'frontend' }); + expect((config.semgrep as { extraArgs: string[] }).extraArgs).toEqual(['--config', 'p/owasp-top-ten']); +}); + +it('per-repo semgrep overrides $global semgrep at the key level', async () => { + vi.mocked(readFile).mockResolvedValueOnce(JSON.stringify({ + '$global': { semgrep: { extraArgs: ['--config', 'p/owasp-top-ten'] } }, + 'acme/payments': { semgrep: { extraArgs: ['--config', 'p/python'] } }, + })); + const config = await loadScanConfig({ owner: 'acme', repo: 'payments' }); + expect((config.semgrep as { extraArgs: string[] }).extraArgs).toEqual(['--config', 'p/python']); +}); + it('DEFAULT_CONFIG.piAgent has timeoutMinutes 10', () => { expect((DEFAULT_CONFIG.piAgent as Record).timeoutMinutes).toBe(10); }); @@ -437,3 +455,4 @@ describe('loadScanConfig()', () => { expect((config.piAgent as Record).timeoutMinutes).toBe(15); }); }); + diff --git a/src/config.ts b/src/config.ts index cf7438d..bb7fd75 100644 --- a/src/config.ts +++ b/src/config.ts @@ -95,10 +95,10 @@ export async function loadScanConfig({ owner, repo }: { owner: string; repo: str mode: repoOverrides.mode ?? globalConfig.mode ?? DEFAULT_CONFIG.mode, contextLines: repoOverrides.contextLines ?? globalConfig.contextLines ?? DEFAULT_CONFIG.contextLines, timeoutMinutes: repoOverrides.timeoutMinutes ?? globalConfig.timeoutMinutes ?? DEFAULT_CONFIG.timeoutMinutes, - semgrep: { ...DEFAULT_CONFIG.semgrep, ...(repoOverrides.semgrep ?? {}) }, - trufflehog: { ...DEFAULT_CONFIG.trufflehog, ...(repoOverrides.trufflehog ?? {}) }, - claude: { ...DEFAULT_CONFIG.claude, ...(repoOverrides.claude ?? {}) }, - piAgent: { ...DEFAULT_CONFIG.piAgent, ...(repoOverrides.piAgent ?? {}) }, + semgrep: { ...DEFAULT_CONFIG.semgrep, ...(globalConfig.semgrep ?? {}), ...(repoOverrides.semgrep ?? {}) }, + trufflehog:{ ...DEFAULT_CONFIG.trufflehog, ...(globalConfig.trufflehog ?? {}), ...(repoOverrides.trufflehog ?? {}) }, + claude: { ...DEFAULT_CONFIG.claude, ...(globalConfig.claude ?? {}), ...(repoOverrides.claude ?? {}) }, + piAgent: { ...DEFAULT_CONFIG.piAgent, ...(globalConfig.piAgent ?? {}), ...(repoOverrides.piAgent ?? {}) }, notifications: { ...globalNotifications, ...repoNotifications }, labels: { ...globalLabels, ...repoLabels }, trigger: { ...DEFAULT_CONFIG.trigger, ...globalTrigger, ...(repoOverrides.trigger ?? {}) },