From 2e78a7117da87ec84852fd049aa6f3ab8f85a430 Mon Sep 17 00:00:00 2001 From: Norbert Szulc <norbert@icetek.io> Date: Thu, 6 Jun 2024 13:23:47 +0200 Subject: [PATCH] fix!: normalize Python depName in every manager (#27733) --- docs/usage/python.md | 7 +++ lib/modules/manager/pep621/utils.ts | 3 +- .../manager/pip-compile/extract.spec.ts | 1 + lib/modules/manager/pip-compile/extract.ts | 9 +--- .../__snapshots__/extract.spec.ts.snap | 41 ++++++++++++++++++ .../manager/pip_requirements/extract.spec.ts | 1 + .../manager/pip_requirements/extract.ts | 2 + .../__snapshots__/extract.spec.ts.snap | 16 +++++++ lib/modules/manager/pip_setup/extract.ts | 2 + lib/modules/manager/pipenv/extract.ts | 2 + .../__snapshots__/extract.spec.ts.snap | 43 +++++++++++++++++++ lib/modules/manager/setup-cfg/extract.ts | 2 + lib/modules/platform/github/index.spec.ts | 32 ++++++++++++++ lib/modules/platform/github/index.ts | 5 ++- lib/modules/platform/utils/github-alerts.ts | 14 ++++++ .../repository/init/vulnerability.spec.ts | 34 --------------- lib/workers/repository/init/vulnerability.ts | 8 +--- 17 files changed, 172 insertions(+), 50 deletions(-) create mode 100644 lib/modules/platform/utils/github-alerts.ts diff --git a/docs/usage/python.md b/docs/usage/python.md index 031d49640d..6b3751c213 100644 --- a/docs/usage/python.md +++ b/docs/usage/python.md @@ -23,6 +23,13 @@ Legacy versions with the `===` prefix are ignored. 1. Renovate searches for the latest version on [PyPI](https://pypi.org/) to decide if there are upgrades 1. If the source package includes a GitHub URL as its source, and has a "changelog" file _or_ uses GitHub releases, a Release Note will be embedded in the generated PR +## Package name matching + +Your `matchPackageName` or `matchPackagePattern` rules will be matching against normalized names. +So if you have specified package `some.package` or `ANOTHER_DEP` in your package files (`requirements.txt`, `pyproject.toml`), they will be treated as `some-package` and `another-dep` respecitvely. +Not only they will be case insensitive but will replace any amount `._-` to a single `-`. +[Consult Python packaging documentation for the specification](https://packaging.python.org/en/latest/specifications/name-normalization/). + ## Alternate registries By default Renovate checks for upgrades on the `pypi.org` registry. diff --git a/lib/modules/manager/pep621/utils.ts b/lib/modules/manager/pep621/utils.ts index 13293e38c2..dcc3bb8cc2 100644 --- a/lib/modules/manager/pep621/utils.ts +++ b/lib/modules/manager/pep621/utils.ts @@ -3,6 +3,7 @@ import { logger } from '../../../logger'; import { regEx } from '../../../util/regex'; import { parse as parseToml } from '../../../util/toml'; import { PypiDatasource } from '../../datasource/pypi'; +import { normalizePythonDepName } from '../../datasource/pypi/common'; import type { PackageDependency } from '../types'; import { PyProject, PyProjectSchema } from './schema'; import type { Pep508ParseResult } from './types'; @@ -60,7 +61,7 @@ export function pep508ToPackageDependency( } const dep: PackageDependency = { - packageName: parsed.packageName, + packageName: normalizePythonDepName(parsed.packageName), depName: parsed.packageName, datasource: PypiDatasource.id, depType, diff --git a/lib/modules/manager/pip-compile/extract.spec.ts b/lib/modules/manager/pip-compile/extract.spec.ts index cab96c8f09..fd70448a9a 100644 --- a/lib/modules/manager/pip-compile/extract.spec.ts +++ b/lib/modules/manager/pip-compile/extract.spec.ts @@ -384,6 +384,7 @@ describe('modules/manager/pip-compile/extract', () => { datasource: 'pypi', depType: 'indirect', depName: 'bards-friend', + packageName: 'bards-friend', lockedVersion: '1.0.0', enabled: false, }); diff --git a/lib/modules/manager/pip-compile/extract.ts b/lib/modules/manager/pip-compile/extract.ts index 9960fb3b4c..2be0ad3fd3 100644 --- a/lib/modules/manager/pip-compile/extract.ts +++ b/lib/modules/manager/pip-compile/extract.ts @@ -2,7 +2,6 @@ import upath from 'upath'; import { logger } from '../../../logger'; import { readLocalFile } from '../../../util/fs'; import { ensureLocalPath } from '../../../util/fs/util'; -import { normalizePythonDepName } from '../../datasource/pypi/common'; import { extractPackageFile as extractRequirementsFile } from '../pip_requirements/extract'; import { extractPackageFile as extractSetupPyFile } from '../pip_setup'; import type { @@ -165,9 +164,7 @@ export async function extractAllPackageFiles( } for (const dep of packageFileContent.deps) { const lockedVersion = lockedDeps?.find( - (lockedDep) => - normalizePythonDepName(lockedDep.depName!) === - normalizePythonDepName(dep.depName!), + (lockedDep) => lockedDep.packageName! === dep.packageName!, )?.currentVersion; if (lockedVersion) { dep.lockedVersion = lockedVersion; @@ -246,9 +243,7 @@ function extendWithIndirectDeps( for (const lockedDep of lockedDeps) { if ( !packageFileContent.deps.find( - (dep) => - normalizePythonDepName(lockedDep.depName!) === - normalizePythonDepName(dep.depName!), + (dep) => lockedDep.packageName! === dep.packageName!, ) ) { packageFileContent.deps.push(indirectDep(lockedDep)); diff --git a/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap index beb0d0c9f5..4bbeef11ea 100644 --- a/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap @@ -8,23 +8,27 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() extracts "currentVersion": "0.3.1", "datasource": "pypi", "depName": "some-package", + "packageName": "some-package", }, { "currentValue": "==1.0.0", "currentVersion": "1.0.0", "datasource": "pypi", "depName": "some-other-package", + "packageName": "some-other-package", }, { "currentValue": undefined, "datasource": "pypi", "depName": "sphinx", + "packageName": "sphinx", }, { "currentValue": "==1.9", "currentVersion": "1.9", "datasource": "pypi", "depName": "not_semver", + "packageName": "not-semver", }, ], "registryUrls": [ @@ -40,30 +44,35 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() extracts "currentVersion": "1", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==0.6.27", "currentVersion": "0.6.27", "datasource": "pypi", "depName": "distribute", + "packageName": "distribute", }, { "currentValue": "==0.2", "currentVersion": "0.2", "datasource": "pypi", "depName": "dj-database-url", + "packageName": "dj-database-url", }, { "currentValue": "==2.4.5", "currentVersion": "2.4.5", "datasource": "pypi", "depName": "psycopg2", + "packageName": "psycopg2", }, { "currentValue": "==0.1.2", "currentVersion": "0.1.2", "datasource": "pypi", "depName": "wsgiref", + "packageName": "wsgiref", }, ] `; @@ -75,12 +84,14 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles c "currentVersion": "1.11.23", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==0.6.27", "currentVersion": "0.6.27", "datasource": "pypi", "depName": "distribute", + "packageName": "distribute", "skipReason": "ignored", }, { @@ -88,18 +99,21 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles c "currentVersion": "0.2", "datasource": "pypi", "depName": "dj-database-url", + "packageName": "dj-database-url", }, { "currentValue": "==2.4.5", "currentVersion": "2.4.5", "datasource": "pypi", "depName": "psycopg2", + "packageName": "psycopg2", }, { "currentValue": "==0.1.2", "currentVersion": "0.1.2", "datasource": "pypi", "depName": "wsgiref", + "packageName": "wsgiref", }, ] `; @@ -115,36 +129,42 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e "currentVersion": "2.0.12", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==4.1.1", "currentVersion": "4.1.1", "datasource": "pypi", "depName": "celery", + "packageName": "celery", }, { "currentValue": "== 3.2.1", "currentVersion": "3.2.1", "datasource": "pypi", "depName": "foo", + "packageName": "foo", }, { "currentValue": "==0.3.1", "currentVersion": "0.3.1", "datasource": "pypi", "depName": "some-package", + "packageName": "some-package", }, { "currentValue": "==1.0.0", "currentVersion": "1.0.0", "datasource": "pypi", "depName": "some-other-package", + "packageName": "some-other-package", }, { "currentValue": "==1.9", "currentVersion": "1.9", "datasource": "pypi", "depName": "not_semver", + "packageName": "not-semver", }, ], "registryUrls": [ @@ -164,36 +184,42 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e "currentVersion": "2.0.12", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==4.1.1", "currentVersion": "4.1.1", "datasource": "pypi", "depName": "celery", + "packageName": "celery", }, { "currentValue": "== 3.2.1", "currentVersion": "3.2.1", "datasource": "pypi", "depName": "foo", + "packageName": "foo", }, { "currentValue": "==0.3.1", "currentVersion": "0.3.1", "datasource": "pypi", "depName": "some-package", + "packageName": "some-package", }, { "currentValue": "==1.0.0", "currentVersion": "1.0.0", "datasource": "pypi", "depName": "some-other-package", + "packageName": "some-other-package", }, { "currentValue": "==1.9", "currentVersion": "1.9", "datasource": "pypi", "depName": "not_semver", + "packageName": "not-semver", }, ], } @@ -210,36 +236,42 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e "currentVersion": "2.0.12", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==4.1.1", "currentVersion": "4.1.1", "datasource": "pypi", "depName": "celery", + "packageName": "celery", }, { "currentValue": "== 3.2.1", "currentVersion": "3.2.1", "datasource": "pypi", "depName": "foo", + "packageName": "foo", }, { "currentValue": "==0.3.1", "currentVersion": "0.3.1", "datasource": "pypi", "depName": "some-package", + "packageName": "some-package", }, { "currentValue": "==1.0.0", "currentVersion": "1.0.0", "datasource": "pypi", "depName": "some-other-package", + "packageName": "some-other-package", }, { "currentValue": "==1.9", "currentVersion": "1.9", "datasource": "pypi", "depName": "not_semver", + "packageName": "not-semver", }, ], } @@ -253,18 +285,21 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e "currentVersion": "2.0.12", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==4.1.1", "currentVersion": "4.1.1", "datasource": "pypi", "depName": "celery", + "packageName": "celery", }, { "currentValue": "== 3.2.1", "currentVersion": "3.2.1", "datasource": "pypi", "depName": "foo", + "packageName": "foo", }, ], "registryUrls": [ @@ -281,18 +316,21 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e "currentVersion": "2.0.12", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==4.1.1", "currentVersion": "4.1.1", "datasource": "pypi", "depName": "celery", + "packageName": "celery", }, { "currentValue": "== 3.2.1", "currentVersion": "3.2.1", "datasource": "pypi", "depName": "foo", + "packageName": "foo", }, ], "registryUrls": [ @@ -309,18 +347,21 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() should ha "currentVersion": "1.9.1", "datasource": "pypi", "depName": "Django", + "packageName": "django", }, { "currentValue": "==0.22.1", "currentVersion": "0.22.1", "datasource": "pypi", "depName": "bgg", + "packageName": "bgg", }, { "currentValue": "==2016.1.8", "currentVersion": "2016.1.8", "datasource": "pypi", "depName": "html2text", + "packageName": "html2text", }, ], } diff --git a/lib/modules/manager/pip_requirements/extract.spec.ts b/lib/modules/manager/pip_requirements/extract.spec.ts index 76932dce19..f088de89f6 100644 --- a/lib/modules/manager/pip_requirements/extract.spec.ts +++ b/lib/modules/manager/pip_requirements/extract.spec.ts @@ -190,6 +190,7 @@ some-package==0.3.1`; currentVersion: '20.3.0', datasource: 'pypi', depName: 'attrs', + packageName: 'attrs', }, ], }); diff --git a/lib/modules/manager/pip_requirements/extract.ts b/lib/modules/manager/pip_requirements/extract.ts index 3d1a3a7bfc..1921ae49a9 100644 --- a/lib/modules/manager/pip_requirements/extract.ts +++ b/lib/modules/manager/pip_requirements/extract.ts @@ -6,6 +6,7 @@ import { isSkipComment } from '../../../util/ignore'; import { newlineRegex, regEx } from '../../../util/regex'; import { GitTagsDatasource } from '../../datasource/git-tags'; import { PypiDatasource } from '../../datasource/pypi'; +import { normalizePythonDepName } from '../../datasource/pypi/common'; import type { PackageDependency, PackageFileContent } from '../types'; import { extractPackageFileFlags } from './common'; import type { PipRequirementsManagerData } from './types'; @@ -81,6 +82,7 @@ export function extractPackageFile( dep = { ...dep, depName, + packageName: normalizePythonDepName(depName), currentValue, datasource: PypiDatasource.id, }; diff --git a/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap index 7246f4f88a..9ebc8247dc 100644 --- a/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap @@ -10,6 +10,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 49, }, + "packageName": "celery", }, { "currentValue": ">=1.7", @@ -18,6 +19,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 52, }, + "packageName": "logging-tree", }, { "currentValue": ">=2.2", @@ -26,6 +28,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 53, }, + "packageName": "pygments", }, { "currentValue": ">=5.0", @@ -34,6 +37,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 54, }, + "packageName": "psutil", }, { "currentValue": ">=3.0", @@ -42,6 +46,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 55, }, + "packageName": "objgraph", }, { "currentValue": ">=1.11.23,<2.0", @@ -50,6 +55,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 58, }, + "packageName": "django", }, { "currentValue": ">=0.11,<2.0", @@ -58,6 +64,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 61, }, + "packageName": "flask", }, { "currentValue": ">=1.4,<2.0", @@ -66,6 +73,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 62, }, + "packageName": "blinker", }, { "currentValue": ">=19.7.0,<20.0", @@ -74,6 +82,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 74, }, + "packageName": "gunicorn", }, { "currentValue": ">=0.15.3,<0.16", @@ -82,6 +91,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 75, }, + "packageName": "werkzeug", }, { "currentValue": ">=3.2.1,<4.0", @@ -90,6 +100,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 75, }, + "packageName": "statsd", }, { "currentValue": ">=2.10.0,<3.0", @@ -98,6 +109,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 76, }, + "packageName": "requests", "skipReason": "ignored", }, { @@ -107,6 +119,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 77, }, + "packageName": "raven", }, { "currentValue": ">=0.15.2,<0.17", @@ -115,6 +128,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 78, }, + "packageName": "future", }, { "currentValue": ">=1.0.16,<2.0", @@ -123,6 +137,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 79, }, + "packageName": "ipaddress", }, { "currentValue": ">=5.5.2,<6.0.0", @@ -131,6 +146,7 @@ exports[`modules/manager/pip_setup/extract extractPackageFile() returns found de "managerData": { "lineNumber": 80, }, + "packageName": "zope-interface", }, ], } diff --git a/lib/modules/manager/pip_setup/extract.ts b/lib/modules/manager/pip_setup/extract.ts index cef10e2322..d1bb84626b 100644 --- a/lib/modules/manager/pip_setup/extract.ts +++ b/lib/modules/manager/pip_setup/extract.ts @@ -2,6 +2,7 @@ import { RANGE_PATTERN } from '@renovatebot/pep440'; import { lang, lexer, parser, query as q } from 'good-enough-parser'; import { regEx } from '../../../util/regex'; import { PypiDatasource } from '../../datasource/pypi'; +import { normalizePythonDepName } from '../../datasource/pypi/common'; import type { ExtractConfig, PackageDependency, @@ -45,6 +46,7 @@ function depStringHandler( const dep: PackageDependency<ManagerData> = { depName, + packageName: normalizePythonDepName(depName), currentValue, managerData: { lineNumber: token.line - 1, diff --git a/lib/modules/manager/pipenv/extract.ts b/lib/modules/manager/pipenv/extract.ts index 10cc367e37..cfdae749cb 100644 --- a/lib/modules/manager/pipenv/extract.ts +++ b/lib/modules/manager/pipenv/extract.ts @@ -6,6 +6,7 @@ import { localPathExists } from '../../../util/fs'; import { regEx } from '../../../util/regex'; import { parse as parseToml } from '../../../util/toml'; import { PypiDatasource } from '../../datasource/pypi'; +import { normalizePythonDepName } from '../../datasource/pypi/common'; import type { PackageDependency, PackageFileContent } from '../types'; import type { PipFile, PipRequirement, PipSource } from './types'; @@ -76,6 +77,7 @@ function extractFromSection( const dep: PackageDependency = { depType: sectionName, depName, + packageName: normalizePythonDepName(depName), managerData: {}, }; if (currentValue) { diff --git a/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap index bef3179985..f0be467fd0 100644 --- a/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap @@ -8,12 +8,14 @@ exports[`modules/manager/setup-cfg/extract extractPackageFile() extracts depende "datasource": "pypi", "depName": "coloredlogs", "depType": "install", + "packageName": "coloredlogs", }, { "currentValue": "~=1.0", "datasource": "pypi", "depName": "first", "depType": "install", + "packageName": "first", }, { "currentValue": "==2.2", @@ -21,48 +23,56 @@ exports[`modules/manager/setup-cfg/extract extractPackageFile() extracts depende "datasource": "pypi", "depName": "second", "depType": "install", + "packageName": "second", }, { "currentValue": ">=3.0", "datasource": "pypi", "depName": "third", "depType": "install", + "packageName": "third", }, { "currentValue": ">=5.5.5", "datasource": "pypi", "depName": "quux", "depType": "install", + "packageName": "quux", }, { "currentValue": "~=2.1", "datasource": "pypi", "depName": "python-dateutil", "depType": "install", + "packageName": "python-dateutil", }, { "currentValue": ">=1.1.1", "datasource": "pypi", "depName": "foo", "depType": "install", + "packageName": "foo", }, { "currentValue": ">=3.3.3.", "datasource": "pypi", "depName": "baz", "depType": "install", + "packageName": "baz", }, { "currentValue": "~=0.4", "datasource": "pypi", "depName": "docopt", "depType": "install", + "packageName": "docopt", }, { "currentValue": "~=2.1", "datasource": "pypi", "depName": "fs", "depType": "install", + "packageName": "fs", }, { "currentValue": "==1.0", @@ -70,198 +80,231 @@ exports[`modules/manager/setup-cfg/extract extractPackageFile() extracts depende "datasource": "pypi", "depName": "nmspc.pkg", "depType": "install", + "packageName": "nmspc-pkg", }, { "currentValue": "~=2.18", "datasource": "pypi", "depName": "requests", "depType": "install", + "packageName": "requests", }, { "currentValue": "~=1.2.3", "datasource": "pypi", "depName": "compact", "depType": "install", + "packageName": "compact", }, { "currentValue": ">=2.27.0", "datasource": "pypi", "depName": "responses", "depType": "install", + "packageName": "responses", }, { "currentValue": "~=1.4", "datasource": "pypi", "depName": "six", "depType": "setup", + "packageName": "six", }, { "currentValue": "~=4.19", "datasource": "pypi", "depName": "tqdm", "depType": "setup", + "packageName": "tqdm", }, { "currentValue": "~=6.0", "datasource": "pypi", "depName": "tenacity", "depType": "setup", + "packageName": "tenacity", }, { "currentValue": "~=3.6", "datasource": "pypi", "depName": "typing", "depType": "test", + "packageName": "typing", }, { "currentValue": "~=1.7", "datasource": "pypi", "depName": "verboselogs", "depType": "test", + "packageName": "verboselogs", }, { "currentValue": undefined, "datasource": "pypi", "depName": "piexif", "depType": "extra", + "packageName": "piexif", }, { "currentValue": undefined, "datasource": "pypi", "depName": "Pillow", "depType": "extra", + "packageName": "pillow", }, { "currentValue": ">=2.2.2", "datasource": "pypi", "depName": "bar", "depType": "extra", + "packageName": "bar", }, { "currentValue": ">=4.4.4", "datasource": "pypi", "depName": "qux", "depType": "extra", + "packageName": "qux", }, { "currentValue": "~=0.1", "datasource": "pypi", "depName": "contexter", "depType": "extra", + "packageName": "contexter", }, { "currentValue": "~=2.0", "datasource": "pypi", "depName": "mock", "depType": "extra", + "packageName": "mock", }, { "currentValue": "~=0.6", "datasource": "pypi", "depName": "parameterized", "depType": "extra", + "packageName": "parameterized", }, { "currentValue": "~=2.12", "datasource": "pypi", "depName": "green", "depType": "extra", + "packageName": "green", }, { "currentValue": undefined, "datasource": "pypi", "depName": "coverage", "depType": "extra", + "packageName": "coverage", }, { "currentValue": undefined, "datasource": "pypi", "depName": "codecov", "depType": "extra", + "packageName": "codecov", }, { "currentValue": undefined, "datasource": "pypi", "depName": "codacy-coverage", "depType": "extra", + "packageName": "codacy-coverage", }, { "currentValue": "~=1.7", "datasource": "pypi", "depName": "sphinx", "depType": "extra", + "packageName": "sphinx", }, { "currentValue": "~=0.6", "datasource": "pypi", "depName": "sphinx-bootstrap-theme", "depType": "extra", + "packageName": "sphinx-bootstrap-theme", }, { "currentValue": "~=2.6", "datasource": "pypi", "depName": "semantic-version", "depType": "extra", + "packageName": "semantic-version", }, { "currentValue": undefined, "datasource": "pypi", "depName": "docutils", "depType": "extra", + "packageName": "docutils", }, { "currentValue": undefined, "datasource": "pypi", "depName": "Pygments", "depType": "extra", + "packageName": "pygments", }, { "currentValue": ">=0.9", "datasource": "pypi", "depName": "aiortc", "depType": "install", + "packageName": "aiortc", }, { "currentValue": ">=8.1", "datasource": "pypi", "depName": "websockets", "depType": "install", + "packageName": "websockets", }, { "currentValue": ">=3.6", "datasource": "pypi", "depName": "aiohttp", "depType": "install", + "packageName": "aiohttp", }, { "currentValue": ">=6.0", "datasource": "pypi", "depName": "pyee", "depType": "install", + "packageName": "pyee", }, { "currentValue": ">=8.1", "datasource": "pypi", "depName": "websockets", "depType": "install", + "packageName": "websockets", }, { "currentValue": ">=0.3", "datasource": "pypi", "depName": "dataclasses_json", "depType": "install", + "packageName": "dataclasses-json", }, { "currentValue": ">=10.0", "datasource": "pypi", "depName": "coloredlogs", "depType": "install", + "packageName": "coloredlogs", }, { "currentValue": "~=8.0.0", "datasource": "pypi", "depName": "av", "depType": "install", + "packageName": "av", }, ], } diff --git a/lib/modules/manager/setup-cfg/extract.ts b/lib/modules/manager/setup-cfg/extract.ts index 3aaca63523..017f9903ad 100644 --- a/lib/modules/manager/setup-cfg/extract.ts +++ b/lib/modules/manager/setup-cfg/extract.ts @@ -3,6 +3,7 @@ import { RANGE_PATTERN } from '@renovatebot/pep440'; import { logger } from '../../../logger'; import { newlineRegex, regEx } from '../../../util/regex'; import { PypiDatasource } from '../../datasource/pypi'; +import { normalizePythonDepName } from '../../datasource/pypi/common'; import type { PackageDependency, PackageFileContent, Result } from '../types'; function getSectionName(str: string): string { @@ -73,6 +74,7 @@ function parseDep( const dep: PackageDependency = { depName, + packageName: normalizePythonDepName(depName), currentValue, datasource: PypiDatasource.id, depType, diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 4577891621..47127a5504 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -3889,6 +3889,38 @@ describe('modules/platform/github/index', () => { ); expect(logger.logger.error).not.toHaveBeenCalled(); }); + + it('returns normalized names for PIP ecosystem', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + scope + .get( + '/repos/some/repo/dependabot/alerts?state=open&direction=asc&per_page=100', + ) + .reply(200, [ + { + security_advisory: { + description: 'description', + identifiers: [{ type: 'type', value: 'value' }], + references: [], + }, + security_vulnerability: { + package: { + ecosystem: 'pip', + name: 'FrIeNdLy.-.BARD', + }, + vulnerable_version_range: '0.0.2', + first_patched_version: { identifier: '0.0.3' }, + }, + dependency: { + manifest_path: 'bar/foo', + }, + }, + ]); + await github.initRepo({ repository: 'some/repo' }); + const res = await github.getVulnerabilityAlerts(); + expect(res[0].security_vulnerability!.package.name).toBe('friendly-bard'); + }); }); describe('getJsonFile()', () => { diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index a805ed7d7a..01f508b5ff 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -64,6 +64,7 @@ import type { UpdatePrConfig, } from '../types'; import { repoFingerprint } from '../util'; +import { normalizeNamePerEcosystem } from '../utils/github-alerts'; import { smartTruncate } from '../utils/pr-body'; import { remoteBranchExists } from './branch'; import { coerceRestPr, githubApi } from './common'; @@ -2008,7 +2009,9 @@ export async function getVulnerabilityAlerts(): Promise<VulnerabilityAlert[]> { } = alert.security_vulnerability; const patch = firstPatchedVersion?.identifier; - const key = `${ecosystem.toLowerCase()}/${name}`; + const normalizedName = normalizeNamePerEcosystem({ name, ecosystem }); + alert.security_vulnerability.package.name = normalizedName; + const key = `${ecosystem.toLowerCase()}/${normalizedName}`; const range = vulnerableVersionRange; const elem = shortAlerts[key] || {}; elem[range] = coerceToNull(patch); diff --git a/lib/modules/platform/utils/github-alerts.ts b/lib/modules/platform/utils/github-alerts.ts new file mode 100644 index 0000000000..b34a75e094 --- /dev/null +++ b/lib/modules/platform/utils/github-alerts.ts @@ -0,0 +1,14 @@ +import type { VulnerabilityPackage } from '../../../types'; +import { normalizePythonDepName } from '../../datasource/pypi/common'; + +export function normalizeNamePerEcosystem({ + name, + ecosystem, +}: VulnerabilityPackage): string { + switch (ecosystem) { + case 'pip': + return normalizePythonDepName(name); + default: + return name; + } +} diff --git a/lib/workers/repository/init/vulnerability.spec.ts b/lib/workers/repository/init/vulnerability.spec.ts index 96d1a68ccc..1be284c8e9 100644 --- a/lib/workers/repository/init/vulnerability.spec.ts +++ b/lib/workers/repository/init/vulnerability.spec.ts @@ -351,39 +351,5 @@ describe('workers/repository/init/vulnerability', () => { expect(res.packageRules).toMatchSnapshot(); expect(res.packageRules).toHaveLength(1); }); - - it('returns pip alerts with normalized name', async () => { - // TODO #22198 - delete config.vulnerabilityAlerts!.enabled; - platform.getVulnerabilityAlerts.mockResolvedValue([ - { - dismissed_reason: null, - dependency: { - manifest_path: 'requirements.txt', - }, - security_advisory: { - description: 'Description', - identifiers: [ - { type: 'GHSA', value: 'GHSA-m956-frf4-m2wr' }, - { type: 'CVE', value: 'CVE-2016-2137' }, - ], - references: [ - { url: 'https://nvd.nist.gov/vuln/detail/CVE-2016-9587' }, - ], - }, - security_vulnerability: { - package: { name: 'Pillow', ecosystem: 'pip' }, - first_patched_version: { identifier: '2.1.4' }, - vulnerable_version_range: '< 2.1.4', - }, - }, - ]); - const res = await detectVulnerabilityAlerts(config); - expect(res.packageRules).toHaveLength(1); - expect(res.packageRules![0].matchPackageNames).toEqual([ - 'Pillow', - 'pillow', - ]); - }); }); }); diff --git a/lib/workers/repository/init/vulnerability.ts b/lib/workers/repository/init/vulnerability.ts index fb64fca278..264ba11d69 100644 --- a/lib/workers/repository/init/vulnerability.ts +++ b/lib/workers/repository/init/vulnerability.ts @@ -8,7 +8,6 @@ import { NpmDatasource } from '../../../modules/datasource/npm'; import { NugetDatasource } from '../../../modules/datasource/nuget'; import { PackagistDatasource } from '../../../modules/datasource/packagist'; import { PypiDatasource } from '../../../modules/datasource/pypi'; -import { normalizePythonDepName } from '../../../modules/datasource/pypi/common'; import { RubyGemsDatasource } from '../../../modules/datasource/rubygems'; import { platform } from '../../../modules/platform'; import * as allVersioning from '../../../modules/versioning'; @@ -191,12 +190,7 @@ export async function detectVulnerabilityAlerts( matchPackageNames: [depName], matchFileNames, }; - if ( - datasource === PypiDatasource.id && - normalizePythonDepName(depName) !== depName - ) { - matchRule.matchPackageNames?.push(normalizePythonDepName(depName)); - } + // Remediate only direct dependencies matchRule = { ...matchRule, -- GitLab