8 студзеня аўтар colors апублікаваў версію 1.4.44-liberty-2. Яна друкавала “LIBERTY LIBERTY LIBERTY”, сцяг з сімвалаў ASCII і потым смецце ў бясконцым цыкле. За 3 дні да гэтага выйшаў faker 6.6.6, у якім кода не было зусім. У трэдах пасля гэтага спрачаліся, ці меў аўтар на гэта права. Мой адказ на такія гісторыі заўсёды быў стандартны: камітаваць lockfile і пініць версіі. Але колькі праектаў гэта насамрэч закранула, я не ўяўляў.
У лістападзе 2020 года той самы аўтар адкрыў на GitHub issue з назвай “No more free work from Marak”. Кампаніям там прапаноўваліся 2 варыянты: гадавы кантракт з аўтарам або форк, “fork the project and have someone else work on it”. Пакуль год не скончыўся, я вырашыў праверыць, як далёка дацягваецца адзін мейнтэйнер, які ламае ўласны пакет. І які з 2 варыянтаў у выніку спраўдзіўся.
Першая версія, якую ўдалося прачытаць
Зламаных версій у npm больш няма. Рэестр яшчэ паказвае 1.4.44-liberty-2, 1.4.1 і 1.4.2 з часам публікацыі, але тарболы выдалены. Яшчэ 4 месцы, якія я праверыў, у тым ліку npmmirror і jsDelivr, адказваюць 404. Таму я пачаў з гісторыі git у Marak/colors.js. За 3 хвіліны да каміта, які падымае версію да liberty-2, іншы каміт дадае 10 радкоў у lib/index.js. Яны нават не парсяцца. Каміт “Fix bug” праз 2 хвіліны прыбірае лішнюю кропку з коскай. Пасля праўкі:
/* remove this line after testing */
let am = require('../lib/custom/american');
am();
for (let i = 666; i < Infinity; i++) {
if (i % 333) {
// console.log('testing'.zalgo.rainbow)
}
console.log('testing testing testing testing testing testing testing'.zalgo)
}
Я запусціў гэта на Node 16.13.1, тагачасным LTS на 8 студзеня. require('colors') надрукаваў каля 60 МБ, пакуль яго не забіў мой таймаўт у 3 секунды. Да наступнага радка майго скрыпта ён так і не дайшоў. require('colors/safe'), уваход, які не чапае String.prototype, вярнуўся за 0,1 секунды і нічога не надрукаваў. Прычына ў тым, што safe.js грузіць lib/colors.js наўпрост, а цыкл стаіць толькі ў lib/index.js.
Далей я праверыў, хто ўвогуле паставіў бы liberty-2. Гэта прэрэліз, а дыяпазон накшталт ^1.4.0 прэрэлізы не бярэ ніколі. Я правяраў праз npm-pick-manifest 6.1.1, гэта той код, якім npm 8.1 выбірае версію. Калі latest паказвае на прэрэліз, ^1.4.0 усё роўна дае 1.4.0. Зламаную версію даюць толькі latest і *. У Live Server у package.json стаяла "colors": "latest". Першы каментар у issue пра паломку пакінуў якраз адзін з карыстальнікаў Live Server.
Спіс пакетаў я ўзяў з npm-high-impact 1.1.0, тую яго частку, дзе не менш за 1 мільён спамповак у тыдзень, гэта 4366 пакетаў npm. Спіс лістападаўскі, значыць гэта топ канца года, а не студзеня. У 31 з іх colors у нейкі момант быў у залежнасцях. На 8 студзеня наўпрост ён быў у 9, разам яны мелі 21 мільён спамповак за першы тыдзень студзеня. Ніводзін з 9 liberty-2 не атрымаў бы. 8 з іх грузяць толькі colors/safe. Толькі cli-progress грузіць звычайны colors.
Да гэтага моманту палова паста была напісана. У загалоўку стаяла, што завісне 1 з 9 топавых пакетаў. Я зыходзіў з таго, што ў 1.4.2 той самы цыкл, што ў liberty-2, хоць гэтага не правяраў.
1.4.2
1.4.1 выйшла тым самым вечарам, а 1.4.2 праз дзень. Гэта звычайныя версіі, таму пры свежай устаноўцы без lockfile усе дыяпазоны з ^ ішлі на іх. 7 з 9 атрымлівалі 1.4.2. Выключэнні толькі cli-table (пін на 1.0.3) і jasmine-spec-reporter (пін на 1.4.0). Паводле паведамлення DABH ад 11 студзеня (каміты ў colors з 2018 года), npm гэтыя версіі выдаліў. Паводле бюлетэня бяспекі GitHub ад 10 студзеня, цыкл ёсць ва ўсіх 3 версіях, але дзе менавіта ў кодзе, не сказана.
10 студзеня Wayback Machine захаваў тарбол 1.4.2. Я звярыў яго з хешам integrity з lockfile рэпазіторыя ngx-ui-scroll. Там 1.4.2 паставілі 9 студзеня і ў той жа дзень адкацілі з паведамленнем “tests don’t work with 1.4.2”. Хеш супадае. У lib/index.js той самы цыкл. У safe.js ён таксама ёсць, пасля новага каментара:
/* attempting to patch existing bug */
Выходзіць, colors/safe быў бяспечным усяго 1 дзень. Я паставіў кожны з 9 пакетаў у версіі, бягучай на 8 студзеня, праз npm 8.1.2. Потым замяніў у дрэве ўсе копіі colors на 1.4.2 і запусціў на тым самым Node. 3 з іх завісаюць на require: logform, cli-progress і тэставы ранер Playwright. Астатнія 4 як бібліятэкі загружаюцца нармальна і завісаюць, як толькі загружаецца частка, што працуе з колерам. У каманд http-server і jscodeshift гэта сам запуск. karma завісае, калі загружае свой рэпарцёр, а cli-table3 на першай табліцы з каляровым загалоўкам. 2 пакеты з пінам працуюць.
Што рабіла 1.4.1, я не ведаю: яе копію я не знайшоў нідзе, нават у Wayback Machine. У ngx-ui-scroll 1.4.1 праляжала ў lockfile 17 гадзін. За гэты час там былі каміты з праўкай тэстаў і канфіга karma. Менавіта на яе яны спачатку і адкаціліся. Тэсты ў іх ідуць праз karma, а яна грузіць толькі colors/safe. Гэта адпавядала б версіі 1.4.1, у якой цыкл стаіць толькі ў lib/index.js. Але праз 90 хвілін яны перайшлі на 1.4.0, не растлумачыўшы чаму. І гэта 1 рэпазіторый.
Як хутка сышлі
7 з 9 адрэагавалі за 5 дзён. cli-progress выпусціў версію без colors 9 студзеня, cli-table3 у той жа дзень запініў 1.4.0. Яшчэ 4 падцягнуліся 10 студзеня, сярод іх logform і Playwright. karma зрабіла гэта 13 студзеня. Да канца года 3 з 9 залежаць ад @colors/colors, форка, які DABH выпусціў у лютым. winston, які атрымліваў colors праз logform, таксама перайшоў на яго. DABH да таго ж мейнтэйнер logform і winston.
У faker таксама з’явіўся форк ад супольнасці, @faker-js/faker, праз 5 дзён пасля 6.6.6. Сам faker не быў у звычайных dependencies ні ў аднаго з 4366. Ён жыве ў devDependencies, а 6.6.6 гэта новая мажорная версія, таму ^5.5.3 па-ранейшаму дае 5.5.3.
Імя застаецца
Вось гэта мне здаецца дзіўным. На npmjs.com у снежні ў colors стаіць версія 1.4.0, у faker 6.6.6. У абодвух 1 мейнтэйнер, marak. Зламаныя версіі colors выдалілі, але імя нікому не перадалі. faker 6.6.6 дагэтуль latest, а кода ў ім няма. README з аднаго радка пра Аарона Шварца, а ў .github/FUNDING.yml усё гэтак жа github: marak. npm install faker сёння ставіць пакет, у якім require('faker') падае з MODULE_NOT_FOUND.
Спампоўкі таксама амаль не зрушыліся. У лістападзе ў colors было 88,5 мільёна спамповак, на 8% менш, чым у лістападзе 2021 года, а ў @colors/colors 47,7 мільёна. У faker 11,0 мільёна, на 7% менш, чым год таму, супраць 6,6 мільёна ў форка. API npm не дзеліць спампоўкі па версіях, таму колькі з 11 мільёнаў прыпадае на старую 5.5.3, я сказаць не магу.
З 2 варыянтаў 2020 года я бачу форк. Топавыя пакеты адрэагавалі за тыдзень, у асноўным пінам на 1.4.0. Але імя засталося ў аўтара. Большая частка спамповак дагэтуль ідзе на гэтае імя. Форк colors выпусціў DABH, чые ўласныя logform і winston ад colors залежалі. Падазраю, што так трымаецца шмат інфраструктуры, але 9 пакетаў занадта мала, каб гэта сцвярджаць.
Чаго я не правяраў
Транзітыўных залежных за межамі топу. Хутчэй за ўсё, большая частка з 88 мільёнаў спамповак colors прыходзіць адтуль. Колькі праектаў мелі lockfile і так і не ўбачылі зламаных версій. Код 1.4.1. І дакладны час, калі npm выдаліў 3 версіі, бо рэестр яго не паказвае.