@nitra/cursor 1.8.113 → 1.8.114

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/k8s.mdc CHANGED
@@ -214,6 +214,15 @@ spec:
214
214
 
215
215
  Якщо в `k8s/base/` є **`configmap.yaml`** і **Deployment**, і цей Deployment посилається рівно на **один** ConfigMap — `metadata.name` ConfigMap має збігатися з `metadata.name` Deployment. Точні умови перевірки — **`check-k8s.mjs`**.
216
216
 
217
+ ## ConfigMap для Hasura-Deployment
218
+
219
+ Якщо в `k8s/base/` поруч із **`configmap.yaml`** є **Deployment** з образом **`hasura/graphql-engine`**, у `data` ConfigMap **обов'язково** має бути ключ **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS`** зі значенням **`"true"`**. Точні умови перевірки — **`check-k8s.mjs`**.
220
+
221
+ ```yaml
222
+ data:
223
+ HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS: 'true'
224
+ ```
225
+
217
226
  ## Kustomize: структура каталогів (`base` / overlays)
218
227
 
219
228
  Трансформуй дерева **`**/k8s`**, щоб **винести спільне** через [Kustomize](https://kustomize.io/): один канонічний **`base`** і тонкі **overlays** для інших середовищ.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.113",
3
+ "version": "1.8.114",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -56,6 +56,11 @@
56
56
  * Dockerfile — правило docker.mdc, скрипт check-docker.mjs.
57
57
  *
58
58
  * **Структура `HTTPRoute` для Hasura-Deployment:** звіряється канон 4 правил у **`spec.rules`** (редиректи **`<prefix>/ql`** і **`<prefix>/ql/`** на **`<prefix>/ql/console`** 302, **`PathPrefix <prefix>/ql`** + **URLRewrite** на **`/`**, окреме WebSocket-правило з **`RequestHeaderModifier`** remove **`Authorization`**). **Префікс параметризовано** (рядок перед **`/ql`** у першому Hasura-правилі). **Прив'язка** — за **`metadata.name`** у тому ж каталозі, що й **Deployment** з образом **`hasura/graphql-engine`** (див. k8s.mdc). **Додаткові правила** поверх канону дозволені.
59
+ *
60
+ * **ConfigMap для Hasura-Deployment:** якщо в `k8s/base/` є `configmap.yaml` і поруч Deployment з образом
61
+ * **`hasura/graphql-engine`**, то в `data` ConfigMap обов'язково має бути ключ
62
+ * **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS`** зі значенням **`"true"`** (приймається булеве `true`
63
+ * або рядок `"true"`, без регістрової залежності).
59
64
  */
60
65
  import { existsSync } from 'node:fs'
61
66
  import { readFile, readdir, stat, unlink } from 'node:fs/promises'
@@ -1959,6 +1964,49 @@ export function isHasuraDeploymentManifest(manifest) {
1959
1964
  return containerListHasHasuraImage(p.containers) || containerListHasHasuraImage(p.initContainers)
1960
1965
  }
1961
1966
 
1967
+ /**
1968
+ * Обов'язковий ключ у **`data`** ConfigMap для Hasura-Deployment (узгоджено з k8s.mdc).
1969
+ */
1970
+ export const HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY = 'HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS'
1971
+
1972
+ /**
1973
+ * Чи значення поля `data.<key>` у ConfigMap читається як логічне **true**.
1974
+ * ConfigMap у Kubernetes тримає значення як рядки, але в YAML часто пишуть без лапок —
1975
+ * тому приймаємо і булевий **true**, і рядок **"true"** (без регістрової залежності).
1976
+ * @param {unknown} v значення з `data[HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY]`
1977
+ * @returns {boolean} true, якщо значення — `true` або рядок `'true'`
1978
+ */
1979
+ function isConfigMapValueTrue(v) {
1980
+ if (v === true) return true
1981
+ if (typeof v === 'string' && v.trim().toLowerCase() === 'true') return true
1982
+ return false
1983
+ }
1984
+
1985
+ /**
1986
+ * Чи порушує ConfigMap вимогу щодо **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS: "true"`** (k8s.mdc).
1987
+ * Перевірка застосовна, коли в тому ж каталозі є Hasura-Deployment (див. `isHasuraDeploymentManifest`).
1988
+ * @param {unknown} manifest корінь YAML-документа ConfigMap
1989
+ * @returns {string | null} текст порушення або null, якщо не ConfigMap / ключ є і значення `true`
1990
+ */
1991
+ export function hasuraConfigMapRemoteSchemaPermissionsViolation(manifest) {
1992
+ if (manifest === null || manifest === undefined || typeof manifest !== 'object' || Array.isArray(manifest))
1993
+ return null
1994
+ const rec = /** @type {Record<string, unknown>} */ (manifest)
1995
+ if (rec.kind !== 'ConfigMap') return null
1996
+ const data = rec.data
1997
+ if (data === null || data === undefined || typeof data !== 'object' || Array.isArray(data)) {
1998
+ return `data.${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}: додай ключ зі значенням "true" (Deployment з hasura/graphql-engine — див. k8s.mdc)`
1999
+ }
2000
+ const d = /** @type {Record<string, unknown>} */ (data)
2001
+ if (!Object.hasOwn(d, HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY)) {
2002
+ return `data.${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}: додай ключ зі значенням "true" (Deployment з hasura/graphql-engine — див. k8s.mdc)`
2003
+ }
2004
+ if (!isConfigMapValueTrue(d[HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY])) {
2005
+ return `data.${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}: значення має бути "true" (зараз: ${JSON.stringify(d[HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY])}) (див. k8s.mdc)`
2006
+ }
2007
+ return null
2008
+ }
2009
+
1962
2010
  const K8S_YAML_EXT_RE = /\.ya?ml$/iu
1963
2011
 
1964
2012
  /**
@@ -3305,6 +3353,63 @@ async function validateConfigMapNameMatchesDeployment(root, yamlFilesAbs, fail,
3305
3353
  }
3306
3354
  }
3307
3355
 
3356
+ /**
3357
+ * Знаходить перший документ **ConfigMap** у файлі (з `metadata.name`).
3358
+ * @param {string} absPath абсолютний шлях до YAML-файлу
3359
+ * @returns {Promise<Record<string, unknown> | null>} об'єкт ConfigMap або null
3360
+ */
3361
+ async function readFirstConfigMapDoc(absPath) {
3362
+ let raw
3363
+ try {
3364
+ raw = await readFile(absPath, 'utf8')
3365
+ } catch {
3366
+ return null
3367
+ }
3368
+ let docs
3369
+ try {
3370
+ docs = parseAllDocuments(raw)
3371
+ } catch {
3372
+ return null
3373
+ }
3374
+ for (const doc of docs) {
3375
+ if (doc.errors.length > 0) continue
3376
+ const obj = doc.toJSON()
3377
+ if (obj !== null && typeof obj === 'object' && !Array.isArray(obj)) {
3378
+ const rec = /** @type {Record<string, unknown>} */ (obj)
3379
+ if (rec.kind === 'ConfigMap') return rec
3380
+ }
3381
+ }
3382
+ return null
3383
+ }
3384
+
3385
+ /**
3386
+ * Для кожного `k8s/base/configmap.yaml`, у каталозі якого поруч є Hasura-Deployment,
3387
+ * вимагає у `data` ключ **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS`** зі значенням **`"true"`** (k8s.mdc).
3388
+ * @param {string} root корінь репозиторію
3389
+ * @param {string[]} yamlFilesAbs yaml під k8s
3390
+ * @param {(msg: string) => void} fail callback при помилці
3391
+ * @param {(msg: string) => void} passFn callback при успіху
3392
+ */
3393
+ async function validateHasuraConfigMapRemoteSchemaPermissions(root, yamlFilesAbs, fail, passFn) {
3394
+ const cmFiles = yamlFilesAbs.filter(abs => {
3395
+ const rel = relative(root, abs).replaceAll('\\', '/')
3396
+ return CONFIGMAP_BASE_PATH_RE.test(`/${rel}`) || rel === 'k8s/base/configmap.yaml'
3397
+ })
3398
+ for (const cmAbs of cmFiles) {
3399
+ const rel = relative(root, cmAbs).replaceAll('\\', '/') || cmAbs
3400
+ const deployment = await findDeploymentDocInDir(dirname(cmAbs))
3401
+ if (deployment === null || !isHasuraDeploymentManifest(deployment)) continue
3402
+ const cm = await readFirstConfigMapDoc(cmAbs)
3403
+ if (cm === null) continue
3404
+ const violation = hasuraConfigMapRemoteSchemaPermissionsViolation(cm)
3405
+ if (violation !== null) {
3406
+ fail(`${rel}: ${violation}`)
3407
+ } else {
3408
+ passFn(`${rel}: ${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}="true" для Hasura-Deployment (k8s.mdc)`)
3409
+ }
3410
+ }
3411
+ }
3412
+
3308
3413
  /**
3309
3414
  * Перевіряє відповідність проєкту правилам k8s.mdc.
3310
3415
  * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
@@ -3348,5 +3453,7 @@ export async function check() {
3348
3453
 
3349
3454
  await validateConfigMapNameMatchesDeployment(root, yamlFiles, fail, pass)
3350
3455
 
3456
+ await validateHasuraConfigMapRemoteSchemaPermissions(root, yamlFiles, fail, pass)
3457
+
3351
3458
  return reporter.getExitCode()
3352
3459
  }