From 483ec832a721c117a47f598bc5aed63aa704f151 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Fri, 23 May 2025 13:04:03 +0100 Subject: [PATCH 1/6] feat: allow enhanced scan to run without impacting builds --- packages/build/src/log/messages/core_steps.js | 53 ++++---- .../plugins_core/secrets_scanning/index.ts | 12 +- .../build/tests/secrets_scanning/tests.js | 127 ++++++++++++++++-- 3 files changed, 155 insertions(+), 37 deletions(-) diff --git a/packages/build/src/log/messages/core_steps.js b/packages/build/src/log/messages/core_steps.js index bdc2501881..5f008cbfba 100644 --- a/packages/build/src/log/messages/core_steps.js +++ b/packages/build/src/log/messages/core_steps.js @@ -128,14 +128,19 @@ export const logSecretsScanSuccessMessage = function (logs, msg) { log(logs, msg, { color: THEME.highlightWords }) } -export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, groupedResults }) { +export const logSecretsScanFailBuildMessage = function ({ + logs, + scanResults, + groupedResults, + enhancedScanShouldImpactBuilds, +}) { const { secretMatches, enhancedSecretMatches } = groupedResults const secretMatchesKeys = Object.keys(secretMatches) const enhancedSecretMatchesKeys = Object.keys(enhancedSecretMatches) logErrorSubHeader( logs, - `Scanning complete. ${scanResults.scannedFilesCount} file(s) scanned. Secrets scanning found ${secretMatchesKeys.length} instance(s) of secrets${enhancedSecretMatchesKeys.length > 0 ? ` and ${enhancedSecretMatchesKeys.length} instance(s) of likely secrets` : ''} in build output or repo code.\n`, + `Scanning complete. ${scanResults.scannedFilesCount} file(s) scanned. Secrets scanning found ${secretMatchesKeys.length} instance(s) of secrets${enhancedSecretMatchesKeys.length > 0 && enhancedScanShouldImpactBuilds ? ` and ${enhancedSecretMatchesKeys.length} instance(s) of likely secrets` : ''} in build output or repo code.\n`, ) // Explicit secret matches @@ -162,28 +167,30 @@ export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, gro ) } - // Likely secret matches from enhanced scan - enhancedSecretMatchesKeys.forEach((key, index) => { - logError(logs, `${index === 0 && secretMatchesKeys.length ? '\n' : ''}"${key}***" detected as a likely secret:`) - - enhancedSecretMatches[key] - .sort((a, b) => { - return a.file > b.file ? 0 : 1 - }) - .forEach(({ lineNumber, file }) => { - logError(logs, `found value at line ${lineNumber} in ${file}`, { indent: true }) - }) - }) + if (enhancedScanShouldImpactBuilds) { + // Likely secret matches from enhanced scan + enhancedSecretMatchesKeys.forEach((key, index) => { + logError(logs, `${index === 0 && secretMatchesKeys.length ? '\n' : ''}"${key}***" detected as a likely secret:`) + + enhancedSecretMatches[key] + .sort((a, b) => { + return a.file > b.file ? 0 : 1 + }) + .forEach(({ lineNumber, file }) => { + logError(logs, `found value at line ${lineNumber} in ${file}`, { indent: true }) + }) + }) - if (enhancedSecretMatchesKeys.length) { - logError( - logs, - `\nTo prevent exposing secrets, the build will fail until these likely secret values are not found in build output or repo files.`, - ) - logError( - logs, - `\nIf these are expected, use ENHANCED_SECRETS_SCAN_OMIT_VALUES, or ENHANCED_SECRETS_SCAN_ENABLED to prevent detecting.`, - ) + if (enhancedSecretMatchesKeys.length) { + logError( + logs, + `\nTo prevent exposing secrets, the build will fail until these likely secret values are not found in build output or repo files.`, + ) + logError( + logs, + `\nIf these are expected, use ENHANCED_SECRETS_SCAN_OMIT_VALUES, or ENHANCED_SECRETS_SCAN_ENABLED to prevent detecting.`, + ) + } } logError( diff --git a/packages/build/src/plugins_core/secrets_scanning/index.ts b/packages/build/src/plugins_core/secrets_scanning/index.ts index e3b79edec0..3be7507e5c 100644 --- a/packages/build/src/plugins_core/secrets_scanning/index.ts +++ b/packages/build/src/plugins_core/secrets_scanning/index.ts @@ -30,6 +30,7 @@ const coreStep: CoreStepFunction = async function ({ netlifyConfig, explicitSecretKeys, enhancedSecretScan, + featureFlags, systemLog, deployId, api, @@ -38,6 +39,7 @@ const coreStep: CoreStepFunction = async function ({ const passedSecretKeys = (explicitSecretKeys || '').split(',') const envVars = netlifyConfig.build.environment as Record + const enhancedScanShouldImpactBuilds = featureFlags?.enhanced_secret_scan_impacts_builds ?? false systemLog?.({ passedSecretKeys, buildDir }) @@ -54,14 +56,16 @@ const coreStep: CoreStepFunction = async function ({ log(logs, `SECRETS_SCAN_OMIT_PATHS override option set to: ${envVars['SECRETS_SCAN_OMIT_PATHS']}\n`) } const enhancedScanningEnabledInEnv = isEnhancedSecretsScanningEnabled(envVars) - if (enhancedSecretScan && !enhancedScanningEnabledInEnv) { + if (enhancedSecretScan && enhancedScanShouldImpactBuilds && !enhancedScanningEnabledInEnv) { logSecretsScanSkipMessage( logs, 'Enhanced secrets detection disabled via ENHANCED_SECRETS_SCAN_ENABLED flag set to false.', ) } + if ( enhancedSecretScan && + enhancedScanShouldImpactBuilds && enhancedScanningEnabledInEnv && envVars['ENHANCED_SECRETS_SCAN_OMIT_VALUES'] !== undefined ) { @@ -73,7 +77,7 @@ const coreStep: CoreStepFunction = async function ({ const keysToSearchFor = getSecretKeysToScanFor(envVars, passedSecretKeys) - if (keysToSearchFor.length === 0 && !enhancedSecretScan) { + if (keysToSearchFor.length === 0 && (!enhancedSecretScan || !enhancedScanShouldImpactBuilds)) { logSecretsScanSkipMessage( logs, 'Secrets scanning skipped because no env vars marked as secret are set to non-empty/non-trivial values or they are all omitted with SECRETS_SCAN_OMIT_KEYS env var setting.', @@ -123,6 +127,7 @@ const coreStep: CoreStepFunction = async function ({ keysToSearchFor, enhancedPrefixMatches: enhancedSecretMatches.length ? enhancedSecretMatches.map((match) => match.key) : [], enhancedScanning: enhancedSecretScan && enhancedScanningEnabledInEnv, + enhancedSecretScanImpactsBuild: enhancedScanShouldImpactBuilds, } systemLog?.(attributesForLogsAndSpan) @@ -135,7 +140,7 @@ const coreStep: CoreStepFunction = async function ({ const secretScanResult: SecretScanResult = { scannedFilesCount: scanResults?.scannedFilesCount ?? 0, secretsScanMatches: secretMatches ?? [], - enhancedSecretsScanMatches: enhancedSecretMatches ?? [], + enhancedSecretsScanMatches: enhancedScanShouldImpactBuilds && enhancedSecretMatches ? enhancedSecretMatches : [], } reportValidations({ api, secretScanResult, deployId, systemLog }) } @@ -154,6 +159,7 @@ const coreStep: CoreStepFunction = async function ({ logs, scanResults, groupedResults: groupScanResultsByKeyAndScanType(scanResults), + enhancedScanShouldImpactBuilds, }) const error = new Error(`Secrets scanning found secrets in build.`) diff --git a/packages/build/tests/secrets_scanning/tests.js b/packages/build/tests/secrets_scanning/tests.js index a14405b850..223c646efb 100644 --- a/packages/build/tests/secrets_scanning/tests.js +++ b/packages/build/tests/secrets_scanning/tests.js @@ -133,18 +133,31 @@ test('secrets scanning should not scan .cache/ directory', async (t) => { t.true(output.includes(`No secrets detected in build output or repo code!`)) }) -// Enhanced secret scanning +// Enhanced secret scanning with enhanced_secret_scan_impacts_builds enabled test('secrets scanning, enhanced scan should not run when disabled', async (t) => { const { requests } = await new Fixture('./fixtures/src_scanning_disabled') - .withFlags({ debug: false, enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(requests.length === 0) }) test('secrets scanning, should skip when enhanced scan and likely secrets passed but SECRETS_SCAN_OMIT_PATHS omits all files', async (t) => { const { requests } = await new Fixture('./fixtures/src_scanning_omit_all_paths') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + explicitSecretKeys: '', + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + enhancedSecretScan: true, + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(requests.length === 0) @@ -152,7 +165,14 @@ test('secrets scanning, should skip when enhanced scan and likely secrets passed test('secrets scanning, enhanced scan should not find matches when disabled with ENHANCED_SECRETS_SCAN_ENABLED set to false', async (t) => { const { requests } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets_disabled') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + explicitSecretKeys: '', + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + enhancedSecretScan: true, + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(requests.length === 1) const request = requests[0] @@ -161,7 +181,14 @@ test('secrets scanning, enhanced scan should not find matches when disabled with test('secrets scanning, enhanced scan should skip matches defined in ENHANCED_SECRETS_SCAN_OMIT_VALUES', async (t) => { const { requests, output } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets_omitted') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + explicitSecretKeys: '', + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(normalizeOutput(output).includes('ENHANCED_SECRETS_SCAN_OMIT_VALUES override option set')) @@ -172,15 +199,27 @@ test('secrets scanning, enhanced scan should skip matches defined in ENHANCED_SE test('secrets scanning, ENHANCED_SECRETS_SCAN_OMIT_VALUES not logged if enhanced scanning not enabled', async (t) => { const { output } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets_omitted') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: false, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + explicitSecretKeys: '', + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) - t.false(normalizeOutput(output).includes('ENHANCED_SECRETS_SCAN_OMIT_VALUES override option set')) }) test('secrets scanning, should run when enhanced scan enabled and no env vars set', async (t) => { const { requests } = await new Fixture('./fixtures/src_default') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + explicitSecretKeys: '', + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(requests.length === 1) @@ -193,7 +232,13 @@ test('secrets scanning, should run when enhanced scan enabled and no env vars se test('secrets scanning, should not find secrets in files without known prefixes', async (t) => { const { requests } = await new Fixture('./fixtures/src_scanning_no_likely_enhanced_scan_secrets') - .withFlags({ debug: false, enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(requests.length === 1) @@ -206,7 +251,14 @@ test('secrets scanning, should not find secrets in files without known prefixes' test('secrets scanning, run and report result to API when there are no secrets and enhanced scan is enabled with likely secrets', async (t) => { const { requests } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + enhancedSecretScan: true, + explicitSecretKeys: '', + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.true(requests.length === 1) @@ -220,7 +272,14 @@ test('secrets scanning, run and report result to API when there are no secrets a test('secrets scanning, should fail build and report to API when enhanced scan finds likely secret in the src and build output', async (t) => { const { output, requests } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets') - .withFlags({ debug: false, explicitSecretKeys: '', enhancedSecretScan: true, deployId: 'test', token: 'test' }) + .withFlags({ + debug: false, + enhancedSecretScan: true, + explicitSecretKeys: '', + featureFlags: { enhanced_secret_scan_impacts_builds: true }, + deployId: 'test', + token: 'test', + }) .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) t.assert(normalizeOutput(output).includes(`"sk_***" detected as a likely secret`)) @@ -243,6 +302,7 @@ test('secrets scanning, should report success to API when enhanced scans finds n .withFlags({ debug: false, enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: true }, deployId: 'test', token: 'test', }) @@ -263,8 +323,53 @@ test('secrets scanning, enhanced scanning failure should produce a user error', debug: false, explicitSecretKeys: '', enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: true }, }) .runBuildProgrammatic() // Severity code of 2 is user error t.is(severityCode, 2) }) + +// enhanced scanning enabled, but without impact to builds + +test('secrets scanning, should not log enhanced scan info when enhanced_secret_scan_impacts_builds is false', async (t) => { + const { output } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets') + .withFlags({ + debug: false, + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: false }, + deployId: 'test', + token: 'test', + }) + .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) + + const normalizedOutput = normalizeOutput(output) + t.false(normalizedOutput.includes('detected as a likely secret')) +}) + +test('secrets scanning, should not fail build when enhanced scan finds likely secrets but enhanced_secret_scan_impacts_builds is false', async (t) => { + const { severityCode } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets') + .withFlags({ + debug: false, + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: false }, + }) + .runBuildProgrammatic() + + // Severity code of 0 means success, 2 would be user error + t.is(severityCode, 0) +}) + +test('secrets scanning, should not log omit values message when enhanced_secret_scan_impacts_builds is false', async (t) => { + const { output } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets_omitted') + .withFlags({ + debug: false, + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: false }, + deployId: 'test', + token: 'test', + }) + .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) + + t.false(normalizeOutput(output).includes('ENHANCED_SECRETS_SCAN_OMIT_VALUES')) +}) From 302bd5339a44fdef0e0e55474a1fd01a59c58bf3 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Fri, 23 May 2025 13:52:17 +0100 Subject: [PATCH 2/6] fix: check only normal scan matches for build success --- packages/build/src/plugins_core/secrets_scanning/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/build/src/plugins_core/secrets_scanning/index.ts b/packages/build/src/plugins_core/secrets_scanning/index.ts index 3be7507e5c..de6608dbde 100644 --- a/packages/build/src/plugins_core/secrets_scanning/index.ts +++ b/packages/build/src/plugins_core/secrets_scanning/index.ts @@ -145,7 +145,11 @@ const coreStep: CoreStepFunction = async function ({ reportValidations({ api, secretScanResult, deployId, systemLog }) } - if (!scanResults || scanResults.matches.length === 0) { + if ( + !scanResults || + scanResults.matches.length === 0 || + (!enhancedScanShouldImpactBuilds && (secretMatches?.length ?? 0) === 0) + ) { logSecretsScanSuccessMessage( logs, `Secrets scanning complete. ${scanResults?.scannedFilesCount} file(s) scanned. No secrets detected in build output or repo code!`, From eb912df84c3d59a8482988eda0d8ad56dc06b182 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Fri, 23 May 2025 13:57:30 +0100 Subject: [PATCH 3/6] chore: simplify --- packages/build/src/plugins_core/secrets_scanning/index.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/build/src/plugins_core/secrets_scanning/index.ts b/packages/build/src/plugins_core/secrets_scanning/index.ts index de6608dbde..c78bd76850 100644 --- a/packages/build/src/plugins_core/secrets_scanning/index.ts +++ b/packages/build/src/plugins_core/secrets_scanning/index.ts @@ -145,11 +145,7 @@ const coreStep: CoreStepFunction = async function ({ reportValidations({ api, secretScanResult, deployId, systemLog }) } - if ( - !scanResults || - scanResults.matches.length === 0 || - (!enhancedScanShouldImpactBuilds && (secretMatches?.length ?? 0) === 0) - ) { + if (!scanResults || scanResults.matches.length === 0 || (!enhancedScanShouldImpactBuilds && !secretMatches?.length)) { logSecretsScanSuccessMessage( logs, `Secrets scanning complete. ${scanResults?.scannedFilesCount} file(s) scanned. No secrets detected in build output or repo code!`, From 73e1440311414b6fd56bf867a5967978d34f6b04 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Fri, 23 May 2025 16:40:12 +0100 Subject: [PATCH 4/6] chore: be more explicit about logic on when to run --- .../plugins_core/secrets_scanning/index.ts | 35 +++++++++++------- .../build/tests/secrets_scanning/tests.js | 36 ++++++++++++++++++- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/packages/build/src/plugins_core/secrets_scanning/index.ts b/packages/build/src/plugins_core/secrets_scanning/index.ts index c78bd76850..9dceffc8ba 100644 --- a/packages/build/src/plugins_core/secrets_scanning/index.ts +++ b/packages/build/src/plugins_core/secrets_scanning/index.ts @@ -39,7 +39,9 @@ const coreStep: CoreStepFunction = async function ({ const passedSecretKeys = (explicitSecretKeys || '').split(',') const envVars = netlifyConfig.build.environment as Record - const enhancedScanShouldImpactBuilds = featureFlags?.enhanced_secret_scan_impacts_builds ?? false + // When the flag is disabled, we may still run the scan if a secrets scan would otherwise take place anyway + // In this case, we hide any output to the user and simply gather the information in our logs + const enhancedScanShouldRunInActiveMode = featureFlags?.enhanced_secret_scan_impacts_builds ?? false systemLog?.({ passedSecretKeys, buildDir }) @@ -56,7 +58,8 @@ const coreStep: CoreStepFunction = async function ({ log(logs, `SECRETS_SCAN_OMIT_PATHS override option set to: ${envVars['SECRETS_SCAN_OMIT_PATHS']}\n`) } const enhancedScanningEnabledInEnv = isEnhancedSecretsScanningEnabled(envVars) - if (enhancedSecretScan && enhancedScanShouldImpactBuilds && !enhancedScanningEnabledInEnv) { + const enhancedScanConfigured = enhancedSecretScan && enhancedScanningEnabledInEnv + if (enhancedSecretScan && enhancedScanShouldRunInActiveMode && !enhancedScanningEnabledInEnv) { logSecretsScanSkipMessage( logs, 'Enhanced secrets detection disabled via ENHANCED_SECRETS_SCAN_ENABLED flag set to false.', @@ -64,9 +67,8 @@ const coreStep: CoreStepFunction = async function ({ } if ( - enhancedSecretScan && - enhancedScanShouldImpactBuilds && - enhancedScanningEnabledInEnv && + enhancedScanShouldRunInActiveMode && + enhancedScanConfigured && envVars['ENHANCED_SECRETS_SCAN_OMIT_VALUES'] !== undefined ) { log( @@ -77,7 +79,11 @@ const coreStep: CoreStepFunction = async function ({ const keysToSearchFor = getSecretKeysToScanFor(envVars, passedSecretKeys) - if (keysToSearchFor.length === 0 && (!enhancedSecretScan || !enhancedScanShouldImpactBuilds)) { + // In passive mode, only run the enhanced scan if we have explicit secret keys + const enhancedScanShouldRun = enhancedScanShouldRunInActiveMode + ? enhancedScanConfigured + : enhancedScanConfigured && keysToSearchFor.length > 0 + if (keysToSearchFor.length === 0 && !enhancedScanShouldRun) { logSecretsScanSkipMessage( logs, 'Secrets scanning skipped because no env vars marked as secret are set to non-empty/non-trivial values or they are all omitted with SECRETS_SCAN_OMIT_KEYS env var setting.', @@ -111,7 +117,7 @@ const coreStep: CoreStepFunction = async function ({ keys: keysToSearchFor, base: buildDir as string, filePaths, - enhancedScanning: enhancedSecretScan && enhancedScanningEnabledInEnv, + enhancedScanning: enhancedScanShouldRun, omitValuesFromEnhancedScan: getOmitValuesFromEnhancedScanForEnhancedScanFromEnv(envVars), }) @@ -126,8 +132,8 @@ const coreStep: CoreStepFunction = async function ({ secretsFilesCount: scanResults.scannedFilesCount, keysToSearchFor, enhancedPrefixMatches: enhancedSecretMatches.length ? enhancedSecretMatches.map((match) => match.key) : [], - enhancedScanning: enhancedSecretScan && enhancedScanningEnabledInEnv, - enhancedSecretScanImpactsBuild: enhancedScanShouldImpactBuilds, + enhancedScanning: enhancedScanShouldRun, + enhancedScanActiveMode: enhancedScanShouldRunInActiveMode, } systemLog?.(attributesForLogsAndSpan) @@ -140,12 +146,17 @@ const coreStep: CoreStepFunction = async function ({ const secretScanResult: SecretScanResult = { scannedFilesCount: scanResults?.scannedFilesCount ?? 0, secretsScanMatches: secretMatches ?? [], - enhancedSecretsScanMatches: enhancedScanShouldImpactBuilds && enhancedSecretMatches ? enhancedSecretMatches : [], + enhancedSecretsScanMatches: + enhancedScanShouldRunInActiveMode && enhancedSecretMatches ? enhancedSecretMatches : [], } reportValidations({ api, secretScanResult, deployId, systemLog }) } - if (!scanResults || scanResults.matches.length === 0 || (!enhancedScanShouldImpactBuilds && !secretMatches?.length)) { + if ( + !scanResults || + scanResults.matches.length === 0 || + (!enhancedScanShouldRunInActiveMode && !secretMatches?.length) + ) { logSecretsScanSuccessMessage( logs, `Secrets scanning complete. ${scanResults?.scannedFilesCount} file(s) scanned. No secrets detected in build output or repo code!`, @@ -159,7 +170,7 @@ const coreStep: CoreStepFunction = async function ({ logs, scanResults, groupedResults: groupScanResultsByKeyAndScanType(scanResults), - enhancedScanShouldImpactBuilds, + enhancedScanShouldImpactBuilds: enhancedScanShouldRunInActiveMode, }) const error = new Error(`Secrets scanning found secrets in build.`) diff --git a/packages/build/tests/secrets_scanning/tests.js b/packages/build/tests/secrets_scanning/tests.js index 223c646efb..74147c63a7 100644 --- a/packages/build/tests/secrets_scanning/tests.js +++ b/packages/build/tests/secrets_scanning/tests.js @@ -167,7 +167,7 @@ test('secrets scanning, enhanced scan should not find matches when disabled with const { requests } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets_disabled') .withFlags({ debug: false, - explicitSecretKeys: '', + explicitSecretKeys: 'ENV_VAR_1', featureFlags: { enhanced_secret_scan_impacts_builds: true }, deployId: 'test', token: 'test', @@ -373,3 +373,37 @@ test('secrets scanning, should not log omit values message when enhanced_secret_ t.false(normalizeOutput(output).includes('ENHANCED_SECRETS_SCAN_OMIT_VALUES')) }) + +test('secrets scanning, should run enhanced scan in passive mode when explicit keys are present', async (t) => { + const { requests } = await new Fixture('./fixtures/src_scanning_env_vars_set_non_empty') + .withFlags({ + debug: false, + explicitSecretKeys: 'ENV_VAR_1', + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: false }, + deployId: 'test', + token: 'test', + }) + .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) + + t.true(requests.length === 1) + const request = requests[0] + t.is(request.url, '/api/v1/deploys/test/validations_report') + t.truthy(request.body.secrets_scan.scannedFilesCount) + t.truthy(request.body.secrets_scan.enhancedSecretsScanMatches) +}) + +test('secrets scanning, should not run enhanced scan in passive mode when no explicit keys', async (t) => { + const { requests } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets') + .withFlags({ + debug: false, + explicitSecretKeys: '', + enhancedSecretScan: true, + featureFlags: { enhanced_secret_scan_impacts_builds: false }, + deployId: 'test', + token: 'test', + }) + .runBuildServer({ path: '/api/v1/deploys/test/validations_report' }) + + t.true(requests.length === 0) +}) From 150b6012a1c38fd5040801d8bc2de72a34bf8ec1 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Fri, 23 May 2025 17:16:10 +0100 Subject: [PATCH 5/6] chore: consistency for naming --- packages/build/src/log/messages/core_steps.js | 6 +++--- packages/build/src/plugins_core/secrets_scanning/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/build/src/log/messages/core_steps.js b/packages/build/src/log/messages/core_steps.js index 5f008cbfba..b83f2ed518 100644 --- a/packages/build/src/log/messages/core_steps.js +++ b/packages/build/src/log/messages/core_steps.js @@ -132,7 +132,7 @@ export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, groupedResults, - enhancedScanShouldImpactBuilds, + enhancedScanShouldRunInActiveMode, }) { const { secretMatches, enhancedSecretMatches } = groupedResults const secretMatchesKeys = Object.keys(secretMatches) @@ -140,7 +140,7 @@ export const logSecretsScanFailBuildMessage = function ({ logErrorSubHeader( logs, - `Scanning complete. ${scanResults.scannedFilesCount} file(s) scanned. Secrets scanning found ${secretMatchesKeys.length} instance(s) of secrets${enhancedSecretMatchesKeys.length > 0 && enhancedScanShouldImpactBuilds ? ` and ${enhancedSecretMatchesKeys.length} instance(s) of likely secrets` : ''} in build output or repo code.\n`, + `Scanning complete. ${scanResults.scannedFilesCount} file(s) scanned. Secrets scanning found ${secretMatchesKeys.length} instance(s) of secrets${enhancedSecretMatchesKeys.length > 0 && enhancedScanShouldRunInActiveMode ? ` and ${enhancedSecretMatchesKeys.length} instance(s) of likely secrets` : ''} in build output or repo code.\n`, ) // Explicit secret matches @@ -167,7 +167,7 @@ export const logSecretsScanFailBuildMessage = function ({ ) } - if (enhancedScanShouldImpactBuilds) { + if (enhancedScanShouldRunInActiveMode) { // Likely secret matches from enhanced scan enhancedSecretMatchesKeys.forEach((key, index) => { logError(logs, `${index === 0 && secretMatchesKeys.length ? '\n' : ''}"${key}***" detected as a likely secret:`) diff --git a/packages/build/src/plugins_core/secrets_scanning/index.ts b/packages/build/src/plugins_core/secrets_scanning/index.ts index 9dceffc8ba..1bb49d3478 100644 --- a/packages/build/src/plugins_core/secrets_scanning/index.ts +++ b/packages/build/src/plugins_core/secrets_scanning/index.ts @@ -170,7 +170,7 @@ const coreStep: CoreStepFunction = async function ({ logs, scanResults, groupedResults: groupScanResultsByKeyAndScanType(scanResults), - enhancedScanShouldImpactBuilds: enhancedScanShouldRunInActiveMode, + enhancedScanShouldRunInActiveMode, }) const error = new Error(`Secrets scanning found secrets in build.`) From 926342c2681d2d287d2d685c83c87e2b6b7ee33d Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Thu, 29 May 2025 11:09:50 +0200 Subject: [PATCH 6/6] test: fix wrong conflict resolution --- packages/build/tests/secrets_scanning/tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/build/tests/secrets_scanning/tests.js b/packages/build/tests/secrets_scanning/tests.js index 3820819ad6..7f6197bfa6 100644 --- a/packages/build/tests/secrets_scanning/tests.js +++ b/packages/build/tests/secrets_scanning/tests.js @@ -299,7 +299,7 @@ for (const { testPrefix, featureFlags } of [ const { requests } = await new Fixture('./fixtures/src_scanning_likely_enhanced_scan_secrets_disabled') .withFlags({ debug: false, - explicitSecretKeys: '', + explicitSecretKeys: 'ENV_VAR_1', enhancedSecretScan: true, deployId: 'test', token: 'test',