@nitra/cursor 1.9.18 → 1.9.19

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@
4
4
 
5
5
  Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
6
6
 
7
+ ## [1.9.19] - 2026-05-14
8
+
9
+ ### Removed
10
+
11
+ - **`abie.mdc` (`1.19 → 1.20`) — повністю прибрано підтримку `ru`-overlay:** видалено секції «overlay **ru** і nginx-sidecar для WebSocket (Hasura)», «overlay **ru** і **Service** (headless → NodePort)», «overlay **ru** і HealthCheckPolicy»; з секцій «HTTPRoute (ua / ru)», «nodeSelector (overlay)», «env-файли», «Git branches» видалено `ru`-гілку. Залишається лише `dev` + `ua`. Таблиця env-файлів — без `ru.env` / `cluster.local` / YC. У workflow `clean-merged-branch.yml` обов'язкові токени `ignore_branches`: `dev,ua` (раніше `dev,ua,ru`).
12
+ - **`check-abie.mjs` — drop ru-логіки:** видалено всі функції з суфіксом / префіксом `Ru` (`isRuKustomizationPath`, `serviceDocumentRequiresAbieRuNodePortOverlay`, `ensureRuKustomizationHealthCheckDelete`, `ensureRuAbieServiceNodePortPatches`, `ensureAbieNginxSidecarForHasura` + усі допоміжні), regex / константи для `ru` overlay (`PATCH_PARENT_REF_NS_RU_RE`, `WEBSOCKET_ANNOTATION_RE`, `REMOVE_CLUSTER_IP*_RE`, `HASURA_IMAGE_MARKER`, `NGINX_SIDECAR_*`, `ABIE_RU_HTTPROUTE_HOST_MARKERS`, `HASURA_JWT_SECRET_IN_KUSTOMIZATION`). Перейменування: `ensureUaRuAbieNodeSelectorPatches` → `ensureUaAbieNodeSelectorPatches`, `ensureUaRuAbieHttpRoutePatches` → `ensureUaAbieHttpRoutePatches`. Тип `mode` — лише `'ua'`. Файл скоротився з ≈2013 до ≈880 рядків.
13
+ - **`check-k8s.mjs` — drop `ruKustomizationHasHealthCheckDeletePatch`:** export видалено разом з допоміжними regex; решта k8s-логіки без змін.
14
+ - **`check-hasura.mjs` — only `<cluster>.internal`:** `INTERNAL_HASURA_URL_RE` більше не приймає `cluster.local`; повідомлення про помилку згадує лише GKE-формат.
15
+ - **Rego — `abie.clean_merged_ignore_branches`:** `required_branches := {"dev", "ua"}` (раніше `{"dev", "ua", "ru"}`); тести оновлено.
16
+ - **`abie.base_deployment_preem` rego — коментар:** «Overlays (ua/ru)» → «Overlay ua».
17
+ - **`.cspell.json`:** зі списку слів прибрано `napitkivmeste` та `выбирайонлайн` (мову `ru-ru` у `language` залишено для коректного спелл-чеку коментарів/документації).
18
+ - **`k8s.mdc` приклади:** у переліку overlays залишилось `ua/`, `prod/` без `ru/`.
19
+ - **`hasura.mdc` / `tests/check-hasura.test.mjs`:** приклад "неправильного" публічного домену змінено з `napitkivmeste.tech` на `vybeerai.com.ua`.
20
+
21
+ ### Tests
22
+
23
+ - **`tests/check-abie.test.mjs` — переписано (1210 → ≈480 рядків):** видалено всі тести `ru`-overlay (NodePort Service, HealthCheckPolicy delete, nginx-sidecar, websocket annotation, `ru-apruv` env-URL, ru parentRef regex). Залишено dev/ua сценарії.
24
+ - **`tests/check-hasura.test.mjs`:** видалено 2 тести на `cluster.local` / `ru-apruv`.
25
+ - **`tests/check-k8s-schema.test.mjs`:** видалено `describe('ruKustomizationHasHealthCheckDeletePatch')` і `isDevLikeK8sEnvSegment('ru')` assertion.
26
+ - **`tests/check-k8s-images.test.mjs`:** ASCII-збіг `ru: "true"` як ім'я label у фікстурі перейменовано на `preem: "false"`.
27
+
7
28
  ## [1.9.18] - 2026-05-13
8
29
 
9
30
  ### Changed
@@ -8,6 +8,8 @@
8
8
 
9
9
  abie-kustomize - [abie]
10
10
 
11
+ abie-clean - [abie]
12
+
11
13
  fix - завжди
12
14
 
13
15
  llm-patch - завжди
package/mdc/abie.mdc CHANGED
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  description: Правила для проєктів AbInBev Efes
3
3
  alwaysApply: true
4
- version: '1.19'
4
+ version: '1.20'
5
5
  ---
6
6
 
7
- Правило **abie** для споживачів **@nitra/cursor**: **k8s** (Deployment + **HealthCheckPolicy** у **`hc.yaml`**, overlay **ua** / **ru** — **nodeSelector**, **HTTPRoute** (будь-який непорожній **`target.name`**, для спільних сервісів **`auth-run-hl`** / **`file-link-hl`** — **`namespace: dev`** у base та patch **`…/backendRefs/…/namespace`** у **ua** / **ru**), у overlay **ru** — кожен **Service** (у т. ч. **headless** / **`-hl`**) → **`spec.type: NodePort`** через **JSON6902** у **`kustomization.yaml`**, видалення **HealthCheckPolicy** у **ru**), гілки **dev**, **ua**, **ru** у **clean-merged-branch**, а також заборона тримати артефакти **Firebase Hosting** у **підкаталогах першого рівня** (безпосередні діти кореня репозиторію; у самому корені ці імена не вимагаються до видалення).
7
+ Правило **abie** для споживачів **@nitra/cursor**: **k8s** (Deployment + **HealthCheckPolicy** у **`hc.yaml`**, overlay **ua** — **nodeSelector**, **HTTPRoute** (будь-який непорожній **`target.name`**, для спільних сервісів **`auth-run-hl`** / **`file-link-hl`** — **`namespace: dev`** у base та patch **`…/backendRefs/…/namespace`** у **ua**)), гілки **dev**, **ua** у **clean-merged-branch**, а також заборона тримати артефакти **Firebase Hosting** у **підкаталогах першого рівня** (безпосередні діти кореня репозиторію; у самому корені ці імена не вимагаються до видалення).
8
8
 
9
9
  **`npx @nitra/cursor check abie`** виконується лише якщо в **`.n-cursor.json`** у **`rules`** є **`abie`** — інакше вихід **0** без зауважень.
10
10
 
@@ -34,15 +34,15 @@ spec:
34
34
  name: СЕРВІС-hl
35
35
  ```
36
36
 
37
- ## k8s: overlay **HTTPRoute** (**ua** / **ru**)
37
+ ## k8s: overlay **HTTPRoute** (**ua**)
38
38
 
39
- За наявності **Deployment** під **k8s** і наявності **Vite** (**`vite.config.js`**, **`vite.config.mjs`** або **`vite.config.ts`** у каталозі пакета) у **`ua/kustomization.yaml`** та **`ru/kustomization.yaml`** цього пакета потрібні **inline JSON6902** у **`patches`**: **target** **`kind: HTTPRoute`**, **непорожній `name`** (як у маніфесті маршруту). Мають бути зміни **`/spec/hostnames`** (домени abie — у скрипті) та **`/spec/parentRefs/0/namespace`** (**`ua`** / **`ru`**, також дозволені префікси **`ua-*`** / **`ru-*`**, наприклад **`ua-b2b`**, **`ru-b2b`**). Для **ru** — анотація **`gwin.yandex.cloud/rules.http.upgradeTypes: websocket`** лише якщо в **тому ж** **`ru/kustomization.yaml`** є згадка **`HASURA_GRAPHQL_JWT_SECRET`** (типово patch на **ConfigMap** Hasura). Як обирати **`op`** (**add** / **replace** тощо) у patch — **k8s.mdc** (розділ про JSON patch у kustomization).
39
+ За наявності **Deployment** під **k8s** і наявності **Vite** (**`vite.config.js`**, **`vite.config.mjs`** або **`vite.config.ts`** у каталозі пакета) у **`ua/kustomization.yaml`** цього пакета потрібні **inline JSON6902** у **`patches`**: **target** **`kind: HTTPRoute`**, **непорожній `name`** (як у маніфесті маршруту). Мають бути зміни **`/spec/hostnames`** (домени abie — у скрипті) та **`/spec/parentRefs/0/namespace`** (**`ua`**, також дозволені префікси **`ua-*`**, наприклад **`ua-b2b`**). Як обирати **`op`** (**add** / **replace** тощо) у patch — **k8s.mdc** (розділ про JSON patch у kustomization).
40
40
 
41
41
  ### HTTPRoute: спільні сервіси **`auth-run-hl`**, **`file-link-hl`**
42
42
 
43
43
  У **HTTPRoute** у шляху з **`…/k8s/base/…`** у **`spec.hostnames`** дозволені лише **`aiml.live`**, **`*.aiml.live`** та інші піддомени **aiml.live** (перевірка в **`check-abie.mjs`**).
44
44
 
45
- Ці **Service** (headless **`-hl`**) живуть у **базовому** неймспейсі **`dev`**. У маніфесті **HTTPRoute** під **`k8s`** (шар без **`ua/`** та **`ru/`** — наприклад **`…/k8s/base/hr.yaml`**) для кожного **`backendRefs`** до такого сервісу явно вкажи **`namespace: dev`** і порт **8080**:
45
+ Ці **Service** (headless **`-hl`**) живуть у **базовому** неймспейсі **`dev`**. У маніфесті **HTTPRoute** під **`k8s`** (шар без **`ua/`** — наприклад **`…/k8s/base/hr.yaml`**) для кожного **`backendRefs`** до такого сервісу явно вкажи **`namespace: dev`** і порт **8080**:
46
46
 
47
47
  ```yaml title="…/k8s/base/hr.yaml (фрагмент)"
48
48
  spec:
@@ -60,7 +60,7 @@ spec:
60
60
  port: 8080
61
61
  ```
62
62
 
63
- У **`ua/kustomization.yaml`** та **`ru/kustomization.yaml`** додай до того самого **inline** patch на **`HTTPRoute`** (той самий **`target.name`**) операції **JSON6902** з **`path`**: **`/spec/rules/<i>/backendRefs/<j>/namespace`**, де **`<i>`** / **`<j>`** — індекси відповідно до порядку **`spec.rules`** та **`backendRefs`** у base-файлі; **`value`**: **`ua`** / **`ru`** (також дозволені **`ua-*`** / **`ru-*`**). Якщо кілька таких **`backendRefs`**, потрібна окрема операція для кожного.
63
+ У **`ua/kustomization.yaml`** додай до того самого **inline** patch на **`HTTPRoute`** (той самий **`target.name`**) операції **JSON6902** з **`path`**: **`/spec/rules/<i>/backendRefs/<j>/namespace`**, де **`<i>`** / **`<j>`** — індекси відповідно до порядку **`spec.rules`** та **`backendRefs`** у base-файлі; **`value`**: **`ua`** (також дозволені **`ua-*`**). Якщо кілька таких **`backendRefs`**, потрібна окрема операція для кожного.
64
64
 
65
65
  ```yaml title="…/ua/kustomization.yaml (фрагмент)"
66
66
  - target:
@@ -82,219 +82,9 @@ spec:
82
82
  value: ua
83
83
  ```
84
84
 
85
- ```yaml title="…/ru/kustomization.yaml (фрагмент)"
86
- - target:
87
- kind: HTTPRoute
88
- name: my-httproute
89
- patch: |-
90
- - op: replace
91
- path: /spec/hostnames
92
- value:
93
- - "napitkivmeste.tech" # зокрема выбирайонлайн.рф, *.napitkivmeste.tech, *.выбирайонлайн.рф
94
- - op: replace
95
- path: /spec/parentRefs/0/namespace
96
- value: ru
97
- - op: replace
98
- path: /spec/rules/0/backendRefs/0/namespace
99
- value: ru
100
- - op: replace
101
- path: /spec/rules/0/backendRefs/1/namespace
102
- value: ru
103
- ```
85
+ ## k8s: overlay **ua** і nodeSelector
104
86
 
105
- Якщо в цьому ж файлі є **`HASURA_GRAPHQL_JWT_SECRET`** (Hasura з JWT), додай окремий patch на **HTTPRoute** з анотацією для WebSocket:
106
-
107
- ```yaml title="…/ru/kustomization.yaml (фрагмент, після patch на ConfigMap з HASURA_GRAPHQL_JWT_SECRET)"
108
- - target:
109
- kind: HTTPRoute
110
- name: my-httproute
111
- patch: |-
112
- - op: add
113
- path: /metadata/annotations
114
- value:
115
- gwin.yandex.cloud/rules.http.upgradeTypes: "websocket"
116
- ```
117
-
118
- ## k8s: overlay **ru** і nginx-sidecar для WebSocket (Hasura)
119
-
120
- YC ALB (gwin) має баг: якщо HTTPRoute-правило містить одночасно `URLRewrite` (ReplacePrefixMatch) і `upgrade_types: websocket` — ALB не обробляє WebSocket і повертає 404.
121
- <https://center.yandex.cloud/support/tickets/TX549394>
122
-
123
- Обхідний варіант: nginx-sidecar у поді, що сам виконує rewrite і передає WebSocket до Hasura.
124
-
125
- **Умова:** в дереві `k8s` є Deployment з image `hasura/graphql-engine` (або `newName` на нього через `images:` у kustomization) **і** `ru/kustomization.yaml` містить `HASURA_GRAPHQL_JWT_SECRET` (patch на ConfigMap Hasura з JWT).
126
-
127
- ### Що потрібно зробити
128
-
129
- **1. `ru/configmap-nginx.yaml`** — ConfigMap з nginx.conf:
130
-
131
- ```yaml title="…/k8s/ru/configmap-nginx.yaml"
132
- # yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/configmap-v1.json
133
- apiVersion: v1
134
- kind: ConfigMap
135
- metadata:
136
- name: СЕРВІС-nginx
137
- namespace: ru-NAMESPACE
138
- data:
139
- nginx.conf: |
140
- user nginx;
141
- worker_processes auto;
142
- error_log /dev/null;
143
-
144
- events {
145
- worker_connections 1024;
146
- }
147
-
148
- http {
149
- access_log off;
150
-
151
- map $http_upgrade $connection_upgrade {
152
- default upgrade;
153
- '' close;
154
- }
155
-
156
- server {
157
- listen 8081;
158
- server_name _;
159
-
160
- location /healthz {
161
- add_header Content-Type text/plain;
162
- return 200 "healthy";
163
- }
164
-
165
- # WebSocket: ALB не робить rewrite (URLRewrite + upgrade = bug YC ALB)
166
- # nginx переписує /PREFIX/* → /* і передає до Hasura
167
- location /PREFIX/ {
168
- rewrite ^/PREFIX/(.*)$ /$1 break;
169
- proxy_pass http://127.0.0.1:8080;
170
- proxy_http_version 1.1;
171
- proxy_set_header Upgrade $http_upgrade;
172
- proxy_set_header Connection $connection_upgrade;
173
- proxy_set_header Host $host;
174
- }
175
-
176
- # HTTP: ALB вже зробив prefix_rewrite → /, nginx просто передає
177
- location / {
178
- proxy_pass http://127.0.0.1:8080;
179
- proxy_http_version 1.1;
180
- proxy_set_header Upgrade $http_upgrade;
181
- proxy_set_header Connection $connection_upgrade;
182
- proxy_set_header Host $host;
183
- }
184
- }
185
- }
186
- ```
187
-
188
- **2. `ru/kustomization.yaml`** — додати до `resources` та чотири patch-блоки:
189
-
190
- ```yaml title="…/k8s/ru/kustomization.yaml (фрагмент)"
191
- resources:
192
- - ../base
193
- - configmap-nginx.yaml # ← додати
194
-
195
- patches:
196
- # Headless Service: замінити ports на два іменованих (hasura:8080 + proxy:8081)
197
- - target:
198
- kind: Service
199
- name: СЕРВІС-hl
200
- patch: |-
201
- - op: replace
202
- path: /spec/type
203
- value: NodePort
204
- - op: remove
205
- path: /spec/clusterIP
206
- - op: replace
207
- path: /spec/ports
208
- value:
209
- - name: hasura
210
- protocol: TCP
211
- port: 8080
212
- - name: proxy
213
- protocol: TCP
214
- port: 8081
215
-
216
- # Deployment: додати nginx-sidecar контейнер та volume
217
- - target:
218
- kind: Deployment
219
- name: СЕРВІС
220
- patch: |-
221
- - op: add
222
- path: /spec/template/spec/containers/-
223
- value:
224
- name: СЕРВІС-p
225
- image: nginx:alpine-slim
226
- ports:
227
- - containerPort: 8081
228
- protocol: TCP
229
- volumeMounts:
230
- - name: nginx-conf
231
- mountPath: /etc/nginx/nginx.conf
232
- subPath: nginx.conf
233
- resources: {}
234
- - op: add
235
- path: /spec/template/spec/volumes
236
- value:
237
- - name: nginx-conf
238
- configMap:
239
- name: СЕРВІС-nginx
240
-
241
- # HTTPRoute: прибрати URLRewrite-фільтри з PathPrefix-правила,
242
- # направити трафік на nginx:8081, видалити мертве WebSocket-правило
243
- - target:
244
- kind: HTTPRoute
245
- name: СЕРВІС
246
- patch: |-
247
- - op: remove
248
- path: /spec/rules/INDEX_PATHPREFIX/filters
249
- - op: replace
250
- path: /spec/rules/INDEX_PATHPREFIX/backendRefs/0/port
251
- value: 8081
252
- - op: remove
253
- path: /spec/rules/INDEX_WEBSOCKET
254
- ```
255
-
256
- > `INDEX_PATHPREFIX` і `INDEX_WEBSOCKET` — індекси правил у `base/hr.yaml`. Після видалення filters ALB більше не додає `prefix_rewrite`, тому nginx-sidecar отримує оригінальний шлях і сам виконує rewrite.
257
-
258
- **Примітка щодо Service:** якщо в base у `-hl` Service два порти задаються вперше, `spec.ports[*].name` є обов'язковим — без нього `kubectl apply` поверне помилку `Required value`.
259
-
260
- ## k8s: overlay **ru** і **Service** (у т. ч. headless → NodePort)
261
-
262
- Для кожного **Service** в YAML під **`…/k8s/…`**, де шлях файлу **не** містить **`k8s/ua/`** чи **`k8s/ru/`** (маніфести base / спільного шару; у т. ч. **headless** з **`spec.clusterIP: None`** і **`-hl`**), якщо ще не **`spec.type: NodePort`** / **`LoadBalancer`** / **`ExternalName`**, у **`k8s/ru/kustomization.yaml`** того ж пакета (overlay **ru**) додай **inline** **JSON6902** у **`patches`**: **`target.kind: Service`**, **`target.name`** як у маніфеста, **`path: /spec/type`**, **`value: NodePort`**. Якщо в base було **`spec.clusterIP: None`**, у тому ж **patch** додай **`op: remove`** для **`/spec/clusterIP`**. Якщо в base **явно** задано **`spec.clusterIPs`** (зокрема **`['None']`**), додай **`op: remove`** і для **`/spec/clusterIPs`** — інакше **API** може відхилити **NodePort** (*`spec.clusterIPs[0]: Invalid value: "None"`*). **Не** додавай **`remove`** на **`/spec/clusterIPs`**, якщо ключа **немає** в base: **`kubectl kustomize`** тоді падає (*Unable to remove nonexistent key*). Якщо в base лише **`clusterIP: None`**, а помилка лишається після **`kubectl apply -k`** (злиття з уже існуючим **Service** у кластері), тимчасово **видали** **`Service`** у **`ru`** і застосуй знову, або додай у base поле **`clusterIPs`**, щоб **`remove`** у patch був валідний для **kustomize**. Деталі — **`check-abie.mjs`**.
263
-
264
- ```yaml title="…/ru/kustomization.yaml (фрагмент, headless → NodePort, без clusterIPs у base)"
265
- patches:
266
- - target:
267
- kind: Service
268
- name: user-site-hl
269
- patch: |-
270
- - op: replace
271
- path: /spec/type
272
- value: NodePort
273
- - op: remove
274
- path: /spec/clusterIP
275
- ```
276
-
277
- Якщо в base у цього **Service** уже є **`spec.clusterIPs`**, той самий **patch** розшир **remove** на **`/spec/clusterIPs`** (див. **`check-abie.mjs`**).
278
-
279
- ## k8s: overlay **ru** і HealthCheckPolicy
280
-
281
- Якщо в дереві **k8s** є **HealthCheckPolicy**, у **`ru/kustomization.yaml`** має бути patch **`$patch: delete`** для політики (узгоджено з **k8s.mdc**; перевірка в **`check-k8s.mjs`**, **`ruKustomizationHasHealthCheckDeletePatch`**). Підстав реальне ім’я замість **`СЕРВІС`**:
282
-
283
- ```yaml title="…/ru/kustomization.yaml (фрагмент)"
284
- patches:
285
- - target:
286
- kind: HealthCheckPolicy
287
- name: СЕРВІС
288
- patch: |-
289
- kind: HealthCheckPolicy
290
- metadata:
291
- name: СЕРВІС
292
- $patch: delete
293
- ```
294
-
295
- ## k8s: overlay **ua** / **ru** і nodeSelector
296
-
297
- У **`…/ua/kustomization.yaml`** та **`…/ru/kustomization.yaml`** того пакета, у дереві **`k8s`** якого є **Deployment**, потрібен patch на **`kind: Deployment`**: **ua** — **`spec.template.spec.nodeSelector`** з **`preem: false`**; **ru** — **`spec.template.spec.nodeSelector`** з **`yandex.cloud/preemptible: false`**. Форму **JSON6902** (шлях **`/spec/template/spec/nodeSelector`**, **`op`**) див. **k8s.mdc**.
87
+ У **`…/ua/kustomization.yaml`** того пакета, у дереві **`k8s`** якого є **Deployment**, потрібен patch на **`kind: Deployment`**: **`spec.template.spec.nodeSelector`** з **`preem: false`**. Форму **JSON6902** (шлях **`/spec/template/spec/nodeSelector`**, **`op`**) див. **k8s.mdc**.
298
88
 
299
89
  ```yaml title="…/ua/kustomization.yaml (фрагмент)"
300
90
  patches:
@@ -308,21 +98,9 @@ patches:
308
98
  preem: 'false'
309
99
  ```
310
100
 
311
- ```yaml title="…/ru/kustomization.yaml (фрагмент)"
312
- patches:
313
- - target:
314
- kind: Deployment
315
- name: my-app
316
- patch: |-
317
- - op: replace
318
- path: /spec/template/spec/nodeSelector
319
- value:
320
- yandex.cloud/preemptible: "false"
321
- ```
322
-
323
101
  ### Базовий Deployment (`…/base/`)
324
102
 
325
- Якщо **Deployment** у YAML під **`k8s`** лежить у шляху з сегментом **`base`**, у **`spec.template.spec.nodeSelector`** має бути **`preem`** зі значенням **істинно** (**`true`** або рядок **`'true'`**); overlay **ua** / **ru** підміняє селектор.
103
+ Якщо **Deployment** у YAML під **`k8s`** лежить у шляху з сегментом **`base`**, у **`spec.template.spec.nodeSelector`** має бути **`preem`** зі значенням **істинно** (**`true`** або рядок **`'true'`**); overlay **ua** підміняє селектор.
326
104
 
327
105
  ```yaml title="…/base/deploy.yaml (фрагмент)"
328
106
  spec:
@@ -332,19 +110,18 @@ spec:
332
110
  preem: 'true' # буде замінено через kustomize
333
111
  ```
334
112
 
335
- ## Внутрішньокластерні URL у env-файлах (dev / ua / ru)
113
+ ## Внутрішньокластерні URL у env-файлах (dev / ua)
336
114
 
337
115
  Правило стосується **будь-якого** внутрішньокластерного URL у env-файлах abie-проєкту, а не лише `HASURA_GRAPHQL_ENDPOINT`. Це може бути URL до Hasura, KVCMS, `auth-run-hl`, `file-link-hl` чи будь-якого іншого Service у кластері — у всіх випадках DNS-суфікс і namespace-префікс мають відповідати **середовищу** з імені env-файлу.
338
116
 
339
- abie-проєкти живуть у **трьох різних кластерах** (dev / ua у GKE, ru у Yandex Cloud), тож DNS-суфікс і namespace у URL відрізняються між `*.env`-файлами:
117
+ abie-проєкти живуть у **двох GKE-кластерах** (dev / ua), тож DNS-суфікс і namespace у URL відрізняються між `*.env`-файлами:
340
118
 
341
119
  | env-файл (basename) | namespace-префікс у URL | DNS-суфікс кластера | примітка |
342
120
  | --- | --- | --- | --- |
343
121
  | `dev.env`, `.dev.env` | `dev-…` | `abie-dev.internal` | GKE-кластер dev |
344
122
  | `ua.env`, `.ua.env` | `ua-…` | `abie-ua.internal` | GKE-кластер ua |
345
- | `ru.env`, `.ru.env` | `ru-…` | `cluster.local` | YC-кластер ru, стандартний k8s DNS |
346
123
 
347
- Канонічна форма URL — `http://<service>.<namespace>.svc.<cluster-dns-suffix>:<port>`. Для GKE (dev / ua) суфікс — `<cluster>.internal`; для YC (ru) — фіксований `cluster.local` (у YC у DNS сервісу немає окремого імені кластера).
124
+ Канонічна форма URL — `http://<service>.<namespace>.svc.<cluster-dns-suffix>:<port>`. Суфікс — `<cluster>.internal`.
348
125
 
349
126
  Приклади для одного env-файлу з двома сервісами (Hasura + KVCMS):
350
127
 
@@ -358,19 +135,14 @@ HASURA_GRAPHQL_ENDPOINT=http://apruv-h-hl.ua-apruv.svc.abie-ua.internal:8080
358
135
  KVCMS_URL=http://kvcms-hl.ua-apruv.svc.abie-ua.internal:8080
359
136
  ```
360
137
 
361
- ```env title="hasura/.ru.env"
362
- HASURA_GRAPHQL_ENDPOINT=http://apruv-h-hl.ru-apruv.svc.cluster.local:8080
363
- KVCMS_URL=http://kvcms-hl.ru-apruv.svc.cluster.local:8080
364
- ```
365
-
366
- `<namespace>` (наприклад `dev-apruv` / `ua-apruv` / `ru-apruv`) — `metadata.name` цільового namespace після kustomize-overlay для відповідного середовища; `<service>` — `metadata.name` headless Service (`-hl`) того сервісу, до якого йде URL.
138
+ `<namespace>` (наприклад `dev-apruv` / `ua-apruv`) — `metadata.name` цільового namespace після kustomize-overlay для відповідного середовища; `<service>` — `metadata.name` headless Service (`-hl`) того сервісу, до якого йде URL.
367
139
 
368
- **Перевірка `check-abie.mjs`** сканує всі `*.env` файли, basename яких збігається з `dev.env` / `ua.env` / `ru.env` (з провідною крапкою чи без), знаходить **усі** internal URL (`http://<svc>.<ns>.svc.<dns>` — як для Hasura-ендпоінта, так і для KVCMS чи будь-якого іншого) і вимагає, щоб для кожного:
140
+ **Перевірка `check-abie.mjs`** сканує всі `*.env` файли, basename яких збігається з `dev.env` / `ua.env` (з провідною крапкою чи без), знаходить **усі** internal URL (`http://<svc>.<ns>.svc.<dns>` — як для Hasura-ендпоінта, так і для KVCMS чи будь-якого іншого) і вимагає, щоб для кожного:
369
141
 
370
- - DNS-суфікс відповідав env: `abie-dev.internal` / `abie-ua.internal` / `cluster.local`;
371
- - namespace починався з `dev-` / `ua-` / `ru-` відповідно.
142
+ - DNS-суфікс відповідав env: `abie-dev.internal` / `abie-ua.internal`;
143
+ - namespace починався з `dev-` / `ua-` відповідно.
372
144
 
373
- Загальне правило про **внутрішній** URL (не публічний домен) для `HASURA_GRAPHQL_ENDPOINT` лишається у **`hasura.mdc`** (для nitra і abie) — `check-hasura.mjs` приймає обидва кластерні DNS-формати (`<cluster>.internal` і `cluster.local`).
145
+ Загальне правило про **внутрішній** URL (не публічний домен) для `HASURA_GRAPHQL_ENDPOINT` лишається у **`hasura.mdc`** (для nitra і abie) — `check-hasura.mjs` приймає кластерний DNS-формат `<cluster>.internal`.
374
146
 
375
147
  ## Firebase Hosting
376
148
 
@@ -378,11 +150,11 @@ KVCMS_URL=http://kvcms-hl.ru-apruv.svc.cluster.local:8080
378
150
 
379
151
  ## Git branches
380
152
 
381
- У **`.github/workflows/clean-merged-branch.yml`** у кроці **`phpdocker-io/github-actions-delete-abandoned-branches`** значення **`with.ignore_branches`** має містити **dev**, **ua** та **ru** (разом з іншими гілками, якщо потрібно):
153
+ У **`.github/workflows/clean-merged-branch.yml`** у кроці **`phpdocker-io/github-actions-delete-abandoned-branches`** значення **`with.ignore_branches`** має містити **dev** та **ua** (разом з іншими гілками, якщо потрібно):
382
154
 
383
155
  ```yaml title=".github/workflows/clean-merged-branch.yml (фрагмент)"
384
156
  with:
385
- ignore_branches: main,dev,ua,ru
157
+ ignore_branches: main,dev,ua
386
158
  ```
387
159
 
388
160
  ## Перевірка
@@ -398,6 +170,6 @@ with:
398
170
  - **`http_route_base/`** → `abie.http_route_base` — у HTTPRoute під `…/k8s/.../base/...` усі `spec.hostnames` мають бути в домені `aiml.live` (включно з `*.aiml.live` та піддоменами). **Цільові файли:** `…/k8s/.../base/.../hr.yaml`.
399
171
  - **`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`.
400
172
  - **`base_deployment_preem/`** → `abie.base_deployment_preem` — Deployment у base/ має `spec.template.spec.nodeSelector.preem` зі значенням `true` (boolean або рядок). **Цільові файли:** ресурсні YAML під `…/k8s/.../base/...`.
401
- - **`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,ru` (case-insensitive). **Цільові файли:** `.github/workflows/clean-merged-branch.yml`.
173
+ - **`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`.
402
174
 
403
- Cross-file логіка (парність HCP↔Deployment у каталозі, обчислений `<deployment.name>-hl` для `targetRef.name`, валідація ru/ua-overlay JSON6902 patches на Service/HTTPRoute, env→cluster DNS, аналіз cross-namespace backendRefs у пакетах) лишається у **`check-abie.mjs`** — Rego не читає файлову систему й не робить cross-document резолюцію.
175
+ Cross-file логіка (парність HCP↔Deployment у каталозі, обчислений `<deployment.name>-hl` для `targetRef.name`, валідація ua-overlay JSON6902 patches на HTTPRoute, env→cluster DNS, аналіз cross-namespace backendRefs у пакетах) лишається у **`check-abie.mjs`** — Rego не читає файлову систему й не робить cross-document резолюцію.
package/mdc/hasura.mdc CHANGED
@@ -12,7 +12,7 @@ alwaysApply: false
12
12
  Приклад **неправильного** значення:
13
13
 
14
14
  ```env
15
- HASURA_GRAPHQL_ENDPOINT=https://napitkivmeste.tech/contract/ql
15
+ HASURA_GRAPHQL_ENDPOINT=https://vybeerai.com.ua/contract/ql
16
16
  ```
17
17
 
18
18
  Правильне значення:
package/mdc/k8s.mdc CHANGED
@@ -310,7 +310,7 @@ data:
310
310
 
311
311
  ### Overlays (не-dev)
312
312
 
313
- - У каталозі кожного іншого середовища (наприклад **`ru/`**, **`prod/`**) має бути **мінімум файлів**: типово лише **`kustomization.yaml`** (посилання на `base`, `patches`, `replacements`, `components` тощо) і ресурси чи додаткові YAML, **необхідні лише для цього overlay**.
313
+ - У каталозі кожного іншого середовища (наприклад **`ua/`**, **`prod/`**) має бути **мінімум файлів**: типово лише **`kustomization.yaml`** (посилання на `base`, `patches`, `replacements`, `components` тощо) і ресурси чи додаткові YAML, **необхідні лише для цього overlay**.
314
314
  - Відмінності від dev вносяться **оверрайдами** (patches, `images`, `replicas`, `configMapGenerator` тощо), а не копіюванням повного дерева з `base`.
315
315
 
316
316
  ### Namespace
@@ -387,7 +387,7 @@ images:
387
387
 
388
388
  Інші назви каталогу (`scale/`, `hpa-component/`, `pdb-component/`) — fail.
389
389
 
390
- **Overlays** (`ua/`, `ru/`, прод-overlays) підключають `components: [- ../components]` і додають JSON6902-патчі для прод-значень: `/spec/minReplicas`, `/spec/maxReplicas` (HPA), `/spec/minAvailable` (PDB). Dev-середовище (`base`) HPA/PDB не отримує — як і потрібно.
390
+ **Overlays** (`ua/`, прод-overlays) підключають `components: [- ../components]` і додають JSON6902-патчі для прод-значень: `/spec/minReplicas`, `/spec/maxReplicas` (HPA), `/spec/minAvailable` (PDB). Dev-середовище (`base`) HPA/PDB не отримує — як і потрібно.
391
391
 
392
392
  **`<pkg>/k8s/components/kustomization.yaml`** має `kind: Component` (не `kind: Kustomization`) — це **джерело** канонічних HPA/PDB для всіх overlays, а не overlay сам по собі. Прод-перезаписи (`/spec/minReplicas`, `/spec/maxReplicas`, `/spec/minAvailable`) живуть у `<env>/kustomization.yaml`, що підключає Component через `components:`. У самому Component patches не потрібні — він env-неутральний; **`check k8s`** не вимагає прод-патчів від `components/kustomization.yaml`.
393
393
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.9.18",
3
+ "version": "1.9.19",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -2,8 +2,8 @@
2
2
  # `npm/scripts/check-abie.mjs` (abie.mdc): кожен `Deployment` у файлах під
3
3
  # `…/k8s/.../base/…` має `spec.template.spec.nodeSelector.preem` зі
4
4
  # значенням, що вважається істинним (boolean `true` або рядок `"true"`
5
- # без урахування регістру). Overlays (ua/ru) далі підміняють селектор
6
- # JSON6902-патчами на `preem: false` / `yandex.cloud/preemptible: false`.
5
+ # без урахування регістру). Overlay ua далі підміняє селектор
6
+ # JSON6902-патчем на `preem: false`.
7
7
  #
8
8
  # Запуск (локально, лише для одного base-YAML з Deployment):
9
9
  # conftest test path/to/k8s/base/deployment.yaml \
@@ -2,7 +2,7 @@
2
2
  # з `npm/scripts/check-abie.mjs` (abie.mdc): у workflow
3
3
  # `.github/workflows/clean-merged-branch.yml` крок з
4
4
  # `uses: phpdocker-io/github-actions-delete-abandoned-branches` має у
5
- # `with.ignore_branches` містити усі обовʼязкові токени `dev,ua,ru`
5
+ # `with.ignore_branches` містити усі обовʼязкові токени `dev,ua`
6
6
  # (case-insensitive, кома-розділені).
7
7
  #
8
8
  # Запуск (локально):
@@ -23,7 +23,7 @@ package abie.clean_merged_ignore_branches
23
23
  import rego.v1
24
24
 
25
25
  # Обовʼязкові гілки в `ignore_branches` (узгоджено з `ABIE_REQUIRED_IGNORE_BRANCHES`).
26
- required_branches := {"dev", "ua", "ru"}
26
+ required_branches := {"dev", "ua"}
27
27
 
28
28
  # Префікс `uses:` для GitHub Action, у якого читаємо `with.ignore_branches`.
29
29
  target_action_marker := "phpdocker-io/github-actions-delete-abandoned-branches"
@@ -24,23 +24,23 @@ test_deny_ignore_branches_missing if {
24
24
  }
25
25
 
26
26
  test_deny_missing_required_token if {
27
- count(clean_merged_ignore_branches.deny) > 0 with input as mk_workflow({"ignore_branches": "dev,ua"})
27
+ count(clean_merged_ignore_branches.deny) > 0 with input as mk_workflow({"ignore_branches": "dev"})
28
28
  }
29
29
 
30
30
  test_deny_completely_wrong_tokens if {
31
31
  count(clean_merged_ignore_branches.deny) > 0 with input as mk_workflow({"ignore_branches": "main,develop"})
32
32
  }
33
33
 
34
- test_allow_all_three_tokens if {
35
- count(clean_merged_ignore_branches.deny) == 0 with input as mk_workflow({"ignore_branches": "dev,ua,ru"})
34
+ test_allow_required_tokens if {
35
+ count(clean_merged_ignore_branches.deny) == 0 with input as mk_workflow({"ignore_branches": "dev,ua"})
36
36
  }
37
37
 
38
38
  # Регістронезалежне порівняння і пропуск пробілів.
39
39
  test_allow_uppercase_with_spaces if {
40
- count(clean_merged_ignore_branches.deny) == 0 with input as mk_workflow({"ignore_branches": " DEV , UA , RU "})
40
+ count(clean_merged_ignore_branches.deny) == 0 with input as mk_workflow({"ignore_branches": " DEV , UA "})
41
41
  }
42
42
 
43
- extra_branches_workflow := mk_workflow({"ignore_branches": "dev,ua,ru,main,release/*"})
43
+ extra_branches_workflow := mk_workflow({"ignore_branches": "dev,ua,main,release/*"})
44
44
 
45
45
  # Додаткові гілки після обов'язкових — дозволено.
46
46
  test_allow_extra_branches if {