Last active
July 12, 2018 17:37
-
-
Save trs/46fee9bacbd0e58a029d283996cb7eb9 to your computer and use it in GitHub Desktop.
Quick script to scan a directory of projects for infected eslint-scope installs (rev 3.7.2). Runs in node 8+.
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
const path = require('path'); | |
const fs = require('fs'); | |
const {exec} = require('child_process'); | |
const PROJECTS_DIR = process.cwd() || __dirname; | |
const BAD_PACKAGES = [ | |
{ | |
name: 'eslint-scope', | |
revisions: ['3.7.2'] | |
}, | |
{ | |
name: 'eslint-config-eslint', | |
revisions: ['5.0.2'] | |
} | |
]; | |
const DEPENDENCY_KEYS = [ | |
'dependencies', | |
'devDependencies', | |
'peerDependencies', | |
'bundledDependencies', | |
'optionalDependencies' | |
]; | |
const projectDirectories = fs.readdirSync(PROJECTS_DIR) | |
.filter(d => fs.statSync(path.join(PROJECTS_DIR, d)).isDirectory()) | |
.filter(d => fs.existsSync(path.join(PROJECTS_DIR, d, 'package.json'))); | |
function recurseCheckDependencies(dependencies, subpath = []) { | |
const matchedSubdepdencies = []; | |
Object.keys(dependencies).forEach(packageName => { | |
const packageInfo = dependencies[packageName]; | |
for (const {name, revisions} of BAD_PACKAGES) { | |
if (packageName.trim() === name) { | |
if (revisions.includes(packageInfo.version.trim())) { | |
console.log('bad revision found!'); | |
matchedSubdepdencies.push(subpath.concat([packageName, packageInfo.version.trim()])); | |
} | |
} | |
} | |
if (packageInfo.dependencies) { | |
const matchedSub = recurseCheckDependencies( | |
packageInfo.dependencies, | |
subpath.concat([packageName]) | |
); | |
if (matchedSub && matchedSub.length) { | |
matchedSubdepdencies.push(...matchedSub); | |
} | |
} | |
}); | |
if (matchedSubdepdencies.length > 0) { | |
return matchedSubdepdencies; | |
} | |
return null; | |
} | |
async function checkDirectory(d) { | |
console.log(`checking project ${d}`); | |
const fullPath = path.join(PROJECTS_DIR, d); | |
const rawResult = await new Promise(resolve => exec('npm list --json', { | |
cwd: fullPath, | |
maxBuffer: 10000 * 1024 | |
}, (error, stdout, stderr) => { | |
if (stdout && stdout.length) { | |
resolve(stdout); | |
} | |
resolve(stdout || stderr); | |
})); | |
const result = JSON.parse(rawResult); | |
return DEPENDENCY_KEYS.reduce((total, key) => { | |
const matched = recurseCheckDependencies(result[key] || {}) || []; | |
if (matched && matched.length) { | |
console.log(` !!! [${key}] found bad revisions (${key})`, matched.map(m => m.join(' -> '))); | |
} else { | |
console.log(` OK (${key})`); | |
} | |
return [...total, ...matched]; | |
}, []); | |
} | |
async function checkAllDirectories() { | |
const allBadPaths = []; | |
for (let di = 0; di < projectDirectories.length; di++) { | |
const d = projectDirectories[di]; | |
try { | |
const badPaths = await checkDirectory(d); | |
if (badPaths && badPaths.length) { | |
allBadPaths.push(...badPaths.map(p => [d].concat(p))); | |
} | |
} catch (err) { | |
console.log(`failed to scan ${d}`, err); | |
} | |
} | |
if (!allBadPaths.length) { | |
console.log('completed successfully'); | |
} else { | |
console.log('!!! Bad packages found'); | |
allBadPaths.forEach(p => { | |
console.log(p.join(' -> ')); | |
}); | |
} | |
} | |
(async function () { | |
try { | |
await checkAllDirectories(); | |
} catch (err) { | |
console.error('failed', err); | |
} finally { | |
process.exit(0); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment