From 2e7df6d30e48bddb8867eaabc84a4e5556f4f0fc Mon Sep 17 00:00:00 2001 From: Sargun Vohra Date: Mon, 9 Jan 2023 10:42:25 -0800 Subject: [PATCH 1/4] Add --extra-args Signed-off-by: Sargun Vohra --- docs/schema.d.ts | 7 +++++++ docs/schema.json | 8 ++++++++ lib/config.ts | 17 +++++++++++++++++ lib/npm-auditer.ts | 4 ++++ lib/pnpm-auditer.ts | 4 ++++ lib/yarn-auditer.ts | 4 ++++ 6 files changed, 44 insertions(+) diff --git a/docs/schema.d.ts b/docs/schema.d.ts index a799fdf9..5e904fe1 100644 --- a/docs/schema.d.ts +++ b/docs/schema.d.ts @@ -112,4 +112,11 @@ export interface Schema { * @default false */ "skip-dev"?: boolean; + + /** + * Extra arguments to pass to the underlying audit command. + * + * @default [] + */ + "extra-args"?: string[]; } diff --git a/docs/schema.json b/docs/schema.json index 2e9da334..93c05a46 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -58,6 +58,14 @@ "description": "The directory containing the package.json to audit.", "type": "string" }, + "extra-args": { + "default": [], + "description": "Extra arguments to pass to the underlying audit command.", + "items": { + "type": "string" + }, + "type": "array" + }, "high": { "default": false, "description": "Prevent integration with high or higher vulnerabilities.", diff --git a/lib/config.ts b/lib/config.ts index 1a239cfe..7d811622 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -25,6 +25,15 @@ function mapReportTypeInput( } } +function mapExtraArgumentsInput( + config: Pick +) { + // These args will often be flags for another command, so we + // want to have some way of escaping args that start with a -. + // We'll look for and remove a single backslash at the start, if present. + return config["extra-args"].map((a) => a.replace(/^\\/, "")); +} + export type AuditCiPreprocessedConfig = { /** Exit for low or above vulnerabilities */ l: boolean; @@ -78,6 +87,8 @@ export type AuditCiPreprocessedConfig = { "pass-enoaudit": boolean; /** skip devDependencies */ "skip-dev": boolean; + /** extra positional args for underlying audit command */ + "extra-args": string[]; }; // Rather than exporting a weird union type, we resolve the type to a simple object. @@ -163,6 +174,7 @@ function mapArgvToAuditCiConfig(argv: AuditCiPreprocessedConfig) { }), "report-type": mapReportTypeInput(argv), allowlist: allowlist, + "extra-args": mapExtraArgumentsInput(argv), }; return result; } @@ -276,6 +288,11 @@ export async function runYargs(): Promise { describe: "Skip devDependencies", type: "boolean", }, + "extra-args": { + default: [], + describe: "Pass additional arguments to the underlying audit command", + type: "array", + }, }) .help("help"); diff --git a/lib/npm-auditer.ts b/lib/npm-auditer.ts index 3bc00b27..3783fc9c 100644 --- a/lib/npm-auditer.ts +++ b/lib/npm-auditer.ts @@ -12,6 +12,7 @@ async function runNpmAudit( registry, _npm, "skip-dev": skipDevelopmentDependencies, + "extra-args": extraArguments, } = config; const npmExec = _npm || "npm"; @@ -32,6 +33,9 @@ async function runNpmAudit( if (skipDevelopmentDependencies) { arguments_.push("--production"); } + if (extraArguments) { + arguments_.push(...extraArguments); + } const options = { cwd: directory }; await runProgram(npmExec, arguments_, options, outListener, errorListener); if (stderrBuffer.length > 0) { diff --git a/lib/pnpm-auditer.ts b/lib/pnpm-auditer.ts index c8440b56..dca1c69d 100644 --- a/lib/pnpm-auditer.ts +++ b/lib/pnpm-auditer.ts @@ -16,6 +16,7 @@ async function runPnpmAudit( registry, _pnpm, "skip-dev": skipDevelopmentDependencies, + "extra-args": extraArguments, } = config; const pnpmExec = _pnpm || "pnpm"; @@ -45,6 +46,9 @@ async function runPnpmAudit( if (skipDevelopmentDependencies) { arguments_.push("--prod"); } + if (extraArguments) { + arguments_.push(...extraArguments); + } const options = { cwd: directory }; await runProgram(pnpmExec, arguments_, options, outListener, errorListener); if (stderrBuffer.length > 0) { diff --git a/lib/yarn-auditer.ts b/lib/yarn-auditer.ts index 7370c676..5f15cdcc 100644 --- a/lib/yarn-auditer.ts +++ b/lib/yarn-auditer.ts @@ -59,6 +59,7 @@ export async function audit( "output-format": outputFormat, _yarn, directory, + "extra-args": extraArguments, } = config; const yarnExec = _yarn || "yarn"; let missingLockFile = false; @@ -210,6 +211,9 @@ export async function audit( ); } } + if (extraArguments) { + arguments_.push(...extraArguments); + } await runProgram(yarnExec, arguments_, options, outListener, errorListener); if (missingLockFile) { console.warn( From a40fc84ad6a83df6cd9e98c18f75c652c2d3e64f Mon Sep 17 00:00:00 2001 From: Sargun Vohra Date: Mon, 9 Jan 2023 11:09:19 -0800 Subject: [PATCH 2/4] reorder expected vulns in tests Signed-off-by: Sargun Vohra --- test/yarn-auditer.spec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/yarn-auditer.spec.js b/test/yarn-auditer.spec.js index ab7cd945..cd6caa3f 100644 --- a/test/yarn-auditer.spec.js +++ b/test/yarn-auditer.spec.js @@ -372,10 +372,10 @@ describe("yarn-auditer", function testYarnAuditer() { expect(summary).to.eql( summaryWithDefault({ failedLevelsFound: ["high", "moderate"], - advisoriesFound: ["GHSA-rvg8-pwq2-xj7q", "GHSA-38f5-ghc2-fcmv"], + advisoriesFound: ["GHSA-38f5-ghc2-fcmv", "GHSA-rvg8-pwq2-xj7q"], advisoryPathsFound: [ - "GHSA-rvg8-pwq2-xj7q|audit-ci-yarn-workspace-moderate-vulnerability>base64url", "GHSA-38f5-ghc2-fcmv|audit-ci-yarn-workspace-high-vulnerability>cryo", + "GHSA-rvg8-pwq2-xj7q|audit-ci-yarn-workspace-moderate-vulnerability>base64url", ], }) ); @@ -409,14 +409,14 @@ describe("yarn-auditer", function testYarnAuditer() { summaryWithDefault({ failedLevelsFound: ["critical", "high", "moderate"], advisoriesFound: [ - "GHSA-rvg8-pwq2-xj7q", "GHSA-28xh-wpgr-7fm8", "GHSA-38f5-ghc2-fcmv", + "GHSA-rvg8-pwq2-xj7q", ], advisoryPathsFound: [ - "GHSA-rvg8-pwq2-xj7q|base64url", "GHSA-28xh-wpgr-7fm8|open", "GHSA-38f5-ghc2-fcmv|cryo", + "GHSA-rvg8-pwq2-xj7q|base64url", ], }) ); @@ -437,10 +437,10 @@ describe("yarn-auditer", function testYarnAuditer() { expect(summary).to.eql( summaryWithDefault({ failedLevelsFound: ["high", "moderate"], - advisoriesFound: ["GHSA-rvg8-pwq2-xj7q", "GHSA-38f5-ghc2-fcmv"], + advisoriesFound: ["GHSA-38f5-ghc2-fcmv", "GHSA-rvg8-pwq2-xj7q"], advisoryPathsFound: [ - "GHSA-rvg8-pwq2-xj7q|base64url", "GHSA-38f5-ghc2-fcmv|cryo", + "GHSA-rvg8-pwq2-xj7q|base64url", ], }) ); From 0fbe92bb605b9efabd533bbba6ff11e2b599f61d Mon Sep 17 00:00:00 2001 From: Sargun Vohra Date: Mon, 9 Jan 2023 11:48:41 -0800 Subject: [PATCH 3/4] add basic test Signed-off-by: Sargun Vohra --- test/yarn-auditer.spec.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/yarn-auditer.spec.js b/test/yarn-auditer.spec.js index cd6caa3f..2b8e12f4 100644 --- a/test/yarn-auditer.spec.js +++ b/test/yarn-auditer.spec.js @@ -446,6 +446,30 @@ describe("yarn-auditer", function testYarnAuditer() { ); } ); + (canRunYarnBerry ? it : it.skip)( + "reports summary with vulnerabilities in yarn berry workspaces with extra-args: --environment production", + async () => { + const summary = await audit( + config({ + directory: testDirectory("yarn-berry-workspace"), + levels: { moderate: true }, + "extra-args": ["--environment", "production"], + "report-type": "important", + }), + (_summary) => _summary + ); + expect(summary).to.eql( + summaryWithDefault({ + failedLevelsFound: ["high", "moderate"], + advisoriesFound: ["GHSA-38f5-ghc2-fcmv", "GHSA-rvg8-pwq2-xj7q"], + advisoryPathsFound: [ + "GHSA-38f5-ghc2-fcmv|cryo", + "GHSA-rvg8-pwq2-xj7q|base64url", + ], + }) + ); + } + ); it("does not report duplicate paths", async () => { const summary = await audit( config({ From f95addf2c90bf99568fc044d7cf655415569083d Mon Sep 17 00:00:00 2001 From: Sargun Vohra Date: Mon, 9 Jan 2023 12:09:15 -0800 Subject: [PATCH 4/4] update readme Signed-off-by: Sargun Vohra --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index cbd3ff91..1c710c17 100644 --- a/README.md +++ b/README.md @@ -271,6 +271,7 @@ scripts: | | --retry-count | The number of attempts audit-ci calls an unavailable registry before failing (default `5`) | | | --config | Path to the audit-ci configuration file | | | --skip-dev | Skip auditing devDependencies (default `false`) | +| | --extra-args | Extra arguments to pass to the underlying audit command (default: `[]`) | ### Config file specification @@ -385,6 +386,23 @@ Or, with the CLI: npx audit-ci@^6 --report-type summary ``` +### Pass additional args to Yarn to exclude a certain package from audit + +With a `JSONC` config file, in a project on Yarn v3.3.0 or later: + +```jsonc +{ + "$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json", + "extra-args": ["--exclude", "example"] +} +``` + +Or, with the CLI: + +```sh +npx audit-ci@^6 --extra-args '\--exclude' example +``` + ### Example config file and different directory usage #### test/npm-config-file/audit-ci.jsonc