@7n/rules 1.29.0 → 1.29.1

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
+ ## [1.29.1] - 2026-07-19
4
+
5
+ ### Changed
6
+
7
+ - release: @7n/rules@1.29.0, @7n/rules-lang-js@0.5.0
8
+
3
9
  ## [1.29.0] - 2026-07-19
4
10
 
5
11
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/rules",
3
- "version": "1.29.0",
3
+ "version": "1.29.1",
4
4
  "description": "CLI еталонних правил і skills (префікс n-): синк у репозиторій, дельта-lint, конформність",
5
5
  "keywords": [
6
6
  "cli",
@@ -4,5 +4,9 @@
4
4
  "files": {
5
5
  "walkGlob": "**/dremio_v2/config/logback.xml"
6
6
  }
7
+ },
8
+ "lint": {
9
+ "scope": "per-file",
10
+ "glob": ["**/dremio_v2/templates/zookeeper.yaml"]
7
11
  }
8
12
  }
@@ -29,3 +29,32 @@ Rego-пакет: `k8s.dremio_logging`
29
29
  ```
30
30
 
31
31
  **Autofix:** відсутній (detection-only, як `hasura_httproute`) — XML-трансформ складніший за YAML `setIn`; T0-fix, за потреби, окремою ітерацією.
32
+
33
+ ## ZooKeeper: root level вбудованого logback.xml
34
+
35
+ JS-детектор (не rego): `main.mjs`, `lint(ctx)`, per-file, glob `**/dremio_v2/templates/zookeeper.yaml`.
36
+
37
+ **Чому окремо від rego вище:** `zookeeper.yaml` — vendored Helm-темплейт (Go-template синтаксис `{{ ... }}`), НЕ валідний YAML/XML, conftest розпарсити не може.
38
+
39
+ **Що перевіряється:** якщо файл визначає `ConfigMap` з `data["logback.xml"]` (bundled-конфіг образу `zookeeper:3.8.4-jre-17`, монтується поверх `/conf/logback.xml`), його `<root level="...">` має бути `warn`/`error`/`off` (case-insensitive) — не `info`/`debug`/`trace` (дефолт бандлованого файлу) і не відсутній.
40
+
41
+ **Чому:** readiness/liveness `ruok`-проби виконуються кожні ~10s на кожен zk-под; `NIOServerCnxn` логує це на INFO незалежно від навантаження. Керувати рівнем ззовні НЕ вдається для цього образу:
42
+ - `ZOO_LOG4J_PROP` — змінна Bitnami-образів, тут взагалі не читається жодним скриптом.
43
+ - `-Dzookeeper.console.threshold=WARN` через `JVMFLAGS` — перебивається `<property name="zookeeper.console.threshold" value="INFO"/>` у бандлованому файлі.
44
+
45
+ Єдиний робочий шлях (підтверджено живою перевіркою в проді) — змонтувати власний `logback.xml` (`ConfigMap` + `volumeMount subPath: logback.xml` поверх `/conf/logback.xml`) з іншим `root level`.
46
+
47
+ **Приклад валідного фрагмента:**
48
+
49
+ ```yaml
50
+ data:
51
+ logback.xml: |
52
+ <configuration>
53
+ ...
54
+ <root level="WARN">
55
+ <appender-ref ref="CONSOLE" />
56
+ </root>
57
+ </configuration>
58
+ ```
59
+
60
+ **Autofix:** відсутній (detection-only) — текстовий Helm-темплейт, ризиковано трансформувати блайндово; T0-fix, за потреби, окремою ітерацією.
@@ -0,0 +1,67 @@
1
+ /** @see ./dremio_logging.mdc */
2
+
3
+ /**
4
+ * JS-доповнення до `k8s.dremio_logging` (rego) для `dremio_v2/templates/zookeeper.yaml` —
5
+ * vendored Helm-темплейт ZooKeeper (Go-template синтаксис, `{{ ... }}`), тому НЕ валідний
6
+ * YAML/XML і conftest його розпарсити не може (звідси JS, не rego, для цього файлу).
7
+ *
8
+ * Перевіряє: якщо файл визначає `ConfigMap` з ключем `data["logback.xml"]` (bundled-конфіг
9
+ * образу `zookeeper:3.8.4-jre-17`, змонтований поверх `/conf/logback.xml`), його
10
+ * `<root level="...">` має бути `warn`/`error`/`off` — не `info` (дефолт бандлованого файлу).
11
+ *
12
+ * Чому: readiness/liveness-проби (`ruok`) виконуються кожні ~10s на кожен zk-под;
13
+ * `NIOServerCnxn` логує це на INFO незалежно від навантаження. Спроби керувати рівнем ззовні
14
+ * (`ZOO_LOG4J_PROP` — Bitnami-змінна, тут не читається; `-Dzookeeper.console.threshold`
15
+ * через JVMFLAGS — перебивається `<property name="zookeeper.console.threshold" value="INFO"/>`
16
+ * у бандлованому файлі) не працюють для цього образу — єдиний робочий шлях: змонтувати
17
+ * власний `logback.xml` з іншим `root level`.
18
+ */
19
+ import { readFile } from 'node:fs/promises'
20
+ import { join } from 'node:path'
21
+
22
+ import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
23
+
24
+ const ROOT_LEVEL_RE = /<root\s+level\s*=\s*["']([^"']+)["']/iu
25
+ const LOGBACK_XML_KEY_RE = /logback\.xml:\s*\|/u
26
+ const ALLOWED_ROOT_LEVELS = new Set(['warn', 'error', 'off'])
27
+
28
+ /**
29
+ * Чи файл (Helm-темплейт ZooKeeper) визначає вбудований `logback.xml` з надто гучним
30
+ * `<root level="...">` (info/debug/trace, чи взагалі відсутній тег root).
31
+ * @param {string} content вміст `dremio_v2/templates/zookeeper.yaml`
32
+ * @returns {string | null} текст порушення, або null — якщо `logback.xml`-блоку немає
33
+ * (нема чого перевіряти) чи `root level` вже warn/error/off
34
+ */
35
+ export function zkLogbackRootLevelViolation(content) {
36
+ if (!LOGBACK_XML_KEY_RE.test(content)) return null // немає вбудованого logback.xml — не наша справа
37
+ const m = ROOT_LEVEL_RE.exec(content)
38
+ if (m === null) {
39
+ return 'zookeeper.yaml: вбудований logback.xml без <root level="..."> — додай ConfigMap-оверрайд з level="warn" (k8s.mdc)'
40
+ }
41
+ const level = m[1].toLowerCase()
42
+ if (ALLOWED_ROOT_LEVELS.has(level)) return null
43
+ return `zookeeper.yaml: вбудований logback.xml має <root level="${m[1]}"> — постав "warn" або строгіше (error/off), бо ruok-проби кожні ~10s заливають Cloud Logging на INFO (k8s.mdc)`
44
+ }
45
+
46
+ /**
47
+ * Detector `k8s.dremio_logging` для ZooKeeper-темплейту (per-file, read-only).
48
+ * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
49
+ * @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями.
50
+ */
51
+ export async function lint(ctx) {
52
+ const reporter = createViolationReporter(ctx)
53
+ const { fail } = reporter
54
+
55
+ for (const rel of ctx.files ?? []) {
56
+ let content
57
+ try {
58
+ content = await readFile(join(ctx.cwd, rel), 'utf8')
59
+ } catch {
60
+ continue
61
+ }
62
+ const violation = zkLogbackRootLevelViolation(content)
63
+ if (violation !== null) fail(`${rel}: ${violation}`, 'zk-logback-root-level')
64
+ }
65
+
66
+ return reporter.result()
67
+ }