@7n/rules 1.8.1 → 1.8.3

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
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.3] - 2026-07-17
4
+
5
+ ### Changed
6
+
7
+ - release: @7n/rules@1.8.2
8
+
9
+ ## [1.8.2] - 2026-07-17
10
+
11
+ ### Fixed
12
+
13
+ - bun/licensee: розрізняти crash інструмента (stderr) від реального ліцензійного порушення (stdout, --errors-only)
14
+ - k8s/manifests: знизити когнітивну складність ensureHasuraConfigMapRequiredEnv нижче порогу sonarjs
15
+
3
16
  ## [1.8.1] - 2026-07-17
4
17
 
5
18
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/rules",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "CLI еталонних правил і skills (префікс n-): синк у репозиторій, дельта-lint, конформність",
5
5
  "keywords": [
6
6
  "cli",
@@ -3,35 +3,28 @@ type: JS Module
3
3
  title: main.mjs
4
4
  resource: npm/rules/bun/licensee/main.mjs
5
5
  docgen:
6
- crc: bbaca446
7
- model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
- score: 90
9
- issues: surzhik,judge:inaccurate:0.96
10
- judgeModel: openai-codex/gpt-5.4-mini
6
+ crc: 48c72e2b
7
+ model: manual
11
8
  ---
12
9
 
13
10
  ## Огляд
14
11
 
15
- Встановлює конфігурацію ліцензій, спираючись на файл .licensee.json, якщо він відсутній. Виконує перевірку відповідності ліцензій усіх npm-залежностей проєкту встановленим вимогам, що визначаються в конфігурації. У випадку виявлення порушень, система повідомляє про них, підтверджуючи чисту відповідність або фіксуючи розбіжності. Маркери повідомлень згадуються у Поведінці: (bun.mdc).
12
+ Read-only detector `bun/licensee`: перевіряє ліцензії npm-залежностей проєкту через зовнішній інструмент `licensee` (`bun x licensee`), звіряючи їх з allowlist у `.licensee.json`. Розрізняє два принципово різні провали: `licensee` знайшов реально заборонену ліцензію (`license-violation`) і `licensee` сам впав з помилкою (`licensee-crashed`), наприклад через несумісність `@npmcli/arborist` (яким він читає `node_modules`) з деревом, зібраним `bun install`.
16
13
 
17
14
  ## Поведінка
18
15
 
19
- Поведінка:
20
-
21
- 1. Викликається `lint` для запуску перевірки ліцензій npm-залежностей.
22
- 2. Якщо файл конфігурації `.licensee.json` відсутній:
23
- a. Якщо режим читання лише (`readOnly`) увімкнено, повідомляється, що необхідно запустити `npx @7n/rules fix bun` локально для генерації (bun.mdc).
24
- b. Якщо режим читання лише вимкнено, створюється `.licensee.json` з дефолтним allowlist (`blueOak: bronze`) та повідомляється про створення конфігурації.
25
- 3. Визначається команда `bun`. Якщо `bun` не знайдена у системному шляху, повідомляється про це (bun.mdc).
26
- 4. Виконується команда `bun x licensee --production --quiet` у корені проєкту.
27
- 5. Якщо команда `licensee` завершується успішно (статус 0), повідомляється, що ліцензії відповідають вимогам.
28
- 6. Якщо команда `licensee` завершується з помилкою (не 0), повідомляється про порушення ліцензій (код) (bun.mdc).
16
+ 1. Якщо `.licensee.json` відсутній — `licensee-config-missing`; генерація конфігу — окремий T0-фікс (`fix-licensee.mjs`), не тут.
17
+ 2. Якщо `bun` не знайдено в PATH — `bun-missing`.
18
+ 3. Запускає `bun x licensee --production --errors-only` (без `--quiet` реальне порушення потребує деталі: ім'я/версія/ліцензія пакета, які `licensee` пише в stdout через `print()`).
19
+ 4. Статус 0 без порушень.
20
+ 5. Статус 0 і є вивід у **stderr** — трактується як crash/`die()` самого `licensee` (invalid config або необроблений виняток усередині тула), НЕ як ліцензійне порушення: `licensee-crashed`, повідомлення включає stderr і підказку перевірити вручну `bunx licensee --production`.
21
+ 6. Статус 0 і stderr порожній, є вивід у **stdout** — це справжній `NOT APPROVED`-звіт від `licensee` (`--errors-only` друкує лише невідповідні пакети): `license-violation` з деталлю пакета/ліцензії у повідомленні.
29
22
 
30
23
  ## Публічний API
31
24
 
32
- lint — аналізує код на відповідність заданим стилістичним нормам у контексті `bun`.
33
- licensee — перевіряє відповідність ліцензій усіх використаних npm-залежностей файлу `.licensee.json`.
25
+ - `lint(ctx)`detector-контракт unified lint surface; повертає `{ violations }`.
34
26
 
35
27
  ## Гарантії поведінки
36
28
 
37
- - (специфічних машинно-виведених гарантій немає)
29
+ - Read-only: не пише `.licensee.json` і не змінює `node_modules`/lockfile сам (побічний ефект `bun x` — авто-встановлення пакета `licensee`, якщо відсутній у bunx-кеші, — керується bun, не цим модулем).
30
+ - Канал stdout/stderr — єдиний сигнал розрізнення crash vs реальне порушення; текстові евристики за вмістом повідомлення не використовуються.
@@ -34,11 +34,27 @@ export function lint(ctx) {
34
34
  return reporter.result()
35
35
  }
36
36
 
37
- const r = spawnSync(bun, ['x', 'licensee', '--production', '--quiet'], { cwd, encoding: 'utf8', shell: false })
37
+ // Без --quiet: `licensee` пише реальні NOT APPROVED записи (name/version/license) у
38
+ // stdout через print() — деталь замість голого "код 1". Crash/die() усередині
39
+ // самого тула (invalid config, внутрішній виняток на кшталт "Cannot read properties
40
+ // of undefined (reading 'localeCompare')" — спостережено з @npmcli/arborist на
41
+ // bun-based node_modules) завжди йде у stderr через die(); легітимний звіт про
42
+ // порушення — лише у stdout. Канал розрізняє crash від реального порушення.
43
+ const r = spawnSync(bun, ['x', 'licensee', '--production', '--errors-only'], { cwd, encoding: 'utf8', shell: false })
38
44
  if (r.status !== 0) {
39
- const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
40
- const detail = out ? `\n${out}` : ''
41
- fail(`lint-bun: licensee — порушення ліцензій (код ${r.status}, bun.mdc)${detail}`, 'license-violation')
45
+ const stderr = (r.stderr ?? '').trim().slice(0, 2000)
46
+ if (stderr) {
47
+ fail(
48
+ `lint-bun: licensee — інструмент завершився з помилкою, це НЕ підтверджене ліцензійне порушення ` +
49
+ `(код ${r.status}, bun.mdc). Ймовірна причина — несумісність @npmcli/arborist (яким licensee читає ` +
50
+ `node_modules) з деревом, зібраним bun install. Перевір вручну: \`bunx licensee --production\`.\n${stderr}`,
51
+ 'licensee-crashed'
52
+ )
53
+ } else {
54
+ const stdout = (r.stdout ?? '').trim().slice(0, 2000)
55
+ const detail = stdout ? `\n${stdout}` : ''
56
+ fail(`lint-bun: licensee — порушення ліцензій (код ${r.status}, bun.mdc)${detail}`, 'license-violation')
57
+ }
42
58
  }
43
59
  return reporter.result()
44
60
  }
@@ -11,7 +11,7 @@ Rego-пакет: `k8s.hasura_configmap`
11
11
  | `HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS` | `"true"` |
12
12
  | `HASURA_GRAPHQL_ENABLE_RELAY` | `"false"` |
13
13
  | `HASURA_GRAPHQL_ENABLE_TELEMETRY` | `"false"` |
14
- | `HASURA_GRAPHQL_ENABLED_LOG_TYPES` | `"startup,http-log"` (точно) |
14
+ | `HASURA_GRAPHQL_ENABLED_LOG_TYPES` | `"startup,http-log"` (точно; base/dev; overlay має патчем замінити на `"startup"` — `http-log` лише для base/dev) |
15
15
  | `HASURA_GRAPHQL_ENABLED_APIS` | `"metadata,graphql,pgdump"` (base/dev; overlay має патчем замінити на `"metadata,graphql"`) |
16
16
  | `HASURA_GRAPHQL_DISABLE_EVENTING` | ключ обов'язковий, значення довільне (рекомендовано `"true"`) |
17
17
 
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: fix-manifests.mjs
4
4
  resource: npm/rules/k8s/manifests/fix-manifests.mjs
5
5
  docgen:
6
- crc: 7245cdbe
6
+ crc: e0c44174
7
7
  ---
8
8
 
9
9
  ## Огляд
@@ -157,6 +157,22 @@ function isFalsyBool(v) {
157
157
  return typeof v === 'string' && v.trim().toLowerCase() === 'false'
158
158
  }
159
159
 
160
+ /**
161
+ * Визначає значення для одного `HASURA_GRAPHQL_*` ключа за очікуванням із
162
+ * `HASURA_REQUIRED_ENV_VALUES`: `null` — довільне значення, проставляється лише
163
+ * якщо ключ відсутній (дефолт `'true'`); `'true'`/`'false'` — булеве порівняння
164
+ * (case-insensitive, `isTruthyBool`/`isFalsyBool`); інакше — точний рядок.
165
+ * @param {string|null} expected очікуване значення з `HASURA_REQUIRED_ENV_VALUES`
166
+ * @param {unknown} current поточне значення ключа в `data` (може бути `undefined`)
167
+ * @returns {string|null} значення для `setIn`, або `null`, якщо змін не потрібно
168
+ */
169
+ function resolveHasuraEnvValue(expected, current) {
170
+ if (expected === null) return current === undefined ? 'true' : null
171
+ if (expected === 'true') return isTruthyBool(current) ? null : 'true'
172
+ if (expected === 'false') return isFalsyBool(current) ? null : 'false'
173
+ return current === expected ? null : expected
174
+ }
175
+
160
176
  /**
161
177
  * Проставляє обов'язкові `HASURA_GRAPHQL_*` env-ключі (`HASURA_REQUIRED_ENV_VALUES`,
162
178
  * дзеркалить `k8s.hasura_configmap.rego`) у `data` документа `kind: ConfigMap`. Ключ з
@@ -177,32 +193,10 @@ export function ensureHasuraConfigMapRequiredEnv(content) {
177
193
 
178
194
  let changed = false
179
195
  for (const [key, expected] of Object.entries(HASURA_REQUIRED_ENV_VALUES)) {
180
- const current = doc.getIn(['data', key])
181
- if (expected === null) {
182
- if (current === undefined) {
183
- doc.setIn(['data', key], 'true')
184
- changed = true
185
- }
186
- continue
187
- }
188
- if (expected === 'true') {
189
- if (!isTruthyBool(current)) {
190
- doc.setIn(['data', key], 'true')
191
- changed = true
192
- }
193
- continue
194
- }
195
- if (expected === 'false') {
196
- if (!isFalsyBool(current)) {
197
- doc.setIn(['data', key], 'false')
198
- changed = true
199
- }
200
- continue
201
- }
202
- if (current !== expected) {
203
- doc.setIn(['data', key], expected)
204
- changed = true
205
- }
196
+ const value = resolveHasuraEnvValue(expected, doc.getIn(['data', key]))
197
+ if (value === null) continue
198
+ doc.setIn(['data', key], value)
199
+ changed = true
206
200
  }
207
201
  if (!changed) return null
208
202
  return doc.toString()
@@ -4922,6 +4922,12 @@ const HASURA_OVERLAY_ENABLED_APIS = 'metadata,graphql'
4922
4922
  /** JSON-Pointer ключа `HASURA_GRAPHQL_ENABLED_APIS` у `data` ConfigMap (для JSON6902-патчів). */
4923
4923
  const HASURA_ENABLED_APIS_DATA_POINTER = '/data/HASURA_GRAPHQL_ENABLED_APIS'
4924
4924
 
4925
+ /** Очікуване `HASURA_GRAPHQL_ENABLED_LOG_TYPES` у non-base/dev overlay (без `http-log` — він лише для base/dev). */
4926
+ const HASURA_OVERLAY_ENABLED_LOG_TYPES = 'startup'
4927
+
4928
+ /** JSON-Pointer ключа `HASURA_GRAPHQL_ENABLED_LOG_TYPES` у `data` ConfigMap (для JSON6902-патчів). */
4929
+ const HASURA_ENABLED_LOG_TYPES_DATA_POINTER = '/data/HASURA_GRAPHQL_ENABLED_LOG_TYPES'
4930
+
4925
4931
  /**
4926
4932
  * Чи дерево kustomization (`resources` / `bases` / `components` / `crds`, рекурсивно) містить
4927
4933
  * **Hasura-Deployment** у шарі base (образ `hasura/graphql-engine`). Маркер того, що overlay успадковує
@@ -4965,18 +4971,19 @@ function firstValidYamlJsonFromPatchText(patchText) {
4965
4971
  }
4966
4972
 
4967
4973
  /**
4968
- * Значення `data.HASURA_GRAPHQL_ENABLED_APIS` з JSON6902-патчу (масив операцій).
4969
- * Повертає значення першої `add`/`replace`-операції на `/data/HASURA_GRAPHQL_ENABLED_APIS`.
4974
+ * Значення `data.<dataKey>` з JSON6902-патчу (масив операцій).
4975
+ * Повертає значення першої `add`/`replace`-операції на `/data/<dataKey>`.
4970
4976
  * @param {unknown[]} ops масив JSON6902-операцій
4977
+ * @param {string} dataPointer JSON-Pointer ключа (`/data/<dataKey>`)
4971
4978
  * @returns {string | null} присвоєне значення (рядок) або null
4972
4979
  */
4973
- function enabledApisValueFromJson6902(ops) {
4980
+ function hasuraDataKeyValueFromJson6902(ops, dataPointer) {
4974
4981
  for (const item of ops) {
4975
4982
  if (item === null || typeof item !== 'object' || Array.isArray(item)) continue
4976
4983
  const rec = /** @type {Record<string, unknown>} */ (item)
4977
4984
  const op = typeof rec.op === 'string' ? rec.op.trim().toLowerCase() : ''
4978
4985
  const path = typeof rec.path === 'string' ? normalizeJsonPatchPath(rec.path) : ''
4979
- if ((op === 'add' || op === 'replace') && path === HASURA_ENABLED_APIS_DATA_POINTER) {
4986
+ if ((op === 'add' || op === 'replace') && path === dataPointer) {
4980
4987
  return typeof rec.value === 'string' ? rec.value : JSON.stringify(rec.value)
4981
4988
  }
4982
4989
  }
@@ -4984,42 +4991,58 @@ function enabledApisValueFromJson6902(ops) {
4984
4991
  }
4985
4992
 
4986
4993
  /**
4987
- * Значення `data.HASURA_GRAPHQL_ENABLED_APIS` зі Strategic-Merge-патчу (об'єкт із `data`).
4994
+ * Значення `data.<dataKey>` зі Strategic-Merge-патчу (об'єкт із `data`).
4988
4995
  * @param {object} parsed розпарсений об'єкт patch
4996
+ * @param {string} dataKey ключ у `data` (наприклад `HASURA_GRAPHQL_ENABLED_APIS`)
4989
4997
  * @returns {string | null} присвоєне значення (рядок) або null
4990
4998
  */
4991
- function enabledApisValueFromStrategicMerge(parsed) {
4999
+ function hasuraDataKeyValueFromStrategicMerge(parsed, dataKey) {
4992
5000
  const data = /** @type {Record<string, unknown>} */ (parsed).data
4993
5001
  if (data === null || typeof data !== 'object' || Array.isArray(data)) return null
4994
5002
  const d = /** @type {Record<string, unknown>} */ (data)
4995
- if (!Object.hasOwn(d, 'HASURA_GRAPHQL_ENABLED_APIS')) return null
4996
- const v = d.HASURA_GRAPHQL_ENABLED_APIS
5003
+ if (!Object.hasOwn(d, dataKey)) return null
5004
+ const v = d[dataKey]
4997
5005
  return typeof v === 'string' ? v : JSON.stringify(v)
4998
5006
  }
4999
5007
 
5000
5008
  /**
5001
- * Значення, яке inline-`patch` присвоює `data.HASURA_GRAPHQL_ENABLED_APIS`. Підтримка двох форматів:
5002
- * **JSON6902** (`op` add/replace на `/data/HASURA_GRAPHQL_ENABLED_APIS`) і **Strategic Merge**
5003
- * (`data.HASURA_GRAPHQL_ENABLED_APIS`). Зовнішні patch-файли (`patches[].path`) не охоплені — Plan B trade-off.
5009
+ * Значення, яке inline-`patch` присвоює `data.<dataKey>`. Підтримка двох форматів:
5010
+ * **JSON6902** (`op` add/replace на `/data/<dataKey>`) і **Strategic Merge** (`data.<dataKey>`).
5011
+ * Зовнішні patch-файли (`patches[].path`) не охоплені — Plan B trade-off.
5004
5012
  * @param {string} patchText вміст поля `patch`
5013
+ * @param {string} dataKey ключ у `data`
5014
+ * @param {string} dataPointer JSON-Pointer ключа (`/data/<dataKey>`)
5005
5015
  * @returns {string | null} присвоєне значення (рядок) або null, якщо patch не чіпає цей ключ
5006
5016
  */
5007
- export function enabledApisValueFromPatchText(patchText) {
5017
+ function hasuraDataKeyValueFromPatchText(patchText, dataKey, dataPointer) {
5008
5018
  const t = typeof patchText === 'string' ? patchText.trim() : ''
5009
5019
  if (t === '') return null
5010
5020
  const parsed = firstValidYamlJsonFromPatchText(t)
5011
- if (Array.isArray(parsed)) return enabledApisValueFromJson6902(parsed)
5021
+ if (Array.isArray(parsed)) return hasuraDataKeyValueFromJson6902(parsed, dataPointer)
5012
5022
  if (parsed === null || typeof parsed !== 'object') return null
5013
- return enabledApisValueFromStrategicMerge(parsed)
5023
+ return hasuraDataKeyValueFromStrategicMerge(parsed, dataKey)
5014
5024
  }
5015
5025
 
5016
5026
  /**
5017
- * Значення, яке `patches[]` kustomization присвоюють `data.HASURA_GRAPHQL_ENABLED_APIS` на цілі **ConfigMap**.
5027
+ * Значення, яке inline-`patch` присвоює `data.HASURA_GRAPHQL_ENABLED_APIS`. Підтримка двох форматів:
5028
+ * **JSON6902** (`op` add/replace на `/data/HASURA_GRAPHQL_ENABLED_APIS`) і **Strategic Merge**
5029
+ * (`data.HASURA_GRAPHQL_ENABLED_APIS`). Зовнішні patch-файли (`patches[].path`) не охоплені — Plan B trade-off.
5030
+ * @param {string} patchText вміст поля `patch`
5031
+ * @returns {string | null} присвоєне значення (рядок) або null, якщо patch не чіпає цей ключ
5032
+ */
5033
+ export function enabledApisValueFromPatchText(patchText) {
5034
+ return hasuraDataKeyValueFromPatchText(patchText, 'HASURA_GRAPHQL_ENABLED_APIS', HASURA_ENABLED_APIS_DATA_POINTER)
5035
+ }
5036
+
5037
+ /**
5038
+ * Значення, яке `patches[]` kustomization присвоюють `data.<dataKey>` на цілі **ConfigMap**.
5018
5039
  * Повертає значення першого patch-а, що чіпає цей ключ, або null, якщо такого немає.
5019
5040
  * @param {Record<string, unknown>} kust об'єкт kustomization.yaml
5041
+ * @param {string} dataKey ключ у `data`
5042
+ * @param {string} dataPointer JSON-Pointer ключа (`/data/<dataKey>`)
5020
5043
  * @returns {string | null} присвоєне значення або null
5021
5044
  */
5022
- export function hasuraEnabledApisOverrideValue(kust) {
5045
+ function hasuraDataKeyOverrideValue(kust, dataKey, dataPointer) {
5023
5046
  const patches = kust.patches
5024
5047
  if (!Array.isArray(patches)) return null
5025
5048
  for (const p of patches) {
@@ -5027,12 +5050,32 @@ export function hasuraEnabledApisOverrideValue(kust) {
5027
5050
  const pr = /** @type {Record<string, unknown>} */ (p)
5028
5051
  if (typeof pr.patch !== 'string') continue
5029
5052
  if (resolvePatchTargetKind(pr) !== 'ConfigMap') continue
5030
- const v = enabledApisValueFromPatchText(pr.patch)
5053
+ const v = hasuraDataKeyValueFromPatchText(pr.patch, dataKey, dataPointer)
5031
5054
  if (v !== null) return v
5032
5055
  }
5033
5056
  return null
5034
5057
  }
5035
5058
 
5059
+ /**
5060
+ * Значення, яке `patches[]` kustomization присвоюють `data.HASURA_GRAPHQL_ENABLED_APIS` на цілі **ConfigMap**.
5061
+ * Повертає значення першого patch-а, що чіпає цей ключ, або null, якщо такого немає.
5062
+ * @param {Record<string, unknown>} kust об'єкт kustomization.yaml
5063
+ * @returns {string | null} присвоєне значення або null
5064
+ */
5065
+ export function hasuraEnabledApisOverrideValue(kust) {
5066
+ return hasuraDataKeyOverrideValue(kust, 'HASURA_GRAPHQL_ENABLED_APIS', HASURA_ENABLED_APIS_DATA_POINTER)
5067
+ }
5068
+
5069
+ /**
5070
+ * Значення, яке `patches[]` kustomization присвоюють `data.HASURA_GRAPHQL_ENABLED_LOG_TYPES` на цілі **ConfigMap**.
5071
+ * Повертає значення першого patch-а, що чіпає цей ключ, або null, якщо такого немає.
5072
+ * @param {Record<string, unknown>} kust об'єкт kustomization.yaml
5073
+ * @returns {string | null} присвоєне значення або null
5074
+ */
5075
+ export function hasuraEnabledLogTypesOverrideValue(kust) {
5076
+ return hasuraDataKeyOverrideValue(kust, 'HASURA_GRAPHQL_ENABLED_LOG_TYPES', HASURA_ENABLED_LOG_TYPES_DATA_POINTER)
5077
+ }
5078
+
5036
5079
  /**
5037
5080
  * Для кожного **non-base/dev** overlay `kustomization.yaml`, що успадковує Hasura-base (Deployment з
5038
5081
  * `hasura/graphql-engine`), вимагає у `patches[]` перевизначення **`data.HASURA_GRAPHQL_ENABLED_APIS`**
@@ -5070,6 +5113,43 @@ async function validateHasuraOverlayEnabledApisOverride(root, yamlFilesAbs, fail
5070
5113
  }
5071
5114
  }
5072
5115
 
5116
+ /**
5117
+ * Для кожного **non-base/dev** overlay `kustomization.yaml`, що успадковує Hasura-base (Deployment з
5118
+ * `hasura/graphql-engine`), вимагає у `patches[]` перевизначення **`data.HASURA_GRAPHQL_ENABLED_LOG_TYPES`**
5119
+ * до **`"startup"`** (`http-log` лишається строго для base/dev — прод не пише per-request access-лог у
5120
+ * Cloud Logging). `kind: Component` пропускається (env-неутральне джерело, не overlay).
5121
+ * @param {string} root корінь репозиторію
5122
+ * @param {string[]} yamlFilesAbs yaml під k8s
5123
+ * @param {(msg: string) => void} fail callback при помилці
5124
+ * @param {(msg: string) => void} passFn callback при успіху
5125
+ */
5126
+ async function validateHasuraOverlayEnabledLogTypesOverride(root, yamlFilesAbs, fail, passFn) {
5127
+ const rootNorm = resolve(root)
5128
+ const kustFiles = yamlFilesAbs.filter(abs => basename(abs) === 'kustomization.yaml')
5129
+ for (const kustAbs of kustFiles) {
5130
+ const rel = (relative(rootNorm, kustAbs) || kustAbs).replaceAll('\\', '/')
5131
+ const segment = k8sEnvSegmentFromRelPath(rel)
5132
+ if (segment === null || segment === 'base' || segment === 'dev') continue
5133
+ const kust = await readFirstYamlObject(kustAbs)
5134
+ if (kust === null || kust.kind === 'Component') continue
5135
+ if (!(await kustomizationTreeHasHasuraDeployment(kustAbs, rootNorm))) continue
5136
+ const value = hasuraEnabledLogTypesOverrideValue(kust)
5137
+ if (value === HASURA_OVERLAY_ENABLED_LOG_TYPES) {
5138
+ passFn(
5139
+ `${rel}: overlay '${segment}' перевизначає HASURA_GRAPHQL_ENABLED_LOG_TYPES="${HASURA_OVERLAY_ENABLED_LOG_TYPES}" (k8s.mdc)`
5140
+ )
5141
+ } else if (value === null) {
5142
+ fail(
5143
+ `${rel}: overlay '${segment}' має у patches[] перевизначати data.HASURA_GRAPHQL_ENABLED_LOG_TYPES до "${HASURA_OVERLAY_ENABLED_LOG_TYPES}" (http-log лише для base/dev) (k8s.mdc)`
5144
+ )
5145
+ } else {
5146
+ fail(
5147
+ `${rel}: overlay '${segment}' patch data.HASURA_GRAPHQL_ENABLED_LOG_TYPES має бути "${HASURA_OVERLAY_ENABLED_LOG_TYPES}" (зараз: ${JSON.stringify(value)}) (k8s.mdc)`
5148
+ )
5149
+ }
5150
+ }
5151
+ }
5152
+
5073
5153
  /**
5074
5154
  * Шукає HPA за `scaleTargetRef.name` серед документів.
5075
5155
  * @param {Record<string, unknown>[]} hpaDocs масив HPA-документів
@@ -6658,6 +6738,8 @@ export async function lint(ctx) {
6658
6738
 
6659
6739
  await validateHasuraOverlayEnabledApisOverride(root, yamlFiles, fail, pass)
6660
6740
 
6741
+ await validateHasuraOverlayEnabledLogTypesOverride(root, yamlFiles, fail, pass)
6742
+
6661
6743
  return reporter.result()
6662
6744
  }
6663
6745