Skip to content

Commit

Permalink
feat: remediate to greater than or equal versions for github alerts (#…
Browse files Browse the repository at this point in the history
…31393)

Co-authored-by: Michael Kriese <[email protected]>
  • Loading branch information
rarkins and viceice authored Sep 18, 2024
1 parent 373fcbd commit dce6912
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 8 deletions.
1 change: 1 addition & 0 deletions lib/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ export interface PackageRule
matchUpdateTypes?: UpdateType[];
registryUrls?: string[] | null;
vulnerabilitySeverity?: string;
vulnerabilityFixVersion?: string;
}

export interface ValidationMessage {
Expand Down
1 change: 1 addition & 0 deletions lib/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const ignoredNodes = [
'vulnerabilityAlertsOnly',
'vulnerabilityAlert',
'isVulnerabilityAlert',
'vulnerabilityFixVersion', // not intended to be used by end users but may be by Mend apps
'copyLocalLibs', // deprecated - functionality is now enabled by default
'prBody', // deprecated
'minimumConfidence', // undocumented feature flag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() returns go alerts 1`] = `
[
{
"allowedVersions": "1.8.3",
"force": {
"branchTopic": "{{{datasource}}}-{{{depNameSanitized}}}-vulnerability",
"commitMessageSuffix": "[SECURITY]",
Expand All @@ -30,14 +29,14 @@ exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() retur
go",
],
"vulnerabilityFixVersion": "1.8.3",
},
]
`;

exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() returns maven alerts 1`] = `
[
{
"allowedVersions": "2.7.9.4",
"force": {
"branchTopic": "{{{datasource}}}-{{{depNameSanitized}}}-vulnerability",
"commitMessageSuffix": "[SECURITY]",
Expand All @@ -64,14 +63,14 @@ exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() retur
An issue was discovered in FasterXML jackson-databind prior to 2.7.9.4, 2.8.11.2, and 2.9.6. When Default Typing is enabled (either globally or for a specific property), the service has the Jodd-db jar (for database access for the Jodd framework) in the classpath, and an attacker can provide an LDAP service to access, it is possible to make the service execute a malicious payload.",
],
"vulnerabilityFixVersion": "2.7.9.4",
},
]
`;

exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() returns pip alerts 1`] = `
[
{
"allowedVersions": "==2.2.1.0",
"force": {
"branchTopic": "{{{datasource}}}-{{{depNameSanitized}}}-vulnerability",
"commitMessageSuffix": "[SECURITY]",
Expand Down Expand Up @@ -113,6 +112,7 @@ Ansible before version 2.2.0 fails to properly sanitize fact variables sent from
Ansible before versions 2.1.4, 2.2.1 is vulnerable to an improper input validation in Ansible's handling of data sent from client systems. An attacker with control over a client system being managed by Ansible and the ability to send facts back to the Ansible server could use this flaw to execute arbitrary code on the Ansible server using the Ansible server privileges.",
],
"vulnerabilityFixVersion": "2.2.1.0",
},
]
`;
6 changes: 1 addition & 5 deletions lib/workers/repository/init/vulnerability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,6 @@ export async function detectVulnerabilityAlerts(
logger.warn({ err }, 'Error generating vulnerability PR notes');
}
// TODO: types (#22198)
const allowedVersions =
datasource === PypiDatasource.id
? `==${val.firstPatchedVersion!}`
: val.firstPatchedVersion;
const matchFileNames =
datasource === GoDatasource.id
? [fileName.replace('go.sum', 'go.mod')]
Expand All @@ -191,7 +187,7 @@ export async function detectVulnerabilityAlerts(
// Remediate only direct dependencies
matchRule = {
...matchRule,
allowedVersions,
vulnerabilityFixVersion: val.firstPatchedVersion,
prBodyNotes,
isVulnerabilityAlert: true,
force: {
Expand Down
119 changes: 119 additions & 0 deletions lib/workers/repository/process/lookup/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,125 @@ describe('workers/repository/process/lookup/index', () => {
]);
});

it('uses vulnerabilityFixVersion when a version', async () => {
config.currentValue = '1.0.0';
config.isVulnerabilityAlert = true;
config.vulnerabilityFixVersion = '1.1.0';
config.packageName = 'q';
config.datasource = NpmDatasource.id;
httpMock.scope('https://registry.npmjs.org').get('/q').reply(200, qJson);

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'non-major',
newMajor: 1,
newMinor: 1,
newPatch: 0,
newValue: '1.1.0',
newVersion: '1.1.0',
releaseTimestamp: expect.any(String),
updateType: 'minor',
},
]);
});

it('takes a later release when vulnerabilityFixVersion does not exist', async () => {
config.currentValue = '1.0.0';
config.isVulnerabilityAlert = true;
config.vulnerabilityFixVersion = '1.0.2';
config.packageName = 'q';
config.datasource = NpmDatasource.id;
httpMock.scope('https://registry.npmjs.org').get('/q').reply(200, qJson);

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'non-major',
newMajor: 1,
newMinor: 1,
newPatch: 0,
newValue: '1.1.0',
newVersion: '1.1.0',
releaseTimestamp: expect.any(String),
updateType: 'minor',
},
]);
});

it('uses vulnerabilityFixVersion when a range', async () => {
config.currentValue = '1.0.0';
config.isVulnerabilityAlert = true;
config.vulnerabilityFixVersion = '>= 1.1.0';
config.packageName = 'q';
config.datasource = NpmDatasource.id;
httpMock.scope('https://registry.npmjs.org').get('/q').reply(200, qJson);

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'non-major',
newMajor: 1,
newMinor: 1,
newPatch: 0,
newValue: '1.1.0',
newVersion: '1.1.0',
releaseTimestamp: expect.any(String),
updateType: 'minor',
},
]);
});

it('ignores vulnerabilityFixVersion if not a version', async () => {
config.currentValue = '1.0.0';
config.isVulnerabilityAlert = true;
config.vulnerabilityFixVersion = 'abc';
config.packageName = 'q';
config.datasource = NpmDatasource.id;
httpMock.scope('https://registry.npmjs.org').get('/q').reply(200, qJson);

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toEqual([
{
bucket: 'non-major',
newMajor: 1,
newMinor: 0,
newPatch: 1,
newValue: '1.0.1',
newVersion: '1.0.1',
releaseTimestamp: expect.any(String),
updateType: 'patch',
},
]);
});

it('returns no results if vulnerabilityFixVersion is too high', async () => {
config.currentValue = '1.0.0';
config.isVulnerabilityAlert = true;
config.vulnerabilityFixVersion = '5.1.0';
config.packageName = 'q';
config.datasource = NpmDatasource.id;
httpMock.scope('https://registry.npmjs.org').get('/q').reply(200, qJson);

const { updates } = await Result.wrap(
lookup.lookupUpdates(config),
).unwrapOrThrow();

expect(updates).toBeEmptyArray();
});

it('supports minor and major upgrades for ranged versions', async () => {
config.currentValue = '~0.4.0';
config.rangeStrategy = 'pin';
Expand Down
45 changes: 45 additions & 0 deletions lib/workers/repository/process/lookup/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,51 @@ export async function lookupUpdates(
);
let shrinkedViaVulnerability = false;
if (config.isVulnerabilityAlert) {
if (config.vulnerabilityFixVersion) {
res.vulnerabilityFixVersion = config.vulnerabilityFixVersion;
if (versioning.isValid(config.vulnerabilityFixVersion)) {
let fixedFilteredReleases;
if (versioning.isVersion(config.vulnerabilityFixVersion)) {
// Retain only releases greater than or equal to the fix version
fixedFilteredReleases = filteredReleases.filter(
(release) =>
!versioning.isGreaterThan(
config.vulnerabilityFixVersion!,
release.version,
),
);
} else {
// Retain only releases which max the fix constraint
fixedFilteredReleases = filteredReleases.filter((release) =>
versioning.matches(
release.version,
config.vulnerabilityFixVersion!,
),
);
}
// Warn if this filtering results caused zero releases
if (fixedFilteredReleases.length === 0 && filteredReleases.length) {
logger.warn(
{
releases: filteredReleases,
vulnerabilityFixVersion: config.vulnerabilityFixVersion,
packageName: config.packageName,
},
'No releases satisfy vulnerabilityFixVersion',
);
}
// Use the additionally filtered releases
filteredReleases = fixedFilteredReleases;
} else {
logger.warn(
{
vulnerabilityFixVersion: config.vulnerabilityFixVersion,
packageName: config.packageName,
},
'vulnerabilityFixVersion is not valid',
);
}
}
filteredReleases = filteredReleases.slice(0, 1);
shrinkedViaVulnerability = true;
logger.debug(
Expand Down
2 changes: 2 additions & 0 deletions lib/workers/repository/process/lookup/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface LookupUpdateConfig
replacementNameTemplate?: string;
replacementVersion?: string;
extractVersion?: string;
vulnerabilityFixVersion?: string;
}

export interface UpdateResult {
Expand All @@ -68,4 +69,5 @@ export interface UpdateResult {
warnings: ValidationMessage[];
versioning?: string;
currentVersionTimestamp?: string;
vulnerabilityFixVersion?: string;
}

0 comments on commit dce6912

Please sign in to comment.