Skip to content

Commit

Permalink
Add files for Yarn 3 (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
quinnturner authored Jun 1, 2024
1 parent bc67ffe commit 3aad5c6
Show file tree
Hide file tree
Showing 189 changed files with 154,290 additions and 3,625 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
test/yarn-berry.cjs
test/yarn-*.cjs
dist
coverage
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test/yarn-berry.cjs linguist-vendored
test/yarn-*.cjs linguist-vendored
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
test/yarn-berry.cjs
coverage
test/yarn-*.cjs
**/pnpm-lock.yaml
**/*-output.json
**/.pnp.cjs
test/*/*.json
41 changes: 1 addition & 40 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,43 +1,4 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Mocha All",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"-r",
"ts-node/register",
"--timeout",
"999999",
"--extensions",
"ts",
"--recursive",
"--colors",
"${workspaceFolder}/test/*.spec.ts"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "node",
"request": "launch",
"name": "Mocha Current File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"-r",
"ts-node/register",
"--timeout",
"999999",
"--extensions",
"ts",
"--recursive",
"--colors",
"${file}"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}
]
"configurations": []
}
36 changes: 26 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ threshold while ignoring allowlisted advisories.
## Requirements

- Node >=16
- _(Optional)_ Yarn ^1.12.3 || Yarn >=2.4.0
- _(Optional)_ Yarn ^1.12.3 || Yarn >=2.4.0 && <4.0.0
- _(Optional)_ PNPM >=4.3.0
- _(Optional)_ Bun

## Limitations

- Yarn Classic workspaces does not audit `devDependencies`. See [this issue](https://github.com/yarnpkg/yarn/issues/7047) for more information.
- Yarn v4 is not supported because it provides similar functionality to `audit-ci`.
For more information, see the [documentation on `yarn npm audit`](https://yarnpkg.com/cli/npm/audit#options).
- Bun is supported by exporting the `bun.lockb` into a Yarn v1 `yarn.lock` file.
Accordingly, it requires Yarn v1 to run `audit-ci` and it has the same limitations as Yarn v1.

## Set up

Expand All @@ -40,6 +45,7 @@ The downside of this approach is that the CI may run a `postinstall` script of a
npm install -D audit-ci
yarn add -D audit-ci
pnpm install -D audit-ci
bun install -D audit-ci
```

The next section gives examples using `audit-ci` in various CI environments.
Expand All @@ -59,11 +65,21 @@ Also, it suppresses an advisory of `axios` and a transitive advisory of `react-s
// https://github.com/advisories/GHSA-rp65-9cf3-cjxr
// Alternatively, allowlist "GHSA-rp65-9cf3-cjxr" to suppress this nth-check advisory across all paths
// or "*|react-scripts>*" to suppress advisories for all transitive dependencies of "react-scripts".
"GHSA-rp65-9cf3-cjxr|react-scripts>@svgr/webpack>@svgr/plugin-svgo>svgo>css-select>nth-check"
]
"GHSA-rp65-9cf3-cjxr|react-scripts>@svgr/webpack>@svgr/plugin-svgo>svgo>css-select>nth-check",
],
}
```

### Bun

Bun supports exporting the `bun.lockb` into a Yarn v1 `yarn.lock` file.

```sh
bun install -y
```

Afterwards, you can run `audit-ci` with the `yarn` package manager.

### Allowlisting

Allowlists are a mechanism to suppress an advisory warning from the audit. A team may want to suppress an advisory when:
Expand Down Expand Up @@ -320,8 +336,8 @@ With a `JSONC` config file, execute with `npx audit-ci --config ./audit-ci.jsonc
// https://github.com/advisories/GHSA-rp65-9cf3-cjxr
// Alternatively, allowlist "GHSA-rp65-9cf3-cjxr" to suppress this nth-check advisory across all paths
// or "*|react-scripts>*" to suppress advisories for all transitive dependencies of "react-scripts".
"GHSA-rp65-9cf3-cjxr|react-scripts>@svgr/webpack>@svgr/plugin-svgo>svgo>css-select>nth-check"
]
"GHSA-rp65-9cf3-cjxr|react-scripts>@svgr/webpack>@svgr/plugin-svgo>svgo>css-select>nth-check",
],
}
```

Expand Down Expand Up @@ -359,7 +375,7 @@ With a `JSONC` config file:
{
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"critical": true,
"report-type": "full"
"report-type": "full",
}
```

Expand All @@ -376,7 +392,7 @@ With a `JSONC` config file:
```jsonc
{
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"report-type": "summary"
"report-type": "summary",
}
```

Expand All @@ -393,7 +409,7 @@ With a `JSONC` config file, in a project on Yarn Berry v3.3.0 or later:
```jsonc
{
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"extra-args": ["--exclude", "example"]
"extra-args": ["--exclude", "example"],
}
```

Expand All @@ -420,9 +436,9 @@ npx audit-ci@^7 --extra-args '\--exclude' example
"GHSA-6354-6mhv-mvv5|example3",
"GHSA-42xw-2xvc-qx8m|example4",
"GHSA-42xw-2xvc-qx8m|example5>example4",
"*|example6>*"
"*|example6>*",
],
"registry": "https://registry.npmjs.org"
"registry": "https://registry.npmjs.org",
}
```

Expand Down
3 changes: 2 additions & 1 deletion lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ export function mapAuditCiConfigToAuditCiFullConfig(
}

export async function runYargs(): Promise<AuditCiFullConfig> {
const { argv } = yargs().config("config", (configPath) =>
const { argv } = yargs()
.config("config", (configPath) =>
// Supports JSON, JSONC, & JSON5
jju.parse(readFileSync(configPath, "utf8"), {
// When passing an allowlist using NSRecord syntax, yargs will throw an error
Expand Down
56 changes: 15 additions & 41 deletions lib/yarn-auditor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { YarnAudit, YarnBerryAuditReport } from "audit-types";
import { execSync } from "child_process";
import * as semver from "semver";
import type { YarnAudit, Yarn2And3AuditReport } from "audit-types";
import { blue, red, yellow } from "./colors.js";
import { reportAudit, runProgram } from "./common.js";
import {
Expand All @@ -9,38 +7,14 @@ import {
type AuditCiFullConfig,
} from "./config.js";
import Model, { type Summary } from "./model.js";

const MINIMUM_YARN_CLASSIC_VERSION = "1.12.3";
const MINIMUM_YARN_BERRY_VERSION = "2.4.0";
/**
* Change this to the appropriate version when
* yarn audit --registry is supported:
* @see https://github.com/yarnpkg/yarn/issues/7012
*/
const MINIMUM_YARN_AUDIT_REGISTRY_VERSION = "99.99.99";

function getYarnVersion(cwd?: string) {
const version = execSync("yarn -v", { cwd }).toString().replace("\n", "");
return version;
}

function yarnSupportsClassicAudit(yarnVersion: string | semver.SemVer) {
return semver.satisfies(yarnVersion, `^${MINIMUM_YARN_CLASSIC_VERSION}`);
}

function yarnSupportsBerryAudit(yarnVersion: string | semver.SemVer) {
return semver.gte(yarnVersion, MINIMUM_YARN_BERRY_VERSION);
}

function yarnSupportsAudit(yarnVersion: string | semver.SemVer) {
return (
yarnSupportsClassicAudit(yarnVersion) || yarnSupportsBerryAudit(yarnVersion)
);
}

function yarnAuditSupportsRegistry(yarnVersion: string | semver.SemVer) {
return semver.gte(yarnVersion, MINIMUM_YARN_AUDIT_REGISTRY_VERSION);
}
import {
MINIMUM_YARN_BERRY_VERSION,
MINIMUM_YARN_CLASSIC_VERSION,
getYarnVersion,
yarnAuditSupportsRegistry,
yarnSupportsAudit,
yarnSupportsClassicAudit,
} from "./yarn-version.js";

const printJson = (data: unknown) => {
console.log(JSON.stringify(data, undefined, 2));
Expand Down Expand Up @@ -83,7 +57,7 @@ export async function auditWithFullConfig(
let missingLockFile = false;
const model = new Model(config);

const yarnVersion = getYarnVersion(directory);
const yarnVersion = getYarnVersion(yarnExec, directory);
const isYarnVersionSupported = yarnSupportsAudit(yarnVersion);
if (!isYarnVersionSupported) {
throw new Error(
Expand All @@ -94,7 +68,7 @@ export async function auditWithFullConfig(
const yarnName = isYarnClassic ? `Yarn` : `Yarn Berry`;

function isClassicGuard(
response: YarnAudit.AuditResponse | YarnBerryAuditReport.AuditResponse,
response: YarnAudit.AuditResponse | Yarn2And3AuditReport.AuditResponse,
): response is YarnAudit.AuditResponse {
return isYarnClassic;
}
Expand Down Expand Up @@ -147,7 +121,7 @@ export async function auditWithFullConfig(
printJson(data);
}
}
: ({ metadata }: { metadata: YarnBerryAuditReport.AuditMetadata }) => {
: ({ metadata }: { metadata: Yarn2And3AuditReport.AuditMetadata }) => {
printJson(metadata);
};
break;
Expand All @@ -159,7 +133,7 @@ export async function auditWithFullConfig(
printJson(data);
}
}
: ({ metadata }: { metadata: YarnBerryAuditReport.AuditMetadata }) => {
: ({ metadata }: { metadata: Yarn2And3AuditReport.AuditMetadata }) => {
printJson(metadata);
};
break;
Expand All @@ -172,7 +146,7 @@ export async function auditWithFullConfig(
}

function outListener(
line: YarnAudit.AuditResponse | YarnBerryAuditReport.AuditResponse,
line: YarnAudit.AuditResponse | Yarn2And3AuditReport.AuditResponse,
) {
try {
if (isClassicGuard(line)) {
Expand All @@ -193,7 +167,7 @@ export async function auditWithFullConfig(
printAuditData(line);

if ("advisories" in line) {
for (const advisory of Object.values<YarnBerryAuditReport.Advisory>(
for (const advisory of Object.values<Yarn2And3AuditReport.Advisory>(
line.advisories,
)) {
model.process(advisory);
Expand Down
39 changes: 39 additions & 0 deletions lib/yarn-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { execSync } from "child_process";
import semver from "semver";

export const MINIMUM_YARN_CLASSIC_VERSION = "1.12.3";
export const MINIMUM_YARN_BERRY_VERSION = "2.4.0";
/**
* Change this to the appropriate version when
* yarn audit --registry is supported:
* @see https://github.com/yarnpkg/yarn/issues/7012
*/
const MINIMUM_YARN_AUDIT_REGISTRY_VERSION = "99.99.99";

export function yarnSupportsClassicAudit(yarnVersion: string | semver.SemVer) {
return semver.satisfies(yarnVersion, `^${MINIMUM_YARN_CLASSIC_VERSION}`);
}

export function yarnSupportsBerryAudit(yarnVersion: string | semver.SemVer) {
return semver.gte(yarnVersion, MINIMUM_YARN_BERRY_VERSION);
}

export function yarnSupportsAudit(yarnVersion: string | semver.SemVer) {
return (
yarnSupportsClassicAudit(yarnVersion) || yarnSupportsBerryAudit(yarnVersion)
);
}

export function yarnAuditSupportsRegistry(yarnVersion: string | semver.SemVer) {
return semver.gte(yarnVersion, MINIMUM_YARN_AUDIT_REGISTRY_VERSION);
}

const versionMap = new Map<string, string>();
export function getYarnVersion(yarnExec = "yarn", cwd?: string) {
const key = `${yarnExec}:${cwd}`;
let version = versionMap.get(key);
if (version) return version;
version = execSync(`${yarnExec} -v`, { cwd }).toString().replace("\n", "");
versionMap.set(key, version);
return version;
}
Loading

0 comments on commit 3aad5c6

Please sign in to comment.