diff --git a/lib/config/presets.ts b/lib/config/presets.ts index 95933fa9d61af3118bc99bef472769cbe2c02153..9af6b7b778cc91f58f22f7073e3aa65f143c52a9 100644 --- a/lib/config/presets.ts +++ b/lib/config/presets.ts @@ -7,6 +7,7 @@ import * as npm from '../datasource/npm'; import * as gitlab from '../datasource/gitlab'; import { RenovateConfig } from './common'; import { mergeChildConfig } from './utils'; +import { regEx } from '../util/regex'; const datasources = { github, @@ -126,7 +127,7 @@ export function replaceArgs( if (is.string(obj)) { let returnStr = obj; for (const [arg, argVal] of Object.entries(argMapping)) { - const re = new RegExp(`{{${arg}}}`, 'g'); + const re = regEx(`{{${arg}}}`, 'g'); returnStr = returnStr.replace(re, argVal); } return returnStr; diff --git a/lib/config/validation.ts b/lib/config/validation.ts index 91984b7cfe38ce22c799d8aaf390440d512466a2..8c30c3aea5a61d639f32653af51bc13df97d2551 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -1,10 +1,10 @@ import is from '@sindresorhus/is'; -import safe from 'safe-regex'; import { getOptions, RenovateOptions } from './definitions'; import { resolveConfigPresets } from './presets'; import { hasValidSchedule, hasValidTimezone } from '../workers/branch/schedule'; import * as managerValidator from './validation-helpers/managers'; import { RenovateConfig, ValidationMessage } from './common'; +import { regEx } from '../util/regex'; const options = getOptions(); @@ -183,13 +183,7 @@ export async function validateConfig( !(val && val.length === 1 && val[0] === '*') ) { try { - RegExp(val as any); - if (!safe(val as any)) { - errors.push({ - depName: 'Configuration Error', - message: `Unsafe regExp for ${currentPath}: \`${val}\``, - }); - } + regEx(val as any); } catch (e) { errors.push({ depName: 'Configuration Error', @@ -198,21 +192,15 @@ export async function validateConfig( } } if (key === 'fileMatch') { - try { - for (const fileMatch of val) { - RegExp(fileMatch); - if (!safe(fileMatch)) { - errors.push({ - depName: 'Configuration Error', - message: `Unsafe regExp for ${currentPath}: \`${fileMatch}\``, - }); - } + for (const fileMatch of val) { + try { + regEx(fileMatch); + } catch (e) { + errors.push({ + depName: 'Configuration Error', + message: `Invalid regExp for ${currentPath}: \`${fileMatch}\``, + }); } - } catch (e) { - errors.push({ - depName: 'Configuration Error', - message: `Invalid regExp for ${currentPath}: \`${val}\``, - }); } } if ( diff --git a/lib/datasource/go/index.ts b/lib/datasource/go/index.ts index 9bbfde96b5070cb7c10b8103c323727184236696..b555235fce897cf6bfab4d2361fe648059361715 100644 --- a/lib/datasource/go/index.ts +++ b/lib/datasource/go/index.ts @@ -2,6 +2,7 @@ import { logger } from '../../logger'; import got from '../../util/got'; import * as github from '../github'; import { DigestConfig, PkgReleaseConfig, ReleaseResult } from '../common'; +import { regEx } from '../../util/regex'; interface DataSource { datasource: string; @@ -30,7 +31,7 @@ async function getDatasource(name: string): Promise<DataSource | null> { hostType: 'go', })).body; const sourceMatch = res.match( - new RegExp(`<meta\\s+name="go-source"\\s+content="${name}\\s+([^\\s]+)`) + regEx(`<meta\\s+name="go-source"\\s+content="${name}\\s+([^\\s]+)`) ); if (sourceMatch) { const [, goSourceUrl] = sourceMatch; diff --git a/lib/manager/ansible/update.ts b/lib/manager/ansible/update.ts index a24b5328775000c21b9e1fd20d4f021969600cf0..8b7b2282f6af1ea85302019157fc1439b4a65476 100644 --- a/lib/manager/ansible/update.ts +++ b/lib/manager/ansible/update.ts @@ -1,6 +1,7 @@ import { logger } from '../../logger'; import { getNewFrom } from '../dockerfile/update'; import { Upgrade } from '../common'; +import { regEx } from '../../util/regex'; export default function updateDependency( fileContent: string, @@ -11,7 +12,7 @@ export default function updateDependency( logger.debug(`ansible.updateDependency(): ${newFrom}`); const lines = fileContent.split('\n'); const lineToChange = lines[upgrade.managerData.lineNumber]; - const imageLine = new RegExp(/^(\s*image:\s*'?"?)[^\s'"]+('?"?\s*)$/); + const imageLine = regEx(`^(\\s*image:\\s*'?"?)[^\\s'"]+('?"?\\s*)$`); if (!lineToChange.match(imageLine)) { logger.debug('No image line found'); return null; diff --git a/lib/manager/bazel/extract.ts b/lib/manager/bazel/extract.ts index f97ba65b08f2f21caaff569e491c2cc0b0bec58c..ae420a6d53515b2066eb51981801fa9cdb5a4136 100644 --- a/lib/manager/bazel/extract.ts +++ b/lib/manager/bazel/extract.ts @@ -3,6 +3,7 @@ import parse from 'github-url-from-git'; import { parse as _parse } from 'url'; import { logger } from '../../logger'; import { PackageDependency, PackageFile } from '../common'; +import { regEx } from '../../util/regex'; interface UrlParsedResult { repo: string; @@ -78,7 +79,7 @@ function parseContent(content: string): string[] { (acc, prefix) => [ ...acc, ...content - .split(new RegExp(prefix + '\\s*\\(', 'g')) + .split(regEx(prefix + '\\s*\\(', 'g')) .slice(1) .map(base => { const ind = findBalancedParenIndex(base); diff --git a/lib/manager/bazel/update.ts b/lib/manager/bazel/update.ts index 3f55a4a21ab61da0cbc5aa387654dce34855356e..7f9f4e55d0f68948c710a054059dd7b932c31416 100644 --- a/lib/manager/bazel/update.ts +++ b/lib/manager/bazel/update.ts @@ -2,6 +2,7 @@ import { fromStream } from 'hasha'; import got from '../../util/got'; import { logger } from '../../logger'; import { Upgrade } from '../common'; +import { regEx } from '../../util/regex'; function updateWithNewVersion( content: string, @@ -137,7 +138,7 @@ export async function updateDependency( const hash = await getHashFromUrl(url); newDef = setNewHash(upgrade.managerData.def, hash); newDef = newDef.replace( - new RegExp(`(strip_prefix\\s*=\\s*)"[^"]*"`), + regEx(`(strip_prefix\\s*=\\s*)"[^"]*"`), `$1"${shortRepo}-${upgrade.newDigest}"` ); const match = @@ -151,7 +152,7 @@ export async function updateDependency( if (newDef.endsWith('\n')) { existingRegExStr += '\n'; } - const existingDef = new RegExp(existingRegExStr); + const existingDef = regEx(existingRegExStr); // istanbul ignore if if (!fileContent.match(existingDef)) { logger.info('Cannot match existing string'); diff --git a/lib/manager/buildkite/update.ts b/lib/manager/buildkite/update.ts index 14e7da9691c531b5e61e54b17ca45f62b9a44dbd..943cd4e09d325633fc5528c3ffbae1d81c39c7af 100644 --- a/lib/manager/buildkite/update.ts +++ b/lib/manager/buildkite/update.ts @@ -1,5 +1,6 @@ import { logger } from '../../logger'; import { Upgrade } from '../common'; +import { regEx } from '../../util/regex'; export function updateDependency( currentFileContent: string, @@ -10,7 +11,7 @@ export function updateDependency( logger.debug(`buildkite.updateDependency: ${upgrade.newValue}`); const lines = currentFileContent.split('\n'); const lineToChange = lines[lineIdx]; - const depLine = new RegExp(/^(\s+[^#]+#)[^:]+(:.*)$/); + const depLine = regEx(`^(\\s+[^#]+#)[^:]+(:.*)$`); if (!lineToChange.match(depLine)) { logger.debug('No image line found'); return null; diff --git a/lib/manager/bundler/extract.ts b/lib/manager/bundler/extract.ts index 7d7da5032cff0f6cf02579e9efb997ba7e2abc4d..3deb6481f926c230f6743ef161a349e7032d6ce0 100644 --- a/lib/manager/bundler/extract.ts +++ b/lib/manager/bundler/extract.ts @@ -2,6 +2,7 @@ import { logger } from '../../logger'; import { isValid } from '../../versioning/ruby'; import { PackageFile, PackageDependency } from '../common'; import { platform } from '../../platform'; +import { regEx } from '../../util/regex'; export { extractPackageFile }; @@ -22,7 +23,7 @@ async function extractPackageFile( sourceMatch = sourceMatch || line.match( - new RegExp(`^source ${delimiter}([^${delimiter}]+)${delimiter}\\s*$`) + regEx(`^source ${delimiter}([^${delimiter}]+)${delimiter}\\s*$`) ); } if (sourceMatch) { @@ -32,9 +33,7 @@ async function extractPackageFile( for (const delimiter of delimiters) { rubyMatch = rubyMatch || - line.match( - new RegExp(`^ruby ${delimiter}([^${delimiter}]+)${delimiter}`) - ); + line.match(regEx(`^ruby ${delimiter}([^${delimiter}]+)${delimiter}`)); } if (rubyMatch) { res.compatibility = { ruby: rubyMatch[1] }; @@ -43,9 +42,9 @@ async function extractPackageFile( let gemDelimiter: string; for (const delimiter of delimiters) { const gemMatchRegex = `^gem ${delimiter}([^${delimiter}]+)${delimiter}(,\\s+${delimiter}([^${delimiter}]+)${delimiter}){0,2}`; - if (line.match(new RegExp(gemMatchRegex))) { + if (line.match(regEx(gemMatchRegex))) { gemDelimiter = delimiter; - gemMatch = gemMatch || line.match(new RegExp(gemMatchRegex)); + gemMatch = gemMatch || line.match(regEx(gemMatchRegex)); } } if (gemMatch) { @@ -56,7 +55,7 @@ async function extractPackageFile( if (gemMatch[3]) { dep.currentValue = gemMatch[0] .substring(`gem ${gemDelimiter}${dep.depName}${gemDelimiter},`.length) - .replace(new RegExp(gemDelimiter, 'g'), '') + .replace(regEx(gemDelimiter, 'g'), '') .trim(); if (!isValid(dep.currentValue)) { dep.skipReason = 'invalid-value'; @@ -100,7 +99,7 @@ async function extractPackageFile( } for (const delimiter of delimiters) { const sourceBlockMatch = line.match( - new RegExp(`^source\\s+${delimiter}(.*?)${delimiter}\\s+do`) + regEx(`^source\\s+${delimiter}(.*?)${delimiter}\\s+do`) ); if (sourceBlockMatch) { const repositoryUrl = sourceBlockMatch[1]; diff --git a/test/config/__snapshots__/validation.spec.ts.snap b/test/config/__snapshots__/validation.spec.ts.snap index efe8cdf624bfafc242834e6761f8f8b4c90c528e..72bc3fe2ad93ddaac24d0433b1ce21b688e44ff4 100644 --- a/test/config/__snapshots__/validation.spec.ts.snap +++ b/test/config/__snapshots__/validation.spec.ts.snap @@ -59,10 +59,6 @@ Array [ "depName": "Configuration Error", "message": "Invalid regExp for npm.fileMatch: \`abc ([a-z]+) ([a-z]+))\`", }, - Object { - "depName": "Configuration Error", - "message": "Unsafe regExp for docker.fileMatch: \`(x+x+)+y\`", - }, ] `; @@ -113,7 +109,7 @@ Array [ }, Object { "depName": "Configuration Error", - "message": "Unsafe regExp for packageRules[0].excludePackagePatterns: \`(x+x+)+y\`", + "message": "Invalid regExp for packageRules[0].excludePackagePatterns: \`(x+x+)+y\`", }, ] `; diff --git a/test/config/validation.spec.ts b/test/config/validation.spec.ts index 38f4ad7be99b70e75bd8c67187a2125a65c38b69..a0d3f3b944d33dc51cfed5591d4ac13ede996c19 100644 --- a/test/config/validation.spec.ts +++ b/test/config/validation.spec.ts @@ -138,6 +138,7 @@ describe('config/validation', () => { expect(errors).toMatchSnapshot(); expect(errors).toHaveLength(0); }); + it('errors for unsafe fileMatches', async () => { const config = { npm: { @@ -151,8 +152,20 @@ describe('config/validation', () => { config ); expect(warnings).toHaveLength(0); - expect(errors).toHaveLength(2); + expect(errors).toHaveLength(1); expect(errors).toMatchSnapshot(); }); + + it('validates regEx for each fileMatch', async () => { + const config = { + fileMatch: ['js', '***$}{]]['], + }; + const { warnings, errors } = await configValidation.validateConfig( + config, + true + ); + expect(warnings).toHaveLength(0); + expect(errors).toHaveLength(1); + }); }); });