Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/plugin-js-packages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"dependencies": {
"@code-pushup/models": "0.48.0",
"@code-pushup/utils": "0.48.0",
"build-md": "^0.4.1",
"semver": "^7.6.0",
"zod": "^3.22.4"
}
Expand Down
25 changes: 14 additions & 11 deletions packages/plugin-js-packages/src/lib/runner/audit/transform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { md } from 'build-md';
import type { AuditOutput, Issue } from '@code-pushup/models';
import { apostrophize, objectToEntries } from '@code-pushup/utils';
import { objectToEntries } from '@code-pushup/utils';
import {
AuditSeverity,
DependencyGroup,
Expand Down Expand Up @@ -72,27 +73,29 @@ export function vulnerabilitiesToIssues(
return vulnerabilities.map((detail): Issue => {
const versionRange =
detail.versionRange === '*'
? '**all** versions'
: `versions **${detail.versionRange}**`;
? md`${md.bold('all')} versions`
: md`versions ${md.bold(detail.versionRange)}`;
const directDependency =
typeof detail.directDependency === 'string' &&
detail.directDependency !== ''
? `\`${detail.directDependency}\``
? md.code(detail.directDependency)
: '';
const depHierarchy =
directDependency === ''
? `\`${detail.name}\` dependency`
: `${apostrophize(directDependency)} dependency \`${detail.name}\``;
const depHierarchy = directDependency
? md`${directDependency}'s dependency ${md.code(detail.name)}`
: md`${md.code(detail.name)} dependency`;

const vulnerabilitySummary = `has a **${detail.severity}** vulnerability in ${versionRange}.`;
const vulnerabilitySummary = md`has a ${md.bold(
detail.severity,
)} vulnerability in ${versionRange}.`;
const fixInfo = detail.fixInformation ? ` ${detail.fixInformation}` : '';
const additionalInfo =
detail.title != null && detail.url != null
? ` More information: [${detail.title}](${detail.url})`
? md` More information: ${md.link(detail.url, detail.title)}`
: '';

return {
message: `${depHierarchy} ${vulnerabilitySummary}${fixInfo}${additionalInfo}`,
message:
md`${depHierarchy} ${vulnerabilitySummary}${fixInfo}${additionalInfo}`.toString(),
severity: auditLevelMapping[detail.severity],
};
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ describe('vulnerabilitiesToDisplayValue', () => {
});

describe('vulnerabilitiesToIssues', () => {
const vulnerabilityDefaults: Vulnerability = {
name: 'verdaccio',
severity: 'high',
versionRange: '<=5.28.0',
fixInformation: false,
directDependency: true,
};

it('should provide a vulnerability summary', () => {
expect(
vulnerabilitiesToIssues(
Expand Down Expand Up @@ -250,11 +258,12 @@ describe('vulnerabilitiesToIssues', () => {
vulnerabilitiesToIssues(
[
{
...vulnerabilityDefaults,
name: 'tough-cookie',
title: 'tough-cookie Prototype Pollution vulnerability',
url: 'https://github.com/advisories/GHSA-72xf-g2v4-qvf3',
},
] as Vulnerability[],
],
defaultAuditLevelMapping,
),
).toEqual<Issue[]>([
Expand All @@ -271,16 +280,17 @@ describe('vulnerabilitiesToIssues', () => {
vulnerabilitiesToIssues(
[
{
...vulnerabilityDefaults,
name: '@cypress/request',
directDependency: 'cypress',
},
] as Vulnerability[],
],
defaultAuditLevelMapping,
),
).toEqual<Issue[]>([
expect.objectContaining({
message: expect.stringContaining(
"`cypress`' dependency `@cypress/request` has",
"`cypress`'s dependency `@cypress/request` has",
Comment thread
matejchalk marked this conversation as resolved.
),
}),
]);
Expand All @@ -291,10 +301,11 @@ describe('vulnerabilitiesToIssues', () => {
vulnerabilitiesToIssues(
[
{
...vulnerabilityDefaults,
name: 'semver',
directDependency: '',
},
] as Vulnerability[],
],
defaultAuditLevelMapping,
),
).toEqual<Issue[]>([
Expand All @@ -309,11 +320,12 @@ describe('vulnerabilitiesToIssues', () => {
vulnerabilitiesToIssues(
[
{
...vulnerabilityDefaults,
name: 'verdaccio',
severity: 'high',
directDependency: true,
},
] as Vulnerability[],
],
{ ...defaultAuditLevelMapping, high: 'info' },
),
).toEqual<Issue[]>([
Expand All @@ -329,11 +341,12 @@ describe('vulnerabilitiesToIssues', () => {
vulnerabilitiesToIssues(
[
{
...vulnerabilityDefaults,
name: 'request',
versionRange: '*',
directDependency: true,
},
] as Vulnerability[],
],
defaultAuditLevelMapping,
),
).toEqual<Issue[]>([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { md } from 'build-md';
import { ReleaseType, clean, diff, neq } from 'semver';
import type { AuditOutput, Issue } from '@code-pushup/models';
import { objectFromEntries, pluralize } from '@code-pushup/utils';
Expand Down Expand Up @@ -89,10 +90,12 @@ export function outdatedToIssues(dependencies: OutdatedResult): Issue[] {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const outdatedLevel = diff(current, latest)!;
const packageReference =
url == null ? `\`${name}\`` : `[\`${name}\`](${url})`;
url == null ? md.code(name) : md.link(url, md.code(name));

return {
message: `Package ${packageReference} requires a **${outdatedLevel}** update from **${current}** to **${latest}**.`,
message: md`Package ${packageReference} requires a ${md.bold(
outdatedLevel,
)} update from ${md.bold(current)} to ${md.bold(latest)}.`.toString(),
severity: outdatedSeverity[outdatedLevel],
};
});
Expand Down
10 changes: 5 additions & 5 deletions packages/utils/src/lib/reports/log-stdout-summary.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {beforeAll, describe, expect, vi} from 'vitest';
import {removeColorCodes} from '@code-pushup/test-utils';
import {ui} from '../logging';
import {binaryIconPrefix, logCategories} from './log-stdout-summary';
import {ScoredReport} from './types';
import { beforeAll, describe, expect, vi } from 'vitest';
import { removeColorCodes } from '@code-pushup/test-utils';
import { ui } from '../logging';
import { binaryIconPrefix, logCategories } from './log-stdout-summary';
import { ScoredReport } from './types';

describe('logCategories', () => {
let logs: string[];
Expand Down