Skip to content

Instantly share code, notes, and snippets.

@paambaati
Last active November 24, 2021 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paambaati/b7dd99d67f5402b62d7f8ef95ef65e01 to your computer and use it in GitHub Desktop.
Save paambaati/b7dd99d67f5402b62d7f8ef95ef65e01 to your computer and use it in GitHub Desktop.
Generate yarn resolutions for audit-ci fixes

How to use this

node auditResolutions.js

This will print some output that looks like this –

{"css-select@npm:2.1.0/nth-check":">=2.0.1"}
{"css-select@npm:4.1.3/nth-check":">=2.0.1"}

Simply paste this in your package.json

{
    "name": "my-project",
+   "resolutions": {
+       "css-select@npm:2.1.0/nth-check": ">=2.0.1",
+       "css-select@npm:4.1.3/nth-check": ">=2.0.1"
+   }
}
// Script that generates yarn resolutions for your audit-ci advisories.
// Requires `audit-ci` and `yarn` installed.
// Assumes `audit-ci.json` as your audit-ci configuration file present in the current working directory.
const { EOL } = require('os')
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const getAuditCIOutput = async (configPath) => {
try {
// Would be nice if `audit-ci` exported a programmable interface :-(
return await exec(`npx --yes audit-ci --config ${configPath} --report-type full`, {
stdio: ['ignore', 'ignore', 'ignore']
})
} catch (err) {
return {
stdout: err.stdout,
stderr: err.stderr,
}
}
}
const parseAuditCIOutput = (input) => input
.trim()
.substring(input.indexOf('{') - 1, input.lastIndexOf('}') + 1)
.replaceAll(EOL, '')
.trim()
const buildResolutions = async (advisories) => {
const whys = advisories.map((advisory) => {
const { module_name: moduleName } = advisory
// TODO: Get this programmatically from `@yarnpkg/plugin-essentials`
// TODO: Build fallback for npm
return exec(`yarn why ${moduleName} --json`)
})
const responses = await Promise.all(whys)
return advisories.map((advisory, index) => {
const { module_name: moduleName, patched_versions: patchedVersion } = advisory
const { stdout: yarnWhy } = responses[index]
const moduleUsages = yarnWhy.trim().split(EOL).map(_ => {
return JSON.parse(_)
})
const recommendedResolutions = moduleUsages.map(moduleUsage => {
return {
[`${moduleUsage.value}/${moduleName}`]: patchedVersion
}
})
return recommendedResolutions
})
}
(async () => {
const { stdout: auditCIRawOutput } = await getAuditCIOutput('audit-ci.json')
const jsonString = parseAuditCIOutput(auditCIRawOutput)
const auditJSON = JSON.parse(jsonString)
const advisories = Object.values(auditJSON.advisories)
const resolutions = await buildResolutions(advisories)
resolutions[0].forEach(resolution => console.log(JSON.stringify(resolution)))
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment