@nitra/cursor 12.8.5 → 12.8.7

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 (202) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/bin/n-cursor.js +5 -5
  3. package/package.json +1 -1
  4. package/rules/abie/js/http_route_base.mdc +25 -0
  5. package/rules/abie/js/ua_http_route.mdc +1 -1
  6. package/rules/abie/main.mdc +12 -0
  7. package/rules/adr/js/hooks.mdc +32 -0
  8. package/rules/adr/js/madr_format.mdc +96 -0
  9. package/rules/adr/js/settings_policy.mdc +34 -0
  10. package/rules/adr/main.mdc +13 -95
  11. package/rules/bun/js/bunfig.mdc +12 -0
  12. package/rules/bun/js/layout.mdc +60 -0
  13. package/rules/bun/js/lint.mdc +9 -0
  14. package/rules/bun/js/package_json.mdc +19 -0
  15. package/rules/bun/main.mdc +9 -61
  16. package/rules/capacitor/js/ios_spm.mdc +69 -0
  17. package/rules/capacitor/js/version.mdc +29 -0
  18. package/rules/capacitor/main.mdc +8 -22
  19. package/rules/changelog/js/agent-workflow.mdc +15 -0
  20. package/rules/changelog/js/changelog-format.mdc +33 -0
  21. package/rules/changelog/js/comparison-models.mdc +40 -0
  22. package/rules/changelog/main.mdc +4 -98
  23. package/rules/ci4/js/marksman_config.mdc +31 -0
  24. package/rules/ci4/js/vscode_extensions.mdc +33 -0
  25. package/rules/ci4/main.mdc +14 -14
  26. package/rules/docker/js/compile.mdc +44 -0
  27. package/rules/docker/js/hadolint.mdc +50 -0
  28. package/rules/docker/js/mirror.mdc +13 -0
  29. package/rules/docker/js/multistage.mdc +13 -0
  30. package/rules/docker/js/native-addon.mdc +43 -0
  31. package/rules/docker/js/nginx-tag.mdc +7 -0
  32. package/rules/docker/js/nginx-user.mdc +37 -0
  33. package/rules/docker/js/non-root.mdc +39 -0
  34. package/rules/docker/main.mdc +15 -196
  35. package/rules/ga/js/lint_toolchain.mdc +15 -0
  36. package/rules/ga/js/required_workflows.mdc +35 -0
  37. package/rules/ga/js/vscode.mdc +17 -0
  38. package/rules/ga/js/workflow_common.mdc +108 -0
  39. package/rules/ga/js/workflows.mdc +32 -0
  40. package/rules/ga/js/zizmor.mdc +7 -0
  41. package/rules/ga/main.mdc +17 -125
  42. package/rules/graphql/js/tooling.mdc +13 -0
  43. package/rules/graphql/js/vscode_extensions.mdc +13 -0
  44. package/rules/graphql/main.mdc +3 -22
  45. package/rules/hasura/js/internal_urls.mdc +27 -0
  46. package/rules/hasura/js/migrations.mdc +13 -0
  47. package/rules/hasura/js/svc_hl.mdc +17 -0
  48. package/rules/hasura/main.mdc +8 -30
  49. package/rules/image-avif/js/avif_generation.mdc +26 -0
  50. package/rules/image-avif/js/package_json_optout.mdc +21 -0
  51. package/rules/image-avif/main.mdc +7 -34
  52. package/rules/image-compress/js/package_json.mdc +7 -0
  53. package/rules/image-compress/js/package_setup.mdc +13 -0
  54. package/rules/image-compress/main.mdc +4 -12
  55. package/rules/js/docs/index.md +3 -3
  56. package/rules/js/js/dep-policy.mdc +17 -0
  57. package/rules/js/js/eslint-config.mdc +28 -0
  58. package/rules/js/js/extensions.mdc +8 -0
  59. package/rules/js/js/file-extensions.mdc +12 -0
  60. package/rules/js/js/for-in.mdc +26 -0
  61. package/rules/js/js/jscpd.mdc +42 -0
  62. package/rules/js/js/knip.mdc +15 -0
  63. package/rules/js/js/lint-js-workflow.mdc +58 -0
  64. package/rules/js/js/oxlintrc.mdc +20 -0
  65. package/rules/js/js/package-json.mdc +31 -0
  66. package/rules/js/js/tests.mdc +9 -0
  67. package/rules/js/js/utils-lib-structure.mdc +15 -0
  68. package/rules/js/main.mdc +21 -214
  69. package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
  70. package/rules/js-bun-db/js/connection.mdc +42 -0
  71. package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
  72. package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
  73. package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
  74. package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
  75. package/rules/js-bun-db/js/query-safety.mdc +117 -0
  76. package/rules/js-bun-db/js/sql-array.mdc +88 -0
  77. package/rules/js-bun-db/js/unsafe.mdc +65 -0
  78. package/rules/js-bun-db/main.mdc +15 -605
  79. package/rules/js-bun-redis/js/imports.mdc +47 -0
  80. package/rules/js-bun-redis/js/package_json.mdc +44 -0
  81. package/rules/js-bun-redis/main.mdc +3 -11
  82. package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
  83. package/rules/js-mssql/js/mssql-pool.mdc +56 -0
  84. package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
  85. package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
  86. package/rules/js-mssql/js/mssql-version.mdc +7 -0
  87. package/rules/js-mssql/main.mdc +10 -198
  88. package/rules/js-run/js/check-env.mdc +35 -0
  89. package/rules/js-run/js/conn-aliases.mdc +109 -0
  90. package/rules/js-run/js/jsconfig.mdc +20 -0
  91. package/rules/js-run/js/otel-configmap.mdc +6 -0
  92. package/rules/js-run/js/pino.mdc +6 -0
  93. package/rules/js-run/js/project-structure.mdc +11 -0
  94. package/rules/js-run/js/runtime.mdc +14 -0
  95. package/rules/js-run/js/scope.mdc +11 -0
  96. package/rules/js-run/js/settimeout.mdc +11 -0
  97. package/rules/js-run/js/temporal.mdc +5 -0
  98. package/rules/js-run/main.mdc +16 -218
  99. package/rules/k8s/js/configmap.mdc +41 -0
  100. package/rules/k8s/js/deployment_resources.mdc +49 -0
  101. package/rules/k8s/js/hasura_httproute.mdc +91 -0
  102. package/rules/k8s/js/hpa_apiversion.mdc +27 -0
  103. package/rules/k8s/js/ingress_gateway.mdc +16 -0
  104. package/rules/k8s/js/kustomize_structure.mdc +144 -0
  105. package/rules/k8s/js/lint_k8s.mdc +72 -0
  106. package/rules/k8s/js/multidoc_yaml.mdc +5 -0
  107. package/rules/k8s/js/network_policy.mdc +136 -0
  108. package/rules/k8s/js/schema_modeline.mdc +57 -0
  109. package/rules/k8s/js/service.mdc +44 -0
  110. package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
  111. package/rules/k8s/main.mdc +30 -843
  112. package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
  113. package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
  114. package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
  115. package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
  116. package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
  117. package/rules/nginx-default-tpl/main.mdc +6 -112
  118. package/rules/npm-module/js/docs/index.md +5 -5
  119. package/rules/npm-module/js/docs/rule_meta.md +6 -6
  120. package/rules/npm-module/js/docs/skill_meta.md +8 -8
  121. package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
  122. package/rules/npm-module/js/package_structure.mdc +62 -0
  123. package/rules/npm-module/js/rule_meta.mdc +11 -0
  124. package/rules/npm-module/js/skill_meta.mdc +11 -0
  125. package/rules/npm-module/main.mdc +10 -55
  126. package/rules/php/js/lint_php_yml.mdc +12 -0
  127. package/rules/php/js/tooling.mdc +66 -0
  128. package/rules/php/main.mdc +7 -66
  129. package/rules/python/js/lint_python_yml.mdc +23 -0
  130. package/rules/python/js/pyproject_toml.mdc +32 -0
  131. package/rules/python/js/tooling.mdc +23 -0
  132. package/rules/python/main.mdc +9 -33
  133. package/rules/rego/js/rego-lint.mdc +31 -0
  134. package/rules/rego/js/vscode_extensions.mdc +11 -0
  135. package/rules/rego/js/vscode_settings.mdc +13 -0
  136. package/rules/rego/main.mdc +8 -24
  137. package/rules/rust/js/coverage.mdc +28 -0
  138. package/rules/rust/js/lint.mdc +22 -0
  139. package/rules/rust/js/tauri_composition.mdc +8 -0
  140. package/rules/rust/js/vscode_extensions.mdc +12 -0
  141. package/rules/rust/main.mdc +8 -38
  142. package/rules/security/js/rego_policies.mdc +15 -0
  143. package/rules/security/js/sample_secret.mdc +19 -0
  144. package/rules/security/js/trufflehog.mdc +21 -0
  145. package/rules/security/main.mdc +7 -35
  146. package/rules/style/js/admin-table.mdc +88 -0
  147. package/rules/style/js/colors.mdc +21 -0
  148. package/rules/style/js/gap.mdc +22 -0
  149. package/rules/style/js/quasar-fixes.mdc +32 -0
  150. package/rules/style/js/quasar.mdc +7 -0
  151. package/rules/style/js/tooling.mdc +85 -0
  152. package/rules/style/main.mdc +13 -253
  153. package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
  154. package/rules/tauri/js/tool_surface.mdc +21 -0
  155. package/rules/tauri/js/tooling.mdc +25 -0
  156. package/rules/tauri/main.mdc +8 -78
  157. package/rules/test/js/cargo_mutants_config.mdc +18 -0
  158. package/rules/test/js/docs/index.md +7 -7
  159. package/rules/test/js/location.mdc +52 -0
  160. package/rules/test/js/no-console-store-restore.mdc +11 -0
  161. package/rules/test/js/no-process-chdir.mdc +15 -0
  162. package/rules/test/js/no-relative-fs-path.mdc +22 -0
  163. package/rules/test/js/sandbox-aware-test.mdc +28 -0
  164. package/rules/test/js/stryker_config.mdc +26 -0
  165. package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
  166. package/rules/test/main.mdc +18 -184
  167. package/rules/text/js/ci-lint-text.mdc +15 -0
  168. package/rules/text/js/cspell.mdc +81 -0
  169. package/rules/text/js/dotenv-linter.mdc +16 -0
  170. package/rules/text/js/forbidden-prettier.mdc +13 -0
  171. package/rules/text/js/markdownlint.mdc +25 -0
  172. package/rules/text/js/oxfmt.mdc +35 -0
  173. package/rules/text/js/package-json.mdc +26 -0
  174. package/rules/text/js/shellcheck.mdc +18 -0
  175. package/rules/text/js/v8r.mdc +23 -0
  176. package/rules/text/js/vscode.mdc +86 -0
  177. package/rules/text/main.mdc +20 -237
  178. package/rules/vue/js/composition-api.mdc +82 -0
  179. package/rules/vue/js/nheader-layout.mdc +171 -0
  180. package/rules/vue/js/node-imports.mdc +25 -0
  181. package/rules/vue/js/quasar-ui.mdc +32 -0
  182. package/rules/vue/js/structure.mdc +101 -0
  183. package/rules/vue/js/testing.mdc +32 -0
  184. package/rules/vue/js/tfm-translations.mdc +26 -0
  185. package/rules/vue/js/vite-config.mdc +126 -0
  186. package/rules/vue/js/vite-env.mdc +55 -0
  187. package/rules/vue/js/vue-imports.mdc +25 -0
  188. package/rules/vue/main.mdc +16 -640
  189. package/scripts/auto-rules.mjs +6 -6
  190. package/scripts/auto-skills.mjs +3 -3
  191. package/scripts/docs/auto-rules.md +17 -31
  192. package/scripts/docs/auto-skills.md +18 -163
  193. package/scripts/docs/index.md +16 -16
  194. package/scripts/lib/docs/index.md +36 -36
  195. package/scripts/lib/docs/mirror-parity.md +7 -7
  196. package/scripts/lib/docs/rule-meta.md +12 -12
  197. package/scripts/lib/docs/skill-meta.md +9 -9
  198. package/scripts/lib/docs/worktree-notice.md +10 -8
  199. package/scripts/lib/rule-meta.mjs +6 -6
  200. package/scripts/lib/skill-meta.mjs +6 -6
  201. package/scripts/lib/worktree-notice.mjs +2 -2
  202. package/scripts/utils/docs/index.md +14 -14
@@ -0,0 +1,12 @@
1
+ ## CI: `.github/workflows/lint-php.yml`
2
+
3
+ Канон workflow — [lint-php.yml.snippet.yml](./policy/lint_php_yml/template/lint-php.yml.snippet.yml).
4
+
5
+ Файл запускається при push/PR до `dev`/`main` за змінами в `**/*.php`, `composer.json`, `composer.lock`, `phpstan.neon`, `phpstan.neon.dist`, `psalm.xml` або самого workflow.
6
+
7
+ Кроки job `php`:
8
+ 1. `actions/checkout@v6` (без persist-credentials)
9
+ 2. `./.github/actions/setup-bun-deps`
10
+ 3. `shivammathur/setup-php@v2` — PHP 8.5
11
+ 4. `composer install --no-interaction --no-progress --prefer-dist`
12
+ 5. `n-cursor lint php --read-only`
@@ -0,0 +1,66 @@
1
+ ## PHP-інструменти лінту
2
+
3
+ Весь код повинен відповідати PHP 8.5, перевірятися через PHPCompatibility і конвертуватися через Rector.
4
+
5
+ Код має бути добре задокументований через phpDoc:
6
+
7
+ ```php
8
+ /** @param array<int, string> $items */
9
+ function process($items) {
10
+ foreach ($items as $id => $name) {
11
+ // PHPStan знає, що $id — int, $name — string
12
+ }
13
+ }
14
+ ```
15
+
16
+ ### PHP_CodeSniffer (phpcs) і пакет `squizlabs/php_codesniffer`
17
+
18
+ Стиль, базові ризики, за потреби окремі стандарти. Для **SQL injection**, **XSS**, **небезпечні функції** — PHPCS + **php-security-audit** (стандарт `Security`).
19
+
20
+ ```bash
21
+ phpcs --standard=Security app/
22
+ ```
23
+
24
+ ### PHPStan
25
+
26
+ Статичний аналіз типів і смертельних слабких місць; **PHPStan Taint Analysis** (`phpstan/phpstan-taint-analysis`) — для потоку даних (taint) у стилі security-аналізу.
27
+
28
+ ```bash
29
+ vendor/bin/phpstan analyse
30
+ # після підключення розширення taint — у phpstan.neon/ neon.dist
31
+ ```
32
+
33
+ ### PHP-CS-Fixer
34
+
35
+ Форматтер/фіксер коду; у **lint** зазвичай перевірка без змін (`--dry-run`).
36
+
37
+ ```bash
38
+ vendor/bin/php-cs-fixer fix --dry-run --diff
39
+ ```
40
+
41
+ ### Psalm
42
+
43
+ Альтернативний/додатковий аналізатор; **Psalm Security Plugin** (`vimeo/psalm` + пакет на кшталт `psalm/plugin-security` залежно від вибраної збірки) — для security-орієнтованих правил.
44
+
45
+ ```bash
46
+ vendor/bin/psalm
47
+ ```
48
+
49
+ ### `composer audit`
50
+
51
+ Перевірка відомих вразливостей залежностей за даними **Packagist/security-advisories**.
52
+
53
+ ```bash
54
+ composer audit
55
+ ```
56
+
57
+ ## Запуск lint-php
58
+
59
+ `composer`-інструменти не мають єдиного CLI, який сам обходить репозиторій, тому php-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint php`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
60
+
61
+ Скрипт `run-php.mjs`:
62
+
63
+ - якщо `composer.json` у корені відсутній — вихід 0 (перевірка пропущена);
64
+ - якщо `composer.json` є, але `composer` не знайдено в PATH — це помилка;
65
+ - `composer audit` — обовʼязковий;
66
+ - `vendor/bin/php-cs-fixer`, `vendor/bin/phpcs`, `vendor/bin/phpstan`, `vendor/bin/psalm` — запускаються лише якщо встановлені (інакше крок пропускається з повідомленням).
@@ -5,73 +5,14 @@ globs: "**/*.php"
5
5
  alwaysApply: false
6
6
  ---
7
7
 
8
- Весь код повинен відповідати PHP 8.5, перевіряти за допомогою PHPCompatibility, конвертувати за допомогою Rector.
8
+ Весь код повинен відповідати PHP 8.5 (PHPCompatibility + Rector). Лінт запускається через `n-cursor lint php`.
9
9
 
10
- Код повинен бути добре документований за допомогою phpDoc-ів:
10
+ [php-tooling](./js/tooling.mdc)
11
11
 
12
- ```php
13
- /** @param array<int, string> $items */
14
- function process($items) {
15
- foreach ($items as $id => $name) {
16
- // PHPStan знає, що $id — int, $name — string
17
- }
18
- }
19
- ```
12
+ [php-lint_php_yml](./js/lint_php_yml.mdc)
20
13
 
21
- ## Потрібно додати до lint-php
14
+ ## Швидкий gate через conftest
22
15
 
23
- ### PHP_CodeSniffer (phpcs) і пакет `squizlabs/php_codesniffer`
24
-
25
- Стиль, базові ризики, за потреби окремі стандарти. Для **SQL injection**, **XSS**, **небезпечні функції** PHPCS + **php-security-audit** (стандарт `Security`).
26
-
27
- ```bash
28
- phpcs --standard=Security app/
29
- ```
30
-
31
- ### PHPStan
32
-
33
- Статичний аналіз типів і смертельних слабких місць; **PHPStan Taint Analysis** (`phpstan/phpstan-taint-analysis`) — для потоку даних (taint) у стилі security-аналізу.
34
-
35
- ```bash
36
- vendor/bin/phpstan analyse
37
- # після підключення розширення taint — у phpstan.neon/ neon.dist
38
- ```
39
-
40
- ### PHP-CS-Fixer
41
-
42
- Форматтер/фіксер коду; у **lint** зазвичай перевірка без змін (`--dry-run`).
43
-
44
- ```bash
45
- vendor/bin/php-cs-fixer fix --dry-run --diff
46
- ```
47
-
48
- ### Psalm
49
-
50
- Альтернативний/додатковий аналізатор; **Psalm Security Plugin** (`vimeo/psalm` + пакет на кшталт `psalm/plugin-security` залежно від вибраної збірки) — для security-орієнтованих правил.
51
-
52
- ```bash
53
- vendor/bin/psalm
54
- ```
55
-
56
- ### `composer audit`
57
-
58
- Перевірка відомих вразливостей залежностей за даними **Packagist/security-advisories**.
59
-
60
- ```bash
61
- composer audit
62
- ```
63
-
64
- ## lint-php
65
-
66
- `composer`-інструмененти не мають єдиного CLI, який сам обходить репозиторій, тому php-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint php`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
67
-
68
- Скрипт `run-php.mjs`:
69
-
70
- - якщо `composer.json` у корені відсутній — вихід 0 (перевірка пропущена);
71
- - якщо `composer.json` є, але `composer` не знайдено в PATH — це помилка;
72
- - `composer audit` — обовʼязковий;
73
- - `vendor/bin/php-cs-fixer`, `vendor/bin/phpcs`, `vendor/bin/phpstan`, `vendor/bin/psalm` — запускаються лише якщо встановлені (інакше крок пропускається з повідомленням).
74
-
75
- ## CI: `.github/workflows/lint-php.yml`
76
-
77
- - Канон: [lint-php.yml.snippet.yml](./policy/lint_php_yml/template/lint-php.yml.snippet.yml)
16
+ | Пакет | Що перевіряє |
17
+ |---|---|
18
+ | `php.lint_php_yml` | Структуру `.github/workflows/lint-php.yml`наявність канонічних `run:`-кроків |
@@ -0,0 +1,23 @@
1
+ ## CI: `.github/workflows/lint-python.yml`
2
+
3
+ Канонічний workflow: [lint-python.yml.snippet.yml](./policy/lint_python_yml/template/lint-python.yml.snippet.yml)
4
+
5
+ Без кроків `poetry install` / `snok/install-poetry` — лише `astral-sh/setup-uv@v8.0.0` + `uv sync --frozen`.
6
+
7
+ Обовʼязкові кроки:
8
+ - `actions/checkout@v6` з `persist-credentials: false`;
9
+ - `./.github/actions/setup-bun-deps` — встановлення JS-залежностей (для `n-cursor lint`);
10
+ - `astral-sh/setup-uv@v8.0.0` — встановлення uv;
11
+ - `uv sync --frozen` — встановлення Python-залежностей строго з lock-файлу;
12
+ - `n-cursor lint python --read-only` — запуск lint (без auto-fix у CI).
13
+
14
+ `uv` / `ruff` / `mypy` **не** додаються в кореневі `devDependencies` споживача — це окремий toolchain, що ставиться через `astral-sh/setup-uv` у CI або локально.
15
+
16
+ ## Rego: python.lint_python_yml
17
+
18
+ Polісі `policy/lint_python_yml/lint_python_yml.rego` — drift-safe перевірка через `--data template`:
19
+
20
+ - кожен `uses` з template має бути присутнім у workflow input;
21
+ - кожен `run` з template має бути substring серед run-кроків input.
22
+
23
+ Заборона Poetry-кроків (`snok/install-poetry`, `poetry install`) забезпечується відсутністю у каноні: правило вимагає uv-кроки, і жодних poetry-кроків у template немає.
@@ -0,0 +1,32 @@
1
+ ## pyproject.toml: PEP 621 і заборона Poetry
2
+
3
+ Метадані проєкту — у секції **`[project]`** (PEP 621), а **не** в `[tool.poetry]`.
4
+
5
+ Обовʼязкові поля:
6
+ - `[project].name` — назва пакета;
7
+ - `[project].version` — статична версія;
8
+ - `[project].requires-python` — мінімальна версія Python;
9
+ - `[project].dependencies` — залежності (навіть порожній список).
10
+
11
+ Lock-файл — **`uv.lock`** (коммітиться). `poetry.lock` / `poetry.toml` мають бути відсутні.
12
+
13
+ Залежності: `uv add <pkg>`; dev-залежності: `uv add --dev <pkg>`.
14
+
15
+ Канонічний цільовий вигляд `pyproject.toml`: [pyproject.toml.snippet.toml](./policy/pyproject_toml/template/pyproject.toml.snippet.toml)
16
+
17
+ Заборонені під-таблиці `[tool.*]` (Poetry): [pyproject.toml.deny.toml](./policy/pyproject_toml/template/pyproject.toml.deny.toml)
18
+
19
+ ## Міграція з Poetry на uv
20
+
21
+ 1. Прибери `[tool.poetry]` і `poetry.lock` / `poetry.toml`.
22
+ 2. Перенеси метадані в `[project]` (name, version, requires-python, dependencies) за PEP 621.
23
+ 3. Згенеруй lock: `uv lock` → `uv.lock`.
24
+ 4. Dev-залежності: `uv add --dev ruff mypy …`.
25
+
26
+ ## Rego: python.pyproject_toml
27
+
28
+ Polисі `policy/pyproject_toml/pyproject_toml.rego` — дві групи правил:
29
+
30
+ **1. Заборона Poetry** — перевіряє, чи є заборонені під-таблиці `[tool.*]` з `pyproject.toml.deny.toml` (drift-safe через `--data template`).
31
+
32
+ **2. PEP 621** — `[project].name` і `[project].version` мають бути непорожніми рядками.
@@ -0,0 +1,23 @@
1
+ ## Перевірка наявності uv-toolchain і відсутності Poetry
2
+
3
+ JS-перевірка (`js/tooling.mjs`) запускається, якщо в корені репо є `pyproject.toml`. Перевіряє:
4
+
5
+ - `uv.lock` — має існувати (зафіксувати командою `uv lock`);
6
+ - `poetry.lock` / `poetry.toml` — мають **бути відсутніми** (Poetry заборонено);
7
+ - `package.json` — має бути у корені (js-обгортка lint є частиною монорепо);
8
+ - `.github/workflows/lint-python.yml` — має існувати (структуру перевіряє Rego-полісі `python.lint_python_yml`).
9
+
10
+ Якщо `pyproject.toml` відсутній — перевірка пропускається з кодом 0 (проєкт не Python).
11
+
12
+ ## lint-python: JS-скрипт-обгортка
13
+
14
+ Інструменти uv-екосистеми не мають єдиного CLI-обходу репо, тому python-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint python`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
15
+
16
+ Скрипт `rules/python/lint/lint.mjs`:
17
+
18
+ - якщо `pyproject.toml` у корені відсутній — вихід 0 (перевірка пропущена);
19
+ - якщо `pyproject.toml` є, але `uv` не знайдено в PATH — це помилка;
20
+ - `uv lock --check` і `uv sync --frozen` — обовʼязкові;
21
+ - `uv run ruff check --fix .` + `uv run ruff format .` — auto-fix (мутують робоче дерево, як `markdownlint-cli2 --fix` у lint-text);
22
+ - `uv run mypy .` — статична перевірка типів;
23
+ - усі `ruff`/`mypy`-кроки запускаються лише якщо інструмент доступний у середовищі (інакше крок пропускається з повідомленням).
@@ -5,41 +5,17 @@ alwaysApply: false
5
5
  version: '1.0'
6
6
  ---
7
7
 
8
- Python-проєкти ведуться **виключно** на [uv](https://docs.astral.sh/uv/) — єдиний пакет-менеджер і резолвер. **Poetry заборонено.**
8
+ Python-проєкти ведуться **виключно** на [uv](https://docs.astral.sh/uv/) — єдиний пакет-менеджер і резолвер. **Poetry заборонено.** Середовище: `uv sync --frozen` (строго з `uv.lock`).
9
9
 
10
- - Метадані проєкту — у секції **`[project]`** (PEP 621), а **не** в `[tool.poetry]`.
11
- - Lock-файл — **`uv.lock`** (коммітиться). `poetry.lock` / `poetry.toml` мають бути відсутні.
12
- - Залежності: `uv add <pkg>`; dev-залежності: `uv add --dev <pkg>`.
13
- - Середовище: `uv sync --frozen` (строго з `uv.lock`).
10
+ [python-pyproject_toml](./js/pyproject_toml.mdc)
14
11
 
15
- `uv` / `ruff` / `mypy` **не** додаються в кореневі `devDependencies` споживача — це окремий toolchain і ставиться через `astral-sh/setup-uv` у CI або локально (як `composer` / `regal`).
12
+ [python-lint_python_yml](./js/lint_python_yml.mdc)
16
13
 
17
- ## Міграція з Poetry на uv
14
+ [python-tooling](./js/tooling.mdc)
18
15
 
19
- 1. Прибери `[tool.poetry]` і `poetry.lock` / `poetry.toml`.
20
- 2. Перенеси метадані в `[project]` (name, version, requires-python, dependencies) за PEP 621.
21
- 3. Згенеруй lock: `uv lock` → `uv.lock`.
22
- 4. Dev-залежності: `uv add --dev ruff mypy …`.
16
+ ## Швидкий gate через conftest (Rego)
23
17
 
24
- Канонічний цільовий вигляд `pyproject.toml`: [pyproject.toml.snippet.toml](./policy/pyproject_toml/template/pyproject.toml.snippet.toml)
25
-
26
- Заборонені під-таблиці `[tool.*]` (Poetry): [pyproject.toml.deny.toml](./policy/pyproject_toml/template/pyproject.toml.deny.toml)
27
-
28
- ## lint-python
29
-
30
- Інструменти uv-екосистеми не мають єдиного CLI, що сам обходить репозиторій, тому python-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint python`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
31
-
32
- Скрипт `rules/python/lint/lint.mjs`:
33
-
34
- - якщо `pyproject.toml` у корені відсутній — вихід 0 (перевірка пропущена);
35
- - якщо `pyproject.toml` є, але `uv` не знайдено в PATH — це помилка;
36
- - `uv lock --check` і `uv sync --frozen` — обовʼязкові;
37
- - `uv run ruff check --fix .` + `uv run ruff format .` — auto-fix (мутують робоче дерево, як `markdownlint-cli2 --fix` у lint-text);
38
- - `uv run mypy .` — статична перевірка типів;
39
- - усі `ruff`/`mypy`-кроки запускаються лише якщо інструмент доступний у середовищі (інакше крок пропускається з повідомленням).
40
-
41
- ## CI: `.github/workflows/lint-python.yml`
42
-
43
- - Канон: [lint-python.yml.snippet.yml](./policy/lint_python_yml/template/lint-python.yml.snippet.yml)
44
-
45
- Без кроків `poetry install` / `snok/install-poetry` — лише `astral-sh/setup-uv@v8.0.0` + `uv sync --frozen`.
18
+ | Namespace | Що перевіряє |
19
+ |-----------|-------------|
20
+ | `python.pyproject_toml` | Заборона `[tool.poetry]`; наявність `[project].name` і `[project].version` (PEP 621) |
21
+ | `python.lint_python_yml` | Обовʼязкові `uses` і `run`-кроки у `.github/workflows/lint-python.yml` |
@@ -0,0 +1,31 @@
1
+ ## Лінт Rego-файлів (opa / regal / conftest)
2
+
3
+ ```bash
4
+ n-cursor lint rego
5
+ ```
6
+
7
+ Цілі — `npm/rules/` (рекурсивно знаходить `.rego` у `<rule>/policy/<concern>/`).
8
+ Інші `*.rego` поза деревом — додай у `LINT_TARGETS` у `npm/rules/rego/lint/lint.mjs`.
9
+
10
+ `opa` і `regal` — лише у `PATH`, **не** додавай у `dependencies` / `devDependencies`.
11
+
12
+ ### Кроки лінту
13
+
14
+ 1. **`opa check --strict`** — компіляція з типами і строгим режимом: ловить мертвий код,
15
+ неоднозначні правила, незадекларовані змінні. Зупиняє пайплайн при помилці.
16
+ 2. **`regal lint`** — статичний лінтер: v0-синтаксис, неявні set-rules, відхилення від `rego.v1`,
17
+ bugs/idiomatic/performance-правила.
18
+ 3. **`conftest verify`** (опційно) — виконує `test_*` правила у `*_test.rego`.
19
+ Якщо `conftest` відсутній у `PATH` — пропускається без помилки (у CI потрібно встановити).
20
+
21
+ ### Конфіг regal
22
+
23
+ У корені проєкту — `.regal/config.yaml`. Дозволено вимикати окремі правила під специфіку репо
24
+ (наприклад, conftest-полісі — `deny`-правила як де-факто entrypoint-и):
25
+
26
+ ```yaml title=".regal/config.yaml"
27
+ rules:
28
+ idiomatic:
29
+ no-defined-entrypoint:
30
+ level: ignore
31
+ ```
@@ -0,0 +1,11 @@
1
+ ## Розширення VS Code для Rego
2
+
3
+ `.vscode/extensions.json` має містити `tsandall.opa` у масиві `recommendations` —
4
+ це забезпечує LSP-підтримку та форматування через `opa fmt` при збереженні.
5
+
6
+ Канонічний сніпет: [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
7
+
8
+ Перевірка — subset-of: кожне розширення зі сніпету має бути присутнє у `recommendations`.
9
+ Додаткові розширення (від інших правил) — дозволені.
10
+
11
+ Ціль (`target.json`): `.vscode/extensions.json` — обовʼязковий файл.
@@ -0,0 +1,13 @@
1
+ ## Налаштування VS Code для Rego
2
+
3
+ `.vscode/settings.json` має містити `[rego]`-блок з двома ключами:
4
+
5
+ - `editor.defaultFormatter` = `"tsandall.opa"`
6
+ - `editor.formatOnSave` = `true`
7
+
8
+ Канонічний сніпет: [settings.json.snippet.json](./policy/vscode_settings/template/settings.json.snippet.json)
9
+
10
+ Перевірка — leaf-by-leaf: кожен ключ/значення зі сніпету звіряється з файлом.
11
+ Якщо `[rego]`-блок присутній, але не є обʼєктом — окрема помилка типу.
12
+
13
+ Ціль (`target.json`): `.vscode/settings.json` — обовʼязковий файл.
@@ -9,31 +9,15 @@ alwaysApply: false
9
9
 
10
10
  Синтаксичні правила (`rego.v1`, `import rego.v1`, заборона legacy v0) — у `conftest.mdc` (alwaysApply). Цей файл — про **інструментарій**: VS Code, лінтери, форматування.
11
11
 
12
- ## Перевірка
12
+ [rego-rego-lint](./js/rego-lint.mdc)
13
13
 
14
- ```bash
15
- n-cursor lint rego
16
- ```
14
+ ## Швидкий gate через conftest
17
15
 
18
- Цілі `npm/rules/` (рекурсивно знаходить `.rego` у `<rule>/policy/<concern>/`). Інші *.rego поза деревом додай у `LINT_TARGETS` у `npm/rules/rego/lint/lint.mjs`.
16
+ | Пакет | Ціль | Що перевіряє |
17
+ |---|---|---|
18
+ | `rego.vscode_extensions` | `.vscode/extensions.json` | `recommendations` містить `tsandall.opa` |
19
+ | `rego.vscode_settings` | `.vscode/settings.json` | `[rego]`-блок з `defaultFormatter` + `formatOnSave` |
19
20
 
20
- `opa` і `regal` — лише у `PATH`, **не** додавай у `dependencies` / `devDependencies`.
21
+ [rego-vscode_extensions](./js/vscode_extensions.mdc)
21
22
 
22
- ### `.vscode/extensions.json`
23
-
24
- - Канон `recommendations` має містити `tsandall.opa` (LSP, format-on-save через `opa fmt`): [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
25
-
26
- ### `.vscode/settings.json`
27
-
28
- - Канон `[rego]`-block (`editor.defaultFormatter` + `editor.formatOnSave`): [settings.json.snippet.json](./policy/vscode_settings/template/settings.json.snippet.json)
29
-
30
- ## Конфіг regal
31
-
32
- У корені — `.regal/config.yaml`. Дозволено вимикати окремі правила під специфіку репо (наприклад, conftest-полісі — `deny`-правила як де-факто entrypoint-и):
33
-
34
- ```yaml title=".regal/config.yaml"
35
- rules:
36
- idiomatic:
37
- no-defined-entrypoint:
38
- level: ignore
39
- ```
23
+ [rego-vscode_settings](./js/vscode_settings.mdc)
@@ -0,0 +1,28 @@
1
+ ## Покриття + мутаційне тестування Rust
2
+
3
+ Покриття + мутаційне тестування Rust постачаються через `n-cursor coverage` (правило `test.mdc`). Реалізація провайдера — у `npm/rules/rust/coverage/coverage.mjs`: `cargo llvm-cov --json --summary-only` + `cargo mutants --jobs N`.
4
+
5
+ Бінарники: `cargo install cargo-llvm-cov && cargo install cargo-mutants`.
6
+
7
+ ### Паралелізм cargo-mutants
8
+
9
+ Паралельні воркери: дефолт `min(4, cpus/2)`; override через env **`CARGO_MUTANTS_JOBS`**. Прапорець `--in-place` відсутній — cargo-mutants створює власну sandbox-копію в `target/mutants.<i>/`, що сумісне з `--jobs > 1`.
10
+
11
+ ### Incremental mutation через `--in-diff`
12
+
13
+ cargo-mutants **не** має persistent-кешу вердиктів між прогонами (на відміну від Stryker `incremental.json`). Штатний аналог «не передивляйся незмінений код» — scoping за git-diff. Вмикається env-змінною **`CARGO_MUTANTS_BASE_REF`**:
14
+
15
+ - **не задано** (дефолт, типово для `main`) — повний прогін усіх мутантів;
16
+ - задано (напр. `origin/main`, типово для feature-гілки в CI) — мутуються лише рядки, змінені у `<baseRef>...HEAD`. Провайдер бере `git diff --relative <baseRef>...HEAD` з каталогу crate, пише diff у sandbox і передає cargo-mutants `--in-diff`.
17
+
18
+ Краєві випадки: порожній diff (немає змін під crate) → mutation `0/0` без запуску cargo-mutants; невідомий ref / не git-репо → попередження у stderr і fallback до повного прогону.
19
+
20
+ ### Пропуск baseline через `CARGO_MUTANTS_BASELINE=skip`
21
+
22
+ cargo-mutants спершу ганяє немутований baseline (повний build+test), щоб переконатися, що suite зелений. **`CARGO_MUTANTS_BASELINE=skip`** прибирає цей крок (`--baseline skip`), економлячи один повний `cargo test`.
23
+
24
+ Безпечно **лише** коли тести вже зелені у попередньому CI-степі (типовий порядок: `cargo test` → потім `n-cursor coverage` зі `skip`). Без цієї гарантії всі вердикти стають сміттєвими — дефолт: baseline-прогін. Найкорисніше в парі з `--in-diff`.
25
+
26
+ ### CI-кеш `target/` — множник
27
+
28
+ `--in-diff` ріже **кількість** мутантів, кеш `target/` — **вартість кожної** компіляції; вони множаться. Без кешу холодний CI щоразу перебудовує всі залежності, і baseline-build (для Tauri — хвилини) затьмарює економію від меншої кількості мутантів. У workflow, що викликає `n-cursor coverage` для Rust, став `Swatinem/rust-cache@v2` після `dtolnay/rust-toolchain@stable`.
@@ -0,0 +1,22 @@
1
+ ## Лінт Rust: rustfmt + clippy
2
+
3
+ **rustfmt** ([rust-lang/rustfmt](https://github.com/rust-lang/rustfmt)) — форматер; **clippy** ([rust-lang/rust-clippy](https://github.com/rust-lang/rust-clippy)) — лінтер. Запуск — через **`n-cursor lint rust`** (адаптер `main.mjs`):
4
+
5
+ - **локально (fix):** `cargo fmt --all` → `cargo clippy --fix --allow-staged --allow-dirty --all-targets --all-features` → фінальний `cargo clippy --all-targets --all-features -- -D warnings`
6
+ - **`--read-only` (детект, CI):** `cargo fmt --all -- --check` + `cargo clippy --all-targets --all-features -- -D warnings`
7
+
8
+ Без `Cargo.toml` у cwd — no-op (exit 0). Окремого `package.json`-скрипта немає.
9
+
10
+ `cargo`, `rustfmt`, `clippy` **не додавай** у `devDependencies` — це Rust toolchain, ставиться через `rustup` локально або через `dtolnay/rust-toolchain@stable` у CI.
11
+
12
+ ### Канон CI workflow `.github/workflows/lint-rust.yml`
13
+
14
+ [lint-rust.yml.snippet.yml](./policy/lint_rust_yml/template/lint-rust.yml.snippet.yml)
15
+
16
+ Після `actions/checkout@v6` — `dtolnay/rust-toolchain@stable` (з `components: rustfmt, clippy`) + `Swatinem/rust-cache@v2` для кешу `~/.cargo` і `target/`. Bun composite дії тут не потрібен — toolchain ставиться напряму.
17
+
18
+ **Перед** `actions/checkout@v6` у інших workflows йде стандартна послідовність (див. **ga.mdc**). У `lint-rust.yml` bun-composite не потрібен.
19
+
20
+ Rego-перевірка `rust.lint_rust_yml` верифікує:
21
+ - наявність кожного `uses` з канону (`actions/checkout@v6`, `dtolnay/rust-toolchain@stable`, `Swatinem/rust-cache@v2`);
22
+ - наявність кожного `run`-кроку з канону як підрядка серед run-кроків input-файлу.
@@ -0,0 +1,8 @@
1
+ ## Композиція з Tauri
2
+
3
+ Tauri-проєкт завжди має `src-tauri/Cargo.toml`, тому правило `rust` активується автоматично разом з `tauri`. Поділ обов'язків:
4
+
5
+ - `rust` — лінт через `n-cursor lint rust`, `rust-analyzer`, `even-better-toml`, CI workflow.
6
+ - `tauri` — `tauri-apps.tauri-vscode` (див. **tauri.mdc**).
7
+
8
+ Обидва правила перевіряють `.vscode/extensions.json` за `contains`-семантикою; конкурентного запису немає.
@@ -0,0 +1,12 @@
1
+ ## Розширення VS Code для Rust
2
+
3
+ У `.vscode/extensions.json` поле `recommendations` **має містити**:
4
+
5
+ - `rust-lang.rust-analyzer`
6
+ - `tamasfe.even-better-toml`
7
+
8
+ Перевірка `contains`-семантики: інші розширення дозволені, усі з канону мають бути присутні.
9
+
10
+ Канон: [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
11
+
12
+ Rego-перевірка `rust.vscode_extensions` для кожного запису з канону перевіряє його наявність у `recommendations` вхідного файлу.
@@ -5,44 +5,14 @@ alwaysApply: false
5
5
  version: '1.4'
6
6
  ---
7
7
 
8
- **rustfmt** ([rust-lang/rustfmt](https://github.com/rust-lang/rustfmt)) форматер; **clippy** ([rust-lang/rust-clippy](https://github.com/rust-lang/rust-clippy)) лінтер. Запуск — через **`n-cursor lint rust`** (адаптер `js/lint.mjs`): локально (fix) `cargo fmt --all` → `cargo clippy --fix --allow-staged --allow-dirty --all-targets --all-features` → фінальний `cargo clippy --all-targets --all-features -- -D warnings`; у `--read-only` (детект) — `cargo fmt --all -- --check` + `cargo clippy ... -- -D warnings`. Окремого `package.json`-скрипта немає. У CI cargo викликається напряму (див. `lint-rust.yml`).
8
+ Правило забезпечує форматування (rustfmt), лінт (clippy), CI workflow та покриття для Rust-проєктів.
9
9
 
10
- `cargo`, `rustfmt`, `clippy` не додавай у `devDependencies` — це Rust toolchain, ставиться через `rustup` локально або через `dtolnay/rust-toolchain@stable` у CI.
10
+ [rust-lint](./js/lint.mdc)
11
+ [rust-vscode_extensions](./js/vscode_extensions.mdc)
12
+ [rust-tauri_composition](./js/tauri_composition.mdc)
13
+ [rust-coverage](./js/coverage.mdc)
11
14
 
12
- У `.vscode/extensions.json` `recommendations` мають містити `rust-lang.rust-analyzer` і `tamasfe.even-better-toml`: [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
15
+ ## Швидкий gate через conftest
13
16
 
14
- Канон workflow `.github/workflows/lint-rust.yml`: [lint-rust.yml.snippet.yml](./policy/lint_rust_yml/template/lint-rust.yml.snippet.yml)
15
-
16
- Перед **`./.github/actions/setup-bun-deps`** в інших workflows йде **`actions/checkout@v6`** (див. **ga.mdc**). У **lint-rust.yml** після checkout — `dtolnay/rust-toolchain@stable` (з `components: rustfmt, clippy`) + `Swatinem/rust-cache@v2` для кешу `~/.cargo` і `target/`. Bun composite дії тут не потрібен — toolchain ставиться напряму.
17
-
18
- ## Композиція з Tauri
19
-
20
- Tauri-проєкт завжди має `src-tauri/Cargo.toml`, тому правило `rust` активується автоматично разом з `tauri`. Поділ обов'язків:
21
-
22
- - `rust` — лінт через `n-cursor lint rust`, `rust-analyzer`, `even-better-toml`, CI workflow.
23
- - `tauri` — `tauri-apps.tauri-vscode` (див. **tauri.mdc**).
24
-
25
- Обидва правила перевіряють `.vscode/extensions.json` за `contains`-семантикою; конкурентного запису немає.
26
-
27
- ## Покриття + мутаційне тестування Rust
28
-
29
- Покриття + мутаційне тестування Rust постачаються через `n-cursor coverage` (правило `test.mdc`). Реалізація провайдера — у `npm/rules/rust/coverage/coverage.mjs`: `cargo llvm-cov --json --summary-only` + `cargo mutants --jobs N` (паралельні воркери, дефолт `min(4, cpus/2)`; override через env `CARGO_MUTANTS_JOBS`). Прапорець `--in-place` прибраний — cargo-mutants створює власну sandbox-копію в `target/mutants.<i>/`, що сумісне з `--jobs > 1`. Бінарники: `cargo install cargo-llvm-cov && cargo install cargo-mutants`.
30
-
31
- ### Incremental mutation через `--in-diff`
32
-
33
- cargo-mutants **не** має persistent-кешу вердиктів між прогонами (на відміну від Stryker `incremental.json`). Штатний аналог «не передивляйся незмінений код» — scoping за git-diff. Вмикається env-змінною **`CARGO_MUTANTS_BASE_REF`**:
34
-
35
- - **не задано** (дефолт, типово для `main`) — повний прогін усіх мутантів;
36
- - задано (напр. `origin/main`, типово для feature-гілки в CI) — мутуються лише рядки, змінені у `<baseRef>...HEAD`. Провайдер бере `git diff --relative <baseRef>...HEAD` з каталогу crate (шляхи в diff збігаються з тим, що мутує cargo-mutants навіть у monorepo з `src-tauri/`), пише його у sandbox і передає cargo-mutants `--in-diff`.
37
-
38
- Краєві випадки: порожній diff (немає змін під crate) → mutation `0/0` без запуску cargo-mutants; невідомий ref / не git-репо → попередження у stderr і fallback до повного прогону.
39
-
40
- ### Пропуск baseline через `CARGO_MUTANTS_BASELINE=skip`
41
-
42
- cargo-mutants спершу ганяє немутований baseline (повний build+test), щоб переконатися, що suite зелений. Це **фіксована** вартість, незалежна від кількості мутантів — а отже більша частка дрібного `--in-diff`-прогону. **`CARGO_MUTANTS_BASELINE=skip`** прибирає цей крок (cargo-mutants `--baseline skip`), економлячи один повний `cargo test`.
43
-
44
- Безпечно **лише** коли тести вже зелені у попередньому CI-степі (типовий порядок: `cargo test` → потім `n-cursor coverage` зі `skip`). Без цієї гарантії всі вердикти стають сміттєвими, тому дефолт — baseline-прогін. Найкорисніше в парі з `--in-diff`.
45
-
46
- ### CI-кеш `target/` — множник, без якого scoping невидимий
47
-
48
- `--in-diff` ріже **кількість** мутантів, кеш `target/` — **вартість кожної** компіляції; вони множаться. Без кешу холодний CI щоразу перебудовує всі залежності, і baseline-build (для Tauri — хвилини) затьмарює економію від меншої кількості мутантів. У workflow, що викликає `n-cursor coverage` для Rust, став `Swatinem/rust-cache@v2` (кеш `~/.cargo` + `target/`) після `dtolnay/rust-toolchain@stable` — так само, як у `lint-rust.yml`. Sandbox-копії `target/mutants.<i>/` самі не кешуються, але деривуються з кешованих залежностей.
17
+ - `rust.lint_rust_yml` — перевіряє `.github/workflows/lint-rust.yml`: наявність обов'язкових `uses` (`actions/checkout@v6`, `dtolnay/rust-toolchain@stable`, `Swatinem/rust-cache@v2`) та `run`-кроків з канону.
18
+ - `rust.vscode_extensions` — перевіряє `.vscode/extensions.json`: `recommendations` містить `rust-lang.rust-analyzer` і `tamasfe.even-better-toml`.
@@ -0,0 +1,15 @@
1
+ ## Rego-полісі: `package.json` і CI workflow
2
+
3
+ ### `security.package_json` — заборона `trufflehog` у залежностях
4
+
5
+ Перевіряє, що `trufflehog` не потрапив у `dependencies` або `devDependencies` — він є глобальним CLI і не повинен бути npm-залежністю.
6
+
7
+ - Канон deny-списку: [package.json.deny.json](../policy/package_json/template/package.json.deny.json)
8
+
9
+ ### `security.lint_security_yml` — CI workflow з TruffleHog
10
+
11
+ Workflow `.github/workflows/lint-security.yml` обовʼязковий — забезпечує незалежний скан секретів на push/PR (агрегований `lint` локально + окремий fail-fast job на CI).
12
+
13
+ Перевіряється, що серед `uses:` є крок з `trufflesecurity/trufflehog@main`. Універсальні workflow-перевірки (checkout, permissions, persist-credentials) — у `ga.workflow_common`. Для повного скану історії потрібен `fetch-depth: 0`.
14
+
15
+ - Канон workflow: [lint-security.yml.snippet.yml](../policy/lint_security_yml/template/lint-security.yml.snippet.yml)
@@ -0,0 +1,19 @@
1
+ ## Placeholder для секретів — `sample-secret`
2
+
3
+ Фейкові credential-значення у **прикладних файлах** (`.env.example`, `.env.dist`, `*.example`, `*.sample`, `*.template`, вміст каталогів `fixtures/`) пиши як `sample-secret`, а не як bare `secret`.
4
+
5
+ `sample-secret` містить підрядок `sample` із вшитого списку `DefaultFalsePositives` TruffleHog — таке значення сканер відсіює **гарантовано** й незалежно від версії. Bare `secret` наразі не фіксується сканером лише тому, що випадково присутнє у словнику `fp_words.txt`; це крихка поведінка, що залежить від версії інструмента.
6
+
7
+ ### Приклади
8
+
9
+ - Правильно: `DB_PASSWORD=sample-secret`, `password: "sample-secret"`
10
+ - Неправильно: `DB_PASSWORD=secret`, `password: "secret"`
11
+
12
+ ### Що перевіряється
13
+
14
+ Перевіряється лише `secret` у позиції значення (після `=`, `:`, `=>`); імена ключів на кшталт `client_secret` не чіпаються.
15
+
16
+ Concern `security.sample_secret` (`js/sample_secret.mjs`) сканує всі прикладні файли:
17
+ - суфікс basename'а: `.example`, `.sample`, `.template`, `.dist`
18
+ - інфікс у basename'і: `.example.`, `.sample.`, `.template.`
19
+ - сегмент шляху: `fixtures/`, `fixture/`, `__fixtures__/`
@@ -0,0 +1,21 @@
1
+ ## TruffleHog — налаштування та `.trufflehog-exclude`
2
+
3
+ [TruffleHog](https://github.com/trufflesecurity/trufflehog) — глобальний CLI (як `shellcheck`, `conftest`); **не** додавай до `dependencies`/`devDependencies`.
4
+
5
+ Скан запускається через `n-cursor lint security` (CI — `n-cursor lint security --read-only`); окремого `lint-*` скрипта в `package.json` немає.
6
+
7
+ ### Ключові прапори запуску
8
+
9
+ - `trufflehog filesystem .` — сканує робоче дерево як директорію (включно з untracked/gitignored файлами); підкоманда `git file://.` лишається на CI для аудиту історії.
10
+ - `--no-update` — вимикає self-update check (CI-friendly).
11
+ - `--exclude-paths .trufflehog-exclude` — файл з regex-patterns, які треба пропускати (аналог `[allowlist].paths` із gitleaks).
12
+ - `--results=verified,unknown` — показує лише верифіковані секрети + ті, що TruffleHog не зміг перевірити (`unverified` дублікат відсіюється).
13
+ - `--fail` — exit-code `183` за наявності знахідок (щоб лінт падав).
14
+
15
+ ### `.trufflehog-exclude` (рекомендована основа)
16
+
17
+ Канон (допускає розширення): [.trufflehog-exclude.snippet.txt](./templates/trufflehog/.trufflehog-exclude.snippet.txt)
18
+
19
+ **Важливо:** один regex-pattern на рядок, без TOML-обгортки; коментарі починаються з `#`.
20
+
21
+ Перевірка (JS): `js/trufflehog.mjs` — впевнюється, що файл `.trufflehog-exclude` існує в корені й містить канонічні шаблони.