|
// 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))) |
|
})() |