@nitra/cursor 1.8.122 → 1.8.123

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/mdc/abie.mdc CHANGED
@@ -40,6 +40,8 @@ spec:
40
40
 
41
41
  ### HTTPRoute: спільні сервіси **`auth-run-hl`**, **`file-link-hl`**
42
42
 
43
+ У **HTTPRoute** у шляху з **`…/k8s/base/…`** у **`spec.hostnames`** дозволені лише **`aiml.live`**, **`*.aiml.live`** та інші піддомени **aiml.live** (перевірка в **`check-abie.mjs`**).
44
+
43
45
  Ці **Service** (headless **`-hl`**) живуть у **базовому** неймспейсі **`dev`**. У маніфесті **HTTPRoute** під **`k8s`** (шар без **`ua/`** та **`ru/`** — наприклад **`…/k8s/base/hr.yaml`**) для кожного **`backendRefs`** до такого сервісу явно вкажи **`namespace: dev`** і порт **8080**:
44
46
 
45
47
  ```yaml title="…/k8s/base/hr.yaml (фрагмент)"
package/mdc/k8s.mdc CHANGED
@@ -142,7 +142,7 @@ spec:
142
142
  namespace: dev
143
143
  sectionName: https
144
144
  hostnames:
145
- - abie.cloud
145
+ - aiml.live
146
146
  rules:
147
147
  - matches:
148
148
  - path:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.122",
3
+ "version": "1.8.123",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -29,6 +29,7 @@
29
29
  * — тоді в **`ua`/`ru` kustomization** потрібен patch на **`kind: HTTPRoute`**, **непорожній `target.name`**: **`/spec/hostnames`**
30
30
  * (домени abie.mdc), **`/spec/parentRefs/0/namespace`** (**ua** / **ru**); для **ru** — **`gwin.yandex.cloud/rules.http.upgradeTypes: websocket`**,
31
31
  * якщо в тому ж **`kustomization.yaml`** згадується **`HASURA_GRAPHQL_JWT_SECRET`** (Hasura + JWT).
32
+ * **HTTPRoute (base / dev):** у маніфесті **HTTPRoute** у шляху з сегментом **`base`** (наприклад **`…/k8s/base/hr.yaml`**) у **`spec.hostnames`** дозволені лише **`aiml.live`**, **`*.aiml.live`** та інші піддомени **aiml.live** (канонічно порівняння без урахування регістру).
32
33
  * **Спільні бекенди (`auth-run-hl`, `file-link-hl`):** у **HTTPRoute** під **`k8s`** поза overlay **ua** та **ru** (шлях не містить **`k8s/ua/`** чи **`k8s/ru/`**) кожен такий **`backendRefs`** має **`namespace: dev`** і порт **8080**;
33
34
  * у patch overlay **ua** та **ru** — по одному **JSON6902** на **`/spec/rules/…/backendRefs/…/namespace`** з **`value`**: **ua** або **ru** (кількість patch-ів = кількість таких **`backendRefs`** у пакеті).
34
35
  * Вибір **`op`** — **k8s.mdc**.
@@ -63,6 +64,9 @@ const ABIE_SHARED_CROSS_NS_BACKEND_SET = new Set(ABIE_SHARED_CROSS_NS_BACKEND_NA
63
64
  /** Очікуваний URL **`$schema`** для **hc.yaml** (abie.mdc). */
64
65
  export const ABIE_HC_SCHEMA_URL = 'https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json'
65
66
 
67
+ /** Кореневий домен **`spec.hostnames`** для **HTTPRoute** у **`…/k8s/base/…`** (середовище dev, abie.mdc). */
68
+ export const ABIE_BASE_DEV_HTTPROUTE_HOST_ROOT = 'aiml.live'
69
+
66
70
  const MODELINE_RE = /^#\s*yaml-language-server:\s*\$schema=(\S+)\s*$/
67
71
  const LINE_SPLIT_RE = /\r?\n/u
68
72
  const RU_KUSTOMIZATION_PATH_RE = /(^|\/)ru\/kustomization\.yaml$/u
@@ -191,6 +195,84 @@ export function isAbieK8sBaseYamlPath(rel) {
191
195
  return BASE_SEGMENT_RE.test(norm)
192
196
  }
193
197
 
198
+ /**
199
+ * Чи **hostname** дозволений для **HTTPRoute** у **base** (dev): **aiml.live**, **\*.aiml.live** або **\*.…\.aiml.live** (без урахування регістру).
200
+ * @param {string} hostname значення з **spec.hostnames**
201
+ * @returns {boolean} **true**, якщо hostname відповідає abie.mdc
202
+ */
203
+ export function isAllowedAbieBaseDevHostname(hostname) {
204
+ if (typeof hostname !== 'string') {
205
+ return false
206
+ }
207
+ const h = hostname.trim().toLowerCase()
208
+ if (h === '') {
209
+ return false
210
+ }
211
+ const root = ABIE_BASE_DEV_HTTPROUTE_HOST_ROOT
212
+ if (h === root) {
213
+ return true
214
+ }
215
+ if (h === `*.${root}`) {
216
+ return true
217
+ }
218
+ if (h.endsWith(`.${root}`)) {
219
+ return true
220
+ }
221
+ return false
222
+ }
223
+
224
+ /**
225
+ * Повідомлення про недопустимі **spec.hostnames** у **HTTPRoute** у шляху **…/base/…** (abie.mdc).
226
+ * @param {unknown} obj корінь YAML-документа
227
+ * @param {string} rel відносний шлях від кореня репозиторію
228
+ * @returns {string[]} порожньо, якщо перевірка не застосовується або hostnames коректні
229
+ */
230
+ export function abieBaseHttpRouteHostnamesErrors(obj, rel) {
231
+ if (!isAbieK8sBaseYamlPath(rel)) {
232
+ return []
233
+ }
234
+ if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
235
+ return []
236
+ }
237
+ const rec = /** @type {Record<string, unknown>} */ (obj)
238
+ if (rec.kind !== 'HTTPRoute') {
239
+ return []
240
+ }
241
+ const spec = rec.spec
242
+ if (spec === null || typeof spec !== 'object' || Array.isArray(spec)) {
243
+ return []
244
+ }
245
+ const hostnames = /** @type {Record<string, unknown>} */ (spec).hostnames
246
+ if (hostnames === undefined) {
247
+ return []
248
+ }
249
+ /** @type {string[]} */
250
+ const hosts = []
251
+ if (Array.isArray(hostnames)) {
252
+ for (const h of hostnames) {
253
+ if (typeof h === 'string' && h.trim() !== '') {
254
+ hosts.push(h)
255
+ }
256
+ }
257
+ } else if (typeof hostnames === 'string' && hostnames.trim() !== '') {
258
+ hosts.push(hostnames)
259
+ }
260
+ if (hosts.length === 0) {
261
+ return []
262
+ }
263
+ const root = ABIE_BASE_DEV_HTTPROUTE_HOST_ROOT
264
+ /** @type {string[]} */
265
+ const errors = []
266
+ for (const h of hosts) {
267
+ if (!isAllowedAbieBaseDevHostname(h)) {
268
+ errors.push(
269
+ `${rel}: HTTPRoute у base (dev): hostname "${h}" недопустимий — дозволені лише ${root} та піддомени, зокрема *.${root} (abie.mdc)`
270
+ )
271
+ }
272
+ }
273
+ return errors
274
+ }
275
+
194
276
  /**
195
277
  * Чи значення **`preem`** у base **Deployment** вважається «істинним» за abie.mdc (**true** або рядок **`true`** без урахування регістру).
196
278
  * @param {unknown} v значення з YAML
@@ -1050,7 +1132,8 @@ export async function analyzeAbieSharedBackendRefsInPackageK8s(root, pkgAbs, yam
1050
1132
  if (docs) {
1051
1133
  for (const doc of docs) {
1052
1134
  if (doc.errors.length === 0) {
1053
- const st = httpRouteDocSharedCrossNsBackendStats(doc.toJSON(), rel)
1135
+ const json = doc.toJSON()
1136
+ const st = httpRouteDocSharedCrossNsBackendStats(json, rel)
1054
1137
  refCount += st.refCount
1055
1138
  baseErrors.push(...st.errors)
1056
1139
  }
@@ -1504,6 +1587,60 @@ async function checkHttpRouteKustomization(abs, rel, mode, root, yamlFilesAbs, c
1504
1587
  return true
1505
1588
  }
1506
1589
 
1590
+ /**
1591
+ * Для кожного **HTTPRoute** у **`…/k8s/base/…`** з непорожніми **`spec.hostnames`** — лише **aiml.live** та піддомени (abie.mdc).
1592
+ * @param {string} root корінь репозиторію
1593
+ * @param {string[]} yamlFilesAbs yaml під k8s
1594
+ * @param {(msg: string) => void} fail callback при помилці
1595
+ * @param {(msg: string) => void} passFn callback при успішній перевірці
1596
+ * @returns {Promise<void>}
1597
+ */
1598
+ async function ensureAbieBaseHttpRouteHostnames(root, yamlFilesAbs, fail, passFn) {
1599
+ let baseHttpRoutesWithHostnames = 0
1600
+ for (const abs of yamlFilesAbs) {
1601
+ const rel = relative(root, abs).replaceAll('\\', '/') || abs
1602
+ if (isAbieK8sBaseYamlPath(rel)) {
1603
+ const docs = await readAndParseYamlDocs(abs, rel, fail)
1604
+ if (!docs) {
1605
+ return
1606
+ }
1607
+ for (const doc of docs) {
1608
+ if (doc.errors.length === 0) {
1609
+ const json = doc.toJSON()
1610
+ const errs = abieBaseHttpRouteHostnamesErrors(json, rel)
1611
+ if (errs.length > 0) {
1612
+ for (const e of errs) {
1613
+ fail(e)
1614
+ }
1615
+ return
1616
+ }
1617
+ if (json !== null && typeof json === 'object' && !Array.isArray(json)) {
1618
+ const rec = /** @type {Record<string, unknown>} */ (json)
1619
+ if (rec.kind === 'HTTPRoute') {
1620
+ const spec = rec.spec
1621
+ if (spec !== null && typeof spec === 'object' && !Array.isArray(spec)) {
1622
+ const hostnames = /** @type {Record<string, unknown>} */ (spec).hostnames
1623
+ if (Array.isArray(hostnames) && hostnames.some(h => typeof h === 'string' && h.trim() !== '')) {
1624
+ baseHttpRoutesWithHostnames++
1625
+ } else if (typeof hostnames === 'string' && hostnames.trim() !== '') {
1626
+ baseHttpRoutesWithHostnames++
1627
+ }
1628
+ }
1629
+ }
1630
+ }
1631
+ }
1632
+ }
1633
+ }
1634
+ }
1635
+ if (baseHttpRoutesWithHostnames > 0) {
1636
+ passFn(
1637
+ `HTTPRoute у …/k8s/base/…: spec.hostnames відповідають ${ABIE_BASE_DEV_HTTPROUTE_HOST_ROOT} та піддоменам (abie.mdc)`
1638
+ )
1639
+ } else {
1640
+ passFn('Немає HTTPRoute у …/k8s/base/… з непорожніми spec.hostnames — перевірку aiml.live пропущено')
1641
+ }
1642
+ }
1643
+
1507
1644
  /**
1508
1645
  * Якщо є **Deployment** під **k8s**, вимагає в overlay **ua** та **ru** patch **HTTPRoute** (непорожній **target.name**) за abie.mdc
1509
1646
  * лише для пакетів з **vite.config.{js,mjs,ts}** у каталозі пакета (батько **k8s**).
@@ -1959,6 +2096,9 @@ export async function check() {
1959
2096
  pass('Перевіряємо Service → NodePort у ru/kustomization (abie.mdc)')
1960
2097
  await ensureRuAbieServiceNodePortPatches(root, yamlFiles, fail, pass)
1961
2098
 
2099
+ pass('Перевіряємо HTTPRoute spec.hostnames у …/k8s/base/… (aiml.live, abie.mdc)')
2100
+ await ensureAbieBaseHttpRouteHostnames(root, yamlFiles, fail, pass)
2101
+
1962
2102
  if (deploymentDirs.size > 0) {
1963
2103
  pass('Є Deployment — перевіряємо nodeSelector у ua/ru kustomization (abie.mdc)')
1964
2104
  await ensureUaRuAbieNodeSelectorPatches(root, yamlFiles, deploymentDirs, fail, pass)