@nitra/cursor 12.8.7 → 12.8.9

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 (111) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. package/rules/abie/main.mdc +9 -5
  4. package/rules/abie/policy/base_deployment_preem/base_deployment_preem.mdc +22 -0
  5. package/rules/abie/policy/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc +19 -0
  6. package/rules/abie/policy/health_check_policy/health_check_policy.mdc +17 -0
  7. package/rules/abie/policy/http_route_base/http_route_base.mdc +9 -0
  8. package/rules/abie/policy/package_json_shared/package_json_shared.mdc +17 -0
  9. package/rules/adr/main.mdc +4 -0
  10. package/rules/adr/policy/settings_json/settings_json.mdc +7 -0
  11. package/rules/adr/policy/settings_local_json/settings_local_json.mdc +7 -0
  12. package/rules/bun/main.mdc +3 -4
  13. package/rules/bun/policy/bunfig/bunfig.mdc +12 -0
  14. package/rules/bun/policy/package_json/package_json.mdc +14 -0
  15. package/rules/capacitor/main.mdc +1 -3
  16. package/rules/capacitor/policy/package_json/package_json.mdc +9 -0
  17. package/rules/ci4/main.mdc +2 -0
  18. package/rules/ci4/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  19. package/rules/docker/main.mdc +1 -3
  20. package/rules/docker/policy/lint_docker_yml/lint_docker_yml.mdc +14 -0
  21. package/rules/efes/main.mdc +1 -1
  22. package/rules/efes/policy/package_json_shared/package_json_shared.mdc +30 -0
  23. package/rules/ga/main.mdc +15 -10
  24. package/rules/ga/policy/clean_ga_workflows/clean_ga_workflows.mdc +18 -0
  25. package/rules/ga/policy/clean_merged_branch/clean_merged_branch.mdc +22 -0
  26. package/rules/ga/policy/git_ai/git_ai.mdc +19 -0
  27. package/rules/ga/policy/lint_ga/lint_ga.mdc +21 -0
  28. package/rules/ga/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  29. package/rules/ga/policy/vscode_settings/vscode_settings.mdc +9 -0
  30. package/rules/ga/policy/workflow_common/workflow_common.mdc +18 -0
  31. package/rules/ga/policy/zizmor_yml/zizmor_yml.mdc +9 -0
  32. package/rules/graphql/main.mdc +2 -0
  33. package/rules/graphql/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  34. package/rules/hasura/main.mdc +1 -3
  35. package/rules/hasura/policy/svc_hl/svc_hl.mdc +15 -0
  36. package/rules/image-avif/main.mdc +1 -3
  37. package/rules/image-avif/policy/package_json/package_json.mdc +18 -0
  38. package/rules/image-compress/main.mdc +1 -1
  39. package/rules/image-compress/policy/package_json/package_json.mdc +13 -0
  40. package/rules/js/main.mdc +7 -6
  41. package/rules/js/policy/jscpd/jscpd.mdc +14 -0
  42. package/rules/js/policy/lint_js_yml/lint_js_yml.mdc +14 -0
  43. package/rules/js/policy/package_json/package_json.mdc +15 -0
  44. package/rules/js/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  45. package/rules/js-bun-db/main.mdc +1 -6
  46. package/rules/js-bun-db/policy/package_json/package_json.mdc +17 -0
  47. package/rules/js-bun-redis/main.mdc +2 -0
  48. package/rules/js-bun-redis/policy/package_json/package_json.mdc +11 -0
  49. package/rules/js-mssql/main.mdc +1 -1
  50. package/rules/js-mssql/policy/package_json/package_json.mdc +9 -0
  51. package/rules/js-run/main.mdc +5 -3
  52. package/rules/js-run/policy/configmap/configmap.mdc +31 -0
  53. package/rules/js-run/policy/jsconfig/jsconfig.mdc +25 -0
  54. package/rules/js-run/policy/package_json/package_json.mdc +38 -0
  55. package/rules/k8s/main.mdc +21 -13
  56. package/rules/k8s/policy/base_kustomization/base_kustomization.mdc +12 -0
  57. package/rules/k8s/policy/base_manifest/base_manifest.mdc +14 -0
  58. package/rules/k8s/policy/gateway/gateway.mdc +17 -0
  59. package/rules/k8s/policy/hasura_configmap/hasura_configmap.mdc +20 -0
  60. package/rules/k8s/policy/hasura_httproute/hasura_httproute.mdc +16 -0
  61. package/rules/k8s/policy/hpa_pdb/hpa_pdb.mdc +23 -0
  62. package/rules/k8s/policy/kustomization/kustomization.mdc +20 -0
  63. package/rules/k8s/policy/manifest/manifest.mdc +17 -0
  64. package/rules/k8s/policy/network_policy/network_policy.mdc +22 -0
  65. package/rules/k8s/policy/svc_hl_yaml/svc_hl_yaml.mdc +13 -0
  66. package/rules/k8s/policy/svc_yaml/svc_yaml.mdc +12 -0
  67. package/rules/nginx-default-tpl/main.mdc +4 -0
  68. package/rules/nginx-default-tpl/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  69. package/rules/nginx-default-tpl/policy/vscode_settings/vscode_settings.mdc +15 -0
  70. package/rules/npm-module/main.mdc +6 -3
  71. package/rules/npm-module/policy/emit_types_config/emit_types_config.mdc +40 -0
  72. package/rules/npm-module/policy/npm_package_json/npm_package_json.mdc +50 -0
  73. package/rules/npm-module/policy/root_package_json/root_package_json.mdc +37 -0
  74. package/rules/php/main.mdc +1 -3
  75. package/rules/php/policy/lint_php_yml/lint_php_yml.mdc +21 -0
  76. package/rules/python/main.mdc +3 -4
  77. package/rules/python/policy/lint_python_yml/lint_python_yml.mdc +12 -0
  78. package/rules/python/policy/pyproject_toml/pyproject_toml.mdc +13 -0
  79. package/rules/rego/main.mdc +4 -0
  80. package/rules/rego/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  81. package/rules/rego/policy/vscode_settings/vscode_settings.mdc +19 -0
  82. package/rules/rust/main.mdc +2 -2
  83. package/rules/rust/policy/lint_rust_yml/lint_rust_yml.mdc +12 -0
  84. package/rules/rust/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  85. package/rules/security/main.mdc +3 -2
  86. package/rules/security/policy/lint_security_yml/lint_security_yml.mdc +7 -0
  87. package/rules/security/policy/package_json/package_json.mdc +7 -0
  88. package/rules/style/main.mdc +6 -5
  89. package/rules/style/policy/lint_style_yml/lint_style_yml.mdc +13 -0
  90. package/rules/style/policy/package_json/package_json.mdc +18 -0
  91. package/rules/style/policy/vscode_extensions/vscode_extensions.mdc +13 -0
  92. package/rules/style/policy/vscode_settings/vscode_settings.mdc +19 -0
  93. package/rules/tauri/main.mdc +1 -3
  94. package/rules/tauri/policy/vscode_extensions/vscode_extensions.mdc +21 -0
  95. package/rules/test/main.mdc +1 -3
  96. package/rules/test/policy/package_json/package_json.mdc +16 -0
  97. package/rules/text/main.mdc +13 -7
  98. package/rules/text/policy/cspell/cspell.mdc +34 -0
  99. package/rules/text/policy/lint_text/lint_text.mdc +19 -0
  100. package/rules/text/policy/markdownlint/markdownlint.mdc +38 -0
  101. package/rules/text/policy/oxfmtrc/oxfmtrc.mdc +11 -0
  102. package/rules/text/policy/package_json/package_json.mdc +33 -0
  103. package/rules/text/policy/vscode_extensions/vscode_extensions.mdc +13 -0
  104. package/rules/text/policy/vscode_settings/vscode_settings.mdc +13 -0
  105. package/rules/vue/main.mdc +1 -3
  106. package/rules/vue/policy/package_json/package_json.mdc +30 -0
  107. package/scripts/lib/docs/index.md +36 -36
  108. package/scripts/lib/docs/rule-meta.md +10 -9
  109. package/scripts/lib/docs/run-lint.md +8 -8
  110. package/scripts/lib/rule-meta.mjs +2 -1
  111. package/scripts/lib/run-lint.mjs +39 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [12.8.9] - 2026-06-22
4
+
5
+ ### Changed
6
+
7
+ - ♻️ refactor(npm): Вдосконалено логіку `full`-scope правил у delta-режимі
8
+
9
+ ## [12.8.8] - 2026-06-22
10
+
11
+ ### Changed
12
+
13
+ - ✨ feat(rules): policy mdc для всіх npm/rules/*/policy/<concern>/
14
+
3
15
  ## [12.8.7] - 2026-06-22
4
16
 
5
17
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "12.8.7",
3
+ "version": "12.8.9",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -48,11 +48,15 @@ bun add -d @nitra/abie-shared
48
48
 
49
49
  Пакети (директорія в **`npm/policy/abie/`** → namespace → що перевіряє):
50
50
 
51
- - **`http_route_base/`** → `abie.http_route_base` — у HTTPRoute під `…/k8s/.../base/...` усі `spec.hostnames` мають бути в домені `aiml.live` (включно з `*.aiml.live` та піддоменами). **Цільові файли:** `…/k8s/.../base/.../hr.yaml`.
52
- - **`health_check_policy/`** → `abie.health_check_policy` — структура HealthCheckPolicy: `apiVersion: networking.gke.io/v1`, `metadata.name`, `spec.default.config.type: HTTP`, `httpHealthCheck.requestPath` починається з `/`, `port: 8080`, `targetRef.kind: Service`, `targetRef.name` має суфікс `-hl`. **Цільові файли:** `…/k8s/.../hc.yaml`.
53
- - **`base_deployment_preem/`** → `abie.base_deployment_preem` — Deployment у base/ має `spec.template.spec.nodeSelector.preem` зі значенням `true` (boolean або рядок). **Цільові файли:** ресурсні YAML під `…/k8s/.../base/...`.
54
- - **`clean_merged_ignore_branches/`** → `abie.clean_merged_ignore_branches` — у workflow `.github/workflows/clean-merged-branch.yml` крок з `uses: phpdocker-io/github-actions-delete-abandoned-branches` має `with.ignore_branches`, що містить токени `dev,ua` (case-insensitive). **Цільові файли:** `.github/workflows/clean-merged-branch.yml`.
55
- - **`package_json_shared/`** → `abie.package_json_shared` — у кореневому `package.json` `devDependencies` має містити `@nitra/abie-shared` (presence-only, версію не фіксуємо). **Цільові файли:** `package.json`.
51
+ [abie-http-route-base](./policy/http_route_base/http_route_base.mdc)
52
+
53
+ [abie-health-check-policy](./policy/health_check_policy/health_check_policy.mdc)
54
+
55
+ [abie-base-deployment-preem](./policy/base_deployment_preem/base_deployment_preem.mdc)
56
+
57
+ [abie-clean-merged-ignore-branches](./policy/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc)
58
+
59
+ [abie-package-json-shared](./policy/package_json_shared/package_json_shared.mdc)
56
60
 
57
61
  Cross-file / FS-логіка лишається у JS-частинах (`js/<concern>.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
58
62
 
@@ -0,0 +1,22 @@
1
+ ## Rego: `nodeSelector.preem` у base-Deployment
2
+
3
+ Rego-пакет: `abie.base_deployment_preem`
4
+
5
+ Цільові файли: YAML-маніфести Deployment під `…/k8s/.../base/…`.
6
+
7
+ Перевіряє, що кожен `Deployment` має `spec.template.spec.nodeSelector.preem` зі значенням `true` (boolean `true` або рядок `"true"` — без урахування регістру, з обрізаними пробілами). Значення `false` або відсутність ключа — deny.
8
+
9
+ ua-overlay далі підміняє це значення на `preem: false` через JSON6902-патч (`js/ua_node_selector.mjs`). Cross-document перевірка ua-патча — поза Rego.
10
+
11
+ ```yaml title="…/k8s/base/deployment.yaml (фрагмент)"
12
+ spec:
13
+ template:
14
+ spec:
15
+ nodeSelector:
16
+ preem: "true" # ✓ або boolean true
17
+ ```
18
+
19
+ ```yaml
20
+ nodeSelector:
21
+ role: worker # ✗ preem відсутній
22
+ ```
@@ -0,0 +1,19 @@
1
+ ## Rego: `ignore_branches` у `clean-merged-branch.yml`
2
+
3
+ Rego-пакет: `abie.clean_merged_ignore_branches`
4
+
5
+ Цільовий файл: `.github/workflows/clean-merged-branch.yml`.
6
+
7
+ Перевіряє, що у workflow-файлі є крок з `uses: phpdocker-io/github-actions-delete-abandoned-branches` і що його `with.ignore_branches` містить обидва токени `dev` та `ua` (case-insensitive, пробіли навколо токенів обрізаються). Токени зчитуються з template-файлу `data.template.snippet` — зміна канону автоматично змінює вимоги.
8
+
9
+ Канонічний snippet: [clean-merged-branch.yml.snippet.yml](./template/clean-merged-branch.yml.snippet.yml)
10
+
11
+ ```yaml title=".github/workflows/clean-merged-branch.yml (фрагмент)"
12
+ - uses: phpdocker-io/github-actions-delete-abandoned-branches@v2
13
+ with:
14
+ ignore_branches: "dev,ua,main" # ✓ містить dev та ua
15
+ ```
16
+
17
+ ```yaml
18
+ ignore_branches: "main" # ✗ не вистачає dev,ua
19
+ ```
@@ -0,0 +1,17 @@
1
+ ## Rego: структура `HealthCheckPolicy` у `hc.yaml`
2
+
3
+ Rego-пакет: `abie.health_check_policy`
4
+
5
+ Цільові файли: `…/k8s/.../hc.yaml`.
6
+
7
+ Перевіряє для `kind: HealthCheckPolicy` (з `apiVersion` що починається на `networking.gke.io/`):
8
+
9
+ - `apiVersion` — точно `networking.gke.io/v1`;
10
+ - `metadata.name` — непорожній рядок;
11
+ - `spec.default.config.type` — `HTTP`;
12
+ - `spec.default.config.httpHealthCheck.requestPath` — непорожній, починається з `/`;
13
+ - `spec.default.config.httpHealthCheck.port` — `8080`;
14
+ - `spec.targetRef.kind` — `Service`;
15
+ - `spec.targetRef.name` — `<metadata.name>-hl` (якщо `metadata.name` вже закінчується на `-hl` — використовується як є).
16
+
17
+ FS-парність HCP↔Deployment та modeline `$schema` у `hc.yaml` — поза Rego, у `js/hc_pairing.mjs`. JS-опис структури та приклад — у `js/hc_pairing.mdc`.
@@ -0,0 +1,9 @@
1
+ ## Rego: `HTTPRoute` у base-шарі — домени `aiml.live`
2
+
3
+ Rego-пакет: `abie.http_route_base`
4
+
5
+ Цільові файли: `…/k8s/.../base/.../*.yaml` типу HTTPRoute.
6
+
7
+ Перевіряє, що кожен hostname у `spec.hostnames` належить до домену `aiml.live`: точна відповідність `aiml.live`, wildcard `*.aiml.live` або будь-який піддомен `*.aiml.live`. Перевірка case-insensitive. Не є HTTPRoute — пакет не діє.
8
+
9
+ JS-частина (cross-file аналіз ua-overlay, backendRefs, тощо) — у `js/ua_http_route.mjs`. Людинозрозумілий опис + приклади — у `js/http_route_base.mdc`.
@@ -0,0 +1,17 @@
1
+ ## Rego: `@nitra/abie-shared` у `devDependencies`
2
+
3
+ Rego-пакет: `abie.package_json_shared`
4
+
5
+ Цільовий файл: `package.json` (кореневий).
6
+
7
+ Перевіряє presence-only: `devDependencies` має містити ключ `@nitra/abie-shared`. Версію не фіксує. Якщо ключ є лише у `dependencies` (не `devDependencies`) — deny.
8
+
9
+ JS-опис та інструкція встановлення — у секції «`@nitra/abie-shared` у `devDependencies`» в `main.mdc`.
10
+
11
+ ```json title="package.json (фрагмент)"
12
+ {
13
+ "devDependencies": {
14
+ "@nitra/abie-shared": "^1.0.0" // ✓
15
+ }
16
+ }
17
+ ```
@@ -78,4 +78,8 @@ Cursor Agent читає project-level **`.cursor/hooks.json`**. `npx @nitra/curs
78
78
 
79
79
  [adr-settings-policy](./js/settings_policy.mdc)
80
80
 
81
+ [adr-settings_json-policy](./policy/settings_json/settings_json.mdc)
82
+
83
+ [adr-settings_local_json-policy](./policy/settings_local_json/settings_local_json.mdc)
84
+
81
85
  [adr-hooks](./js/hooks.mdc)
@@ -0,0 +1,7 @@
1
+ ## Наявність ADR Stop-хуків у `.claude/settings.json`
2
+
3
+ Rego-пакет: `adr.settings_json`
4
+
5
+ Цільовий файл: `.claude/settings.json`
6
+
7
+ Перевіряє, що project-shared файл містить **обидва** managed Stop-хуки — `capture-decisions.sh` і `normalize-decisions.sh` — у `hooks.Stop[*].hooks[*].command`. Помилка, якщо маркер будь-якого зі скриптів відсутній.
@@ -0,0 +1,7 @@
1
+ ## Відсутність дублів ADR Stop-хуків у `.claude/settings.local.json`
2
+
3
+ Rego-пакет: `adr.settings_local_json`
4
+
5
+ Цільовий файл: `.claude/settings.local.json`
6
+
7
+ Перевіряє **зворотне** до `adr.settings_json`: local-файл **не повинен** містити маркерів `capture-decisions.sh` або `normalize-decisions.sh` у `hooks.Stop[*].hooks[*].command` — інакше кожен скрипт виконається двічі на одну Stop-подію.
@@ -17,7 +17,6 @@ version: '2.1'
17
17
 
18
18
  ## Швидкий gate через conftest
19
19
 
20
- | Namespace | Що перевіряє |
21
- |---|---|
22
- | `bun.bunfig` | Відповідність `bunfig.toml` канонічному шаблону (секції + leaf-ключі) |
23
- | `bun.package_json` | Заборонені top-level поля у root `package.json`; `devDependencies` лише `@nitra/*` + root-only test peers |
20
+ [bun-policy-bunfig](./policy/bunfig/bunfig.mdc)
21
+
22
+ [bun-policy-package_json](./policy/package_json/package_json.mdc)
@@ -0,0 +1,12 @@
1
+ ## Rego-gate: відповідність bunfig.toml канонічному шаблону
2
+
3
+ Rego-пакет: `bun.bunfig`
4
+
5
+ Цільовий файл: `bunfig.toml` (корінь репо).
6
+
7
+ Шаблон (leaf-значення, які gate порівнює): [bunfig.toml.snippet.toml](./template/bunfig.toml.snippet.toml)
8
+
9
+ Gate порівнює кожен leaf-ключ у кожній секції шаблону з фактичним значенням у `bunfig.toml`. Зайві ключі та секції — ігноруються. Deny-повідомлення виникає, якщо:
10
+
11
+ - секція відсутня або не є обʼєктом (`bunfig.toml: відсутня секція [install]`)
12
+ - leaf-ключ має інше значення (`bunfig.toml: у секції [install] має бути linker = "hoisted"`)
@@ -0,0 +1,14 @@
1
+ ## Rego-gate: заборонені поля та devDependencies у кореневому package.json
2
+
3
+ Rego-пакет: `bun.package_json`
4
+
5
+ Цільовий файл: кореневий `package.json`.
6
+
7
+ Список заборонених top-level полів (template-driven): [package.json.deny.json](./template/package.json.deny.json)
8
+
9
+ Gate виносить два класи deny:
10
+
11
+ 1. **Заборонені top-level поля** — будь-яке поле з `package.json.deny.json` присутнє у файлі (навіть із порожнім значенням `{}`).
12
+ 2. **devDependencies не з білого списку** — дозволені лише `@nitra/*` та root-only тестові peer/tools (`vitest`, `@vitest/coverage-v8`, `@stryker-mutator/vitest-runner`, `@playwright/test`). Будь-який інший пакет → deny.
13
+
14
+ Перевірки, що потребують FS або cross-file контексту (наприклад наявність `yarn.lock`), лишаються у JS-шарі.
@@ -13,8 +13,6 @@ version: '1.1'
13
13
 
14
14
  ## Швидкий gate через conftest
15
15
 
16
- | namespace | що перевіряє |
17
- |---|---|
18
- | `capacitor.package_json` | версія `@capacitor/core` у `dependencies` — мінімум major 8 (спрощений JS-порт для одиничного `package.json`) |
16
+ [capacitor-package_json](./policy/package_json/package_json.mdc)
19
17
 
20
18
  JS-перевірка (`platforms.mjs`) — authoritative: підтримує `||`-діапазони, hyphen-range, workspace-monorepo та iOS-специфічну логіку (Podfile).
@@ -0,0 +1,9 @@
1
+ ## Rego-gate: версія `@capacitor/core` у `package.json`
2
+
3
+ Rego-пакет: `capacitor.package_json`
4
+
5
+ Цільовий файл: `package.json` (один файл, `target.json` → `files.single`).
6
+
7
+ Перевіряє наявність `dependencies["@capacitor/core"]` і вимагає, щоб перша мажорна цифра діапазону була ≥ 8. Значення `workspace:*` пропускається без помилки.
8
+
9
+ Спрощений порт JS-логіки: `||`-діапазони та hyphen-range — лише у JS (`fix.mjs`). Цей gate — швидка перевірка одиничного `package.json` (наприклад, через IDE або conftest у CI).
@@ -375,3 +375,5 @@ Rego-перевірки, що запускаються через `conftest` у
375
375
  [ci4-marksman_config](./js/marksman_config.mdc)
376
376
 
377
377
  [ci4-vscode_extensions](./js/vscode_extensions.mdc)
378
+
379
+ [ci4-vscode_extensions-policy](./policy/vscode_extensions/vscode_extensions.mdc)
@@ -0,0 +1,9 @@
1
+ ## Rego-gate: обовʼязкові розширення VSCode
2
+
3
+ Rego-пакет: `ci4.vscode_extensions`
4
+
5
+ Цільовий файл: `.vscode/extensions.json`
6
+
7
+ Перевіряє, що кожен запис з `data.template.snippet.recommendations` присутній у `input.recommendations`. Канонічний шаблон надходить через `--data` у conftest: [extensions.json.snippet.json](./template/extensions.json.snippet.json)
8
+
9
+ Додаткові розширення в масиві дозволені — deny лише на відсутність обовʼязкових.
@@ -15,9 +15,7 @@ alwaysApply: false
15
15
 
16
16
  ## Швидкий gate через conftest
17
17
 
18
- | Пакет | Що перевіряє |
19
- |---|---|
20
- | `docker.lint_docker_yml` | `.github/workflows/lint-docker.yml` відповідає канонічному сніпету (paths, uses, run-підрядки) |
18
+ [docker-lint_docker_yml](./policy/lint_docker_yml/lint_docker_yml.mdc)
21
19
 
22
20
  [docker-mirror](./js/mirror.mdc)
23
21
 
@@ -0,0 +1,14 @@
1
+ ## Перевірка `.github/workflows/lint-docker.yml`
2
+
3
+ Rego-пакет: `docker.lint_docker_yml`
4
+
5
+ Цільовий файл: `.github/workflows/lint-docker.yml`
6
+
7
+ Перевіряє, що CI-workflow lint-docker відповідає канонічному сніпету:
8
+
9
+ - `on.push.paths` містить усі три glob-маски: `**/Dockerfile`, `**/*.Dockerfile`, `**/*.dockerfile`
10
+ - присутні кроки `uses: actions/checkout@v6` та `uses: ./.github/actions/setup-bun-deps`
11
+ - крок install hadolint містить рядок із версією `v2.12.0` (substring-перевірка)
12
+ - крок lint містить `n-cursor lint docker --read-only`
13
+
14
+ Канонічний шаблон: [lint-docker.yml.snippet.yml](./template/lint-docker.yml.snippet.yml)
@@ -20,4 +20,4 @@ bun add -d @nitra/efes-shared
20
20
 
21
21
  Пакети (директорія в **`npm/rules/efes/policy/`** → namespace → що перевіряє):
22
22
 
23
- - **`package_json_shared/`** → `efes.package_json_shared` — у кореневому `package.json` `devDependencies` має містити `@nitra/efes-shared` (presence-only, версію не фіксуємо). **Цільові файли:** `package.json`.
23
+ [efes-package_json_shared](./policy/package_json_shared/package_json_shared.mdc)
@@ -0,0 +1,30 @@
1
+ ## Наявність `@nitra/efes-shared` у `devDependencies`
2
+
3
+ Rego-пакет: `efes.package_json_shared`
4
+
5
+ **Цільовий файл:** `package.json` (корінь проєкту, обовʼязковий).
6
+
7
+ **Що перевіряється:** у `devDependencies` кореневого `package.json` має бути ключ `@nitra/efes-shared`. Версію не фіксуємо — лише presence. Наявність лише у `dependencies` (не `devDependencies`) — теж помилка.
8
+
9
+ **Виправлення:**
10
+
11
+ ```bash
12
+ bun add -d @nitra/efes-shared
13
+ ```
14
+
15
+ **Приклади:**
16
+
17
+ ✓ правильно — `devDependencies` містить пакет:
18
+ ```json
19
+ { "devDependencies": { "@nitra/efes-shared": "^1.0.0" } }
20
+ ```
21
+
22
+ ✗ неправильно — `devDependencies` відсутній або порожній:
23
+ ```json
24
+ { "name": "my-project" }
25
+ ```
26
+
27
+ ✗ неправильно — пакет лише у `dependencies`:
28
+ ```json
29
+ { "dependencies": { "@nitra/efes-shared": "^1.0.0" } }
30
+ ```
package/rules/ga/main.mdc CHANGED
@@ -21,13 +21,18 @@ alwaysApply: false
21
21
 
22
22
  ## Швидкий gate через conftest
23
23
 
24
- Rego-пакети (namespace → що перевіряє):
25
-
26
- - `ga.workflow_common` — усі `*.yml`: concurrency, composite setup-bun-deps, run:>-, мінімальні версії actions, заборона depcheck
27
- - `ga.clean_ga_workflows` — структура `clean-ga-workflows.yml` (cron, permissions, cleanup step)
28
- - `ga.clean_merged_branch` — структура `clean-merged-branch.yml` (cron, permissions, ignore_branches, dry_run)
29
- - `ga.lint_ga` — структура `lint-ga.yml` (triggers, conftest install, n-cursor lint ga --read-only)
30
- - `ga.git_ai` — структура `git-ai.yml` (pr closed trigger, git-ai install + run)
31
- - `ga.vscode_extensions` — `.vscode/extensions.json`: рекомендація `github.vscode-github-actions`
32
- - `ga.vscode_settings` — `.vscode/settings.json`: `editor.defaultFormatter` для github-actions-workflow
33
- - `ga.zizmor_yml` — `.github/zizmor.yml`: `rules.unpinned-uses.config.policies["*"]`
24
+ [ga-workflow_common](./policy/workflow_common/workflow_common.mdc)
25
+
26
+ [ga-clean_ga_workflows](./policy/clean_ga_workflows/clean_ga_workflows.mdc)
27
+
28
+ [ga-clean_merged_branch](./policy/clean_merged_branch/clean_merged_branch.mdc)
29
+
30
+ [ga-lint_ga](./policy/lint_ga/lint_ga.mdc)
31
+
32
+ [ga-git_ai](./policy/git_ai/git_ai.mdc)
33
+
34
+ [ga-vscode_extensions](./policy/vscode_extensions/vscode_extensions.mdc)
35
+
36
+ [ga-vscode_settings](./policy/vscode_settings/vscode_settings.mdc)
37
+
38
+ [ga-zizmor_yml](./policy/zizmor_yml/zizmor_yml.mdc)
@@ -0,0 +1,18 @@
1
+ ## Структура `clean-ga-workflows.yml` — видалення завершених workflow runs
2
+
3
+ Rego-пакет: `ga.clean_ga_workflows`
4
+
5
+ **Цільовий файл:** `.github/workflows/clean-ga-workflows.yml`
6
+
7
+ ### Що перевіряється
8
+
9
+ - `name` — точна відповідність значенню з template
10
+ - `on.schedule[].cron` — має містити cron із template (`0 1 16 * *`)
11
+ - `on.workflow_dispatch` — має бути об'єктом `{}`
12
+ - `jobs.cleanup_old_workflows` — job має існувати
13
+ - `jobs.cleanup_old_workflows.runs-on` — відповідно до template (`ubuntu-latest`)
14
+ - `jobs.cleanup_old_workflows.permissions` — `actions: write`, `contents: read`
15
+ - `steps[0].name` і `steps[0].uses` — відповідно до template (`dmvict/clean-workflow-runs@v1`)
16
+ - `steps[0].with` — `token`, `save_period`, `save_min_runs_number` як у template
17
+
18
+ Канон: [clean-ga-workflows.yml.snippet.yml](./template/clean-ga-workflows.yml.snippet.yml)
@@ -0,0 +1,22 @@
1
+ ## Структура `clean-merged-branch.yml` — видалення злитих гілок
2
+
3
+ Rego-пакет: `ga.clean_merged_branch`
4
+
5
+ **Цільовий файл:** `.github/workflows/clean-merged-branch.yml`
6
+
7
+ ### Що перевіряється
8
+
9
+ - `name` — точна відповідність значенню з template
10
+ - `on.schedule[].cron` — має містити cron із template (`0 1 15 * *`)
11
+ - `on.workflow_dispatch` — має бути об'єктом `{}`
12
+ - `jobs.cleanup_old_branches` — job має існувати
13
+ - `jobs.cleanup_old_branches.permissions` — кожне поле із template (`contents: write`, `pull-requests: read`)
14
+ - `steps` — має бути рівно 2 кроки
15
+ - `steps[0].id` — `delete_stuff`; `steps[0].uses` — `phpdocker-io/github-actions-delete-abandoned-branches@v2.0.3`
16
+ - `steps[0].with.github_token`, `last_commit_age_days` — за template
17
+ - `steps[0].with.ignore_branches` — має містити всі гілки з template (`main,dev`)
18
+ - `steps[0].with.dry_run` — `no` (нормалізується: YAML 1.1 `no` → boolean `false` у conftest)
19
+ - `steps[1].name` — за template; `steps[1].env.DELETED_BRANCHES` — за template
20
+ - `steps[1].run` — містить `Deleted branches:` та `${DELETED_BRANCHES}`
21
+
22
+ Канон: [clean-merged-branch.yml.snippet.yml](./template/clean-merged-branch.yml.snippet.yml)
@@ -0,0 +1,19 @@
1
+ ## Структура `git-ai.yml` — автоматичний запуск git-ai після мержу PR
2
+
3
+ Rego-пакет: `ga.git_ai`
4
+
5
+ **Цільовий файл:** `.github/workflows/git-ai.yml`
6
+
7
+ ### Що перевіряється
8
+
9
+ - `name` — точна відповідність значенню з template (`Git AI`)
10
+ - `on.pull_request.types` — має містити `closed`
11
+ - `jobs.git-ai` — job має існувати
12
+ - `jobs.git-ai.if` — містить `github.event.pull_request.merged == true`
13
+ - `jobs.git-ai.permissions.contents` — за template (`write`)
14
+ - `steps[*].run` (сукупно) — містить substring `https://usegitai.com/install.sh` (інсталяція)
15
+ - `steps[*].run` (сукупно) — містить substring `git-ai ci github run` (запуск)
16
+
17
+ Substring-перевірки замість exact-match через крихкість multi-line `run:` блоків.
18
+
19
+ Канон: [git-ai.yml.snippet.yml](./template/git-ai.yml.snippet.yml)
@@ -0,0 +1,21 @@
1
+ ## Структура `lint-ga.yml` — CI-лінт GitHub Actions файлів
2
+
3
+ Rego-пакет: `ga.lint_ga`
4
+
5
+ **Цільовий файл:** `.github/workflows/lint-ga.yml`
6
+
7
+ ### Що перевіряється
8
+
9
+ - `name` — точна відповідність значенню з template (`Lint GA`)
10
+ - `on.push.branches` — superset: містить `dev` і `main`
11
+ - `on.pull_request.branches` — superset: містить `dev` і `main`
12
+ - `on.push.paths` — superset: містить `.github/actions/**` і `.github/workflows/**`
13
+ - `jobs.lint-ga` — job має існувати
14
+ - `jobs.lint-ga.runs-on` — за template (`ubuntu-latest`)
15
+ - `jobs.lint-ga.permissions.contents` — `read`
16
+ - `jobs.lint-ga.steps` — не порожній
17
+ - `steps[*].uses` — кожен `uses:` з template має бути присутнім у кроках
18
+ - `steps[*].run` (сукупно) — містить `open-policy-agent/conftest` (Install conftest)
19
+ - `steps[*].run` (сукупно) — містить `n-cursor lint ga --read-only`
20
+
21
+ Канон: [lint-ga.yml.snippet.yml](./template/lint-ga.yml.snippet.yml)
@@ -0,0 +1,9 @@
1
+ ## `.vscode/extensions.json` — розширення для GitHub Actions
2
+
3
+ Rego-пакет: `ga.vscode_extensions`
4
+
5
+ **Цільовий файл:** `.vscode/extensions.json`
6
+
7
+ Кожне розширення з template має бути присутнє у `recommendations`. Додаткові розширення від інших правил — допустимі (subset-перевірка).
8
+
9
+ Канон: [extensions.json.snippet.json](./template/extensions.json.snippet.json)
@@ -0,0 +1,9 @@
1
+ ## `.vscode/settings.json` — налаштування форматування GitHub Actions workflow
2
+
3
+ Rego-пакет: `ga.vscode_settings`
4
+
5
+ **Цільовий файл:** `.vscode/settings.json`
6
+
7
+ Перевіряє 2-рівневу структуру: для кожного `<block-key>` з template кожен `<leaf-key>` у відповідному блоці input має точно відповідати очікуваному значенню. Ключі можуть містити дужки та крапки (VS Code-конвенція, наприклад `[github-actions-workflow]`).
8
+
9
+ Канон: [settings.json.snippet.json](./template/settings.json.snippet.json)
@@ -0,0 +1,18 @@
1
+ ## Універсальні Rego-перевірки для всіх workflow-файлів
2
+
3
+ Rego-пакет: `ga.workflow_common`
4
+
5
+ **Цільові файли:** `.github/workflows/*.yml` (кожен файл окремо)
6
+
7
+ ### Що перевіряється
8
+
9
+ - **concurrency** — обов'язкова наявність блоку; `group` = `${{ github.ref }}-${{ github.workflow }}`; `cancel-in-progress: true`
10
+ - **Заборонені кроки** — `oven-sh/setup-bun`, `actions/cache`, `bun install` у будь-якому `uses:`/`run:` (мають бути інкапсульовані у composite `setup-bun-deps`)
11
+ - **Порядок кроків** — якщо є `setup-bun-deps`, перед ним обов'язковий `actions/checkout@`
12
+ - **Shell-продовження** — `\` перед переносом рядка у `run:` заборонено; треба `run: >-`
13
+ - **Заборонені команди** — `depcheck` у `run:` (мігровано на `knip`)
14
+ - **Мінімальні версії** — `uses:` з marketplace-actions перевіряються за канонічним JSON
15
+
16
+ Канон мінімальних версій: [uses-min-versions.snippet.json](./template/uses-min-versions.snippet.json)
17
+
18
+ Детальна документація поведінки — у [ga-workflow_common](../../js/workflow_common.mdc).
@@ -0,0 +1,9 @@
1
+ ## `.github/zizmor.yml` — конфігурація zizmor для unpinned-uses
2
+
3
+ Rego-пакет: `ga.zizmor_yml`
4
+
5
+ **Цільовий файл:** `.github/zizmor.yml`
6
+
7
+ Перевіряє `rules.unpinned-uses.config.policies["*"]` — значення має точно відповідати template (`ref-pin`). Всі вкладені об'єкти читаються через `object.get` із дефолтами, тож відсутні ключі коректно детектуються як порушення.
8
+
9
+ Канон: [zizmor.yml.snippet.yml](./template/zizmor.yml.snippet.yml)
@@ -10,3 +10,5 @@ alwaysApply: false
10
10
  [graphql-tooling](./js/tooling.mdc)
11
11
 
12
12
  [graphql-vscode-extensions](./js/vscode_extensions.mdc)
13
+
14
+ [graphql-vscode-extensions-policy](./policy/vscode_extensions/vscode_extensions.mdc)
@@ -0,0 +1,9 @@
1
+ ## Rego-перевірка наявності graphql.vscode-graphql у recommendations
2
+
3
+ Rego-пакет: `graphql.vscode_extensions`
4
+
5
+ Цільовий файл: `.vscode/extensions.json` (передається явно через `runConftestBatch` — без `target.json`, тому не auto-discoverable).
6
+
7
+ Перевіряє: поле `recommendations` містить рядок `"graphql.vscode-graphql"`. Порожній масив або відсутнє поле — deny. Додаткові записи дозволені.
8
+
9
+ Запускається умовно — лише якщо JS-сканер виявив `gql\`…\`` у джерелах проєкту.
@@ -15,6 +15,4 @@ alwaysApply: false
15
15
 
16
16
  ## Швидкий gate через conftest
17
17
 
18
- | Пакет | Файл | Що перевіряє |
19
- |---|---|---|
20
- | `hasura.svc_hl` | `policy/svc_hl/svc_hl.rego` | Іменування headless/clusterIP Service: суфікси `-h-hl` та `-h` |
18
+ [hasura-svc_hl](./policy/svc_hl/svc_hl.mdc)
@@ -0,0 +1,15 @@
1
+ ## Rego-gate: іменування headless та clusterIP Service
2
+
3
+ Rego-пакет: `hasura.svc_hl`
4
+
5
+ Цільові файли: `hasura/k8s/base/svc.yaml`, `hasura/k8s/base/svc-hl.yaml`
6
+
7
+ Перевіряє два правила іменування Kubernetes Service:
8
+
9
+ - **Headless Service** (`spec.clusterIP: None`) — ім'я має закінчуватись на `-h-hl`
10
+ - **ClusterIP Service** (не headless) — ім'я має закінчуватись на `-h`
11
+
12
+ Ресурси з `kind != "Service"` пропускаються без помилок.
13
+
14
+ ✓ `db-h-hl` (headless), `db-h` (clusterIP)
15
+ ✗ `contract-h` як headless, `db-h-hl` як clusterIP
@@ -13,6 +13,4 @@ alwaysApply: false
13
13
 
14
14
  ## Швидкий gate через conftest
15
15
 
16
- | Rego-пакет | Що перевіряє |
17
- |---|---|
18
- | `image_avif.package_json` | typo-ключі, тип поля та тип `disable-avif` в опт-аут конфігу `package.json` |
16
+ [image-avif-package_json](./policy/package_json/package_json.mdc)
@@ -0,0 +1,18 @@
1
+ ## Rego-gate: структура опт-аут конфігу у package.json
2
+
3
+ Rego-пакет: `image-avif.package_json`
4
+
5
+ Цільові файли: `package.json` (передається через `--input` у conftest).
6
+
7
+ Перевіряє три умови:
8
+
9
+ - **Тип поля** — `"@nitra/minify-image"` має бути обʼєктом (якщо задано); рядок, масив чи boolean → deny.
10
+ - **Тип прапора** — `"@nitra/minify-image.disable-avif"` має бути `boolean`; рядок або число → deny.
11
+ - **Typo-ключі** — забороняє ключі зі списку deny-template [`package.json.deny.json`](./template/package.json.deny.json) (наприклад, `"disabled-avif"` замість `"disable-avif"`).
12
+
13
+ Deny-template: [package.json.deny.json](./template/package.json.deny.json)
14
+
15
+ ✓ `{ "@nitra/minify-image": { "disable-avif": true } }`
16
+ ✗ `{ "@nitra/minify-image": { "disabled-avif": true } }` — typo-ключ
17
+ ✗ `{ "@nitra/minify-image": "disable-avif" }` — поле не є обʼєктом
18
+ ✗ `{ "@nitra/minify-image": { "disable-avif": "yes" } }` — не boolean
@@ -15,4 +15,4 @@ CLI [`@nitra/minify-image`](https://www.npmjs.com/package/@nitra/minify-image) (
15
15
 
16
16
  ## Швидкий gate через conftest
17
17
 
18
- - `image_compress.package_json` — забороняє `@nitra/minify-image` у `dependencies`/`devDependencies` проєкту
18
+ [image-compress-package_json](./policy/package_json/package_json.mdc)
@@ -0,0 +1,13 @@
1
+ ## Заборона `@nitra/minify-image` у залежностях (`package.json`)
2
+
3
+ Rego-пакет: `image_compress.package_json`
4
+
5
+ Цільовий файл: `package.json` (єдиний файл проєкту).
6
+
7
+ Перевіряє поля `dependencies` та `devDependencies`: якщо там присутній пакет `@nitra/minify-image` — deny. Список заборонених пакетів надходить через `--data` з канонічного шаблону:
8
+
9
+ [package.json.deny.json](./template/package.json.deny.json)
10
+
11
+ ✓ `{}` — порожній `package.json` без залежностей
12
+ ✗ `{ "dependencies": { "@nitra/minify-image": "^4.0.1" } }` — заборонено, використовуй `npx`
13
+ ✗ `{ "devDependencies": { "@nitra/minify-image": "^4.0.1" } }` — заборонено, використовуй `npx`
package/rules/js/main.mdc CHANGED
@@ -35,9 +35,10 @@ version: '1.30'
35
35
 
36
36
  Rego-пакети у `policy/` — запускаються `npx @nitra/cursor fix js` або `conftest`:
37
37
 
38
- | Namespace | Що перевіряє |
39
- |---|---|
40
- | `js_lint.package_json` | `package.json`: `"type": "module"`, `engines.node >= 24`, `engines.bun >= 1.3`, `@nitra/eslint-config` >= semver-поріг |
41
- | `js_lint.jscpd` | `.jscpd.json`: `gitignore`, `exitCode`, `reporters` (subset), `minLines >= канон` |
42
- | `js_lint.lint_js_yml` | `.github/workflows/lint-js.yml`: required uses/run кроки, `persist-credentials: false`, заборона `--fix` у CI |
43
- | `js_lint.vscode_extensions` | `.vscode/extensions.json`: наявність трьох канонічних recommendations |
38
+ [js-policy-package_json](./policy/package_json/package_json.mdc)
39
+
40
+ [js-policy-jscpd](./policy/jscpd/jscpd.mdc)
41
+
42
+ [js-policy-lint_js_yml](./policy/lint_js_yml/lint_js_yml.mdc)
43
+
44
+ [js-policy-vscode_extensions](./policy/vscode_extensions/vscode_extensions.mdc)
@@ -0,0 +1,14 @@
1
+ ## Rego-gate `.jscpd.json`
2
+
3
+ Rego-пакет: `js_lint.jscpd`
4
+
5
+ Цільовий файл: `.jscpd.json` у корені проєкту.
6
+
7
+ Що перевіряється:
8
+
9
+ - `gitignore` — точна відповідність (`true`)
10
+ - `exitCode` — точна відповідність (`1`)
11
+ - `reporters` — subset-of: масив має містити всі елементи з канону (`["console"]`)
12
+ - `minLines` — число, значення >= канонічного порогу (`25`); більше дозволено
13
+
14
+ Канон-snippet: [.jscpd.json.snippet.json](./template/.jscpd.json.snippet.json)