Created
January 14, 2020 21:37
-
-
Save ggascoigne/fbe52ddf945813866bf0c9b20488b41d to your computer and use it in GitHub Desktop.
Allow exclusion of yarn audit failures.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Run a vulnerability audit with some retry logic for if the audit | |
// service is temporarily down (which we have seen sometimes in jenkins builds) | |
/* eslint-disable @typescript-eslint/no-var-requires */ | |
require('perish') | |
const execa = require('execa') | |
const path = require('path') | |
const fs = require('fs') | |
const promiseRetry = require('promise-retry') | |
const PROJECT_ROOT_DIRNAME = path.resolve(__dirname, '..') | |
// file created by running | |
// yarn audit --json --non-interactive > ./yarn-audit-known-issues | |
const KNOWN_ISSUES_FILE_NAME = './yarn-audit-known-issues' | |
const getAdvisoryId = item => parseInt(item.data.advisory.id) | |
const getAdvisories = input => { | |
const data = [] | |
input.split('\n').forEach(line => { | |
if (line.length) { | |
const obj = JSON.parse(line) | |
if (obj.type === 'auditAdvisory') data.push(obj) | |
} | |
}) | |
data.sort((item1, item2) => getAdvisoryId(item1) - getAdvisoryId(item2)) | |
return data | |
} | |
const getKnownIssues = () => { | |
if (fs.existsSync(KNOWN_ISSUES_FILE_NAME)) { | |
const data = fs.readFileSync(KNOWN_ISSUES_FILE_NAME) | |
return getAdvisories(data.toString('utf8')) | |
} | |
} | |
const jsonEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b) | |
const dumpException = data => { | |
const advisory = data.data.advisory | |
console.table({ | |
Severity: advisory.severity, | |
Title: advisory.title, | |
Package: advisory.module_name, | |
'Patched in': | |
advisory.patched_versions === '<0.0.0' | |
? 'No patch available' | |
: advisory.patched_versions, | |
'More info': advisory.url | |
}) | |
} | |
const reportIssues = (known = [], current) => { | |
const exceptions = [] | |
if (!known.length) { | |
current.forEach(c => exceptions.push(c)) | |
} else { | |
for (let kIndex = 0, cIndex = 0; ; ) { | |
const k = known[kIndex] | |
const c = current[cIndex] | |
if (!k && !c) break | |
if (jsonEqual(k, c)) { | |
kIndex++ | |
cIndex++ | |
} else { | |
const kId = getAdvisoryId(k) | |
const cId = getAdvisoryId(c) | |
if (kId < cId) { | |
// known error no longer showing up | |
kIndex++ | |
} else if (kId === cId) { | |
// the advisory has changed so we should log it | |
exceptions.push(c) | |
kIndex++ | |
cIndex++ | |
} else { | |
// new error, log it | |
exceptions.push(c) | |
cIndex++ | |
} | |
} | |
} | |
} | |
if (exceptions.length) { | |
console.log('Audit Violations:') | |
exceptions.forEach(dumpException) | |
} | |
} | |
function runAudit() { | |
console.log('running vulnerability audit') | |
promiseRetry(async (retry, attempt) => { | |
const _ = await execa('yarn', ['audit', '--json', '--non-interactive'], { | |
cwd: PROJECT_ROOT_DIRNAME, | |
env: process.env, | |
all: true | |
}).catch(err => { | |
if (err.all.match(/503 Service Unavailable/)) { | |
console.log( | |
`audit service temporarily unavailable, retrying (attempt #${attempt})...` | |
) | |
retry() | |
} | |
const knownIssues = getKnownIssues() | |
const currentIssues = getAdvisories(err.stdout) | |
if (!jsonEqual(knownIssues, currentIssues)) { | |
reportIssues(knownIssues, currentIssues) | |
process.exit(1) | |
} | |
}) | |
}).then() | |
} | |
runAudit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment