Skip to content

Commit

Permalink
feat(plugin-js-packages): use group per check, audit per dependency g…
Browse files Browse the repository at this point in the history
…roup
  • Loading branch information
Tlacenka committed Mar 11, 2024
1 parent 31a0c4f commit 4d7673a
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 70 deletions.
62 changes: 40 additions & 22 deletions packages/plugin-js-packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

📦 **Code PushUp plugin for JavaScript packages.** 🛡️

This plugin allows you to list outdated dependencies and run audit for known vulnerabilities.
This plugin checks for known vulnerabilities and outdated dependencies.
It supports the following package managers:

- [NPM](https://docs.npmjs.com/)
Expand All @@ -17,9 +17,7 @@ It supports the following package managers:

1. If you haven't already, install [@code-pushup/cli](../cli/README.md) and create a configuration file.

2. Insert plugin configuration. By default, `audit` and `outdated` commands will be run.

Default configuration will look as follows:
2. Insert plugin configuration with your package manager. By default, both `audit` and `outdated` checks will be run. The result should look as follows:

```js
import jsPackagesPlugin from '@code-pushup/js-packages-plugin';
Expand All @@ -28,14 +26,12 @@ It supports the following package managers:
// ...
plugins: [
// ...
await jsPackagesPlugin(),
await jsPackagesPlugin({ packageManager: 'npm' }), // replace with your package manager
],
};
```

You may run this plugin with a custom configuration for any supported package manager or command.

A custom configuration will look similarly to the following:
You may run this plugin with a custom configuration for any supported package manager or command. A custom configuration will look similarly to the following:

```js
import jsPackagesPlugin from '@code-pushup/js-packages-plugin';
Expand All @@ -49,7 +45,7 @@ It supports the following package managers:
};
```

3. (Optional) Reference individual audits or the provided plugin group which you wish to include in custom categories (use `npx code-pushup print-config` to list audits and groups).
3. (Optional) Reference individual audits or the provided plugin groups which you wish to include in custom categories (use `npx code-pushup print-config` to list audits and groups).

💡 Assign weights based on what influence each command should have on the overall category score (assign weight 0 to only include as extra info, without influencing category score).

Expand All @@ -58,17 +54,30 @@ It supports the following package managers:
// ...
categories: [
{
slug: 'dependencies',
title: 'Package dependencies',
slug: 'security',
title: 'Security',
refs: [
{
type: 'group',
plugin: 'npm-package-manager', // replace prefix with your package manager
plugin: 'npm-audit', // replace prefix with your package manager
slug: 'js-packages',
weight: 1,
},
],
},
{
slug: 'up-to-date',
title: 'Up-to-date tools',
refs: [
{
type: 'group',
plugin: 'npm-outdated', // replace prefix with your package manager
slug: 'js-packages',
weight: 1,
},
// ...
],
},
// ...
],
};
Expand All @@ -82,16 +91,13 @@ It supports the following package managers:

The plugin accepts the following parameters:

- (optional) `packageManager`: The package manager you are using. Supported values: `npm`, `yarn-classic` (v1), `yarn-modern` (v2+), `pnpm`. Default is `npm`.
- `packageManager`: The package manager you are using. Supported values: `npm`, `yarn-classic` (v1), `yarn-modern` (v2+), `pnpm`.
- (optional) `checks`: Array of checks to be run. Supported commands: `audit`, `outdated`. Both are configured by default.
- (optional) `auditLevelMapping`: If you wish to set a custom level of issue severity based on audit vulnerability level, you may do so here. Any omitted values will be filled in by defaults. Audit levels are: `critical`, `high`, `moderate`, `low` and `info`. Issue severities are: `error`, `warn` and `info`. By default the mapping is as follows: `critical` and `high``error`; `moderate` and `low``warning`; `info``info`.

> [!NOTE]
> All parameters are optional so the plugin can be called with no arguments in the default setting.

### Audits and group

This plugin provides a group for convenient declaration in your config. When defined this way, all measured coverage type audits have the same weight.
This plugin provides a group per check for a convenient declaration in your config.

```ts
// ...
Expand All @@ -103,7 +109,13 @@ This plugin provides a group for convenient declaration in your config. When def
{
type: 'group',
plugin: 'js-packages',
slug: 'npm-package-manager', // replace prefix with your package manager
slug: 'npm-audit', // replace prefix with your package manager
weight: 1,
},
{
type: 'group',
plugin: 'js-packages',
slug: 'npm-outdated', // replace prefix with your package manager
weight: 1,
},
// ...
Expand All @@ -113,7 +125,7 @@ This plugin provides a group for convenient declaration in your config. When def
],
```

Each package manager command still has its own audit. So when you want to include a subset of commands or assign different weights to them, you can do so in the following way:
Each dependency group has its own audit. If you want to check only a subset of dependencies (e.g. run audit and outdated for production dependencies) or assign different weights to them, you can do so in the following way:

```ts
// ...
Expand All @@ -125,15 +137,21 @@ Each package manager command still has its own audit. So when you want to includ
{
type: 'audit',
plugin: 'js-packages',
slug: 'npm-audit', // replace prefix with your package manager
slug: 'npm-audit-prod', // replace prefix with your package manager
weight: 2,
},
{
{
type: 'audit',
plugin: 'js-packages',
slug: 'npm-outdated', // replace prefix with your package manager
slug: 'npm-audit-dev', // replace prefix with your package manager
weight: 1,
},
{
type: 'audit',
plugin: 'js-packages',
slug: 'npm-outdated-prod', // replace prefix with your package manager
weight: 2,
},
// ...
],
},
Expand Down
4 changes: 1 addition & 3 deletions packages/plugin-js-packages/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ export const jsPackagesPluginConfigSchema = z.object({
})
.min(1)
.default(['audit', 'outdated']),
packageManager: packageManagerSchema
.describe('Package manager to be used. Defaults to npm')
.default('npm'),
packageManager: packageManagerSchema.describe('Package manager to be used.'),
auditLevelMapping: z
.record(packageAuditLevelSchema, issueSeveritySchema, {
description:
Expand Down
19 changes: 14 additions & 5 deletions packages/plugin-js-packages/src/lib/config.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ describe('jsPackagesPluginConfigSchema', () => {
});

it('should accept a minimal JS package configuration', () => {
expect(() => jsPackagesPluginConfigSchema.parse({})).not.toThrow();
expect(() =>
jsPackagesPluginConfigSchema.parse({
packageManager: 'pnpm',
} satisfies JSPackagesPluginConfig),
).not.toThrow();
});

it('should fill in default values', () => {
const config = jsPackagesPluginConfigSchema.parse({});
const config = jsPackagesPluginConfigSchema.parse({
packageManager: 'npm',
});
expect(config).toEqual<FinalJSPackagesPluginConfig>({
checks: ['audit', 'outdated'],
packageManager: 'npm',
Expand All @@ -39,9 +45,12 @@ describe('jsPackagesPluginConfigSchema', () => {
});

it('should throw for no passed commands', () => {
expect(() => jsPackagesPluginConfigSchema.parse({ checks: [] })).toThrow(
'too_small',
);
expect(() =>
jsPackagesPluginConfigSchema.parse({
packageManager: 'yarn-classic',
checks: [],
}),
).toThrow('too_small');
});
});

Expand Down
110 changes: 83 additions & 27 deletions packages/plugin-js-packages/src/lib/js-packages-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { name, version } from '../../package.json';
import {
JSPackagesPluginConfig,
PackageCommand,
PackageManager,
jsPackagesPluginConfigSchema,
} from './config';
import { createRunnerConfig } from './runner';
import {
auditDocs,
groupDepDocs,
outdatedDocs,
pkgManagerDocs,
pkgManagerIcons,
Expand All @@ -32,8 +34,9 @@ import {
*
* @returns Plugin configuration.
*/

export async function jsPackagesPlugin(
config: JSPackagesPluginConfig = {},
config: JSPackagesPluginConfig,
): Promise<PluginConfig> {
const jsPackagesPluginConfig = jsPackagesPluginConfigSchema.parse(config);
const pkgManager = jsPackagesPluginConfig.packageManager;
Expand All @@ -44,43 +47,96 @@ export async function jsPackagesPlugin(
'bin.js',
);

const audits: Record<PackageCommand, Audit> = {
return {
slug: 'js-packages',
title: 'Plugin for JS packages',
icon: pkgManagerIcons[pkgManager],
description:
'This plugin runs audit to uncover vulnerabilities and lists outdated dependencies. It supports npm, yarn classic and berry, pnpm package managers.',
docsUrl: pkgManagerDocs[pkgManager],
packageName: name,
version,
audits: createAudits(pkgManager, checks),
groups: createGroups(pkgManager, checks),
runner: await createRunnerConfig(runnerScriptPath, jsPackagesPluginConfig),
};
}

function createGroups(
pkgManager: PackageManager,
checks: PackageCommand[],
): Group[] {
const groups: Record<PackageCommand, Group> = {
audit: {
slug: `${pkgManager}-audit`,
title: `${pkgManagerNames[pkgManager]} audit`,
description: `Lists ${pkgManagerNames[pkgManager]} audit vulnerabilities.`,
description: `Group containing ${pkgManagerNames[pkgManager]} vulnerabilities.`,
docsUrl: auditDocs[pkgManager],
refs: [
// eslint-disable-next-line no-magic-numbers
{ slug: `${pkgManager}-audit-prod`, weight: 8 },
{ slug: `${pkgManager}-audit-dev`, weight: 1 },
{ slug: `${pkgManager}-audit-optional`, weight: 1 },
],
},
outdated: {
slug: `${pkgManager}-outdated`,
title: `${pkgManagerNames[pkgManager]} outdated dependencies`,
description: `Lists ${pkgManagerNames[pkgManager]} outdated dependencies.`,
description: `Group containing outdated ${pkgManagerNames[pkgManager]} dependencies.`,
docsUrl: outdatedDocs[pkgManager],
refs: [
// eslint-disable-next-line no-magic-numbers
{ slug: `${pkgManager}-outdated-prod`, weight: 8 },
{ slug: `${pkgManager}-outdated-dev`, weight: 1 },
{ slug: `${pkgManager}-outdated-optional`, weight: 1 },
],
},
};

const group: Group = {
slug: `${pkgManager}-package-manager`,
title: `${pkgManagerNames[pkgManager]} package manager`,
description: `Group containing both audit and dependencies command audits for the ${pkgManagerNames[pkgManager]} package manager.`,
docsUrl: pkgManagerDocs[pkgManager],
refs: checks.map(check => ({
slug: `${pkgManager}-${check}`,
weight: 1,
})),
};
return checks.map(check => groups[check]);
}

return {
slug: 'js-packages',
title: 'Plugin for JS packages',
icon: pkgManagerIcons[pkgManager],
description:
'This plugin runs audit to uncover vulnerabilities and lists outdated dependencies. It supports npm, yarn classic and berry, pnpm package managers.',
docsUrl: pkgManagerDocs[pkgManager],
packageName: name,
version,
audits: checks.map(check => audits[check]),
groups: [group],
runner: await createRunnerConfig(runnerScriptPath, jsPackagesPluginConfig),
};
function createAudits(
pkgManager: PackageManager,
checks: PackageCommand[],
): Audit[] {
return checks.flatMap(check => [
{
slug: `${pkgManager}-${check}-prod`,
title: getAuditTitle(pkgManager, check, 'prod'),
description: getAuditDescription(check, 'prod'),
docsUrl: groupDepDocs[pkgManager],
},
{
slug: `${pkgManager}-${check}-dev`,
title: getAuditTitle(pkgManager, check, 'dev'),
description: getAuditDescription(check, 'dev'),
docsUrl: groupDepDocs[pkgManager],
},
{
slug: `${pkgManager}-${check}-optional`,
title: getAuditTitle(pkgManager, check, 'optional'),
description: getAuditDescription(check, 'optional'),
docsUrl: groupDepDocs[pkgManager],
},
]);
}

function getAuditTitle(
pkgManager: PackageManager,
check: PackageCommand,
depGroup: 'prod' | 'dev' | 'optional',
) {
return check === 'audit'
? `Vulnerabilities for ${pkgManagerNames[pkgManager]} ${depGroup} dependencies.`
: `Outdated ${pkgManagerNames[pkgManager]} ${depGroup} dependencies.`;
}

function getAuditDescription(
check: PackageCommand,
depGroup: 'prod' | 'dev' | 'optional',
) {
return check === 'audit'
? `Runs security audit on ${depGroup} dependencies.`
: `Checks for outdated ${depGroup} dependencies`;
}
Loading

0 comments on commit 4d7673a

Please sign in to comment.