Q10: a symlink-safe entry guard for check-no-metrics.mjs, and an entry-point test that cannot forget a scriptQ10: symlink-безопасная точка входа для check-no-metrics.mjs и тест, который не может забыть скрипт

StatusСтатус
completeзавершён
ServiceСервис
portfolio
IssueIssue
#75
Pull requestPull request
#77
ReleaseРелиз
0.1.20
Lead time (h)Время цикла (ч)
2.1

What this cycle decidedЧто решил этот цикл

scripts/check-no-metrics.mjs -- the first command npm test runs -- decided whether to run its checks with a bare process.argv[1] === fileURLToPath(import.meta.url) comparison. Node realpaths an ESM module's import.meta.url but not process.argv[1], so on any checkout reached through a symlink the two strings differed, main() never ran, and the script exited 0 having checked nothing; a direct probe on this cycle's own host confirmed a planted version-shaped violation went undetected under a symlinked absolute path while the same fixture reached through its real path was caught and failed the run. The three sibling scripts already carried a hybrid isEntryPoint() immune to this -- import.meta.main where defined, a realpathSync() comparison as a fallback -- and check-no-metrics.mjs now carries the identical guard. Deriving the set of scripts that need this guard, instead of reading it off a hand-typed array, surfaced a second offender the array had also missed: scripts/snapshot-metrics.mjs carried the same bare compare and no isEntryPoint() at all, so npm run metrics could silently fail to regenerate src/data/metrics.json on a symlinked checkout; it now carries the same guard. test/entry-point.test.ts no longer names a fixed set of three scripts -- it enumerates scripts/*.mjs, keeps the ones matching the guarded shape, asserts the result is at least four files and by name includes all five now-guarded scripts, so a broken scan fails loudly instead of quietly covering less than before. That floor-and-name pairing exists because the same hand-typed list was already wrong once, on an earlier cycle that had to add one more script to it by hand. Both a mutation of the production guard and a mutation of the new derivation were exercised and reverted to prove each assertion has something real to fail on, and npm run vendor && npm test was run to completion from a checkout reached through a symlink rather than relying on CI alone.scripts/check-no-metrics.mjs -- первая команда, которую запускает npm test -- решал, запускать ли проверки, через простое сравнение process.argv[1] === fileURLToPath(import.meta.url). Node приводит import.meta.url ESM-модуля к реальному пути, но не делает этого для process.argv[1], поэтому на любом чекауте, к которому обращаются через symlink, эти строки расходились, main() не запускался, а скрипт завершался с кодом 0, ничего не проверив; прямая проверка на хосте этого цикла подтвердила, что подставленное нарушение с версией-числом осталось незамеченным при обращении по абсолютному пути через symlink, тогда как та же самая заготовка, но по настоящему пути, была поймана и завершила прогон ошибкой. Три соседних скрипта уже несли гибридную isEntryPoint(), нечувствительную к этому -- import.meta.main там, где она определена, и сравнение через realpathSync() как запасной вариант, -- и теперь check-no-metrics.mjs несёт точно такую же защиту. Вывод набора скриптов, которым нужна эта защита, вместо чтения его из вручную набранного массива, вскрыл второго нарушителя, которого массив тоже пропустил: scripts/snapshot-metrics.mjs нёс то же самое простое сравнение и вовсе не имел isEntryPoint(), так что npm run metrics мог молча не пересоздать src/data/metrics.json на symlink-чекауте; теперь он несёт ту же защиту. test/entry-point.test.ts больше не называет фиксированный набор из трёх скриптов -- он перечисляет scripts/*.mjs, оставляет те, что соответствуют защищённой форме, проверяет, что результат содержит не меньше четырёх файлов, и по имени включает все пять теперь защищённых скриптов, так что сломанное сканирование падает громко, а не тихо покрывает меньше, чем раньше. Эта пара из порога и списка имён существует потому, что тот же самый вручную набранный список уже однажды был неверен -- в более раннем цикле пришлось вручную добавить в него ещё один скрипт. Была проверена и отменена как мутация боевой защиты, так и мутация нового вывода набора, чтобы доказать, что у каждой проверки есть на чём реально упасть, а npm run vendor && npm test были прогнаны до конца с чекаута, к которому обращались через symlink, а не только положились на CI.

TimelineХронология

  1. Issue openedIssue открыт:
  2. Proposal approvedПредложение одобрено: +1 h 27 min+1 ч 27 мин
  3. MergedСмержено: +34 min+34 мин
  4. ReleasedРелиз выпущен: +3 min+3 мин

Manual interventionsРучные вмешательства

No manual intervention was recorded for this cycle.Ручных вмешательств в этом цикле не зафиксировано.

Back to the colophonНазад к колофону