@nitra/cursor 3.12.0 → 3.13.0
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,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.13.0] - 2026-06-02
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- k8s hasura_configmap: розширено перелік обов'язкових env у ConfigMap Hasura-Deployment — додатково до HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS="true" тепер вимагаються HASURA_GRAPHQL_ENABLE_RELAY="false", HASURA_GRAPHQL_ENABLE_TELEMETRY="false", HASURA_GRAPHQL_ENABLED_LOG_TYPES="startup,http-log" (точний рядок) і HASURA_GRAPHQL_DISABLE_EVENTING (ключ обов'язковий, значення довільне, за замовчуванням "true")
|
|
8
|
+
|
|
3
9
|
## [3.12.0] - 2026-06-02
|
|
4
10
|
|
|
5
11
|
### Added
|
package/package.json
CHANGED
|
@@ -2349,47 +2349,17 @@ export function isHasuraDeploymentManifest(manifest) {
|
|
|
2349
2349
|
}
|
|
2350
2350
|
|
|
2351
2351
|
/**
|
|
2352
|
-
* Обов'
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
function isConfigMapValueTrue(v) {
|
|
2364
|
-
if (v === true) return true
|
|
2365
|
-
if (typeof v === 'string' && v.trim().toLowerCase() === 'true') return true
|
|
2366
|
-
return false
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
|
-
/**
|
|
2370
|
-
* Чи порушує ConfigMap вимогу щодо **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS: "true"`** (k8s.mdc).
|
|
2371
|
-
* Перевірка застосовна, коли в тому ж каталозі є Hasura-Deployment (див. `isHasuraDeploymentManifest`).
|
|
2372
|
-
* @param {unknown} manifest корінь YAML-документа ConfigMap
|
|
2373
|
-
* @returns {string | null} текст порушення або null, якщо не ConfigMap / ключ є і значення `true`
|
|
2374
|
-
*/
|
|
2375
|
-
export function hasuraConfigMapRemoteSchemaPermissionsViolation(manifest) {
|
|
2376
|
-
if (manifest === null || manifest === undefined || typeof manifest !== 'object' || Array.isArray(manifest))
|
|
2377
|
-
return null
|
|
2378
|
-
const rec = /** @type {Record<string, unknown>} */ (manifest)
|
|
2379
|
-
if (rec.kind !== 'ConfigMap') return null
|
|
2380
|
-
const data = rec.data
|
|
2381
|
-
if (data === null || data === undefined || typeof data !== 'object' || Array.isArray(data)) {
|
|
2382
|
-
return `data.${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}: додай ключ зі значенням "true" (Deployment з hasura/graphql-engine — див. k8s.mdc)`
|
|
2383
|
-
}
|
|
2384
|
-
const d = /** @type {Record<string, unknown>} */ (data)
|
|
2385
|
-
if (!Object.hasOwn(d, HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY)) {
|
|
2386
|
-
return `data.${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}: додай ключ зі значенням "true" (Deployment з hasura/graphql-engine — див. k8s.mdc)`
|
|
2387
|
-
}
|
|
2388
|
-
if (!isConfigMapValueTrue(d[HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY])) {
|
|
2389
|
-
return `data.${HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY}: значення має бути "true" (зараз: ${JSON.stringify(d[HASURA_REMOTE_SCHEMA_PERMISSIONS_KEY])}) (див. k8s.mdc)`
|
|
2390
|
-
}
|
|
2391
|
-
return null
|
|
2392
|
-
}
|
|
2352
|
+
* Обов'язкові env-ключі у **`data`** ConfigMap для Hasura-Deployment (узгоджено з
|
|
2353
|
+
* rego-пакетом `k8s.hasura_configmap` та k8s.mdc). Лише для людиночитного pass-повідомлення —
|
|
2354
|
+
* авторитетна пер-документна валідація (наявність ключів і значення) живе в rego.
|
|
2355
|
+
*/
|
|
2356
|
+
export const HASURA_REQUIRED_ENV_KEYS = [
|
|
2357
|
+
'HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS',
|
|
2358
|
+
'HASURA_GRAPHQL_ENABLE_RELAY',
|
|
2359
|
+
'HASURA_GRAPHQL_ENABLE_TELEMETRY',
|
|
2360
|
+
'HASURA_GRAPHQL_ENABLED_LOG_TYPES',
|
|
2361
|
+
'HASURA_GRAPHQL_DISABLE_EVENTING'
|
|
2362
|
+
]
|
|
2393
2363
|
|
|
2394
2364
|
const K8S_YAML_EXT_RE = /\.ya?ml$/iu
|
|
2395
2365
|
|
|
@@ -3676,7 +3646,10 @@ async function validateConfigMapNameMatchesDeployment(root, yamlFilesAbs, fail,
|
|
|
3676
3646
|
|
|
3677
3647
|
/**
|
|
3678
3648
|
* Для кожного `k8s/base/configmap.yaml`, у каталозі якого поруч є Hasura-Deployment,
|
|
3679
|
-
* вимагає у `data`
|
|
3649
|
+
* вимагає у `data` обов'язкові env-ключі (`HASURA_REQUIRED_ENV_KEYS`) з очікуваними
|
|
3650
|
+
* значеннями (`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS="true"`,
|
|
3651
|
+
* `HASURA_GRAPHQL_ENABLE_RELAY="false"`, `HASURA_GRAPHQL_ENABLE_TELEMETRY="false"`,
|
|
3652
|
+
* `HASURA_GRAPHQL_ENABLED_LOG_TYPES="startup,http-log"`, `HASURA_GRAPHQL_DISABLE_EVENTING` — будь-яке) (k8s.mdc).
|
|
3680
3653
|
* @param {string} root корінь репозиторію
|
|
3681
3654
|
* @param {string[]} yamlFilesAbs yaml під k8s
|
|
3682
3655
|
* @param {(msg: string) => void} fail callback при помилці
|
|
@@ -3688,8 +3661,8 @@ async function validateHasuraConfigMapRemoteSchemaPermissions(root, yamlFilesAbs
|
|
|
3688
3661
|
return CONFIGMAP_BASE_PATH_RE.test(`/${rel}`) || rel === 'k8s/base/configmap.yaml'
|
|
3689
3662
|
})
|
|
3690
3663
|
// JS gating: відберемо ConfigMap-файли, у каталозі яких поруч є Hasura-Deployment.
|
|
3691
|
-
// Per-document валідація `data.
|
|
3692
|
-
//
|
|
3664
|
+
// Per-document валідація обов'язкових `data.HASURA_GRAPHQL_*` env — у rego-пакеті
|
|
3665
|
+
// `k8s.hasura_configmap`.
|
|
3693
3666
|
const paired = []
|
|
3694
3667
|
for (const cmAbs of cmFiles) {
|
|
3695
3668
|
const deployment = await findDeploymentDocInDir(dirname(cmAbs))
|
|
@@ -3708,7 +3681,7 @@ async function validateHasuraConfigMapRemoteSchemaPermissions(root, yamlFilesAbs
|
|
|
3708
3681
|
fail(`${rel}: ${v.message}`)
|
|
3709
3682
|
}
|
|
3710
3683
|
if (violations.length === 0) {
|
|
3711
|
-
passFn(`Hasura-ConfigMap (${paired.length})
|
|
3684
|
+
passFn(`Hasura-ConfigMap (${paired.length}) містить обов'язкові env [${HASURA_REQUIRED_ENV_KEYS.join(', ')}] (rego)`)
|
|
3712
3685
|
}
|
|
3713
3686
|
}
|
|
3714
3687
|
|
package/rules/k8s/k8s.mdc
CHANGED
|
@@ -297,11 +297,23 @@ spec:
|
|
|
297
297
|
|
|
298
298
|
## ConfigMap для Hasura-Deployment
|
|
299
299
|
|
|
300
|
-
Якщо в `k8s/base/` поруч із **`configmap.yaml`** є **Deployment** з образом **`hasura/graphql-engine`**, у `data` ConfigMap **обов'язково**
|
|
300
|
+
Якщо в `k8s/base/` поруч із **`configmap.yaml`** є **Deployment** з образом **`hasura/graphql-engine`**, у `data` ConfigMap **обов'язково** мають бути env-ключі:
|
|
301
|
+
|
|
302
|
+
- **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS`** зі значенням **`"true"`**;
|
|
303
|
+
- **`HASURA_GRAPHQL_ENABLE_RELAY`** зі значенням **`"false"`**;
|
|
304
|
+
- **`HASURA_GRAPHQL_ENABLE_TELEMETRY`** зі значенням **`"false"`**;
|
|
305
|
+
- **`HASURA_GRAPHQL_ENABLED_LOG_TYPES`** зі значенням **`"startup,http-log"`** (точний рядок);
|
|
306
|
+
- **`HASURA_GRAPHQL_DISABLE_EVENTING`** — ключ обов'язковий, значення довільне (за замовчуванням **`"true"`**).
|
|
307
|
+
|
|
308
|
+
Точні умови перевірки — rego-пакет **`k8s.hasura_configmap`** (cross-file прив'язка ConfigMap↔Deployment — у `rules/k8s/js/manifests.mjs`).
|
|
301
309
|
|
|
302
310
|
```yaml
|
|
303
311
|
data:
|
|
304
312
|
HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS: 'true'
|
|
313
|
+
HASURA_GRAPHQL_ENABLE_RELAY: 'false'
|
|
314
|
+
HASURA_GRAPHQL_ENABLE_TELEMETRY: 'false'
|
|
315
|
+
HASURA_GRAPHQL_ENABLED_LOG_TYPES: 'startup,http-log'
|
|
316
|
+
HASURA_GRAPHQL_DISABLE_EVENTING: 'true'
|
|
305
317
|
```
|
|
306
318
|
|
|
307
319
|
## Kustomize: структура каталогів (`base` / overlays)
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
# Порт перевірки ConfigMap для Hasura-Deployment з
|
|
2
2
|
# `npm/scripts/rules/k8s/fix.mjs` (k8s.mdc): у ConfigMap, що сусідствує з
|
|
3
|
-
# Hasura-Deployment, у `data` обов'язково
|
|
4
|
-
# `
|
|
3
|
+
# Hasura-Deployment, у `data` обов'язково мають бути env-ключі зі списку
|
|
4
|
+
# `required_env` з очікуваними значеннями:
|
|
5
|
+
# "HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS" → "true"
|
|
6
|
+
# "HASURA_GRAPHQL_ENABLE_RELAY" → "false"
|
|
7
|
+
# "HASURA_GRAPHQL_ENABLE_TELEMETRY" → "false"
|
|
8
|
+
# "HASURA_GRAPHQL_ENABLED_LOG_TYPES" → "startup,http-log" (точний рядок)
|
|
9
|
+
# "HASURA_GRAPHQL_DISABLE_EVENTING" → null (ключ обов'язковий,
|
|
10
|
+
# значення довільне; за замовчуванням рекомендовано "true")
|
|
11
|
+
#
|
|
12
|
+
# Семантика очікуваного значення у `required_env`:
|
|
13
|
+
# "true" — має читатись як логічне true (boolean true або рядок "true", case-insensitive);
|
|
14
|
+
# "false" — має читатись як логічне false (boolean false або рядок "false", case-insensitive);
|
|
15
|
+
# null — ключ обов'язковий, значення довільне (за замовчуванням "true");
|
|
16
|
+
# інший рядок — значення має точно дорівнювати рядку (exact match).
|
|
5
17
|
#
|
|
6
18
|
# Запуск (локально, лише для ConfigMap у каталозі з Hasura-Deployment):
|
|
7
19
|
# conftest test path/to/k8s/.../configmap.yaml \
|
|
8
20
|
# -p npm/policy/k8s/hasura_configmap \
|
|
9
21
|
# --namespace k8s.hasura_configmap
|
|
10
22
|
#
|
|
11
|
-
# Прив'язка ConfigMap-Deployment cross-file — у JS (`rules/k8s/
|
|
23
|
+
# Прив'язка ConfigMap-Deployment cross-file — у JS (`rules/k8s/js/manifests.mjs`:
|
|
12
24
|
# `validateHasuraConfigMapRemoteSchemaPermissions` шукає Hasura-Deployment
|
|
13
25
|
# у тому ж dir-у і викликає conftest з цією намеспейс лише для відповідних
|
|
14
|
-
# ConfigMap-ів).
|
|
15
|
-
#
|
|
26
|
+
# ConfigMap-ів). Rego authoritative для пер-документної валідації; JS лишає
|
|
27
|
+
# лише cross-file orchestration.
|
|
16
28
|
#
|
|
17
29
|
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
18
30
|
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`.
|
|
@@ -20,45 +32,82 @@ package k8s.hasura_configmap
|
|
|
20
32
|
|
|
21
33
|
import rego.v1
|
|
22
34
|
|
|
23
|
-
# Обов'
|
|
24
|
-
|
|
35
|
+
# Обов'язкові env-ключі у `data` (узгоджено з `rules/k8s/js/manifests.mjs` та k8s.mdc).
|
|
36
|
+
# Значення — очікуваний стан ключа (семантика — у шапці файлу).
|
|
37
|
+
required_env := {
|
|
38
|
+
"HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS": "true",
|
|
39
|
+
"HASURA_GRAPHQL_ENABLE_RELAY": "false",
|
|
40
|
+
"HASURA_GRAPHQL_ENABLE_TELEMETRY": "false",
|
|
41
|
+
"HASURA_GRAPHQL_ENABLED_LOG_TYPES": "startup,http-log",
|
|
42
|
+
"HASURA_GRAPHQL_DISABLE_EVENTING": null,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Множина "boolean-подібних" очікувань — для них значення читається як логічне,
|
|
46
|
+
# а не звіряється точним рядком.
|
|
47
|
+
bool_expected := {"true", "false"}
|
|
48
|
+
|
|
49
|
+
# Підказка про очікуване значення для повідомлення про відсутній ключ.
|
|
50
|
+
expected_hint(null) := "(значення довільне, за замовчуванням \"true\")"
|
|
25
51
|
|
|
26
|
-
|
|
27
|
-
"data.%s: додай ключ зі значенням \"true\"",
|
|
28
|
-
"(Deployment з hasura/graphql-engine — k8s.mdc)",
|
|
29
|
-
])
|
|
52
|
+
expected_hint(expected) := sprintf("зі значенням \"%s\"", [expected]) if is_string(expected)
|
|
30
53
|
|
|
31
|
-
key_value_wrong_template := concat(" ", ["data.%s: значення має бути \"
|
|
54
|
+
key_value_wrong_template := concat(" ", ["data.%s: значення має бути \"%s\" (зараз: %v) (k8s.mdc)"])
|
|
55
|
+
|
|
56
|
+
# Ключ відсутній: `data` не об'єкт або в ньому немає обов'язкового ключа.
|
|
57
|
+
deny contains msg if {
|
|
58
|
+
input.kind == "ConfigMap"
|
|
59
|
+
some key, expected in required_env
|
|
60
|
+
not key_present(key)
|
|
61
|
+
msg := sprintf(
|
|
62
|
+
"data.%s: додай ключ %s (Deployment з hasura/graphql-engine — k8s.mdc)",
|
|
63
|
+
[key, expected_hint(expected)],
|
|
64
|
+
)
|
|
65
|
+
}
|
|
32
66
|
|
|
67
|
+
# Очікуване "true", а значення не читається як логічне true.
|
|
33
68
|
deny contains msg if {
|
|
34
69
|
input.kind == "ConfigMap"
|
|
35
|
-
|
|
36
|
-
|
|
70
|
+
d := object.get(input, "data", null)
|
|
71
|
+
is_object(d)
|
|
72
|
+
some key, expected in required_env
|
|
73
|
+
expected == "true"
|
|
74
|
+
key in object.keys(d)
|
|
75
|
+
not is_value_true(d[key])
|
|
76
|
+
msg := sprintf(key_value_wrong_template, [key, "true", d[key]])
|
|
37
77
|
}
|
|
38
78
|
|
|
79
|
+
# Очікуване "false", а значення не читається як логічне false.
|
|
39
80
|
deny contains msg if {
|
|
40
81
|
input.kind == "ConfigMap"
|
|
41
82
|
d := object.get(input, "data", null)
|
|
42
83
|
is_object(d)
|
|
43
|
-
|
|
44
|
-
|
|
84
|
+
some key, expected in required_env
|
|
85
|
+
expected == "false"
|
|
86
|
+
key in object.keys(d)
|
|
87
|
+
not is_value_false(d[key])
|
|
88
|
+
msg := sprintf(key_value_wrong_template, [key, "false", d[key]])
|
|
45
89
|
}
|
|
46
90
|
|
|
91
|
+
# Очікуване — точний рядок (не "true"/"false"/null), а значення не збігається.
|
|
47
92
|
deny contains msg if {
|
|
48
93
|
input.kind == "ConfigMap"
|
|
49
94
|
d := object.get(input, "data", null)
|
|
50
95
|
is_object(d)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
not
|
|
54
|
-
|
|
96
|
+
some key, expected in required_env
|
|
97
|
+
is_string(expected)
|
|
98
|
+
not expected in bool_expected
|
|
99
|
+
key in object.keys(d)
|
|
100
|
+
d[key] != expected
|
|
101
|
+
msg := sprintf(key_value_wrong_template, [key, expected, d[key]])
|
|
55
102
|
}
|
|
56
103
|
|
|
57
|
-
key_present(
|
|
58
|
-
|
|
104
|
+
key_present(key) if {
|
|
105
|
+
d := object.get(input, "data", null)
|
|
106
|
+
is_object(d)
|
|
107
|
+
key in object.keys(d)
|
|
59
108
|
}
|
|
60
109
|
|
|
61
|
-
# Значення вважається "true", якщо це boolean
|
|
110
|
+
# Значення вважається "true"/"false", якщо це відповідний boolean або рядок
|
|
62
111
|
# (case-insensitive). ConfigMap у Kubernetes тримає рядки, але YAML без лапок
|
|
63
112
|
# дає boolean — приймаємо обидва варіанти.
|
|
64
113
|
is_value_true(true)
|
|
@@ -67,3 +116,10 @@ is_value_true(v) if {
|
|
|
67
116
|
is_string(v)
|
|
68
117
|
lower(trim_space(v)) == "true"
|
|
69
118
|
}
|
|
119
|
+
|
|
120
|
+
is_value_false(false)
|
|
121
|
+
|
|
122
|
+
is_value_false(v) if {
|
|
123
|
+
is_string(v)
|
|
124
|
+
lower(trim_space(v)) == "false"
|
|
125
|
+
}
|