@nitra/cursor 5.3.3 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/.claude-template/settings.template.json +2 -2
  2. package/.pi-template/extensions/n-cursor-adr/docs/index.md +13 -24
  3. package/CHANGELOG.md +17 -0
  4. package/bin/n-cursor.js +43 -22
  5. package/lib/docs/llm.md +23 -12
  6. package/lib/docs/models.md +29 -18
  7. package/lib/docs/omlx-trace.md +51 -0
  8. package/lib/docs/omlx.md +31 -15
  9. package/lib/omlx.mjs +2 -5
  10. package/package.json +1 -1
  11. package/rules/abie/docs/fix.md +17 -11
  12. package/rules/adr/docs/fix.md +25 -140
  13. package/rules/bun/docs/fix.md +18 -151
  14. package/rules/capacitor/docs/fix.md +16 -13
  15. package/rules/capacitor/js/docs/platforms.md +31 -43
  16. package/rules/changelog/docs/fix.md +25 -169
  17. package/rules/ci4/docs/fix.md +11 -14
  18. package/rules/doc-files/doc-files.mdc +60 -0
  19. package/rules/doc-files/docs/fix.md +31 -0
  20. package/rules/doc-files/fix.mjs +19 -0
  21. package/{skills → rules}/doc-files/js/docgen-extract.mjs +42 -19
  22. package/{skills → rules}/doc-files/js/docgen-ignore.mjs +2 -1
  23. package/{skills → rules}/doc-files/js/docgen-scan.mjs +9 -1
  24. package/{skills → rules}/doc-files/js/docs/docgen-crc.md +1 -1
  25. package/rules/doc-files/js/docs/docgen-extract-anchors.md +45 -0
  26. package/rules/doc-files/js/docs/docgen-extract.md +39 -0
  27. package/rules/doc-files/js/docs/docgen-files-batch.md +35 -0
  28. package/rules/doc-files/js/docs/docgen-gen.md +46 -0
  29. package/rules/doc-files/js/docs/docgen-ignore.md +37 -0
  30. package/rules/doc-files/js/docs/docgen-prompts.md +39 -0
  31. package/rules/doc-files/js/docs/docgen-scan.md +54 -0
  32. package/rules/doc-files/js/docs/lint.md +36 -0
  33. package/rules/doc-files/js/docs/units-js.md +31 -0
  34. package/rules/doc-files/js/docs/units-rs.md +35 -0
  35. package/rules/doc-files/js/docs/units.md +30 -0
  36. package/rules/doc-files/js/lint.mjs +96 -0
  37. package/{skills → rules}/doc-files/js/units-rs.mjs +37 -17
  38. package/rules/doc-files/lint/docs/lint.md +37 -0
  39. package/rules/doc-files/lint/lint.mjs +105 -0
  40. package/rules/doc-files/meta.json +1 -0
  41. package/rules/docker/docs/fix.md +21 -161
  42. package/rules/efes/docs/fix.md +23 -194
  43. package/rules/feedback/docs/fix.md +10 -8
  44. package/rules/ga/docs/fix.md +10 -5
  45. package/rules/graphql/docs/fix.md +23 -119
  46. package/rules/hasura/docs/fix.md +19 -5
  47. package/rules/hasura/js/docs/internal_urls.md +34 -307
  48. package/rules/image-avif/docs/fix.md +16 -127
  49. package/rules/image-compress/docs/fix.md +20 -141
  50. package/rules/image-compress/js/docs/package_setup.md +22 -182
  51. package/rules/js-bun-db/docs/fix.md +23 -139
  52. package/rules/js-bun-db/js/docs/safety.md +33 -221
  53. package/rules/js-bun-redis/docs/fix.md +25 -114
  54. package/rules/js-bun-redis/js/docs/imports.md +18 -166
  55. package/rules/js-lint/docs/fix.md +30 -108
  56. package/rules/js-lint/js/docs/lint-findings.md +37 -17
  57. package/rules/js-lint/js/docs/lint.md +22 -238
  58. package/rules/js-lint/js/docs/tooling.md +34 -331
  59. package/rules/js-lint-ci/docs/fix.md +16 -149
  60. package/rules/js-lint-ci/js/docs/lint.md +16 -136
  61. package/rules/js-mssql/docs/fix.md +18 -123
  62. package/rules/js-mssql/js/docs/deps.md +28 -251
  63. package/rules/js-run/docs/fix.md +23 -138
  64. package/rules/js-run/js/docs/runtime.md +24 -378
  65. package/rules/k8s/docs/fix.md +18 -123
  66. package/rules/nginx-default-tpl/docs/fix.md +22 -118
  67. package/rules/nginx-default-tpl/js/docs/template.md +38 -360
  68. package/rules/npm-module/docs/fix.md +27 -89
  69. package/rules/npm-module/js/docs/header_doc_pointer.md +15 -15
  70. package/rules/npm-module/js/docs/package_structure.md +36 -258
  71. package/rules/npm-module/js/docs/rule_meta.md +25 -127
  72. package/rules/npm-module/js/docs/skill_meta.md +18 -180
  73. package/rules/php/docs/fix.md +21 -98
  74. package/rules/php/js/docs/tooling.md +20 -143
  75. package/rules/python/docs/fix.md +25 -157
  76. package/rules/python/js/docs/applies.md +20 -98
  77. package/rules/python/js/docs/tooling.md +27 -144
  78. package/rules/rego/docs/fix.md +24 -112
  79. package/rules/rego/js/docs/applies.md +20 -164
  80. package/rules/rego/js/docs/lint.md +15 -110
  81. package/rules/release/docs/fix.md +16 -114
  82. package/rules/rust/docs/fix.md +24 -119
  83. package/rules/rust/js/docs/applies.md +20 -129
  84. package/rules/security/docs/fix.md +21 -78
  85. package/rules/security/js/docs/sample_secret.md +23 -182
  86. package/rules/security/js/docs/trufflehog.md +19 -128
  87. package/rules/style-lint/docs/fix.md +16 -150
  88. package/rules/style-lint/js/docs/lint.md +21 -172
  89. package/rules/style-lint/js/docs/tooling.md +19 -184
  90. package/rules/tauri/docs/fix.md +26 -152
  91. package/rules/tauri/js/docs/cargo_mutants_config.md +21 -159
  92. package/rules/tauri/js/docs/tooling.md +20 -217
  93. package/rules/test/docs/fix.md +19 -127
  94. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +15 -127
  95. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +17 -153
  96. package/rules/test/js/docs/cargo_mutants_config.md +24 -164
  97. package/rules/test/js/docs/location.md +24 -126
  98. package/rules/test/js/docs/no-process-chdir.md +20 -151
  99. package/rules/test/js/docs/no-relative-fs-path.md +24 -261
  100. package/rules/test/js/docs/stryker_config.md +48 -148
  101. package/rules/test/js/docs/vitest-config-pool-forks.md +21 -164
  102. package/rules/text/docs/fix.md +25 -113
  103. package/rules/text/js/docs/forbidden-prettier.md +21 -132
  104. package/rules/text/js/docs/formatting.md +60 -251
  105. package/rules/text/js/docs/lint.md +17 -114
  106. package/rules/vue/docs/fix.md +25 -118
  107. package/rules/vue/js/docs/packages.md +25 -323
  108. package/rules/worktree/docs/fix.md +31 -150
  109. package/scripts/coverage-classify/docs/index.md +23 -209
  110. package/scripts/coverage-classify/docs/verdict-schema.md +14 -159
  111. package/scripts/dispatcher/docs/trace.md +35 -0
  112. package/scripts/docs/auto-rules.md +37 -361
  113. package/scripts/docs/lint-cli.md +12 -13
  114. package/scripts/docs/post-tool-use-fix.md +16 -15
  115. package/scripts/docs/skills-cli.md +26 -23
  116. package/scripts/docs/sync-claude-config.md +94 -34
  117. package/scripts/docs/worktree-cli.md +11 -34
  118. package/scripts/lib/docs/assert-project-root.md +14 -16
  119. package/scripts/lib/docs/changed-files.md +24 -139
  120. package/scripts/lib/docs/discover-check-rules-from-cursor.md +14 -146
  121. package/scripts/lib/docs/rule-predicates.md +20 -17
  122. package/scripts/lib/docs/run-rule-cli.md +14 -18
  123. package/scripts/lib/docs/run-rule.md +13 -20
  124. package/scripts/lib/docs/run-standard-rule.md +12 -15
  125. package/scripts/lib/docs/sync-gitignore-worktree.md +15 -18
  126. package/scripts/lib/rule-predicates.mjs +1 -1
  127. package/scripts/sync-claude-config.mjs +4 -1
  128. package/scripts/utils/docs/with-lock.md +19 -12
  129. package/scripts/utils/with-lock.mjs +4 -2
  130. package/skills/doc-aggregate/SKILL.md +2 -2
  131. package/skills/doc-aggregate/js/docgen-ignore.mjs +6 -6
  132. package/skills/doc-aggregate/js/docs/docgen-ignore.md +1 -1
  133. package/skills/doc-aggregate/js/docs/docgen-scan.md +78 -0
  134. package/skills/doc-files/.changes/260612-0012.md +5 -0
  135. package/skills/doc-files/.changes/260612-0031.md +5 -0
  136. package/skills/doc-files/.changes/260612-0036.md +5 -0
  137. package/skills/doc-files/.changes/260612-0114.md +5 -0
  138. package/skills/doc-files/SKILL.md +6 -6
  139. package/skills/fix/js/docs/llm-worker.md +17 -15
  140. package/skills/fix/js/docs/orchestrator.md +30 -23
  141. package/skills/fix/js/docs/t0.md +26 -16
  142. package/skills/start-check/js/docs/check.md +26 -22
  143. package/skills/taze/js/docs/diff.md +44 -20
  144. package/skills/doc-files/js/docs/docgen-extract-anchors.md +0 -27
  145. package/skills/doc-files/js/docs/docgen-extract.md +0 -29
  146. package/skills/doc-files/js/docs/docgen-files-batch.md +0 -25
  147. package/skills/doc-files/js/docs/docgen-gen.md +0 -30
  148. package/skills/doc-files/js/docs/docgen-prompts.md +0 -32
  149. package/skills/doc-files/js/docs/docgen-scan.md +0 -25
  150. package/skills/doc-files/js/docs/units-rs.md +0 -35
  151. /package/{skills → rules}/doc-files/js/docgen-crc.mjs +0 -0
  152. /package/{skills → rules}/doc-files/js/docgen-extract-anchors.mjs +0 -0
  153. /package/{skills → rules}/doc-files/js/docgen-files-batch.mjs +0 -0
  154. /package/{skills → rules}/doc-files/js/docgen-gen.mjs +0 -0
  155. /package/{skills → rules}/doc-files/js/docgen-prompts.mjs +0 -0
  156. /package/{skills → rules}/doc-files/js/units-js.mjs +0 -0
  157. /package/{skills → rules}/doc-files/js/units.mjs +0 -0
@@ -1,92 +1,35 @@
1
1
  ---
2
2
  docgen:
3
3
  source: npm/rules/security/fix.mjs
4
- crc: 12fc1644
4
+ crc: 38cf876b
5
+ score: 70
5
6
  ---
6
7
 
7
- # fix.mjs — entry-point правила `security`
8
+ # fix.mjs
8
9
 
9
10
  ## Огляд
10
11
 
11
- Файл `npm/rules/security/fix.mjs` це канонічний entry-point правила з ідентифікатором `security` пакета `@nitra/cursor`. Він реалізує стандартний «двозадачний» патерн всіх правил у директорії `npm/rules/<id>/fix.mjs`:
12
+ Файл ініціює виконання визначеного правила. Правило виконує операцію `applies` з використанням `JS-concerns` для отримання `policy` з `mdc-refs`. При завершенні роботи, якщо виконання відбувається через командний рядок, повертається код виходу для встановлення статусу завершення процесу.
12
13
 
13
- 1. **Library mode** — експортує функцію `run(ctx)`, яку викликає CLI-оркестратор пакета (`npx @nitra/cursor fix <id>` або агрегований прогон усіх правил). У цьому режимі правило ділить кеш обходу файлів (`walkCache`) та інший контекст із іншими правилами одного запуску.
14
- 2. **Standalone mode** — якщо файл запущено напряму (наприклад `bun rules/security/fix.mjs`), виконується повний CLI-цикл: завантаження конфігурації, застосування whitelist, друк summary та повернення коду виходу для CI/IDE.
14
+ ## Поведінка
15
15
 
16
- Уся ділова логіка (фази `applies` → `JS-concerns` → `policy` → `mdc-refs`) делегується спільному раннеру `runStandardRule`, тому сам `fix.mjs` залишається тонким shim-ом, який знає лише власну директорію (`import.meta.dirname`) і передає її далі.
16
+ 1. Запуск правила.
17
+ * Передача контексту прогону.
18
+ * Виклик `runStandardRule` з використанням шляху модуля.
19
+ 2. Виконання правила.
20
+ * Виклик `runStandardRule` з контекстом.
21
+ * Виконання операції `applies → JS-concerns → policy → mdc-refs`.
22
+ 3. Вихід з CLI.
23
+ * Перевірка режиму запуску через `isRunAsCli`.
24
+ * Якщо запущено через CLI, повернення коду виходу з `runRuleCli` для встановлення `process.exitCode`.
17
25
 
18
- ## Експорти / API
26
+ ## Публічний API
19
27
 
20
- | Експорт | Тип | Призначення |
21
- | ------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
22
- | `run` | `function(ctx?): Promise<number>` | Іменований експорт — точка входу для library-режиму. Викликається CLI-оркестратором пакета `@nitra/cursor` під час прогону одного або всіх правил. |
28
+ run запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
29
+ Library mode викликається CLI orchestration через `import + run`.
23
30
 
24
- Default-експорт не оголошено. Side-effect частина (CLI-bootstrap) виконується лише за умови, що файл є entry-point процесу (див. розділ «Потік виконання»).
31
+ ## Гарантії поведінки
25
32
 
26
- ## Функції
27
-
28
- ### `run(ctx)`
29
-
30
- ```js
31
- export function run(ctx)
32
- ```
33
-
34
- - **Призначення.** Запустити стандартний пайплайн правила: послідовно виконати фази `applies` → `JS-concerns` → `policy` → `mdc-refs`, делегуючи всю реалізацію спільному модулю `runStandardRule`.
35
- - **Параметри.**
36
- - `ctx` _(опційно)_ — `RuleContext` із `../../scripts/lib/run-standard-rule.mjs`. Контекст одного прогону, який можуть розділяти кілька правил (наприклад, кеш обходу файлів `walkCache`, опції CLI, агрегатор результатів тощо). Якщо `ctx` не передано, `runStandardRule` має сам ініціалізувати дефолтний контекст.
37
- - **Повертає.** `Promise<number>` — числовий exit-code:
38
- - `0` — правило не знайшло порушень (OK);
39
- - `1` — є порушення, які слід репортити вище (failure).
40
- - **Side effects.** Усі побічні ефекти інкапсульовано в `runStandardRule`: читання файлів проєкту через `walkCache`, перевірки policy, можливі повідомлення в `stdout`/`stderr`, оновлення спільного контексту. Сам `run` лише прокидає `import.meta.dirname` поточного файла, щоб раннер знав, до якого правила належить директорія (структура `npm/rules/<id>/` визначає `id`).
41
- - **Винятки.** Власних `throw` немає; будь-які помилки приходять із `runStandardRule` і не перехоплюються — їх обробляє верхній рівень (CLI-оркестратор чи `runRuleCli`).
42
-
43
- ## Залежності
44
-
45
- Імпорти модуля:
46
-
47
- | Модуль | Імпортовані символи | Роль |
48
- | ----------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
49
- | `../../scripts/lib/run-rule-cli.mjs` | `isRunAsCli`, `runRuleCli` | Допоміжні функції для standalone-режиму: визначення, що файл запущений як entry-point процесу (`isRunAsCli`), та повний CLI-цикл (`runRuleCli`) із завантаженням конфігурації, whitelist та друком summary. |
50
- | `../../scripts/lib/run-standard-rule.mjs` | `runStandardRule` | Спільний раннер, що реалізує канонічний пайплайн правила (`applies` → `JS-concerns` → `policy` → `mdc-refs`). Також надає тип `RuleContext`, який використовується в JSDoc. |
51
-
52
- Жодних інших імпортів (зокрема Node-стандартних модулів) у файлі немає — він свідомо тонкий.
53
-
54
- Опосередковано модуль покладається на:
55
-
56
- - стандартну структуру каталогу правила (`npm/rules/<id>/`), яку розпізнає `runStandardRule` через переданий `import.meta.dirname`;
57
- - глобальні Node-механізми `import.meta.url` / `import.meta.dirname` для визначення власного шляху;
58
- - `process.exit` для термінального коду в standalone-режимі.
59
-
60
- ## Потік виконання / Використання
61
-
62
- ### Library-режим (виклик з оркестратора)
63
-
64
- 1. CLI-оркестратор пакета (`npx @nitra/cursor fix` або агрегований прогон усіх правил) робить `import('npm/rules/security/fix.mjs')` і отримує іменований експорт `run`.
65
- 2. Оркестратор готує спільний `RuleContext` (наприклад, ініціалізує `walkCache`, парсить аргументи) і викликає `await run(ctx)`.
66
- 3. `run` повертає `runStandardRule(import.meta.dirname, ctx)` — це promise з exit-code правила.
67
- 4. Оркестратор агрегує exit-коди всіх правил для фінального summary.
68
-
69
- ### Standalone-режим (`bun rules/security/fix.mjs` / `node ...`)
70
-
71
- 1. Після завершення імпортів виконується умовний блок `if (isRunAsCli(import.meta.url)) { ... }`.
72
- 2. `isRunAsCli(import.meta.url)` повертає `true`, лише якщо поточний модуль є entry-point процесу (`process.argv[1]` відповідає `import.meta.url`). Це гарантує, що CLI-логіка не спрацює при звичайному імпорті.
73
- 3. У цій гілці викликається `await runRuleCli(import.meta.dirname)` — повний CLI-цикл правила, еквівалентний `npx @nitra/cursor fix security`: завантаження конфігурації, застосування whitelist, друк summary, повернення exit-code.
74
- 4. Отриманий exit-code передається у `process.exit(...)`, щоб CI/IDE отримали коректний статус.
75
-
76
- Top-level `await` всередині блоку дозволено лише тому, що файл — ESM (`.mjs`), а сам блок виконується тільки в standalone-режимі.
77
-
78
- ### Коментарі ESLint у файлі
79
-
80
- Рядок із `process.exit(await runRuleCli(...))` має локальну директиву:
81
-
82
- ```js
83
-
84
- ```
85
-
86
- Це свідома відмова від загальної заборони `process.exit`: для CLI entry-point потрібно повертати числовий код, інакше CI/IDE не зможуть розрізнити OK і порушення. Заборона залишається активною для решти кодової бази.
87
-
88
- ### Місце у системі правил
89
-
90
- - Директорія `npm/rules/security/` визначає правило з `id = security`. Сам `fix.mjs` не вшиває цей `id` рядком — він виводиться зі шляху через `import.meta.dirname`, який передається до `runStandardRule` / `runRuleCli`.
91
- - Конкретна логіка перевірок (фази `applies` / `JS-concerns` / `policy` / `mdc-refs`) лежить у сусідніх файлах директорії правила та в `runStandardRule`; цей файл лише «склеює» їх із системою CLI пакета `@nitra/cursor`.
92
- - Патерн «library `run` + standalone `process.exit(await runRuleCli(...))`» однаковий для всіх правил пакета — він дозволяє запускати правило і в межах агрегованого прогону, і окремо для відладки/CI.
33
+ - Read-only: файл не виконує операцій запису у файлову систему.
34
+ - Кешує результати в межах одного прогону.
35
+ - Не звертається до мережі.
@@ -1,190 +1,31 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/security/js/sample_secret.mjs
4
+ crc: ff1c0de8
5
+ score: 90
6
+ ---
7
+
1
8
  # sample_secret.mjs
2
9
 
3
10
  ## Огляд
4
11
 
5
- Модуль `sample_secret.mjs` це FS-частина правила `security`, концерн `sample_secret`. Він реалізує перевірку, що фейкові credential-значення у **прикладних** файлах репозиторію записані як канонічний placeholder `sample-secret`, а не як bare `secret`.
6
-
7
- Мотивація: рядок `sample-secret` містить підрядок `sample`, який є у вшитому списку `DefaultFalsePositives` сканера TruffleHog. Завдяки цьому таке значення гарантовано відсіюється сканером незалежно від його версії. Bare `secret` наразі не фіксується TruffleHog лише через випадкову присутність у словнику `fp_words.txt`, що є крихкою поведінкою, залежною від версії інструмента — покладатися на неї не можна.
8
-
9
- «Прикладними» вважаються файли, що відповідають хоча б одному з критеріїв:
10
-
11
- - basename має суфікс `.example`, `.sample`, `.template` або `.dist` (наприклад, `.env.dist`, `config.example`);
12
- - basename має infix `.example.`, `.sample.` або `.template.` (наприклад, `docker-compose.example.yml`, `app.config.sample.json`);
13
- - файл лежить усередині каталогу `fixtures`, `fixture` або `__fixtures__` (на будь-якому рівні дерева).
14
-
15
- Решта файлів не сканується — там слово `secret` майже завжди є частиною реального коду, а не placeholder.
16
-
17
- Порушенням є лише `secret` у **позиції значення** — одразу після `=`, `:` чи `=>` (з опційними одинарними або подвійними лапками). Імена ключів (`client_secret`, `JWT_SECRET`) свідомо не чіпаються: матч прив'язаний до значення, а не до ключа.
18
-
19
- Архітектурний вибір (regex замість AST) пояснюється тим, що прикладні файли — це різнорідні конфіги (`.env`, YAML, JSON, TOML, plain `.dist`), єдиного AST для них немає, тож скан виконується порядково. Вибір JavaScript замість Rego зумовлений необхідністю обходу дерева (`readdir`) для пошуку прикладних файлів, тоді як conftest/Rego парсить лише структуровані документи.
20
-
21
- ## Експорти / API
22
-
23
- Файл є ES-модулем (`.mjs`) і експортує одну публічну функцію:
24
-
25
- | Експорт | Тип | Призначення |
26
- | ------- | ----------------------------------------- | ----------------------------------------------------------------- |
27
- | `check` | `async (cwd?: string) => Promise<number>` | Запускає перевірку та повертає exit-код (0 — OK, 1 — є порушення) |
28
-
29
- Внутрішні артефакти модуля (не експортуються):
30
-
31
- - `EXAMPLE_SUFFIX_RE` — RegExp для перевірки суфікса basename'а прикладного файлу.
32
- - `EXAMPLE_INFIX_RE` — RegExp для перевірки infix'а у basename'і.
33
- - `FIXTURE_DIR_RE` — RegExp для виявлення сегмента шляху з фікстурами.
34
- - `VALUE_SECRET_RE` — RegExp для виявлення bare-`secret` у позиції значення.
35
- - `isExampleFile(relPosix)` — допоміжна функція класифікації файлу.
36
-
37
- ## Функції
38
-
39
- ### `isExampleFile(relPosix)`
40
-
41
- **Сигнатура:** `function isExampleFile(relPosix: string): boolean`
42
-
43
- **Параметри:**
44
-
45
- - `relPosix` (`string`) — відносний шлях файлу від кореня репозиторію у POSIX-форматі (роздільник `/`, не `\`).
46
-
47
- **Повертає:** `boolean` — `true`, якщо файл слід сканувати на наявність bare `secret`.
48
-
49
- **Логіка:**
50
-
51
- 1. Виокремлює basename з `relPosix` шляхом обрізання за останнім `/`.
52
- 2. Перевіряє три умови (логічне АБО):
53
- - `EXAMPLE_SUFFIX_RE.test(base)` — basename закінчується на `.example`, `.sample`, `.template` або `.dist`.
54
- - `EXAMPLE_INFIX_RE.test(base)` — basename містить `.example.`, `.sample.` або `.template.`.
55
- - `FIXTURE_DIR_RE.test(relPosix)` — повний відносний шлях містить сегмент `fixtures`, `fixture` або `__fixtures__`.
56
- 3. Повертає результат диз'юнкції.
57
-
58
- **Side effects:** немає (чиста функція, працює лише з аргументом).
59
-
60
- ### `check(cwd?)`
61
-
62
- **Сигнатура:** `async function check(cwd?: string): Promise<number>`
63
-
64
- **Параметри:**
65
-
66
- - `cwd` (`string`, опційний) — абсолютний шлях до кореня репозиторію. За замовчуванням — `process.cwd()`.
67
-
68
- **Повертає:** `Promise<number>` — exit-код перевірки:
69
-
70
- - `0` — порушень не знайдено (або прикладних файлів не знайдено взагалі);
71
- - `1` — знайдено хоча б один bare `secret` у позиції значення.
72
-
73
- **Алгоритм:**
74
-
75
- 1. Створює репортер через `createCheckReporter()` і деструктурує з нього методи `pass` і `fail`.
76
- 2. Ініціалізує масив `examples` для зберігання пар `{ abs, rel }` прикладних файлів.
77
- 3. Викликає `walkDir(cwd, callback)` — рекурсивний обхід дерева від `cwd`. У callback'у:
78
- - обчислює відносний шлях `rel` через `relative(cwd, abs)`;
79
- - нормалізує роздільники до `/` (заміна `sep` на `/`) — це важливо на Windows;
80
- - якщо `isExampleFile(rel)` повертає `true`, додає об'єкт у `examples`.
81
- 4. Сортує `examples` за `rel` у лексикографічному порядку (`localeCompare`) — детермінує вихід.
82
- 5. Якщо `examples.length === 0`, репортує `pass('прикладних файлів не знайдено — placeholder перевіряти нема де')` і повертає exit-код репортера.
83
- 6. Інакше для кожного файлу:
84
- - читає вміст через `readFile(abs, 'utf8')`;
85
- - при будь-якій помилці читання (`try/catch` без re-throw) файл мовчки пропускається — `continue`;
86
- - розбиває вміст на рядки за `\n`;
87
- - для кожного рядка обрізає завершальний `\r` (CRLF-нормалізація);
88
- - тестує рядок проти `VALUE_SECRET_RE`; якщо матч є:
89
- - інкрементує лічильник `violations`;
90
- - викликає `fail` з повідомленням формату `${rel}:${i + 1}: \`${line.trim()}\` — заміни placeholder \`secret\` на \`sample-secret\` (security.mdc)` (нумерація рядків — 1-based).
91
- 7. Якщо після обходу `violations === 0`, репортує `pass('прикладні файли (${examples.length}) не містять bare \`secret\`')`.
92
- 8. Повертає `reporter.getExitCode()`.
93
-
94
- **Side effects:**
95
-
96
- - Читання файлової системи: рекурсивний `walkDir` і `readFile` для кожного прикладного файлу.
97
- - Виклики `pass`/`fail` репортера, який пише повідомлення у stdout/stderr (поведінка інкапсульована в `createCheckReporter`).
98
-
99
- **Обробка помилок:** помилки `readFile` ловляться і ігноруються (continue). Це дозволяє пропускати файли без прав читання чи з тимчасовими IO-проблемами без падіння всієї перевірки.
100
-
101
- ## Залежності
102
-
103
- ### Стандартна бібліотека Node.js
104
-
105
- | Імпорт | Шлях | Призначення |
106
- | ---------- | ------------------ | ------------------------------------------------------------------ |
107
- | `readFile` | `node:fs/promises` | Асинхронне читання файлу як UTF-8 рядка |
108
- | `relative` | `node:path` | Обчислення відносного шляху від `cwd` до абсолютного шляху |
109
- | `sep` | `node:path` | Платформозалежний роздільник шляхів (`/` на POSIX, `\` на Windows) |
110
-
111
- ### Внутрішні модулі проєкту
112
-
113
- | Імпорт | Шлях | Призначення |
114
- | --------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------- |
115
- | `createCheckReporter` | `../../../scripts/lib/check-reporter.mjs` | Створює об'єкт-репортер з методами `pass`, `fail`, `getExitCode` для уніфікованого виводу check-функцій |
116
- | `walkDir` | `../../../scripts/utils/walkDir.mjs` | Рекурсивний обхід директорії з застосуванням callback'а до кожного файлу |
117
-
118
- ### Регулярні вирази
119
-
120
- Усі RegExp мають флаги `u` (Unicode) і, де потрібно, `i` (case-insensitive):
121
-
122
- - `EXAMPLE_SUFFIX_RE = /\.(?:example|sample|template|dist)$/iu` — суфікс basename'а.
123
- - `EXAMPLE_INFIX_RE = /\.(?:example|sample|template)\./iu` — infix у basename'і (без `dist`, бо `dist` доречно лише як кінцевий суфікс).
124
- - `FIXTURE_DIR_RE = /(?:^|\/)(?:__fixtures__|fixtures?)(?:\/|$)/u` — сегмент шляху з фікстурами (без флага `i`, бо назви каталогів зазвичай у нижньому регістрі).
125
- - `VALUE_SECRET_RE = /[:=]>?\s*(['"]?)secret\1[\s,;}\])]*(?:(?:#|\/\/).*)?$/iu`:
126
- - `[:=]>?` — `=`, `:` або `=>`;
127
- - `\s*` — опційні пробіли;
128
- - `(['"]?)secret\1` — слово `secret` з опційними **парними** лапками (`'`, `"` або без);
129
- - `[\s,;}\])]*` — опційний хвіст (пробіли, кома, крапка з комою, закриваючі дужки);
130
- - `(?:(?:#|\/\/).*)?$` — опційний коментар (`#` для shell/YAML/TOML, `//` для JS/JSON5) до кінця рядка;
131
- - `$` гарантує, що `secret` — увесь токен значення (`secret-key`, `secretValue` не матчаться);
132
- - `[:=]` як префікс відсікає імена ключів (`client_secret`).
133
-
134
- ## Потік виконання / Використання
135
-
136
- ### Типовий сценарій запуску
137
-
138
- Модуль є точкою FS-частини правила `security/sample_secret`. Викликається оркестратором правил (зазвичай через CLI або CI), який:
139
-
140
- 1. Імпортує функцію `check` з `npm/rules/security/js/sample_secret.mjs`.
141
- 2. Викликає `await check(repoRoot)`, де `repoRoot` — абсолютний шлях до кореня монорепо.
142
- 3. Передає отриманий exit-код у власний агрегатор результатів.
143
-
144
- Приклад прямого виклику з CLI-обгортки:
145
-
146
- ```js
147
- import { check } from './sample_secret.mjs'
148
-
149
- const code = await check(process.cwd())
150
- process.exit(code)
151
- ```
152
-
153
- ### Послідовність дій усередині `check`
154
-
155
- ```
156
- walkDir(cwd) ──► фільтр isExampleFile ──► examples[] (відсортовано)
157
-
158
-
159
- для кожного файлу:
160
- readFile ──► split('\n') ──► для кожного рядка:
161
- ├─ обрізати \r
162
- ├─ VALUE_SECRET_RE.test(line)?
163
- │ ├─ ні → пропустити
164
- │ └─ так → fail(rel:line: ...); violations++
165
-
166
- violations === 0 ? pass(...) : (вже були fail)
167
-
168
- return reporter.getExitCode()
169
- ```
170
-
171
- ### Інтеграція з системою правил
172
-
173
- - Файл лежить у `npm/rules/security/js/`, що є FS-частиною модульного правила `security` (концерн `sample_secret`).
174
- - Поряд може існувати Rego/conftest-частина для структурованих перевірок; цей файл відповідає лише за неструктуроване сканування тексту.
175
- - Репортер `createCheckReporter` повертає exit-код, який інтегрується з загальним пайплайном лінтерів/перевірок проєкту.
12
+ Перевірка вмісту файлів на наявність визначених секретних даних. Файл перевіряє вміст файлів на відповідність шаблону.
176
13
 
177
- ### Поведінкові гарантії
14
+ ## Поведінка
178
15
 
179
- - **Детермінізм:** сортування `examples` за `rel.localeCompare` гарантує однаковий порядок повідомлень `fail` на різних запусках.
180
- - **Кросплатформність:** нормалізація `sep → '/'` забезпечує єдиний формат шляхів у логах і регекспах незалежно від ОС.
181
- - **Стійкість:** помилки `readFile` ловляться недоступний файл не валить перевірку.
182
- - **Точність:** прив'язки `[:=]` зліва і `$` справа у `VALUE_SECRET_RE` мінімізують false positives — імена ключів, складені значення (`secret-key`) і слово `secret` у середині рядка не матчаться.
16
+ 1. Початок перевірки.
17
+ 2. Пошук прикладних файлів.
18
+ 3. Сортування знайдених прикладних файлів за алфавітним порядком.
19
+ 4. Ітерація по прикладних файлах.
20
+ 5. Зчитування вмісту кожного файлу.
21
+ 6. Ітерація по рядках у файлі.
22
+ 7. Перевірка кожного рядка на наявність bare secret.
23
+ 8. Реєстрація порушення, якщо рядок відповідає шаблону.
24
+ 9. Завершення перевірки.
25
+ 10. Завершення перевірки з результатом.
183
26
 
184
- ### Що НЕ робить цей модуль
27
+ ## Гарантії поведінки
185
28
 
186
- - Не сканує не-прикладні файли (звичайний код, документація поза `fixtures/`).
187
- - Не перевіряє імена ключів (`client_secret`, `JWT_SECRET` дозволені).
188
- - Не автоматично замінює `secret` на `sample-secret` — лише репортує; виправлення робить розробник вручну.
189
- - Не парсить структуровані формати (YAML/JSON/TOML) — це робота Rego-частини правила, якщо вона існує.
190
- - Не виконує реальну детекцію секретів — це робота TruffleHog; модуль лише гарантує сумісність placeholder'ів із вшитим whitelist'ом TruffleHog.
29
+ - Read-only: файл не виконує операцій запису у файлову систему.
30
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
31
+ - Не звертається до мережі.
@@ -1,137 +1,28 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/security/js/trufflehog.mjs
4
+ crc: 83f277a6
5
+ score: 95
6
+ ---
7
+
1
8
  # trufflehog.mjs
2
9
 
3
10
  ## Огляд
4
11
 
5
- Модуль `trufflehog.mjs` — це FS-частина (файлово-системна перевірка) правила `security` з родини cursor-rules монорепозиторію. Його єдина відповідальність — перевірити, що в корені перевіреного репозиторію присутні два артефакти, без яких правило `security.mdc` вважається порушеним:
6
-
7
- 1. файл `package.json` у корені — самим фактом існування (структуру цього файлу валідує окрема policy `security.package_json` через Rego/OPA, тут вона навмисно не дублюється);
8
- 2. файл `.trufflehog-exclude` у корені, який містить канонічний набір patterns. Оскільки `.trufflehog-exclude` — це plain-text формат (а не JSON/YAML), порівняння виконується методом «text-subset»: усі канонічні рядки зі snippet-шаблону мають бути присутні в репозитарному файлі, але репозиторій може мати додаткові локальні рядки.
9
-
10
- Модуль експортує єдину async-функцію `check`, яка повертає exit-код для подальшого використання CLI-обгорткою (наприклад, скриптом-агрегатором перевірок або CI-сценарієм). Усі повідомлення про результат проходять через спільний reporter, тож формат виводу й коди виходу узгоджені з іншими `check-*` модулями цього репозиторію.
11
-
12
- Файл вмонтований у конвенцію `npm/rules/<rule>/js/`: він навмисно не виконує мережевих або системних операцій, не пише в файли, не запускає підпроцеси — це чиста read-only перевірка артефактів у переданому або поточному cwd.
13
-
14
- ## Експорти / API
15
-
16
- Модуль експортує лише one named export:
17
-
18
- | Експорт | Тип | Призначення |
19
- | ------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
20
- | `check` | `async function (cwd?: string) => Promise<number>` | Запустити перевірки FS-частини правила `security` для заданого кореня репозиторію і повернути числовий exit-код. |
21
-
22
- Default export відсутній. Жодних інших символів (констант, класів, утиліт) модуль назовні не передає; внутрішні константи `HERE` та `SNIPPET_PATH` залишаються приватними для модуля.
23
-
24
- ## Функції
25
-
26
- ### `check(cwd?)`
27
-
28
- Головна (і єдина) експортована функція модуля.
29
-
30
- Сигнатура:
31
-
32
- ```
33
- async function check(cwd: string = process.cwd()): Promise<number>
34
- ```
35
-
36
- Параметри:
37
-
38
- | Ім'я | Тип | Default | Опис |
39
- | ----- | -------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
40
- | `cwd` | `string` | `process.cwd()` | Абсолютний (або відносний до процесу) шлях до кореня репозиторію, який треба перевірити. Усі шляхи до `package.json` і `.trufflehog-exclude` будують через `join(cwd, ...)`. Якщо параметр не передано — використовується поточний робочий каталог процесу Node.js. |
41
-
42
- Повертає: `Promise<number>` — exit-код, який повертає reporter (`reporter.getExitCode()`). Конвенція reporter-а: `0` — усі перевірки `pass`, ненульове значення — є хоча б одна `fail`. Конкретне ненульове значення (1, 2 тощо) визначається реалізацією `createCheckReporter` у `scripts/lib/check-reporter.mjs` і модулем `trufflehog.mjs` не нав'язується.
43
-
44
- Покрокова поведінка:
45
-
46
- 1. Створює локальний reporter через `createCheckReporter()` і деструктурує з нього методи `pass` та `fail` для читабельності викликів.
47
- 2. Перевіряє наявність `package.json` у корені:
48
- - якщо файлу немає — викликає `fail('package.json не знайдено в корені — додай (security.mdc)')` і **одразу** повертає `reporter.getExitCode()`, не виконуючи решту перевірок (це early-exit, оскільки без `package.json` решта канонів безпеки втрачає сенс);
49
- - якщо файл є — викликає `pass('package.json є (структуру перевіряє Rego)')` і йде далі.
50
- 3. Перевіряє наявність `.trufflehog-exclude` у корені:
51
- - якщо файлу немає — викликає `fail('.trufflehog-exclude не знайдено в корені — додай за каноном (security.mdc)')` і повертає exit-код (теж early-exit);
52
- - якщо файл є — переходить до text-subset порівняння.
53
- 4. Читає вміст обох файлів — фактичного `.trufflehog-exclude` із cwd та snippet-шаблону `templates/trufflehog/.trufflehog-exclude.snippet.txt` поряд із модулем — в `utf8`.
54
- 5. Викликає `checkTextSubset(actual, template, { targetPath: '.trufflehog-exclude', source: 'security.mdc' })`. Утиліта повертає масив рядків-повідомлень про помилки: порожній масив означає, що всі канонічні patterns з snippet-у наявні у фактичному файлі.
55
- 6. Для кожного повідомлення з `errors` викликає `fail(msg)`. Якщо `errors` порожній — викликає `pass('.trufflehog-exclude містить канонічні patterns')`.
56
- 7. Повертає `reporter.getExitCode()`.
57
-
58
- Side effects:
59
-
60
- - Читання файлової системи: синхронний `existsSync` (двічі) та асинхронний `readFile` (двічі);
61
- - Запис у reporter (внутрішній акумулятор стану `pass`/`fail`), який, залежно від реалізації, може писати в `stdout`/`stderr`;
62
- - Жодних мутацій FS, жодних мережевих викликів, жодних env-залежностей крім стандартного `process.cwd()` як default-значення параметра.
63
-
64
- Поведінкові інваріанти:
65
-
66
- - Функція **не** кидає винятки в нормальному сценарії «файла нема» — це штатний `fail`. Винятки можливі лише з нижчих рівнів: наприклад, якщо `readFile` не може прочитати існуючий файл через права доступу, або якщо `SNIPPET_PATH` не існує в дистрибутиві модуля (це вже баг дистрибутива, а не вхідних даних).
67
- - Порядок перевірок фіксований: `package.json` → `.trufflehog-exclude` (наявність) → `.trufflehog-exclude` (text-subset). При фейлі на ранньому кроці наступні **не** виконуються.
68
- - Перевірка text-subset не вимагає точної рівності файлів: snippet — це мінімум, репозиторій може містити додаткові рядки понад нього.
69
-
70
- ## Залежності
71
-
72
- Built-in модулі Node.js:
73
-
74
- - `node:fs` — використовується іменований імпорт `existsSync` для перевірки наявності `package.json` та `.trufflehog-exclude` без читання їхнього вмісту;
75
- - `node:fs/promises` — іменований імпорт `readFile` для асинхронного читання текстового вмісту обох файлів у кодуванні `utf8`;
76
- - `node:path` — `dirname` для отримання директорії поточного модуля з його URL і `join` для побудови шляхів до `package.json`, `.trufflehog-exclude` та snippet-шаблону;
77
- - `node:url` — `fileURLToPath` для перетворення `import.meta.url` у звичайний шлях файлової системи (стандартний ESM-патерн).
78
-
79
- Внутрішні модулі репозиторію:
80
-
81
- - `../../../scripts/lib/check-reporter.mjs` — фабрика reporter-а `createCheckReporter`. Reporter інкапсулює стан перевірок: акумулює `pass`/`fail`-повідомлення та віддає кінцевий exit-код через `getExitCode()`. Уся семантика виводу (де і як друкується, як кодуються рівні) лежить там.
82
- - `../../../scripts/lib/template.mjs` — утиліта `checkTextSubset(actual, template, opts)`. Перевіряє, що `template` є підмножиною `actual` (у текстовому сенсі — рядки/блоки шаблону мають зустрічатися у фактичному файлі). Опції `targetPath` та `source` використовуються для форматування повідомлень про помилки (щоб користувач бачив, який саме файл і яке правило порушено).
83
-
84
- Файлові артефакти, які модуль читає в runtime:
85
-
86
- - `<cwd>/package.json` — фактичний package.json репозиторію, що перевіряється (лише наявність);
87
- - `<cwd>/.trufflehog-exclude` — фактичний exclude-файл (наявність + вміст);
88
- - `<HERE>/templates/trufflehog/.trufflehog-exclude.snippet.txt` — канонічний snippet-шаблон, що поставляється разом із модулем. `HERE` = `dirname(fileURLToPath(import.meta.url))`, тобто директорія самого `trufflehog.mjs`. Цей файл — джерело істини для text-subset порівняння.
89
-
90
- Зовнішніх npm-залежностей модуль не має.
91
-
92
- ## Потік виконання / Використання
93
-
94
- Типовий сценарій використання — виклик з вищерівневого скрипта-агрегатора перевірок правила `security`, який послідовно прогоняє FS-частину (`trufflehog.mjs`) і policy-частину (Rego/OPA для структури `package.json`). У цій ролі модуль працює як CLI-сумісна функція:
95
-
96
- ```
97
- import { check } from './trufflehog.mjs'
98
-
99
- const code = await check() // використає process.cwd()
100
- process.exit(code)
101
- ```
102
-
103
- Або з явним коренем:
104
-
105
- ```
106
- import { check } from './trufflehog.mjs'
107
-
108
- const code = await check('/path/to/repo')
109
- process.exit(code)
110
- ```
111
-
112
- Послідовність кроків у runtime (happy path):
113
-
114
- 1. Викликач передає `cwd` (або не передає — береться `process.cwd()`).
115
- 2. Створюється reporter — порожній акумулятор стану.
116
- 3. `existsSync(join(cwd, 'package.json'))` → `true` → `pass(...)`.
117
- 4. `existsSync(join(cwd, '.trufflehog-exclude'))` → `true` → перехід до читання.
118
- 5. Паралельно (через `await` послідовно, але без перехресної залежності) читаються `actual` та `template`.
119
- 6. `checkTextSubset(actual, template, opts)` → `[]` (порожній масив помилок).
120
- 7. Цикл `for (const msg of errors)` нічого не виконує.
121
- 8. Викликається `pass('.trufflehog-exclude містить канонічні patterns')`.
122
- 9. Повертається `reporter.getExitCode()` — у happy-сценарії це `0`.
12
+ Огляд
123
13
 
124
- Гілки відмови (sad paths):
14
+ Файл виконує перевірку конфігураційних файлів та шаблонів для забезпечення безпеки. Перевіряється наявність `package.json` та `.trufflehog-exclude`. Дані з цих файлів використовуються для перевірки відповідності шаблону файлу `security.mdc`.
125
15
 
126
- - Немає `package.json` у `cwd` → один `fail` про відсутність → exit-код ≠ 0, перевірка `.trufflehog-exclude` **не** виконується.
127
- - Є `package.json`, але немає `.trufflehog-exclude` → `pass` для першого та `fail` для другого → exit-код ≠ 0.
128
- - Обидва файли є, але `.trufflehog-exclude` не містить деяких канонічних patterns → стільки `fail`, скільки повідомлень повернула `checkTextSubset` → exit-код ≠ 0. Жодного `pass` про канонічність у цьому випадку не друкується.
16
+ ## Поведінка
129
17
 
130
- Контекст у проєкті:
18
+ 1. Перевірка наявності package.json в корені репозиторію.
19
+ 2. Перевірка наявності .trufflehog-exclude в корені репозиторію.
20
+ 3. Зчитування файлу .trufflehog-exclude.snippet.txt.
21
+ 4. Зчитування шаблону з .trufflehog-exclude.snippet.txt.
22
+ 5. Перевірка відповідності вмісту .trufflehog-exclude шаблону з security.mdc.
23
+ 6. Повернення коду виходу перевірки.
131
24
 
132
- - Модуль належить до родини `npm/rules/<rule>/js/` і реалізує JS-half правила `security`. Поряд із ним очікується тека `templates/trufflehog/` з файлом `.trufflehog-exclude.snippet.txt` — без неї `readFile` для snippet кине помилку.
133
- - Текстовий формат повідомлень `pass`/`fail` ідентичний іншим перевіркам репозиторію (через спільний `check-reporter`), що дозволяє агрегатору одноманітно показувати результати.
134
- - Розділення «FS-частина перевіряє наявність, Rego — структуру» — навмисний design choice: він зафіксований у `security.mdc` і повторений у doc-string модуля. У `trufflehog.mjs` **не** можна додавати парсинг JSON `package.json` чи логіку валідації полів — це порушує контракт із Rego-policy.
135
- - text-subset (а не точна рівність) обраний саме тому, що `.trufflehog-exclude` — plain text без структури: канон постачає мінімум обов'язкових patterns, а команди можуть розширювати свій exclude-файл локальними правилами без порушення security-канону.
25
+ ## Гарантії поведінки
136
26
 
137
- Rebuild test: за цією документацією можна відновити поведінку модуля від інтерфейсу до side-effects — сигнатуру `check`, default-значення `cwd`, послідовність двох FS-перевірок з early-exit, виклик `checkTextSubset` з опціями `targetPath`/`source`, формування exit-коду через `reporter.getExitCode()`, перелік повідомлень `fail`/`pass` і відсутність зовнішніх npm-залежностей.
27
+ - Read-only: файл не виконує операцій запису у файлову систему.
28
+ - Не звертається до мережі.