@nitra/cursor 12.8.6 → 12.8.8

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 (263) 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/js/hooks.mdc +32 -0
  10. package/rules/adr/js/madr_format.mdc +96 -0
  11. package/rules/adr/js/settings_policy.mdc +34 -0
  12. package/rules/adr/main.mdc +17 -95
  13. package/rules/adr/policy/settings_json/settings_json.mdc +7 -0
  14. package/rules/adr/policy/settings_local_json/settings_local_json.mdc +7 -0
  15. package/rules/bun/js/bunfig.mdc +12 -0
  16. package/rules/bun/js/layout.mdc +60 -0
  17. package/rules/bun/js/lint.mdc +9 -0
  18. package/rules/bun/js/package_json.mdc +19 -0
  19. package/rules/bun/main.mdc +7 -60
  20. package/rules/bun/policy/bunfig/bunfig.mdc +12 -0
  21. package/rules/bun/policy/package_json/package_json.mdc +14 -0
  22. package/rules/capacitor/js/ios_spm.mdc +69 -0
  23. package/rules/capacitor/js/version.mdc +29 -0
  24. package/rules/capacitor/main.mdc +6 -22
  25. package/rules/capacitor/policy/package_json/package_json.mdc +9 -0
  26. package/rules/changelog/js/agent-workflow.mdc +15 -0
  27. package/rules/changelog/js/changelog-format.mdc +33 -0
  28. package/rules/changelog/js/comparison-models.mdc +40 -0
  29. package/rules/changelog/main.mdc +4 -98
  30. package/rules/ci4/js/marksman_config.mdc +31 -0
  31. package/rules/ci4/js/vscode_extensions.mdc +33 -0
  32. package/rules/ci4/main.mdc +16 -14
  33. package/rules/ci4/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  34. package/rules/docker/js/compile.mdc +44 -0
  35. package/rules/docker/js/hadolint.mdc +50 -0
  36. package/rules/docker/js/mirror.mdc +13 -0
  37. package/rules/docker/js/multistage.mdc +13 -0
  38. package/rules/docker/js/native-addon.mdc +43 -0
  39. package/rules/docker/js/nginx-tag.mdc +7 -0
  40. package/rules/docker/js/nginx-user.mdc +37 -0
  41. package/rules/docker/js/non-root.mdc +39 -0
  42. package/rules/docker/main.mdc +13 -196
  43. package/rules/docker/policy/lint_docker_yml/lint_docker_yml.mdc +14 -0
  44. package/rules/efes/main.mdc +1 -1
  45. package/rules/efes/policy/package_json_shared/package_json_shared.mdc +30 -0
  46. package/rules/ga/js/lint_toolchain.mdc +15 -0
  47. package/rules/ga/js/required_workflows.mdc +35 -0
  48. package/rules/ga/js/vscode.mdc +17 -0
  49. package/rules/ga/js/workflow_common.mdc +108 -0
  50. package/rules/ga/js/workflows.mdc +32 -0
  51. package/rules/ga/js/zizmor.mdc +7 -0
  52. package/rules/ga/main.mdc +16 -119
  53. package/rules/ga/policy/clean_ga_workflows/clean_ga_workflows.mdc +18 -0
  54. package/rules/ga/policy/clean_merged_branch/clean_merged_branch.mdc +22 -0
  55. package/rules/ga/policy/git_ai/git_ai.mdc +19 -0
  56. package/rules/ga/policy/lint_ga/lint_ga.mdc +21 -0
  57. package/rules/ga/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  58. package/rules/ga/policy/vscode_settings/vscode_settings.mdc +9 -0
  59. package/rules/ga/policy/workflow_common/workflow_common.mdc +18 -0
  60. package/rules/ga/policy/zizmor_yml/zizmor_yml.mdc +9 -0
  61. package/rules/graphql/js/tooling.mdc +13 -0
  62. package/rules/graphql/js/vscode_extensions.mdc +13 -0
  63. package/rules/graphql/main.mdc +4 -21
  64. package/rules/graphql/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  65. package/rules/hasura/js/internal_urls.mdc +27 -0
  66. package/rules/hasura/js/migrations.mdc +13 -0
  67. package/rules/hasura/js/svc_hl.mdc +17 -0
  68. package/rules/hasura/main.mdc +6 -30
  69. package/rules/hasura/policy/svc_hl/svc_hl.mdc +15 -0
  70. package/rules/image-avif/js/avif_generation.mdc +26 -0
  71. package/rules/image-avif/js/package_json_optout.mdc +21 -0
  72. package/rules/image-avif/main.mdc +5 -34
  73. package/rules/image-avif/policy/package_json/package_json.mdc +18 -0
  74. package/rules/image-compress/js/package_json.mdc +7 -0
  75. package/rules/image-compress/js/package_setup.mdc +13 -0
  76. package/rules/image-compress/main.mdc +4 -12
  77. package/rules/image-compress/policy/package_json/package_json.mdc +13 -0
  78. package/rules/js/docs/index.md +3 -3
  79. package/rules/js/js/dep-policy.mdc +17 -0
  80. package/rules/js/js/eslint-config.mdc +28 -0
  81. package/rules/js/js/extensions.mdc +8 -0
  82. package/rules/js/js/file-extensions.mdc +12 -0
  83. package/rules/js/js/for-in.mdc +26 -0
  84. package/rules/js/js/jscpd.mdc +42 -0
  85. package/rules/js/js/knip.mdc +15 -0
  86. package/rules/js/js/lint-js-workflow.mdc +58 -0
  87. package/rules/js/js/oxlintrc.mdc +20 -0
  88. package/rules/js/js/package-json.mdc +31 -0
  89. package/rules/js/js/tests.mdc +9 -0
  90. package/rules/js/js/utils-lib-structure.mdc +15 -0
  91. package/rules/js/main.mdc +19 -211
  92. package/rules/js/policy/jscpd/jscpd.mdc +14 -0
  93. package/rules/js/policy/lint_js_yml/lint_js_yml.mdc +14 -0
  94. package/rules/js/policy/package_json/package_json.mdc +15 -0
  95. package/rules/js/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  96. package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
  97. package/rules/js-bun-db/js/connection.mdc +42 -0
  98. package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
  99. package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
  100. package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
  101. package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
  102. package/rules/js-bun-db/js/query-safety.mdc +117 -0
  103. package/rules/js-bun-db/js/sql-array.mdc +88 -0
  104. package/rules/js-bun-db/js/unsafe.mdc +65 -0
  105. package/rules/js-bun-db/main.mdc +12 -607
  106. package/rules/js-bun-db/policy/package_json/package_json.mdc +17 -0
  107. package/rules/js-bun-redis/js/imports.mdc +47 -0
  108. package/rules/js-bun-redis/js/package_json.mdc +44 -0
  109. package/rules/js-bun-redis/main.mdc +4 -10
  110. package/rules/js-bun-redis/policy/package_json/package_json.mdc +11 -0
  111. package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
  112. package/rules/js-mssql/js/mssql-pool.mdc +56 -0
  113. package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
  114. package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
  115. package/rules/js-mssql/js/mssql-version.mdc +7 -0
  116. package/rules/js-mssql/main.mdc +10 -198
  117. package/rules/js-mssql/policy/package_json/package_json.mdc +9 -0
  118. package/rules/js-run/js/check-env.mdc +35 -0
  119. package/rules/js-run/js/conn-aliases.mdc +109 -0
  120. package/rules/js-run/js/jsconfig.mdc +20 -0
  121. package/rules/js-run/js/otel-configmap.mdc +6 -0
  122. package/rules/js-run/js/pino.mdc +6 -0
  123. package/rules/js-run/js/project-structure.mdc +11 -0
  124. package/rules/js-run/js/runtime.mdc +14 -0
  125. package/rules/js-run/js/scope.mdc +11 -0
  126. package/rules/js-run/js/settimeout.mdc +11 -0
  127. package/rules/js-run/js/temporal.mdc +5 -0
  128. package/rules/js-run/main.mdc +16 -216
  129. package/rules/js-run/policy/configmap/configmap.mdc +31 -0
  130. package/rules/js-run/policy/jsconfig/jsconfig.mdc +25 -0
  131. package/rules/js-run/policy/package_json/package_json.mdc +38 -0
  132. package/rules/k8s/js/configmap.mdc +41 -0
  133. package/rules/k8s/js/deployment_resources.mdc +49 -0
  134. package/rules/k8s/js/hasura_httproute.mdc +91 -0
  135. package/rules/k8s/js/hpa_apiversion.mdc +27 -0
  136. package/rules/k8s/js/ingress_gateway.mdc +16 -0
  137. package/rules/k8s/js/kustomize_structure.mdc +144 -0
  138. package/rules/k8s/js/lint_k8s.mdc +72 -0
  139. package/rules/k8s/js/multidoc_yaml.mdc +5 -0
  140. package/rules/k8s/js/network_policy.mdc +136 -0
  141. package/rules/k8s/js/schema_modeline.mdc +57 -0
  142. package/rules/k8s/js/service.mdc +44 -0
  143. package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
  144. package/rules/k8s/main.mdc +29 -834
  145. package/rules/k8s/policy/base_kustomization/base_kustomization.mdc +12 -0
  146. package/rules/k8s/policy/base_manifest/base_manifest.mdc +14 -0
  147. package/rules/k8s/policy/gateway/gateway.mdc +17 -0
  148. package/rules/k8s/policy/hasura_configmap/hasura_configmap.mdc +20 -0
  149. package/rules/k8s/policy/hasura_httproute/hasura_httproute.mdc +16 -0
  150. package/rules/k8s/policy/hpa_pdb/hpa_pdb.mdc +23 -0
  151. package/rules/k8s/policy/kustomization/kustomization.mdc +20 -0
  152. package/rules/k8s/policy/manifest/manifest.mdc +17 -0
  153. package/rules/k8s/policy/network_policy/network_policy.mdc +22 -0
  154. package/rules/k8s/policy/svc_hl_yaml/svc_hl_yaml.mdc +13 -0
  155. package/rules/k8s/policy/svc_yaml/svc_yaml.mdc +12 -0
  156. package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
  157. package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
  158. package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
  159. package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
  160. package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
  161. package/rules/nginx-default-tpl/main.mdc +8 -110
  162. package/rules/nginx-default-tpl/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  163. package/rules/nginx-default-tpl/policy/vscode_settings/vscode_settings.mdc +15 -0
  164. package/rules/npm-module/js/docs/index.md +5 -5
  165. package/rules/npm-module/js/docs/rule_meta.md +6 -6
  166. package/rules/npm-module/js/docs/skill_meta.md +8 -8
  167. package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
  168. package/rules/npm-module/js/package_structure.mdc +62 -0
  169. package/rules/npm-module/js/rule_meta.mdc +11 -0
  170. package/rules/npm-module/js/skill_meta.mdc +11 -0
  171. package/rules/npm-module/main.mdc +10 -52
  172. package/rules/npm-module/policy/emit_types_config/emit_types_config.mdc +40 -0
  173. package/rules/npm-module/policy/npm_package_json/npm_package_json.mdc +50 -0
  174. package/rules/npm-module/policy/root_package_json/root_package_json.mdc +37 -0
  175. package/rules/php/js/lint_php_yml.mdc +12 -0
  176. package/rules/php/js/tooling.mdc +66 -0
  177. package/rules/php/main.mdc +5 -66
  178. package/rules/php/policy/lint_php_yml/lint_php_yml.mdc +21 -0
  179. package/rules/python/js/lint_python_yml.mdc +23 -0
  180. package/rules/python/js/pyproject_toml.mdc +32 -0
  181. package/rules/python/js/tooling.mdc +23 -0
  182. package/rules/python/main.mdc +7 -32
  183. package/rules/python/policy/lint_python_yml/lint_python_yml.mdc +12 -0
  184. package/rules/python/policy/pyproject_toml/pyproject_toml.mdc +13 -0
  185. package/rules/rego/js/rego-lint.mdc +31 -0
  186. package/rules/rego/js/vscode_extensions.mdc +11 -0
  187. package/rules/rego/js/vscode_settings.mdc +13 -0
  188. package/rules/rego/main.mdc +10 -22
  189. package/rules/rego/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  190. package/rules/rego/policy/vscode_settings/vscode_settings.mdc +19 -0
  191. package/rules/rust/js/coverage.mdc +28 -0
  192. package/rules/rust/js/lint.mdc +22 -0
  193. package/rules/rust/js/tauri_composition.mdc +8 -0
  194. package/rules/rust/js/vscode_extensions.mdc +12 -0
  195. package/rules/rust/main.mdc +8 -38
  196. package/rules/rust/policy/lint_rust_yml/lint_rust_yml.mdc +12 -0
  197. package/rules/rust/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  198. package/rules/security/js/rego_policies.mdc +15 -0
  199. package/rules/security/js/sample_secret.mdc +19 -0
  200. package/rules/security/js/trufflehog.mdc +21 -0
  201. package/rules/security/main.mdc +7 -34
  202. package/rules/security/policy/lint_security_yml/lint_security_yml.mdc +7 -0
  203. package/rules/security/policy/package_json/package_json.mdc +7 -0
  204. package/rules/style/js/admin-table.mdc +88 -0
  205. package/rules/style/js/colors.mdc +21 -0
  206. package/rules/style/js/gap.mdc +22 -0
  207. package/rules/style/js/quasar-fixes.mdc +32 -0
  208. package/rules/style/js/quasar.mdc +7 -0
  209. package/rules/style/js/tooling.mdc +85 -0
  210. package/rules/style/main.mdc +12 -251
  211. package/rules/style/policy/lint_style_yml/lint_style_yml.mdc +13 -0
  212. package/rules/style/policy/package_json/package_json.mdc +18 -0
  213. package/rules/style/policy/vscode_extensions/vscode_extensions.mdc +13 -0
  214. package/rules/style/policy/vscode_settings/vscode_settings.mdc +19 -0
  215. package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
  216. package/rules/tauri/js/tool_surface.mdc +21 -0
  217. package/rules/tauri/js/tooling.mdc +25 -0
  218. package/rules/tauri/main.mdc +6 -78
  219. package/rules/tauri/policy/vscode_extensions/vscode_extensions.mdc +21 -0
  220. package/rules/test/js/cargo_mutants_config.mdc +18 -0
  221. package/rules/test/js/docs/index.md +7 -7
  222. package/rules/test/js/location.mdc +52 -0
  223. package/rules/test/js/no-console-store-restore.mdc +11 -0
  224. package/rules/test/js/no-process-chdir.mdc +15 -0
  225. package/rules/test/js/no-relative-fs-path.mdc +22 -0
  226. package/rules/test/js/sandbox-aware-test.mdc +28 -0
  227. package/rules/test/js/stryker_config.mdc +26 -0
  228. package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
  229. package/rules/test/main.mdc +16 -184
  230. package/rules/test/policy/package_json/package_json.mdc +16 -0
  231. package/rules/text/js/ci-lint-text.mdc +15 -0
  232. package/rules/text/js/cspell.mdc +81 -0
  233. package/rules/text/js/dotenv-linter.mdc +16 -0
  234. package/rules/text/js/forbidden-prettier.mdc +13 -0
  235. package/rules/text/js/markdownlint.mdc +25 -0
  236. package/rules/text/js/oxfmt.mdc +35 -0
  237. package/rules/text/js/package-json.mdc +26 -0
  238. package/rules/text/js/shellcheck.mdc +18 -0
  239. package/rules/text/js/v8r.mdc +23 -0
  240. package/rules/text/js/vscode.mdc +86 -0
  241. package/rules/text/main.mdc +20 -231
  242. package/rules/text/policy/cspell/cspell.mdc +34 -0
  243. package/rules/text/policy/lint_text/lint_text.mdc +19 -0
  244. package/rules/text/policy/markdownlint/markdownlint.mdc +38 -0
  245. package/rules/text/policy/oxfmtrc/oxfmtrc.mdc +11 -0
  246. package/rules/text/policy/package_json/package_json.mdc +33 -0
  247. package/rules/text/policy/vscode_extensions/vscode_extensions.mdc +13 -0
  248. package/rules/text/policy/vscode_settings/vscode_settings.mdc +13 -0
  249. package/rules/vue/js/composition-api.mdc +82 -0
  250. package/rules/vue/js/nheader-layout.mdc +171 -0
  251. package/rules/vue/js/node-imports.mdc +25 -0
  252. package/rules/vue/js/quasar-ui.mdc +32 -0
  253. package/rules/vue/js/structure.mdc +101 -0
  254. package/rules/vue/js/testing.mdc +32 -0
  255. package/rules/vue/js/tfm-translations.mdc +26 -0
  256. package/rules/vue/js/vite-config.mdc +126 -0
  257. package/rules/vue/js/vite-env.mdc +55 -0
  258. package/rules/vue/js/vue-imports.mdc +25 -0
  259. package/rules/vue/main.mdc +15 -641
  260. package/rules/vue/policy/package_json/package_json.mdc +30 -0
  261. package/scripts/docs/index.md +16 -16
  262. package/scripts/lib/docs/index.md +36 -36
  263. package/scripts/utils/docs/index.md +14 -14
@@ -0,0 +1,49 @@
1
+ ## Deployment: `resources.requests` (CPU і memory)
2
+
3
+ У кожному контейнері **`Deployment`** обов'язкові **`resources.requests.cpu`** і **`resources.requests.memory`** (непорожні скаляри Kubernetes Quantity).
4
+
5
+ ### Шар **`…/k8s/…/base/…`** (dev / щільний packing)
6
+
7
+ У **всіх** `Deployment` у файлах під **`…/k8s/…/base/…`** значення **жорстко фіксовані** (для **cpu** допускається число **`0.02`** у YAML):
8
+
9
+ ```yaml
10
+ resources:
11
+ requests:
12
+ cpu: '0.02'
13
+ memory: '128Mi'
14
+ ```
15
+
16
+ **HPA і PDB у base не тримаємо**: ні локальних `hpa.yaml` / `pdb.yaml` поруч із workload-manifest-файлами, ні через `resources` / `components` / `bases`. Канон — sibling каталог **`components/`** (Kustomize Component) поруч з `base/`, який підключають лише прод-overlays. **NetworkPolicy** — навпаки: **обов'язковий і у `base/`**, у вигляді `base/networkpolicy.yaml` підключений через `base/kustomization.yaml` `resources:`.
17
+
18
+ ### Поза base (оверлеї, окремі каталоги)
19
+
20
+ Якщо ще не підібрано власні ліміти під сервіс, орієнтир для **`requests`**:
21
+
22
+ ```yaml
23
+ resources:
24
+ requests:
25
+ cpu: '0.5'
26
+ memory: '512Mi'
27
+ ```
28
+
29
+ У прод-оверлеях підіймай **`cpu` / `memory`** до реального споживання через **`patches`**. **`check k8s`** не вимагає саме **`0.5` / `512Mi`** поза base — лише непорожні **`requests.cpu`** і **`requests.memory`**.
30
+
31
+ ```yaml title="k8s/prod/kustomization.yaml (фрагмент)"
32
+ patches:
33
+ - target:
34
+ kind: Deployment
35
+ name: backend-api
36
+ patch: |-
37
+ - op: replace
38
+ path: /spec/template/spec/containers/0/resources/requests/cpu
39
+ value: '500m'
40
+ - op: replace
41
+ path: /spec/template/spec/containers/0/resources/requests/memory
42
+ value: 1Gi
43
+ ```
44
+
45
+ ### Образ `hasura/graphql-engine`
46
+
47
+ Образ **`hasura/graphql-engine`**: дозволений лише канонічний тег зі списку **`allowed_hasura_images`** у rego-пакеті **`k8s.manifest`** (`policy/manifest/manifest.rego` — єдине джерело істини; допускається префікс **`docker.io/`**); решта — помилка **check k8s**.
48
+
49
+ Поле **`imagePullPolicy`** скрипт **не** перевіряє.
@@ -0,0 +1,91 @@
1
+ ## HTTPRoute для Deployment з `hasura/graphql-engine`
2
+
3
+ **Прив'язка:** **check k8s** вважає **HTTPRoute** Hasura-маршрутом, якщо в **тому самому каталозі** є **`Deployment`** з образом **`hasura/graphql-engine`**, а його **`metadata.name`** збігається з **`metadata.name`** цього **`HTTPRoute`**.
4
+
5
+ **Префікс параметризовано:** **`<prefix>`** — рядок перед **`/ql`** у першому Hasura-правилі (**`Exact <prefix>/ql`**). Може бути порожнім (**`<prefix>`** = **``**, шлях **`/ql`**) або непорожнім (наприклад **`<prefix>`** = **`/notify`**, шлях **`/notify/ql`**). Усі інші Hasura-правила цього **HTTPRoute** мають містити той самий **`<prefix>`**.
6
+
7
+ **Канон — 4 правила у цьому порядку** (додаткові правила поверх канону дозволені):
8
+
9
+ 1. **`Exact <prefix>/ql`** → **`RequestRedirect`** **`ReplaceFullPath <prefix>/ql/console`** **`statusCode: 302`**.
10
+ 2. **`Exact <prefix>/ql/`** → те саме (редирект на **`<prefix>/ql/console`** 302).
11
+ 3. **`PathPrefix <prefix>/ql`** → **`URLRewrite`** **`ReplacePrefixMatch /`**, один **`backendRef`** на headless **Service** (**`-hl`**).
12
+ 4. **WebSocket:** **`PathPrefix <prefix>/ql`** + header **`Upgrade: websocket`** → **`URLRewrite`** **`ReplacePrefixMatch /`** + **`RequestHeaderModifier`** **`remove: [Authorization]`** (авторизація для WebSocket іде всередині messages). Той самий **`backendRef`**.
13
+
14
+ **`parentRefs`**, **`hostnames`**, **`metadata.namespace`** / **`name`** підлаштуй під середовище. У **`backendRefs.name`** вказуй **headless** **Service** з суфіксом **`-hl`**; у прикладі **`db-h-hl`** заміни на фактичне ім'я.
15
+
16
+ ```yaml
17
+ # yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/gateway.networking.k8s.io/httproute_v1beta1.json
18
+ apiVersion: gateway.networking.k8s.io/v1
19
+ kind: HTTPRoute
20
+ metadata:
21
+ name: db-h
22
+ namespace: dev
23
+ spec:
24
+ parentRefs:
25
+ - group: gateway.networking.k8s.io
26
+ kind: Gateway
27
+ name: gw
28
+ namespace: dev
29
+ sectionName: https
30
+ hostnames:
31
+ - aiml.live
32
+ rules:
33
+ - matches:
34
+ - path:
35
+ type: Exact
36
+ value: /ql
37
+ filters:
38
+ - type: RequestRedirect
39
+ requestRedirect:
40
+ path:
41
+ type: ReplaceFullPath
42
+ replaceFullPath: /ql/console
43
+ statusCode: 302
44
+ - matches:
45
+ - path:
46
+ type: Exact
47
+ value: /ql/
48
+ filters:
49
+ - type: RequestRedirect
50
+ requestRedirect:
51
+ path:
52
+ type: ReplaceFullPath
53
+ replaceFullPath: /ql/console
54
+ statusCode: 302
55
+ - matches:
56
+ - path:
57
+ type: PathPrefix
58
+ value: /ql
59
+ filters:
60
+ - type: URLRewrite
61
+ urlRewrite:
62
+ path:
63
+ type: ReplacePrefixMatch
64
+ replacePrefixMatch: /
65
+ backendRefs:
66
+ - name: db-h-hl
67
+ port: 8080
68
+ # у websocket авторизація йде всередині messages
69
+ # Той самий URLRewrite, що й для HTTP: інакше бекенд бачить /ql/v1/graphql замість /v1/graphql
70
+ - matches:
71
+ - path:
72
+ type: PathPrefix
73
+ value: /ql
74
+ headers:
75
+ - type: Exact
76
+ name: Upgrade
77
+ value: websocket
78
+ filters:
79
+ - type: URLRewrite
80
+ urlRewrite:
81
+ path:
82
+ type: ReplacePrefixMatch
83
+ replacePrefixMatch: /
84
+ - type: RequestHeaderModifier
85
+ requestHeaderModifier:
86
+ remove:
87
+ - Authorization
88
+ backendRefs:
89
+ - name: db-h-hl
90
+ port: 8080
91
+ ```
@@ -0,0 +1,27 @@
1
+ ## HorizontalPodAutoscaler: `autoscaling/v2`
2
+
3
+ У manifest-файлах під **`k8s`** заборонено **`apiVersion: autoscaling/v1`** (legacy HPA з єдиною метрикою CPU). Мігруй **HorizontalPodAutoscaler** на **`autoscaling/v2`**: поле **`spec.metrics`** (замість **`spec.targetCPUUtilizationPercentage`**) з **`type: Resource`** і **`target.type: Utilization`** / **`AverageUtilization`**. `check k8s` падає на будь-якому документі з **`apiVersion: autoscaling/v1`**.
4
+
5
+ Ресурси **batch** (наприклад **CronJob**, **Job**): застаріле **`apiVersion: batch/v1beta1`** у файлах під **`k8s`** під час `check k8s` переписується на **`apiVersion: batch/v1`**.
6
+
7
+ ```yaml
8
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/horizontalpodautoscaler-autoscaling-v2.json
9
+ apiVersion: autoscaling/v2
10
+ kind: HorizontalPodAutoscaler
11
+ metadata:
12
+ name: app
13
+ spec:
14
+ scaleTargetRef:
15
+ apiVersion: apps/v1
16
+ kind: Deployment
17
+ name: app
18
+ minReplicas: 1
19
+ maxReplicas: 5
20
+ metrics:
21
+ - type: Resource
22
+ resource:
23
+ name: cpu
24
+ target:
25
+ type: Utilization
26
+ averageUtilization: 70
27
+ ```
@@ -0,0 +1,16 @@
1
+ ## Ingress → Gateway API (GKE)
2
+
3
+ Якщо в дереві **`k8s`** трапляється маніфест з **`kind: Ingress`**, його потрібно **замінити на Gateway API**, а не залишати Ingress. **`check k8s`:** заборонено **`kind: Ingress`**.
4
+
5
+ 1. **HTTPRoute** — окремий файл **`hr.yaml`** (або узгоджене ім'я в команді), **`kind: HTTPRoute`**, `apiVersion` з групи **`gateway.networking.k8s.io`**.
6
+
7
+ 2. **HealthCheckPolicy (GKE)** — окремий файл **`hc.yaml`**:
8
+
9
+ ```yaml
10
+ apiVersion: networking.gke.io/v1
11
+ kind: HealthCheckPolicy
12
+ ```
13
+
14
+ Для `$schema` у першому рядку — приклад **HealthCheckPolicy** у розділі «Визначення схеми YAML» (datree CRDs-catalog).
15
+
16
+ **`spec.targetRef`** (типово **`kind: Service`**) має вказувати на **headless** сервіс — ім'я з суфіксом **`-hl`** (div. **«Service: `svc.yaml` і `svc-hl.yaml`»**).
@@ -0,0 +1,144 @@
1
+ ## Kustomize: структура каталогів (`base` / overlays)
2
+
3
+ Трансформуй дерева **`**/k8s`**, щоб **винести спільне** через [Kustomize](https://kustomize.io/): один канонічний **`base`** і тонкі **overlays** для інших середовищ.
4
+
5
+ ### Джерело правди — середовище dev
6
+
7
+ - За основу бери **все, що відповідає середовищу dev** (як воно має виглядати в кластері для dev).
8
+ - У **такому вигляді** цей набір стає каталогом **`base`**: спільні маніфести без окремої директорії **`dev/`**.
9
+ - Окремої директорії **`dev`** **не повинно існувати**: за середовище **dev** відповідає **`base`**.
10
+
11
+ ### Overlays (не-dev)
12
+
13
+ - У каталозі кожного іншого середовища (наприклад **`ua/`**, **`prod/`**) — мінімум файлів: типово лише **`kustomization.yaml`** і ресурси, **необхідні лише для цього overlay**.
14
+ - Відмінності від dev вносяться **оверрайдами** (patches, `images`, `replicas`, `configMapGenerator` тощо), а не копіюванням повного дерева з `base`.
15
+
16
+ ### Namespace
17
+
18
+ - **`base/kustomization.yaml`:** поле **`namespace:`** має бути **непорожнім** (перевіряє **check k8s**).
19
+ - **Коли `metadata.namespace` обов'язковий у файлі:** YAML під **`k8s`** — непорожній **`metadata.namespace`** для namespaced **kind** (винятки — кластерні **kind**, перелік **`CLUSTER_SCOPED_KINDS`** у **`rules/k8s/fix.mjs`**).
20
+ - **Не додавай** окремі **patches** Kustomize, які лише змінюють **namespace**.
21
+
22
+ ### Рядки, що змінюються між середовищами
23
+
24
+ У manifest-файлах у **`base`** для полів, які **будуть відрізнятися** в інших середовищах, на **тому самому рядку** додай коментар:
25
+
26
+ ```yaml
27
+ image: my-app:dev-tag # буде замінено через kustomize
28
+ ```
29
+
30
+ ### Зміна image — через `images:`, не через `patches[]`
31
+
32
+ Підміну image у Pod-шаблоні Deployment в overlay роби директивою `images:`, а не JSON6902-патчем `op: replace` на `/spec/template/spec/containers/<N>/image`.
33
+
34
+ - У **`name`** — те, що **дослівно** стоїть у `image:` у base **без тегу**.
35
+ - **`newName`** — кінцеве ім'я образу; **`newTag`** — тег для прода.
36
+ - **`digest`** (`@sha256:…`) у `name` / `newName` не чіпай.
37
+
38
+ ```yaml title="k8s/prod/kustomization.yaml (фрагмент)"
39
+ images:
40
+ - name: europe-west4-docker.pkg.dev/abie-ua/c/apply-on-invoice-discount
41
+ newName: europe-west4-docker.pkg.dev/abie-ua/c/apply-on-invoice-discount
42
+ newTag: v2025-04-29
43
+ ```
44
+
45
+ **`check k8s` автоматично** для кожного `kustomization.yaml`:
46
+
47
+ 1. конвертує кожну JSON6902-операцію `op: replace` на `/spec/template/spec/containers/<N>/image` у запис `images:`;
48
+ 2. чистить існуючий блок `images:` — зрізає `:tag` з `name` і видаляє `newTag`, який збігається з відрізаним тегом.
49
+
50
+ ### Міграція зі старої структури
51
+
52
+ Після перенесення у **`base`** та overlays і перевірки (**`check k8s`**, **`lint-k8s`**) **видали** застарілі файли та директорії, що замінені новою схемою.
53
+
54
+ ### `patches[].target`: лише `kind` і `name`
55
+
56
+ У `patches[].target` залишай **тільки** **`kind`** і **`name`** — поля **`group`** і **`version`** прибирай.
57
+
58
+ ```yaml
59
+ # ❌ зайві group / version
60
+ patches:
61
+ - target:
62
+ group: gateway.networking.k8s.io
63
+ version: v1beta1
64
+ kind: Gateway
65
+ name: gw
66
+
67
+ # ✅
68
+ patches:
69
+ - target:
70
+ kind: Gateway
71
+ name: gw
72
+ ```
73
+
74
+ **Виняток:** залишай `group` / `version`, лише якщо в дереві overlay реально співіснують ресурси з однаковими `kind`+`name`, але різними API-групами/версіями.
75
+
76
+ ### Структурний сорт `patches[]` і inline JSON6902
77
+
78
+ `patches[]` у `kustomization.yaml` має бути відсортовано за tuple **`target.kind` → `target.name` → `target.namespace` → `path`** (`localeCompare('en', { sensitivity: 'base' })`).
79
+
80
+ ```yaml
81
+ # ❌ atlas йде перед apruv
82
+ patches:
83
+ - target:
84
+ kind: ReferenceGrant
85
+ name: atlas-to-base
86
+ - target:
87
+ kind: ReferenceGrant
88
+ name: apruv-to-base
89
+
90
+ # ✅
91
+ patches:
92
+ - target:
93
+ kind: ReferenceGrant
94
+ name: apruv-to-base
95
+ - target:
96
+ kind: ReferenceGrant
97
+ name: atlas-to-base
98
+ ```
99
+
100
+ Усередині кожного inline `patches[i].patch` операції теж сортуються за **`path`**, **але лише** коли набір «безпечний»: усі ops — `add` / `replace` і всі `path` попарно дизʼюнктні. Інакше порядок не чіпається.
101
+
102
+ ```yaml
103
+ # ❌ minReplicas перед maxReplicas (за алфавітом max < min)
104
+ patch: |-
105
+ - op: add
106
+ path: /spec/minReplicas
107
+ value: 2
108
+ - op: replace
109
+ path: /spec/maxReplicas
110
+ value: 10
111
+
112
+ # ✅
113
+ patch: |-
114
+ - op: replace
115
+ path: /spec/maxReplicas
116
+ value: 10
117
+ - op: add
118
+ path: /spec/minReplicas
119
+ value: 2
120
+ ```
121
+
122
+ ### Порядок `resources`
123
+
124
+ Елементи **`resources:`** (лише непорожні рядки) мають бути **відсортовані за алфавітом (англ. локаль, як `localeCompare('en')` у `rules/k8s/fix.mjs`)**. Поля **`bases`**, **`components`**, **`crds`** цією перевіркою **не** впорядковуються.
125
+
126
+ ### Локальні шляхи в `kustomization.yaml`
127
+
128
+ Кожен запис без `://` (remote) з `resources` / `bases` / `components` / `crds`, `patchesStrategicMerge`, `patches[].path`, `patchesJson6902[].path`, `configurations[]`, `replacements[].path` має вказувати на **існуючий** у репозиторії файл (`.yaml` / `.yml`) або **каталог**; биті посилання — помилка **`check k8s`**.
129
+
130
+ ### JSON patch у kustomization: `op: replace`
131
+
132
+ Де можливо, змінюй ресурс через **`op: replace`** (одна операція на `path`), а не пару **`remove` + `add`** на той самий шлях.
133
+
134
+ ```yaml title="overlay/kustomization.yaml (фрагмент)"
135
+ patches:
136
+ - target:
137
+ kind: Deployment
138
+ name: x
139
+ patch: |-
140
+ - op: replace
141
+ path: /spec/template/spec/nodeSelector
142
+ value:
143
+ preem: "false"
144
+ ```
@@ -0,0 +1,72 @@
1
+ ## lint-k8s: kubeconform і kubescape
2
+
3
+ Окремо від modeline `$schema` у редакторі варто ганяти CLI-лінтери (**kubeconform** і **kubescape**) по тих самих деревах **`…/k8s`**.
4
+
5
+ **Залежності:** виконувані файли kubeconform, kubescape і kubectl у **PATH** (kustomize використовуємо як вшиту підкоманду **`kubectl kustomize`** — окремий бінарник `kustomize` не потрібен); не додавай їх у **devDependencies**.
6
+
7
+ **Версія Kubernetes для kubeconform** — **`-kubernetes-version 1.33.9`** (semver без префікса `v`; набір схем **`v1.33.9-standalone-strict`**). Для CRD додатково підключай реєстр [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog) другим **`-schema-location`**. За потреби **`-ignore-missing-schemas`**.
8
+
9
+ **kubescape** — вхід через зібраний kustomize-маніфест: для кожного dir-у з `kustomization.yaml` (`kind: Kustomization`; **`kind: Component`** пропускається) `lint-k8s` виконує **`kubectl kustomize <dir>`** і передає stdout у **`kubescape scan <tmp-file>`** з порогом **`--severity-threshold high`**. Маніфест проходить через тимчасовий файл, бо **`kubescape scan` у v4.x не читає stdin**. Якщо в дереві **`…/k8s`** немає жодного `kustomization.yaml` — fallback на dir-скан **`kubescape scan <каталог-k8s>`**. У kubescape немає прапорця **`-kubernetes-version`**.
10
+
11
+ Лінт запускається через правило **`n-cursor lint k8s`** (реалізація — **`npm/rules/k8s/js/lint.mjs`**). Окремий `package.json`-скрипт `lint-k8s` не потрібен.
12
+
13
+ ### Винятки kubescape: `.kubescape-exceptions.json`
14
+
15
+ Якщо в **корені проєкту** є файл **`.kubescape-exceptions.json`** — `lint-k8s` автоматично передає його в `kubescape scan` через **`--exceptions`** ([postureExceptionPolicy](https://github.com/kubescape/kubescape/blob/master/docs/exceptions.md)).
16
+
17
+ Канонічний кейс — **C-0012** (`Applications credentials in configuration files`, High): control тригериться на **ім'я** env, що містить підрядок `secret`/`password`/`key`/`token`, а **не** на значення. Точкове виключення для ConfigMap із цим env: [.kubescape-exceptions.json.snippet.json](./templates/kubescape_exceptions/.kubescape-exceptions.json.snippet.json)
18
+
19
+ Виключай контрольно, а не глобально (не додавай винятки без `attributes.name`/`labels`).
20
+
21
+ ### GitHub Actions: `lint-k8s.yml`
22
+
23
+ Додай workflow **`.github/workflows/lint-k8s.yml`** (гілки **`dev`** і **`main`**, лише **`.yml`**). Після **`checkout`** використовуй локальний composite **`setup-bun-deps`**. Встановлення kubeconform / kubescape — окремі кроки. kustomize не встановлюємо окремо — `kubectl kustomize` вже на github-hosted runner'ах.
24
+
25
+ ```yaml title=".github/workflows/lint-k8s.yml"
26
+ name: Lint K8s
27
+
28
+ on:
29
+ push:
30
+ branches:
31
+ - dev
32
+ - main
33
+ paths:
34
+ - '**/k8s/**/*.yaml'
35
+
36
+ pull_request:
37
+ branches:
38
+ - dev
39
+ - main
40
+
41
+ concurrency:
42
+ group: ${{ github.ref }}-${{ github.workflow }}
43
+ cancel-in-progress: true
44
+
45
+ jobs:
46
+ lint-k8s:
47
+ runs-on: ubuntu-latest
48
+ permissions:
49
+ contents: read
50
+ steps:
51
+ - uses: actions/checkout@v6
52
+ with:
53
+ persist-credentials: false
54
+
55
+ - uses: ./.github/actions/setup-bun-deps
56
+
57
+ - name: Install kubeconform
58
+ run: |
59
+ curl -sSL "https://github.com/yannh/kubeconform/releases/download/v0.7.0/kubeconform-linux-amd64.tar.gz" | tar xz
60
+ sudo mv kubeconform /usr/local/bin/
61
+
62
+ - name: Install kubescape
63
+ run: |
64
+ curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
65
+ echo "$HOME/.kubescape/bin" >> $GITHUB_PATH
66
+
67
+ # kustomize не встановлюємо окремо — використовуємо вбудовану підкоманду `kubectl kustomize`
68
+ # (kubectl уже доступний на github-hosted runner'ах: https://github.com/actions/runner-images).
69
+
70
+ - name: Lint K8s
71
+ run: n-cursor lint k8s --read-only
72
+ ```
@@ -0,0 +1,5 @@
1
+ ## Багатодокументні YAML
2
+
3
+ Одна схема на файл; скрипт звіряє **перший** документ (до наступного `---`). Інші `kind` у тому ж файлі — розділи файли або узгодь у рев'ю.
4
+
5
+ **Розширення:** усі маніфести під **`k8s`**, включно з **`kustomization.yaml`**, — лише **`.yaml`** (розширення **`.yml`** не використовуй).
@@ -0,0 +1,136 @@
1
+ ## NetworkPolicy: канон egress/ingress
2
+
3
+ Для **кожного** workload (**Deployment**, **StatefulSet**, **DaemonSet**, **Job**, **CronJob**) під `k8s` обов'язковий **NetworkPolicy** у **`base/networkpolicy.yaml`** поруч з workload-маніфестом (multi-doc через `---`, якщо workload-ів кілька). `metadata.name` NetworkPolicy **= `metadata.name`** workload; `spec.podSelector.matchLabels.app` **= мітка `app`** з `spec.selector.matchLabels` workload. Відсутні документи **`check k8s`** створює автоматично і додає `networkpolicy.yaml` у `base/kustomization.yaml` `resources:`.
4
+
5
+ Два **повних** snippet-файли (JS-генератор/rego обирають один за `kind` workload-у через анотацію `metadata.annotations['nitra.dev/workload-kind']`):
6
+ - [deployment.snippet.yaml](./policy/network_policy/template/deployment.snippet.yaml) — для `Deployment`/`Job`/`CronJob`/`DaemonSet`
7
+ - [stateful-set.snippet.yaml](./policy/network_policy/template/stateful-set.snippet.yaml) — для `StatefulSet` (містить deployment-канон + intra-replica правила)
8
+
9
+ ### Канонічний `base/networkpolicy.yaml`
10
+
11
+ `networking.k8s.io/v1`, `NetworkPolicy`, **без** `metadata.namespace` (namespace додає `base/kustomization.yaml`).
12
+
13
+ **Ingress:** `from.podSelector: {}` (інші Pod у namespace).
14
+
15
+ **Egress (усі workload-и):**
16
+ - kube-dns через `kube-system` namespaceSelector (UDP/TCP 53);
17
+ - link-local DNS `169.254.0.0/16` (UDP/TCP 53, GKE NodeLocal DNSCache);
18
+ - **TCP 80 і 443** на `0.0.0.0/0` (HTTP/HTTPS назовні);
19
+ - **in-cluster** — `to.namespaceSelector: {}` з **явним списком TCP-портів** (`80, 443, 5432, 3306, 1433, 6379, 8080, 4222, 4317, 4318`).
20
+
21
+ **StatefulSet** додатково має egress/ingress `to/from.podSelector: {}` для intra-replica реплікації.
22
+
23
+ Заборонено: `egress: [{}]`; `to.namespaceSelector: {}` без `ports:` (catch-all).
24
+
25
+ ```yaml title="k8s/base/networkpolicy.yaml"
26
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/networkpolicy-networking-v1.json
27
+ apiVersion: networking.k8s.io/v1
28
+ kind: NetworkPolicy
29
+ metadata:
30
+ name: backend-api
31
+ annotations:
32
+ nitra.dev/workload-kind: Deployment
33
+ spec:
34
+ podSelector:
35
+ matchLabels:
36
+ app: backend-api
37
+ policyTypes:
38
+ - Ingress
39
+ - Egress
40
+ ingress:
41
+ - from:
42
+ - podSelector: {}
43
+ egress:
44
+ - to:
45
+ - namespaceSelector:
46
+ matchLabels:
47
+ kubernetes.io/metadata.name: kube-system
48
+ podSelector:
49
+ matchLabels:
50
+ k8s-app: kube-dns
51
+ ports:
52
+ - protocol: UDP
53
+ port: 53
54
+ - protocol: TCP
55
+ port: 53
56
+ - to:
57
+ - ipBlock:
58
+ cidr: 169.254.0.0/16
59
+ ports:
60
+ - protocol: UDP
61
+ port: 53
62
+ - protocol: TCP
63
+ port: 53
64
+ - to:
65
+ - ipBlock:
66
+ cidr: 0.0.0.0/0
67
+ ports:
68
+ - protocol: TCP
69
+ port: 80
70
+ - protocol: TCP
71
+ port: 443
72
+ - to:
73
+ - namespaceSelector: {}
74
+ ports:
75
+ - protocol: TCP
76
+ port: 80
77
+ - protocol: TCP
78
+ port: 443
79
+ - protocol: TCP
80
+ port: 5432
81
+ - protocol: TCP
82
+ port: 3306
83
+ - protocol: TCP
84
+ port: 1433
85
+ - protocol: TCP
86
+ port: 6379
87
+ - protocol: TCP
88
+ port: 8080
89
+ - protocol: TCP
90
+ port: 4222
91
+ - protocol: TCP
92
+ port: 4317
93
+ - protocol: TCP
94
+ port: 4318
95
+ ```
96
+
97
+ ### HTTPRoute → NetworkPolicy ingress (GCLB + Envoy)
98
+
99
+ Якщо в каталозі workload є **`HTTPRoute`** (Gateway API) з **`backendRef`** на **`<workload>-hl`** Service, **`check k8s`** автоматично додає в NetworkPolicy цього workload **ingress-правило** з фіксованим набором CIDR-ів і **TCP-портами з `backendRefs[].port`** (дедуп, відсортовано за зростанням).
100
+
101
+ Без цього правила трафік від **GKE Gateway** (Envoy proxy-only subnet, наприклад `10.10.0.0/23`) і **Google health checks** блокується базовим NetworkPolicy.
102
+
103
+ CIDR-набір зафіксовано:
104
+ - `35.191.0.0/16` — GCP HC global
105
+ - `130.211.0.0/22` — GCP HC global (legacy)
106
+ - `10.0.0.0/8` — широкий range, покриває proxy-only subnets усіх регіонів GKE
107
+
108
+ ```yaml title="k8s/base/networkpolicy.yaml — workload з HTTPRoute (з GCLB ingress)"
109
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/networkpolicy-networking-v1.json
110
+ apiVersion: networking.k8s.io/v1
111
+ kind: NetworkPolicy
112
+ metadata:
113
+ name: backend-api
114
+ annotations:
115
+ nitra.dev/workload-kind: Deployment
116
+ spec:
117
+ podSelector:
118
+ matchLabels:
119
+ app: backend-api
120
+ policyTypes:
121
+ - Ingress
122
+ - Egress
123
+ ingress:
124
+ - from:
125
+ - podSelector: {}
126
+ - from: # auto-added by check k8s for HTTPRoute-paired workloads
127
+ - ipBlock: { cidr: 35.191.0.0/16 }
128
+ - ipBlock: { cidr: 130.211.0.0/22 }
129
+ - ipBlock: { cidr: 10.0.0.0/8 }
130
+ ports:
131
+ - { protocol: TCP, port: 8080 }
132
+ egress:
133
+ # ... (ідентично до базового прикладу вище)
134
+ ```
135
+
136
+ Алгоритм: функція `collectHttpRouteIngressForWorkload` у **`rules/k8s/js/manifests.mjs`**.
@@ -0,0 +1,57 @@
1
+ ## Визначення схеми YAML (канон `yaml-language-server: $schema`)
2
+
3
+ Для кожного файлу `*.yaml`, у шляху якого є сегмент директорії **`k8s`**, якщо існує **публічна** схема — **перший рядок** — коментар-директива для [YAML Language Server](https://github.com/redhat-developer/yaml-language-server) з URL за `https://`:
4
+
5
+ ```yaml
6
+ # yaml-language-server: $schema=https://...
7
+ ```
8
+
9
+ Далі — вміст маніфесту без зайвого порожнього рядка між коментарем і YAML.
10
+
11
+ **Modeline — опційний:** якщо для конкретного поєднання `apiVersion`/`kind` **немає** надійної публічної схеми (yannh/datree/schemastore не покривають), залиш файл **без** рядка `# yaml-language-server: $schema=…`. **Заборонено** ставити `$schema=file:…` як заглушку.
12
+
13
+ **Виняток — modeline заборонено:** `apiVersion: alb.yc.io/v1alpha1`, `kind: HttpBackendGroup` (Yandex ALB) — рядка **`# yaml-language-server: $schema=…`** у файлі **не** має бути. Перший рядок — одразу YAML (`apiVersion:` тощо). Перевірка — **`rules/k8s/fix.mjs`**.
14
+
15
+ ### Правила визначення URL схеми
16
+
17
+ Орієнтир — **перший документ** (до наступного `---`).
18
+
19
+ 1. **Ім'я** `kustomization.yaml` → `https://json.schemastore.org/kustomization.json`.
20
+
21
+ 2. **`apiVersion: v1`** → yannh, PIN набору схем **`v1.33.9-standalone-strict`**, ref репозиторію для raw URL — **`master`**:
22
+ `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-v1.json`
23
+ `<kind>`: літери в нижньому регістрі без роздільників між CamelCase (наприклад `Service` → `service`).
24
+
25
+ **`kind: Secret`** і **`type: kubernetes.io/basic-auth`** — той самий шаблон, **`secret-v1.json`**:
26
+
27
+ ```yaml
28
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/secret-v1.json
29
+ ```
30
+
31
+ 3. **`apiVersion: group/version`** і **group** у **`YANNH_GROUPS`** у скрипті → yannh:
32
+ `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-<group-частина>-<version>.json`
33
+ де **`<group-частина>`** — **перший сегмент** `group` до першої крапки: для груп без крапок збігається з усією group (`apps/v1` + `Deployment` → `deployment-apps-v1.json`); для `*.k8s.io` / `*.apiserver.k8s.io` — лише префікс до `.k8s.io` (`networking.k8s.io/v1` + `Ingress` → `ingress-networking-v1.json`; `networking.k8s.io/v1` + `NetworkPolicy` → `networkpolicy-networking-v1.json`; `rbac.authorization.k8s.io/v1` + `ClusterRole` → `clusterrole-rbac-v1.json`; `flowcontrol.apiserver.k8s.io/v1` + `FlowSchema` → `flowschema-flowcontrol-v1.json`). У yannh **немає** файлів з фрагментом `-k8s-io-` у назві.
34
+
35
+ 4. **Інакше** (CRD тощо) → [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog). Типово для `$schema` у редакторі — **GitHub Pages**:
36
+ `https://datreeio.github.io/CRDs-catalog/<group>/<kind>_<version>.json`
37
+ (`<kind>` — лише літери та цифри в нижньому регістрі, без роздільників між CamelCase.)
38
+
39
+ **Виняток — `InfisicalSecret`:** `apiVersion: secrets.infisical.com/v1alpha1`, `kind: InfisicalSecret` — канонічний modeline через **raw** на гілці **`main`**:
40
+
41
+ ```yaml
42
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/secrets.infisical.com/infisicalsecret_v1alpha1.json
43
+ ```
44
+
45
+ **Приклад (Gateway API):** `apiVersion: gateway.networking.k8s.io/v1`, `kind: HTTPRoute`:
46
+
47
+ ```yaml
48
+ # yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/gateway.networking.k8s.io/httproute_v1beta1.json
49
+ ```
50
+
51
+ **Приклад (GKE):** `apiVersion: networking.gke.io/v1`, `kind: HealthCheckPolicy`:
52
+
53
+ ```yaml
54
+ # yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json
55
+ ```
56
+
57
+ 5. **Немає надійного публічного URL** — не вигадуй URL і **не** використовуй `$schema=file:…`. Залиш файл **без** рядка `# yaml-language-server: $schema=…` зовсім.
@@ -0,0 +1,44 @@
1
+ ## Service: заборонені анотації GKE
2
+
3
+ У **`kind: Service`** не додавай у **`metadata.annotations`** **`cloud.google.com/neg`** і **`cloud.google.com/backend-config`** (legacy під Ingress / старе балансування GKE). **check k8s** падає, якщо ключ є.
4
+
5
+ ## Service: `svc.yaml` і `svc-hl.yaml` (Gateway API)
6
+
7
+ Пара файлів для кластерного й headless **Service**: **`svc.yaml`** + **`svc-hl.yaml`** в одному каталозі, **`spec.type: ClusterIP`** / **`clusterIP: None`**, імена **`-hl`**, узгодженість пар, маршрути **`gateway.networking.k8s.io`** (**HTTPRoute**, **GRPCRoute**, **TCPRoute**, **TLSRoute**, **UDPRoute**) — **backendRef** лише на сервіси з суфіксом **`-hl`**; якщо **kustomization** посилається на **`svc.yaml`**, у **тому ж** **`kustomization.yaml`** має бути посилання на sibling **`svc-hl.yaml`**. Скрипт **не** створює файли — додай **`svc-hl.yaml`** вручну (копія з правками **name** / **clusterIP**).
8
+
9
+ **Точні умови та повідомлення `fail`** — верхній JSDoc **`npm/scripts/rules/k8s/fix.mjs`**.
10
+
11
+ ### Gateway API: не дублюй namespace у `backendRef`
12
+
13
+ У маршрутах Gateway API (**HTTPRoute**, **GRPCRoute**, **TCPRoute**, **TLSRoute**, **UDPRoute**) у `spec.rules[*].backendRefs[*]` **не** додавай поле **`namespace`**, якщо його значення збігається з **`metadata.namespace`** самого маршруту. **`check k8s`** падає на такому збігу.
14
+
15
+ ```yaml
16
+ # ❌ погано — namespace дублює metadata.namespace маршруту
17
+ apiVersion: gateway.networking.k8s.io/v1
18
+ kind: HTTPRoute
19
+ metadata:
20
+ name: admin-site
21
+ namespace: dev-b2b
22
+ spec:
23
+ rules:
24
+ - backendRefs:
25
+ - name: auth-hl
26
+ namespace: dev-b2b # ← прибери
27
+ port: 8080
28
+ ```
29
+
30
+ ```yaml
31
+ # ✅ добре — namespace лише в metadata
32
+ apiVersion: gateway.networking.k8s.io/v1
33
+ kind: HTTPRoute
34
+ metadata:
35
+ name: admin-site
36
+ namespace: dev-b2b
37
+ spec:
38
+ rules:
39
+ - backendRefs:
40
+ - name: auth-hl
41
+ port: 8080
42
+ ```
43
+
44
+ Якщо backend **дійсно** живе в іншому namespace — поле **`namespace`** у `backendRef` обов'язкове (і потрібен `ReferenceGrant` у тому namespace); правило цього випадку не торкається.