@7n/rules 1.15.0 → 1.16.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 +12 -0
- package/package.json +1 -1
- package/rules/k8s/dremio_logging/concern.json +8 -0
- package/rules/k8s/dremio_logging/dremio_logging.mdc +31 -0
- package/rules/k8s/dremio_logging/dremio_logging.rego +86 -0
- package/skills/taze/js/docs/orchestrate.md +2 -1
- package/skills/taze/js/orchestrate.mjs +45 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.16.1] - 2026-07-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- taze-оркестратор на репо без кореневого package.json (чисто-Python/Rust): npm/bun-гілка тихо пропускається (лог + без npm-рядків у звіті) замість смертельного `bun install → exit 1` до екосистемних провайдерів. Знайдено live-прогоном lang-python плагіна на реальному Python-репо
|
|
8
|
+
|
|
9
|
+
## [1.16.0] - 2026-07-18
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- k8s: новий концерн dremio_logging — logback.xml Dremio Helm-чарту має містити WARN-оверрайди для шести відомо-шумних loggerів (rego, XML через conftest, detection-only)
|
|
14
|
+
|
|
3
15
|
## [1.15.0] - 2026-07-18
|
|
4
16
|
|
|
5
17
|
### Added
|
package/package.json
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
## WARN-оверрайди шумних loggerів у logback.xml Dremio
|
|
2
|
+
|
|
3
|
+
Rego-пакет: `k8s.dremio_logging`
|
|
4
|
+
|
|
5
|
+
**Цільові файли:** `**/dremio_v2/config/logback.xml` — vendored-конфіг логування Dremio Helm-чарту. Це XML (не YAML): conftest парсить його нативно (парсер інферується за розширенням). Кожна env-копія (`dev/dremio_v2/…`, `ua/dremio_v2/…` тощо) перевіряється окремо — без крос-файлової дедуплікації. Cross-file gating (як у `hasura_configmap`) не потрібен: шлях сам ідентифікує Dremio-чарт.
|
|
6
|
+
|
|
7
|
+
**Що перевіряється:** для кожного FQCN зі списку нижче має існувати `<logger name="<FQCN>" level="warn"/>` (рівень case-insensitive; «строгіше» — `error`/`off` — теж ок). Кожен запис-дублікат для FQCN має задовольняти вимогу окремо (конфліктні дублікати — порушення: logback бере останній, конфіг має бути однозначним).
|
|
8
|
+
|
|
9
|
+
| FQCN |
|
|
10
|
+
|------|
|
|
11
|
+
| `com.dremio.sabot.exec.fragment.FragmentExecutor` |
|
|
12
|
+
| `com.dremio.sabot.exec.fragment.FragmentStatusReporter` |
|
|
13
|
+
| `com.dremio.sabot.exec.QueryTicket` |
|
|
14
|
+
| `com.dremio.service.reflection.descriptor.MaterializationCache` |
|
|
15
|
+
| `com.dremio.exec.planner.plancache.PlanCacheSynchronizer` |
|
|
16
|
+
| `com.dremio.exec.planner.plancache.CacheRefresher` |
|
|
17
|
+
|
|
18
|
+
**Чому:** ці loggerи (усі на одному `planning-cache-refresher` треді; підтверджено живою перевіркою в проді) пишуть INFO на кожен запит/фоновий цикл і домінують обсяг логів у Cloud Logging без діагностичної цінності понад WARN. Список фіксований — не розширюй «про запас»; нові loggerи — окремою ітерацією.
|
|
19
|
+
|
|
20
|
+
**Приклад валідного фрагмента:**
|
|
21
|
+
|
|
22
|
+
```xml
|
|
23
|
+
<logger name="com.dremio.sabot.exec.fragment.FragmentExecutor" level="warn"/>
|
|
24
|
+
<logger name="com.dremio.sabot.exec.fragment.FragmentStatusReporter" level="warn"/>
|
|
25
|
+
<logger name="com.dremio.sabot.exec.QueryTicket" level="warn"/>
|
|
26
|
+
<logger name="com.dremio.service.reflection.descriptor.MaterializationCache" level="warn"/>
|
|
27
|
+
<logger name="com.dremio.exec.planner.plancache.PlanCacheSynchronizer" level="warn"/>
|
|
28
|
+
<logger name="com.dremio.exec.planner.plancache.CacheRefresher" level="warn"/>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Autofix:** відсутній (detection-only, як `hasura_httproute`) — XML-трансформ складніший за YAML `setIn`; T0-fix, за потреби, окремою ітерацією.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# WARN-оверрайди шумних loggerів у logback.xml Dremio Helm-чарту.
|
|
2
|
+
#
|
|
3
|
+
# Проблема: перелічені нижче FQCN (усі живуть на одному `planning-cache-refresher`
|
|
4
|
+
# треді) пишуть INFO-логи на кожен запит/фоновий цикл і домінують обсяг у
|
|
5
|
+
# Cloud Logging без діагностичної цінності понад WARN. Вимога: у кожній копії
|
|
6
|
+
# vendored-конфігу `dremio_v2/config/logback.xml` (наприклад `dev/…` і `ua/…` —
|
|
7
|
+
# кожна env-копія перевіряється окремо, без крос-файлової дедуплікації) має бути
|
|
8
|
+
# `<logger name="<FQCN>" level="warn"/>` для кожного FQCN зі списку
|
|
9
|
+
# `required_loggers`, з рівнем "warn" або строгішим ("error", "off").
|
|
10
|
+
#
|
|
11
|
+
# Вхід — XML: conftest інферить парсер за розширенням `.xml`. Конвенція
|
|
12
|
+
# представлення (див. `conftest parse`):
|
|
13
|
+
# - атрибути мають префікс "-" (`-name`, `-level`);
|
|
14
|
+
# - один дочірній елемент → об'єкт, кілька → масив. Тому `<logger>`
|
|
15
|
+
# нормалізується у `loggers` (завжди масив).
|
|
16
|
+
#
|
|
17
|
+
# Запуск (локально):
|
|
18
|
+
# conftest test path/to/dremio_v2/config/logback.xml \
|
|
19
|
+
# -p npm/rules/k8s/dremio_logging \
|
|
20
|
+
# --namespace k8s.dremio_logging
|
|
21
|
+
#
|
|
22
|
+
# Список FQCN підтверджено живою перевіркою в проді — не розширюй «про запас».
|
|
23
|
+
#
|
|
24
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
25
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`.
|
|
26
|
+
package k8s.dremio_logging
|
|
27
|
+
|
|
28
|
+
import rego.v1
|
|
29
|
+
|
|
30
|
+
# Обов'язкові WARN-оверрайди (FQCN відомо-шумних loggerів Dremio).
|
|
31
|
+
required_loggers := {
|
|
32
|
+
"com.dremio.sabot.exec.fragment.FragmentExecutor",
|
|
33
|
+
"com.dremio.sabot.exec.fragment.FragmentStatusReporter",
|
|
34
|
+
"com.dremio.sabot.exec.QueryTicket",
|
|
35
|
+
"com.dremio.service.reflection.descriptor.MaterializationCache",
|
|
36
|
+
"com.dremio.exec.planner.plancache.PlanCacheSynchronizer",
|
|
37
|
+
"com.dremio.exec.planner.plancache.CacheRefresher",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Рівні logback, що задовольняють вимогу «warn або строгіше».
|
|
41
|
+
allowed_levels := {"warn", "error", "off"}
|
|
42
|
+
|
|
43
|
+
# Нормалізація <logger>: один елемент XML-парсер віддає об'єктом, кілька — масивом.
|
|
44
|
+
# Тіла взаємовиключні (is_array/is_object), default покриває відсутність елемента
|
|
45
|
+
# (зокрема logback.xml без <configuration>-кореня → порожній список → deny на
|
|
46
|
+
# кожен обов'язковий FQCN).
|
|
47
|
+
default loggers := []
|
|
48
|
+
|
|
49
|
+
loggers := input.configuration.logger if is_array(input.configuration.logger)
|
|
50
|
+
|
|
51
|
+
loggers := [input.configuration.logger] if is_object(input.configuration.logger)
|
|
52
|
+
|
|
53
|
+
# Усі записи <logger> для заданого FQCN (записи без атрибута name пропускаються).
|
|
54
|
+
entries_for(name) := [l |
|
|
55
|
+
some l in loggers
|
|
56
|
+
l["-name"] == name
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# Нормалізований рівень запису; undefined, якщо атрибут level відсутній або не рядок.
|
|
60
|
+
entry_level(l) := lower(trim_space(l["-level"])) if is_string(l["-level"])
|
|
61
|
+
|
|
62
|
+
# Запис задовольняє вимогу: level читається і є warn/error/off.
|
|
63
|
+
entry_ok(l) if entry_level(l) in allowed_levels
|
|
64
|
+
|
|
65
|
+
# FQCN узагалі не має <logger>-оверрайду.
|
|
66
|
+
deny contains msg if {
|
|
67
|
+
some name in required_loggers
|
|
68
|
+
count(entries_for(name)) == 0
|
|
69
|
+
msg := sprintf(
|
|
70
|
+
"logback.xml: додай <logger name=\"%s\" level=\"warn\"/> — шумний Dremio-logger заливає Cloud Logging (k8s.mdc)",
|
|
71
|
+
[name],
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Оверрайд є, але слабший за warn (info/debug/trace), без level або з не-рядковим
|
|
76
|
+
# level. Вимога до КОЖНОГО запису з цим FQCN: дублікати з конфліктними рівнями
|
|
77
|
+
# (logback бере останній) — теж порушення, конфіг має бути однозначним.
|
|
78
|
+
deny contains msg if {
|
|
79
|
+
some name in required_loggers
|
|
80
|
+
some l in entries_for(name)
|
|
81
|
+
not entry_ok(l)
|
|
82
|
+
msg := sprintf(
|
|
83
|
+
"logback.xml: <logger name=\"%s\"> має рівень %v — постав level=\"warn\" або строгіше (error/off) (k8s.mdc)",
|
|
84
|
+
[name, object.get(l, "-level", "«відсутній»")],
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -3,7 +3,7 @@ type: JS Module
|
|
|
3
3
|
title: orchestrate.mjs
|
|
4
4
|
resource: npm/skills/taze/js/orchestrate.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 256c4e77
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
8
|
score: 100
|
|
9
9
|
issues: judge:inaccurate:0.98
|
|
@@ -36,5 +36,6 @@ docgen:
|
|
|
36
36
|
|
|
37
37
|
- Виконує файлові операції (копіювання/видалення бекапів) і запускає зовнішні команди — НЕ read-only.
|
|
38
38
|
- Перед будь-якою мутацією перевіряє, що `cwd` — ізольований worktree (`assertRunningInWorktree`), інакше кидає виняток.
|
|
39
|
+
- npm/bun-гілка активна лише за кореневим package.json: на чисто-Python/Rust репо вона тихо пропускається (лог + без npm-рядків у звіті), а не валить прогін через `bun install → exit 1`.
|
|
39
40
|
- Виняток усередині одного провайдера (bump/diff/команда) не зупиняє інших — фіксується в `error` запису екосистеми й у звіті; `ok` результату тоді false.
|
|
40
41
|
- Падіння одного пакета в ізольованому виклику раннера не втрачає прогрес по інших записах.
|
|
@@ -289,19 +289,19 @@ function appendEcosystemSection(lines, eco) {
|
|
|
289
289
|
* minorPatch: number,
|
|
290
290
|
* totalChanged: number,
|
|
291
291
|
* results: Array<{pkg:string, workspace:string, from:string, to:string, ok:boolean, error:string|null}>,
|
|
292
|
-
* ecosystems?: Array<object
|
|
293
|
-
*
|
|
292
|
+
* ecosystems?: Array<object>,
|
|
293
|
+
* npmPresent?: boolean
|
|
294
|
+
* }} args дані звіту (`ecosystems` — записи з `runEcosystem`, по одному на провайдера;
|
|
295
|
+
* `npmPresent: false` — репо без кореневого package.json, npm-рядки не друкуються)
|
|
294
296
|
* @returns {string} markdown-звіт
|
|
295
297
|
*/
|
|
296
|
-
export function formatReport({ minorPatch, totalChanged, results, ecosystems = [] }) {
|
|
297
|
-
const lines = [
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
for (const r of results) {
|
|
304
|
-
lines.push(formatResultLine(r, r.workspace))
|
|
298
|
+
export function formatReport({ minorPatch, totalChanged, results, ecosystems = [], npmPresent = true }) {
|
|
299
|
+
const lines = ['## taze: підсумок', '']
|
|
300
|
+
if (npmPresent) {
|
|
301
|
+
lines.push(`- **Оновлено (minor/patch):** ${minorPatch}`, `- **Major-оновлення:** ${results.length}`)
|
|
302
|
+
for (const r of results) {
|
|
303
|
+
lines.push(formatResultLine(r, r.workspace))
|
|
304
|
+
}
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
let ecosystemsTotal = 0
|
|
@@ -339,27 +339,37 @@ export async function runTazeOrchestrator(options = {}) {
|
|
|
339
339
|
|
|
340
340
|
assertRunningInWorktree(cwd, spawnFn)
|
|
341
341
|
|
|
342
|
-
|
|
343
|
-
|
|
342
|
+
// npm/bun-гілка активна лише за кореневим package.json — на чисто-Python/Rust
|
|
343
|
+
// репо `bun install` падає з exit 1, і без цього гейта весь прогін гинув би
|
|
344
|
+
// до екосистемних провайдерів. Той самий принцип «тиші», що й для мовних
|
|
345
|
+
// екосистем: немає сигналу — немає ані кроків, ані згадки у звіті.
|
|
346
|
+
const npmPresent = existsSync(join(cwd, 'package.json'))
|
|
347
|
+
let diff = { major: [], minorPatch: 0, totalChanged: 0 }
|
|
348
|
+
const results = []
|
|
349
|
+
if (npmPresent) {
|
|
350
|
+
log('📦 Бекап package.json...')
|
|
351
|
+
const backedUpWorkspaces = await backupWorkspacePackageFiles(cwd, deps)
|
|
344
352
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
353
|
+
log('⬆️ bunx taze -w -r latest...')
|
|
354
|
+
runCommand('bunx', ['taze', '-w', '-r', 'latest'], cwd, spawnFn)
|
|
355
|
+
log('📥 bun install...')
|
|
356
|
+
runCommand('bun', ['install'], cwd, spawnFn)
|
|
349
357
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
358
|
+
const collectDiff = deps.collectTazeDiff ?? collectTazeDiff
|
|
359
|
+
diff = await collectDiff(cwd)
|
|
360
|
+
log(`🔍 diff: ${diff.major.length} major, ${diff.minorPatch} minor/patch`)
|
|
353
361
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
362
|
+
for (const entry of diff.major) {
|
|
363
|
+
log(`🔧 ${entry.pkg} (${entry.workspace}): ${entry.from} → ${entry.to}...`)
|
|
364
|
+
const outcome = await call(runner, buildDependencyPrompt(entry), cwd, deps)
|
|
365
|
+
results.push({ ...entry, ...outcome })
|
|
366
|
+
log(outcome.ok ? ` ✅ ${entry.pkg}` : ` ❌ ${entry.pkg}: ${outcome.error}`)
|
|
367
|
+
}
|
|
361
368
|
|
|
362
|
-
|
|
369
|
+
await cleanupBackups(cwd, backedUpWorkspaces, deps)
|
|
370
|
+
} else {
|
|
371
|
+
log('⏭ npm/bun: кореневого package.json немає — гілка пропущена')
|
|
372
|
+
}
|
|
363
373
|
|
|
364
374
|
const providers = deps.ecosystemProviders ?? [rustProvider, ...(await loadPluginTazeProviders(cwd, log, deps))]
|
|
365
375
|
const ecosystems = []
|
|
@@ -367,7 +377,13 @@ export async function runTazeOrchestrator(options = {}) {
|
|
|
367
377
|
ecosystems.push(await runEcosystem(provider, { cwd, runner, log, deps, spawnFn, call }))
|
|
368
378
|
}
|
|
369
379
|
|
|
370
|
-
const report = formatReport({
|
|
380
|
+
const report = formatReport({
|
|
381
|
+
minorPatch: diff.minorPatch,
|
|
382
|
+
totalChanged: diff.totalChanged,
|
|
383
|
+
results,
|
|
384
|
+
ecosystems,
|
|
385
|
+
npmPresent
|
|
386
|
+
})
|
|
371
387
|
log(report)
|
|
372
388
|
|
|
373
389
|
const ecosystemsOk = ecosystems.every(eco => eco.error === null && eco.results.every(r => r.ok))
|