@netlify/build 36.0.0 → 36.1.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.
@@ -1,5 +1,4 @@
1
1
  export function getNewEnvChanges(envBefore: any, netlifyConfig: any, netlifyConfigCopy: any): any;
2
2
  export function setEnvChanges(envChanges: any, currentEnv?: NodeJS.ProcessEnv): {
3
3
  [key: string]: string | undefined;
4
- TZ?: string;
5
4
  };
package/lib/log/logger.js CHANGED
@@ -33,7 +33,7 @@ export const getBufferLogs = (config) => {
33
33
  export const log = function (logs, string, config = {}) {
34
34
  const { indent = false, color } = config;
35
35
  const stringA = indent ? indentString(string, INDENT_SIZE) : string;
36
- const stringB = String(stringA).replace(EMPTY_LINES_REGEXP, EMPTY_LINE);
36
+ const stringB = stringA.replace(EMPTY_LINES_REGEXP, EMPTY_LINE);
37
37
  const stringC = color === undefined ? stringB : color(stringB);
38
38
  if (logs && logs.outputFlusher) {
39
39
  logs.outputFlusher.flush();
@@ -34,9 +34,8 @@ export function logDbMigrations({ logs, migrations, srcDir }: {
34
34
  }): void;
35
35
  export function logSecretsScanSkipMessage(logs: any, msg: any): void;
36
36
  export function logSecretsScanSuccessMessage(logs: any, msg: any): void;
37
- export function logSecretsScanFailBuildMessage({ logs, scanResults, groupedResults, enhancedScanShouldRunInActiveMode, }: {
37
+ export function logSecretsScanFailBuildMessage({ logs, scanResults, groupedResults }: {
38
38
  logs: any;
39
39
  scanResults: any;
40
40
  groupedResults: any;
41
- enhancedScanShouldRunInActiveMode: any;
42
41
  }): void;
@@ -1,6 +1,5 @@
1
1
  import path from 'path';
2
2
  import { RUNTIME } from '@netlify/zip-it-and-ship-it';
3
- import { trace } from '@opentelemetry/api';
4
3
  import { log, logArray, logError, logErrorSubHeader, logWarningSubHeader } from '../logger.js';
5
4
  import { THEME } from '../theme.js';
6
5
  const logBundleResultFunctions = ({ functions, headerMessage, logs, error }) => {
@@ -68,6 +67,8 @@ export const trackBundleResults = ({ results = [], systemLog }) => {
68
67
  name: result.name,
69
68
  runtime: result.runtime,
70
69
  bundler: result.runtime === RUNTIME.JAVASCRIPT ? result.bundler : null,
70
+ bundlerReason: result.runtime === RUNTIME.JAVASCRIPT ? (result.bundlerReason ?? null) : null,
71
+ sizeBytes: result.size ?? null,
71
72
  hadFallback: (result.bundlerErrors?.length ?? 0) > 0,
72
73
  hadWarnings: (result.bundlerWarnings?.length ?? 0) > 0,
73
74
  }));
@@ -79,23 +80,13 @@ export const trackBundleResults = ({ results = [], systemLog }) => {
79
80
  const fallbackCount = perFunction.filter((p) => p.hadFallback).length;
80
81
  const warningsCount = perFunction.filter((p) => p.hadWarnings).length;
81
82
  systemLog({
82
- msg: 'Functions bundling completed',
83
+ msg: 'Functions bundling completed successfully',
83
84
  bundlers,
84
85
  bundlerCounts,
85
86
  fallbackCount,
86
87
  warningsCount,
87
88
  functions: perFunction,
88
89
  });
89
- const span = trace.getActiveSpan();
90
- if (span) {
91
- span.setAttribute('build.execution.step.bundler', bundlers);
92
- span.setAttribute('build.execution.step.functions_count', perFunction.length);
93
- span.setAttribute('build.execution.step.bundler.fallback_count', fallbackCount);
94
- span.setAttribute('build.execution.step.bundler.warnings_count', warningsCount);
95
- for (const [bundler, count] of Object.entries(bundlerCounts)) {
96
- span.setAttribute(`build.execution.step.bundler.${bundler}.count`, count);
97
- }
98
- }
99
90
  return { bundlers, fallbackCount, warningsCount };
100
91
  };
101
92
  export const logFunctionsNonExistingDir = function (logs, relativeFunctionsSrc) {
@@ -180,11 +171,11 @@ export const logSecretsScanSkipMessage = function (logs, msg) {
180
171
  export const logSecretsScanSuccessMessage = function (logs, msg) {
181
172
  log(logs, msg, { color: THEME.highlightWords });
182
173
  };
183
- export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, groupedResults, enhancedScanShouldRunInActiveMode, }) {
174
+ export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, groupedResults }) {
184
175
  const { secretMatches, enhancedSecretMatches } = groupedResults;
185
176
  const secretMatchesKeys = Object.keys(secretMatches);
186
177
  const enhancedSecretMatchesKeys = Object.keys(enhancedSecretMatches);
187
- logErrorSubHeader(logs, `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`);
178
+ 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`);
188
179
  // Explicit secret matches
189
180
  secretMatchesKeys.forEach((key) => {
190
181
  logError(logs, `Secret env var "${key}"'s value detected:`);
@@ -200,22 +191,20 @@ export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, gro
200
191
  logError(logs, `\nTo prevent exposing secrets, the build will fail until these secret values are not found in build output or repo files.`);
201
192
  logError(logs, `\nIf these are expected, use SECRETS_SCAN_OMIT_PATHS, SECRETS_SCAN_OMIT_KEYS, or SECRETS_SCAN_ENABLED to prevent detecting.`);
202
193
  }
203
- if (enhancedScanShouldRunInActiveMode) {
204
- // Likely secret matches from enhanced scan
205
- enhancedSecretMatchesKeys.forEach((key, index) => {
206
- logError(logs, `${index === 0 && secretMatchesKeys.length ? '\n' : ''}"${key}***" detected as a likely secret:`);
207
- enhancedSecretMatches[key]
208
- .sort((a, b) => {
209
- return a.file > b.file ? 0 : 1;
210
- })
211
- .forEach(({ lineNumber, file }) => {
212
- logError(logs, `found value at line ${lineNumber} in ${file}`, { indent: true });
213
- });
194
+ // Likely secret matches from enhanced scan
195
+ enhancedSecretMatchesKeys.forEach((key, index) => {
196
+ logError(logs, `${index === 0 && secretMatchesKeys.length ? '\n' : ''}"${key}***" detected as a likely secret:`);
197
+ enhancedSecretMatches[key]
198
+ .sort((a, b) => {
199
+ return a.file > b.file ? 0 : 1;
200
+ })
201
+ .forEach(({ lineNumber, file }) => {
202
+ logError(logs, `found value at line ${lineNumber} in ${file}`, { indent: true });
214
203
  });
215
- if (enhancedSecretMatchesKeys.length) {
216
- logError(logs, `\nTo prevent exposing secrets, the build will fail until these likely secret values are not found in build output or repo files.`);
217
- logError(logs, `\nIf these are expected, use SECRETS_SCAN_SMART_DETECTION_OMIT_VALUES, or SECRETS_SCAN_SMART_DETECTION_ENABLED to prevent detecting.`);
218
- }
204
+ });
205
+ if (enhancedSecretMatchesKeys.length) {
206
+ logError(logs, `\nTo prevent exposing secrets, the build will fail until these likely secret values are not found in build output or repo files.`);
207
+ logError(logs, `\nIf these are expected, use SECRETS_SCAN_SMART_DETECTION_OMIT_VALUES, or SECRETS_SCAN_SMART_DETECTION_ENABLED to prevent detecting.`);
219
208
  }
220
209
  logError(logs, `\nFor more information on secrets scanning, see the Netlify Docs: https://ntl.fyi/configure-secrets-scanning`);
221
210
  };
@@ -40,6 +40,8 @@ const coreStep = async function ({ logs, deployId, buildDir, packagePath, consta
40
40
  try {
41
41
  await pMap(blobsToUpload, async ({ key, contentPath, metadataPath }) => {
42
42
  const { data, metadata } = await getFileWithMetadata(key, contentPath, metadataPath);
43
+ // `data` is a `Buffer`, typed by @types/node as `Buffer<ArrayBufferLike>`, which TS
44
+ // rejects as a `BlobPart`; the runtime value is a valid blob part.
43
45
  await blobStore.set(key, new Blob([data]), { metadata });
44
46
  }, { concurrency: 10 });
45
47
  }
@@ -30,13 +30,9 @@ const coreStep = async ({ api, branch, buildDir, constants, context, logs }) =>
30
30
  if (migrationNames.length > 0 && migrationsSrc) {
31
31
  logDbMigrations({ logs, migrations: migrationNames, srcDir: migrationsSrc });
32
32
  }
33
- // @ts-expect-error This is an internal method for now so it isn't typed yet.
34
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
35
33
  const database = (await api.createSiteDatabase({ site_id: siteId }));
36
34
  let connectionString = database.connection_string;
37
35
  if (context !== 'production') {
38
- // @ts-expect-error This is an internal method for now so it isn't typed yet.
39
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
40
36
  const databaseBranch = (await api.createSiteDatabaseBranch({
41
37
  site_id: siteId,
42
38
  body: { branch_id: branch },
@@ -47,6 +47,8 @@ const coreStep = async function ({ debug, logs, deployId, buildDir, quiet, packa
47
47
  log(logs, `- Uploading blob ${key}`, { indent: true });
48
48
  }
49
49
  const { data, metadata } = await getFileWithMetadata(key, contentPath, metadataPath);
50
+ // `data` is a `Buffer`, typed by @types/node as `Buffer<ArrayBufferLike>`, which TS
51
+ // rejects as a `BlobPart`; the runtime value is a valid blob part.
50
52
  await blobStore.set(key, new Blob([data]), { metadata });
51
53
  }, { concurrency: 10 });
52
54
  }
@@ -5,13 +5,10 @@ import { logSecretsScanFailBuildMessage, logSecretsScanSkipMessage, logSecretsSc
5
5
  import { reportValidations } from '../../status/validations.js';
6
6
  import { getFilePathsToScan, getOmitValuesFromEnhancedScanForEnhancedScanFromEnv, getSecretKeysToScanFor, groupScanResultsByKeyAndScanType, isEnhancedSecretsScanningEnabled, isSecretsScanningEnabled, scanFilesForKeyValues, } from './utils.js';
7
7
  const tracer = trace.getTracer('secrets-scanning');
8
- const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecretKeys, enhancedSecretScan, featureFlags, systemLog, deployId, api, }) {
8
+ const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecretKeys, enhancedSecretScan, systemLog, deployId, api, }) {
9
9
  const stepResults = {};
10
10
  const passedSecretKeys = (explicitSecretKeys || '').split(',');
11
11
  const envVars = netlifyConfig.build.environment;
12
- // When the flag is disabled, we may still run the scan if a secrets scan would otherwise take place anyway
13
- // In this case, we hide any output to the user and simply gather the information in our logs
14
- const enhancedScanShouldRunInActiveMode = featureFlags?.enhanced_secret_scan_impacts_builds ?? false;
15
12
  systemLog?.({ passedSecretKeys, buildDir });
16
13
  if (!isSecretsScanningEnabled(envVars)) {
17
14
  logSecretsScanSkipMessage(logs, 'Secrets scanning disabled via SECRETS_SCAN_ENABLED flag set to false.');
@@ -26,20 +23,14 @@ const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecret
26
23
  }
27
24
  const enhancedScanningEnabledInEnv = isEnhancedSecretsScanningEnabled(envVars);
28
25
  const enhancedScanConfigured = enhancedSecretScan && enhancedScanningEnabledInEnv;
29
- if (enhancedSecretScan && enhancedScanShouldRunInActiveMode && !enhancedScanningEnabledInEnv) {
26
+ if (enhancedSecretScan && !enhancedScanningEnabledInEnv) {
30
27
  logSecretsScanSkipMessage(logs, 'Enhanced secrets detection disabled via SECRETS_SCAN_SMART_DETECTION_ENABLED flag set to false.');
31
28
  }
32
- if (enhancedScanShouldRunInActiveMode &&
33
- enhancedScanConfigured &&
34
- envVars['SECRETS_SCAN_SMART_DETECTION_OMIT_VALUES'] !== undefined) {
29
+ if (enhancedScanConfigured && envVars['SECRETS_SCAN_SMART_DETECTION_OMIT_VALUES'] !== undefined) {
35
30
  log(logs, `SECRETS_SCAN_SMART_DETECTION_OMIT_VALUES override option set to: ${envVars['SECRETS_SCAN_SMART_DETECTION_OMIT_VALUES']}\n`);
36
31
  }
37
32
  const keysToSearchFor = getSecretKeysToScanFor(envVars, passedSecretKeys);
38
- // In passive mode, only run the enhanced scan if we have explicit secret keys
39
- const enhancedScanShouldRun = enhancedScanShouldRunInActiveMode
40
- ? enhancedScanConfigured
41
- : enhancedScanConfigured && keysToSearchFor.length > 0;
42
- if (keysToSearchFor.length === 0 && !enhancedScanShouldRun) {
33
+ if (keysToSearchFor.length === 0 && !enhancedScanConfigured) {
43
34
  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.');
44
35
  return stepResults;
45
36
  }
@@ -60,7 +51,7 @@ const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecret
60
51
  keys: keysToSearchFor,
61
52
  base: buildDir,
62
53
  filePaths,
63
- enhancedScanning: enhancedScanShouldRun,
54
+ enhancedScanning: enhancedScanConfigured,
64
55
  omitValuesFromEnhancedScan: getOmitValuesFromEnhancedScanForEnhancedScanFromEnv(envVars),
65
56
  });
66
57
  secretMatches = scanResults.matches.filter((match) => !match.enhancedMatch);
@@ -73,8 +64,7 @@ const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecret
73
64
  secretsFilesCount: scanResults.scannedFilesCount,
74
65
  keysToSearchFor,
75
66
  enhancedPrefixMatches: enhancedSecretMatches.length ? enhancedSecretMatches.map((match) => match.key) : [],
76
- enhancedScanning: enhancedScanShouldRun,
77
- enhancedScanActiveMode: enhancedScanShouldRunInActiveMode,
67
+ enhancedScanning: enhancedScanConfigured,
78
68
  };
79
69
  systemLog?.(attributesForLogsAndSpan);
80
70
  span.setAttributes(attributesForLogsAndSpan);
@@ -84,13 +74,11 @@ const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecret
84
74
  const secretScanResult = {
85
75
  scannedFilesCount: scanResults?.scannedFilesCount ?? 0,
86
76
  secretsScanMatches: secretMatches ?? [],
87
- enhancedSecretsScanMatches: enhancedScanShouldRunInActiveMode && enhancedSecretMatches ? enhancedSecretMatches : [],
77
+ enhancedSecretsScanMatches: enhancedSecretMatches ? enhancedSecretMatches : [],
88
78
  };
89
79
  reportValidations({ api, secretScanResult, deployId, systemLog });
90
80
  }
91
- if (!scanResults ||
92
- scanResults.matches.length === 0 ||
93
- (!enhancedScanShouldRunInActiveMode && !secretMatches?.length)) {
81
+ if (!scanResults || scanResults.matches.length === 0) {
94
82
  logSecretsScanSuccessMessage(logs, `Secrets scanning complete. ${scanResults?.scannedFilesCount} file(s) scanned. No secrets detected in build output or repo code!`);
95
83
  return stepResults;
96
84
  }
@@ -100,7 +88,6 @@ const coreStep = async function ({ buildDir, logs, netlifyConfig, explicitSecret
100
88
  logs,
101
89
  scanResults,
102
90
  groupedResults: groupScanResultsByKeyAndScanType(scanResults),
103
- enhancedScanShouldRunInActiveMode,
104
91
  });
105
92
  const error = new Error(`Secrets scanning found secrets in build.`);
106
93
  addErrorInfo(error, { type: 'secretScanningFoundSecrets' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "36.0.0",
3
+ "version": "36.1.0",
4
4
  "description": "Netlify build module",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -70,13 +70,13 @@
70
70
  "@netlify/blobs": "^10.4.4",
71
71
  "@netlify/cache-utils": "^7.0.0",
72
72
  "@netlify/config": "^25.0.0",
73
- "@netlify/edge-bundler": "15.0.0",
74
- "@netlify/functions-utils": "^7.0.0",
73
+ "@netlify/edge-bundler": "15.0.1",
74
+ "@netlify/functions-utils": "^7.0.2",
75
75
  "@netlify/git-utils": "^7.0.0",
76
76
  "@netlify/opentelemetry-utils": "^3.0.0",
77
77
  "@netlify/plugins-list": "^6.81.6",
78
78
  "@netlify/run-utils": "^7.0.0",
79
- "@netlify/zip-it-and-ship-it": "15.0.0",
79
+ "@netlify/zip-it-and-ship-it": "15.1.0",
80
80
  "@sindresorhus/slugify": "^2.0.0",
81
81
  "ansi-escapes": "^7.0.0",
82
82
  "ansis": "^4.1.0",
@@ -122,7 +122,7 @@
122
122
  "@netlify/nock-udp": "^6.0.0",
123
123
  "@opentelemetry/api": "~1.8.0",
124
124
  "@opentelemetry/sdk-trace-base": "~1.24.0",
125
- "@types/node": "^18.19.111",
125
+ "@types/node": "^22.12.0",
126
126
  "atob": "^2.1.2",
127
127
  "ava": "^5.0.0",
128
128
  "c8": "^10.0.0",
@@ -152,5 +152,5 @@
152
152
  "engines": {
153
153
  "node": ">=22.12.0"
154
154
  },
155
- "gitHead": "bdaf7cd5e14049c31a236c9432f192f78c6c31c8"
155
+ "gitHead": "677f1bd6db4429d70ce3d207f00c7d603ae2d1bf"
156
156
  }