先日ショッキングな commit が push されたというニュースを知りました。そこで念のため colors や faker の開発者が開発したパッケージを自分のプロジェクトが使用しているかを調べる簡易チェッカーを作ってみました。
経緯
- Dev corrupts NPM libs ‘colors’ and ‘faker’ breaking thousands of apps
- colorsなどのnpmパッケージに悪意あるコードが含まれている問題について
やろうと思えばできてしまうのがオープンソース界隈のエコシステムの怖いところではあります。
詳細は上述の記事をご参照ください。
それよりも、目下気になるのは自分のプロジェクトでこれらの npmパッケージ を使用していないかどうか。
colors や faker を開発した方がメンテナーになっているパッケージ一覧をazu氏が作ってくださったので、このリストを元にパッケージの使用を確認する簡易チェッカーを作ってみました。
成果物
コード (要点のみ)
const path = require('path');
const request = require('request');
const { spawnSync } = require('child_process');
const fs = require('fs');
const marakOwnedUrl = 'https://gist.githubusercontent.com/azu/11b105a9e35dc9d5f07312c24a35c82b/raw/000a0c728ac1748b6fb3c80c8a0753fb1f6a57e8/marak-packages.md';
// 略
request.get({
url: marakOwnedUrl,
}, function (error, response, body) {
const mdStream = body.split("\n");
const packageNamesArray = mdStream.filter((val) => {
return val.length > 0 && !val.startsWith('http');
});
let cnt = {
found: 0,
notfound: 0,
}
let resultStr = `Project: ${projectPathStr}
`;
for (let i = 0; i < packageNamesArray.length; i++) {
console.log(`yarn why ${packageNamesArray[i]}`);
resultStr += `Package "${packageNamesArray[i]}": ${i + 1} / ${packageNamesArray.length}
> yarn why ${packageNamesArray[i]}
`;
console.log(`package "${packageNamesArray[i]}": ${i + 1} / ${packageNamesArray.length}`);
const spawn = spawnSync(`yarn why ${packageNamesArray[i]} --cwd ${projectPathStr}`, { shell: true });
console.log(spawn.stdout.toString());
resultStr += `${spawn.stdout.toString()}
`;
console.log(spawn.stderr.toString());
resultStr += `${spawn.stderr.toString()}
`;
spawn.stderr.toString().length > 0 ? cnt.notfound++ : cnt.found++;
}
const cntMsg = `
Found packages: ${cnt.found}
Not found packages: ${cnt.notfound}`;
console.log(cntMsg);
resultStr += cntMsg;
try{
fs.writeFileSync(path.join(path.join('.', 'dist'), `scan-result-${projectName}.log`), resultStr);
}
catch(e){
console.log(e.message);
}
});
- 先程の mdファイル をHTTPリクエストで取得し、パッケージ名の行のみ(1行の文字列が0(改行のみ)と
http
始まりを除外)処理します - パッケージ名分ループして、
child_process
のspawn
を使用し、yarn why {パッケージ名} --cwd {プロジェクトのパス}
コマンドを実行 (npm
は今回は見ていません)- コマンドライン引数でプロジェクトのパスを指定することで、該当プロジェクトのディレクトリで
yarn why
をしています
- コマンドライン引数でプロジェクトのパスを指定することで、該当プロジェクトのディレクトリで
- 実行結果を
console.log
で表示しつつ、メモリに格納。全ての確認が終わるとテキストファイルにダンプします- 標準出力エラー(パッケージが見付からなかった)と成功(パッケージが見付かった)をカウントして出力に付与しています
- 標準出力エラーを使うために
spawn
を使用
スピード重視でざっくり作りました。ひとまず自分の手元で動いて予期する動作になったので公開しました。
参考
きっかけ
- Dev corrupts NPM libs ‘colors’ and ‘faker’ breaking thousands of apps
- colorsなどのnpmパッケージに悪意あるコードが含まれている問題について
- 高梨陣平さんはTwitterを使っています 「開発者 Marak Squiresは自身のOSSを故意にサボタージュ版をリリース。問題の製品は“faker.js” と “colors.js”。両者共に“LIBERTY LIBERTY LIBERTY.”の3行で始まる無意味な文字列を無限に表示。両者は週250万DL、2240万DLで影響はでかい。NPMはrevertを行いSquiresはGitHubからアクセスを奪われた。Ve」 \/ Twitter
- オープンソース開発者が広く使用されている自分のライブラリを改ざん、大量のプロジェクトに影響 | ソフトアンテナ
- Firebase CLIとかの出力が2022-01-10の一時期に乱れてた件 – Qiita
経緯
前兆
パッケージ一覧
HTTPクライアント
コマンド実行
- Node.js|シェルコマンドを実行する方法(child_process) – わくわくBank
- node.js の execSync の戻り値で stderr を受け取る方法 – スタック・オーバーフロー
stderr
を使用するならばspawn
の方が良い
- Node.js の Child Process 研究 : fork・exec・execFile・spawn の違いをサンプルコードとともに検証 – Neo’s World