@7n/rules 1.20.0 → 1.21.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 +13 -0
- package/package.json +1 -1
- package/rules/bun/licensee/docs/fix-licensee.md +1 -2
- package/rules/bun/licensee/docs/main.md +1 -1
- package/rules/bun/licensee/fix-licensee.mjs +3 -4
- package/rules/bun/licensee/main.mjs +7 -7
- package/rules/docker/lib/docker-hadolint.mjs +6 -8
- package/rules/docker/lib/docs/docker-hadolint.md +1 -1
- package/rules/docker/lint/docs/main.md +1 -1
- package/rules/docker/lint/main.mjs +1 -1
- package/rules/image-compress/check/docs/fix-check.md +1 -2
- package/rules/image-compress/check/docs/main.md +1 -1
- package/rules/image-compress/check/fix-check.mjs +27 -22
- package/rules/image-compress/check/main.mjs +14 -14
- package/rules/js/jscpd_duplicates/docs/main.md +1 -1
- package/rules/js/jscpd_duplicates/main.mjs +7 -8
- package/rules/k8s/kubeconform/docs/main.md +1 -1
- package/rules/k8s/kubeconform/main.mjs +1 -1
- package/rules/k8s/manifests/main.mjs +52 -39
- package/rules/php/cs_fixer/docs/main.md +1 -2
- package/rules/php/cs_fixer/main.mjs +8 -7
- package/rules/php/phpcs/docs/main.md +1 -2
- package/rules/php/phpcs/main.mjs +12 -11
- package/rules/php/project/docs/main.md +1 -2
- package/rules/php/project/main.mjs +19 -16
- package/rules/rego/conftest_verify/docs/main.md +1 -2
- package/rules/rego/conftest_verify/main.mjs +12 -10
- package/rules/rego/lib/docs/run-external-tool.md +1 -1
- package/rules/rego/lib/run-external-tool.mjs +10 -7
- package/rules/rego/opa_check/docs/main.md +1 -1
- package/rules/rego/opa_check/main.mjs +3 -3
- package/rules/rego/regal/docs/main.md +1 -1
- package/rules/rego/regal/main.mjs +3 -3
- package/rules/security/scan/docs/main.md +1 -1
- package/rules/security/scan/main.mjs +9 -9
- package/rules/style/lint/docs/fix-lint.md +1 -1
- package/rules/style/lint/docs/main.md +1 -1
- package/rules/style/lint/fix-lint.mjs +8 -8
- package/rules/style/lint/main.mjs +6 -6
- package/rules/text/cspell-fix/docs/fix-worker.md +1 -1
- package/rules/text/cspell-fix/docs/main.md +1 -1
- package/rules/text/cspell-fix/fix-worker.mjs +1 -1
- package/rules/text/cspell-fix/main.mjs +14 -15
- package/rules/text/oxfmt/docs/fix-oxfmt.md +1 -1
- package/rules/text/oxfmt/docs/main.md +1 -1
- package/rules/text/oxfmt/fix-oxfmt.mjs +3 -3
- package/rules/text/oxfmt/main.mjs +6 -5
- package/rules/text/run-dotenv-linter/docs/fix-run-dotenv-linter.md +1 -2
- package/rules/text/run-dotenv-linter/docs/main.md +1 -1
- package/rules/text/run-dotenv-linter/fix-run-dotenv-linter.mjs +2 -2
- package/rules/text/run-dotenv-linter/main.mjs +19 -24
- package/rules/text/run-shellcheck/docs/fix-run-shellcheck.md +1 -2
- package/rules/text/run-shellcheck/docs/main.md +1 -1
- package/rules/text/run-shellcheck/fix-run-shellcheck.mjs +3 -3
- package/rules/text/run-shellcheck/main.mjs +46 -57
- package/rules/text/run-v8r/docs/main.md +1 -1
- package/rules/text/run-v8r/main.mjs +31 -26
- package/scripts/lib/docs/resolve-plugins.md +1 -1
- package/scripts/lib/lint-surface/blocking-inventory.mjs +12 -40
- package/scripts/lib/lint-surface/docs/blocking-inventory.md +1 -2
- package/scripts/utils/docs/spawn-async.md +1 -2
- package/scripts/utils/spawn-async.mjs +4 -1
- package/rules/python/applies/concern.json +0 -4
- package/rules/python/applies/docs/main.md +0 -29
- package/rules/python/applies/main.mjs +0 -24
- package/rules/python/docs/index.md +0 -11
- package/rules/python/lib/docs/index.md +0 -9
- package/rules/python/lib/docs/uv-run.md +0 -32
- package/rules/python/lib/uv-run.mjs +0 -48
- package/rules/python/main.json +0 -1
- package/rules/python/main.mdc +0 -8
- package/rules/python/mypy/concern.json +0 -7
- package/rules/python/mypy/docs/main.md +0 -32
- package/rules/python/mypy/main.mjs +0 -36
- package/rules/python/project/concern.json +0 -6
- package/rules/python/project/docs/main.md +0 -43
- package/rules/python/project/main.mjs +0 -115
- package/rules/python/pyproject_toml/concern.json +0 -9
- package/rules/python/pyproject_toml/pyproject_toml.mdc +0 -29
- package/rules/python/pyproject_toml/pyproject_toml.rego +0 -53
- package/rules/python/pyproject_toml/template/pyproject.toml.deny.toml +0 -2
- package/rules/python/pyproject_toml/template/pyproject.toml.snippet.toml +0 -12
- package/rules/python/ruff/concern.json +0 -7
- package/rules/python/ruff/docs/fix-ruff.md +0 -34
- package/rules/python/ruff/docs/main.md +0 -35
- package/rules/python/ruff/fix-ruff.mjs +0 -63
- package/rules/python/ruff/main.mjs +0 -52
- package/rules/python/tooling/concern.json +0 -15
- package/rules/python/tooling/docs/index.md +0 -11
- package/rules/python/tooling/docs/main.md +0 -35
- package/rules/python/tooling/main.mjs +0 -45
- package/rules/python/tooling/tooling.mdc +0 -22
- package/rules/rust/applies/concern.json +0 -4
- package/rules/rust/applies/docs/index.md +0 -11
- package/rules/rust/applies/docs/main.md +0 -30
- package/rules/rust/applies/main.mjs +0 -28
- package/rules/rust/check/check.mdc +0 -16
- package/rules/rust/check/concern.json +0 -7
- package/rules/rust/check/docs/fix-check.md +0 -30
- package/rules/rust/check/docs/index.md +0 -11
- package/rules/rust/check/docs/main.md +0 -37
- package/rules/rust/check/fix-check.mjs +0 -79
- package/rules/rust/check/main.mjs +0 -81
- package/rules/rust/docs/index.md +0 -11
- package/rules/rust/lib/docs/has-cargo-toml.md +0 -134
- package/rules/rust/lib/docs/index.md +0 -11
- package/rules/rust/lib/has-cargo-toml.mjs +0 -37
- package/rules/rust/main.json +0 -1
- package/rules/rust/main.mdc +0 -8
- package/rules/rust/package_json/concern.json +0 -10
- package/rules/rust/package_json/package_json.mdc +0 -12
- package/rules/rust/package_json/package_json.rego +0 -20
- package/rules/rust/vscode_extensions/concern.json +0 -11
- package/rules/rust/vscode_extensions/docs/fix-vscode_extensions.md +0 -25
- package/rules/rust/vscode_extensions/docs/index.md +0 -11
- package/rules/rust/vscode_extensions/fix-vscode_extensions.mjs +0 -1
- package/rules/rust/vscode_extensions/template/extensions.json.snippet.json +0 -1
- package/rules/rust/vscode_extensions/vscode_extensions.mdc +0 -9
- package/rules/rust/vscode_extensions/vscode_extensions.rego +0 -15
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* bundled `php/check` (spec docs/specs/2026-07-02-text-check-per-file-split-design.md "Рішення
|
|
5
5
|
* python/php/rego") — php-cs-fixer приймає список конкретних файлів аргументом.
|
|
6
6
|
*/
|
|
7
|
-
import { spawnSync } from 'node:child_process'
|
|
8
7
|
import { existsSync } from 'node:fs'
|
|
9
8
|
import { join, resolve } from 'node:path'
|
|
10
9
|
|
|
11
10
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
11
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
12
12
|
|
|
13
13
|
/** Розширення `.php` — фільтр delta-списку файлів у `lint(ctx)`. */
|
|
14
14
|
const PHP_EXT_RE = /\.php$/u
|
|
@@ -23,11 +23,12 @@ function vendorBin(root) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Detector php/cs_fixer (read-only).
|
|
26
|
+
* Detector php/cs_fixer (read-only). Async (не блокує event loop) — детектор може виконуватись
|
|
27
|
+
* у parallel lane `detectAll()` (ADR 260716-1354).
|
|
27
28
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
28
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат із порушеннями
|
|
29
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями
|
|
29
30
|
*/
|
|
30
|
-
export function lint(ctx) {
|
|
31
|
+
export async function lint(ctx) {
|
|
31
32
|
const reporter = createViolationReporter(ctx)
|
|
32
33
|
const { fail } = reporter
|
|
33
34
|
const root = ctx.cwd
|
|
@@ -40,9 +41,9 @@ export function lint(ctx) {
|
|
|
40
41
|
const abs = vendorBin(root)
|
|
41
42
|
if (!abs) return reporter.result() // php-cs-fixer відсутній у vendor/bin → пропущено
|
|
42
43
|
|
|
43
|
-
const r =
|
|
44
|
-
if (r.
|
|
45
|
-
const code = typeof r.
|
|
44
|
+
const r = await spawnAsync(abs, ['fix', '--dry-run', '--diff', ...targets], { cwd: root })
|
|
45
|
+
if (r.exitCode !== 0) {
|
|
46
|
+
const code = typeof r.exitCode === 'number' ? r.exitCode : 1
|
|
46
47
|
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
47
48
|
const outSuffix = out ? `\n${out}` : ''
|
|
48
49
|
fail(`lint-php: PHP-CS-Fixer (dry-run) — помилка (код ${code}, php.mdc)${outSuffix}`, 'php-cs-fixer-violation')
|
package/rules/php/phpcs/main.mjs
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Виділено з колишнього bundled `php/check` (spec
|
|
5
5
|
* docs/specs/2026-07-02-text-check-per-file-split-design.md "Рішення python/php/rego").
|
|
6
6
|
*/
|
|
7
|
-
import { spawnSync } from 'node:child_process'
|
|
8
7
|
import { existsSync, statSync } from 'node:fs'
|
|
9
8
|
import { join, resolve } from 'node:path'
|
|
10
9
|
|
|
11
10
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
11
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
12
12
|
|
|
13
13
|
/** Розширення `.php` — фільтр delta-списку файлів у `lint(ctx)`. */
|
|
14
14
|
const PHP_EXT_RE = /\.php$/u
|
|
@@ -38,11 +38,12 @@ function vendorBin(root) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Detector php/phpcs (read-only).
|
|
41
|
+
* Detector php/phpcs (read-only). Async (не блокує event loop) — детектор може виконуватись
|
|
42
|
+
* у parallel lane `detectAll()` (ADR 260716-1354).
|
|
42
43
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
43
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат із порушеннями
|
|
44
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями
|
|
44
45
|
*/
|
|
45
|
-
export function lint(ctx) {
|
|
46
|
+
export async function lint(ctx) {
|
|
46
47
|
const reporter = createViolationReporter(ctx)
|
|
47
48
|
const { fail } = reporter
|
|
48
49
|
const root = ctx.cwd
|
|
@@ -55,13 +56,13 @@ export function lint(ctx) {
|
|
|
55
56
|
const abs = vendorBin(root)
|
|
56
57
|
if (!abs) return reporter.result() // phpcs відсутній у vendor/bin → пропущено
|
|
57
58
|
|
|
58
|
-
const r =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (r.
|
|
64
|
-
const code = typeof r.
|
|
59
|
+
const r = await spawnAsync(
|
|
60
|
+
abs,
|
|
61
|
+
['--standard=Security', '--ignore=*/vendor/*,*/node_modules/*,*/.git/*', ...targets],
|
|
62
|
+
{ cwd: root }
|
|
63
|
+
)
|
|
64
|
+
if (r.exitCode !== 0) {
|
|
65
|
+
const code = typeof r.exitCode === 'number' ? r.exitCode : 1
|
|
65
66
|
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
66
67
|
const outSuffix = out ? `\n${out}` : ''
|
|
67
68
|
fail(`lint-php: phpcs (Security) — помилка (код ${code}, php.mdc)${outSuffix}`, 'phpcs-violation')
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: main.mjs
|
|
4
4
|
resource: npm/rules/php/project/main.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: b2bd6168
|
|
7
7
|
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
tier: local-min
|
|
9
8
|
score: 100
|
|
10
9
|
issues: judge:inaccurate:0.97
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* audit. Не входять у delta-план (§5): спрацьовують лише через `n-rules lint --full` або
|
|
8
8
|
* scoped `n-rules lint php`.
|
|
9
9
|
*/
|
|
10
|
-
import { spawnSync } from 'node:child_process'
|
|
11
10
|
import { existsSync } from 'node:fs'
|
|
12
11
|
import { join, resolve } from 'node:path'
|
|
13
12
|
|
|
14
13
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
15
14
|
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
15
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @param {string} root корінь
|
|
@@ -25,19 +25,20 @@ function vendorBin(root, name) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Запускає тул і, на ненульовий код, реєструє порушення.
|
|
28
|
+
* Запускає тул і, на ненульовий код, реєструє порушення. Async (не блокує event loop) —
|
|
29
|
+
* детектор може виконуватись у parallel lane `detectAll()` (ADR 260716-1354).
|
|
29
30
|
* @param {string} label назва кроку
|
|
30
31
|
* @param {string} abs абсолютний шлях
|
|
31
32
|
* @param {string[]} args аргументи команди.
|
|
32
33
|
* @param {string} cwd робочий каталог.
|
|
33
34
|
* @param {(msg: string, reason: string) => void} fail колбек реєстрації порушення.
|
|
34
35
|
* @param {string} reason машиночитна причина порушення.
|
|
35
|
-
* @returns {boolean} true якщо OK, false якщо порушення
|
|
36
|
+
* @returns {Promise<boolean>} true якщо OK, false якщо порушення
|
|
36
37
|
*/
|
|
37
|
-
function runTool(label, abs, args, cwd, fail, reason) {
|
|
38
|
-
const r =
|
|
39
|
-
if (r.
|
|
40
|
-
const code = typeof r.
|
|
38
|
+
async function runTool(label, abs, args, cwd, fail, reason) {
|
|
39
|
+
const r = await spawnAsync(abs, args, { cwd })
|
|
40
|
+
if (r.exitCode === 0) return true
|
|
41
|
+
const code = typeof r.exitCode === 'number' ? r.exitCode : 1
|
|
41
42
|
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
42
43
|
const outSuffix = out ? `\n${out}` : ''
|
|
43
44
|
fail(`lint-php: ${label} — помилка (код ${code}, php.mdc)${outSuffix}`, reason)
|
|
@@ -45,11 +46,11 @@ function runTool(label, abs, args, cwd, fail, reason) {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
|
-
* Detector php/project (read-only).
|
|
49
|
+
* Detector php/project (read-only). Async — `runTool` викликає `spawnAsync` (ADR 260716-1354).
|
|
49
50
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
50
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат із порушеннями
|
|
51
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями
|
|
51
52
|
*/
|
|
52
|
-
export function lint(ctx) {
|
|
53
|
+
export async function lint(ctx) {
|
|
53
54
|
const reporter = createViolationReporter(ctx)
|
|
54
55
|
const { fail } = reporter
|
|
55
56
|
const root = ctx.cwd
|
|
@@ -62,7 +63,9 @@ export function lint(ctx) {
|
|
|
62
63
|
return reporter.result()
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
if (
|
|
66
|
+
if (
|
|
67
|
+
!(await runTool('composer audit', composer, ['audit', '--no-interaction'], root, fail, 'composer-audit-violation'))
|
|
68
|
+
) {
|
|
66
69
|
return reporter.result()
|
|
67
70
|
}
|
|
68
71
|
|
|
@@ -71,18 +74,18 @@ export function lint(ctx) {
|
|
|
71
74
|
* @param {string} label назва кроку.
|
|
72
75
|
* @param {string[]} args аргументи інструменту.
|
|
73
76
|
* @param {string} reason машиночитна причина порушення.
|
|
74
|
-
* @returns {boolean} true якщо OK / пропущено
|
|
77
|
+
* @returns {Promise<boolean>} true якщо OK / пропущено
|
|
75
78
|
*/
|
|
76
|
-
function runOptionalVendorTool(binName, label, args, reason) {
|
|
79
|
+
async function runOptionalVendorTool(binName, label, args, reason) {
|
|
77
80
|
const abs = vendorBin(root, binName)
|
|
78
81
|
if (!abs) return true // тул відсутній у vendor/bin → крок пропущено
|
|
79
|
-
return runTool(label, abs, args, root, fail, reason)
|
|
82
|
+
return await runTool(label, abs, args, root, fail, reason)
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
if (!runOptionalVendorTool('phpstan', 'PHPStan', ['analyse', '--no-progress'], 'phpstan-violation')) {
|
|
85
|
+
if (!(await runOptionalVendorTool('phpstan', 'PHPStan', ['analyse', '--no-progress'], 'phpstan-violation'))) {
|
|
83
86
|
return reporter.result()
|
|
84
87
|
}
|
|
85
|
-
runOptionalVendorTool('psalm', 'Psalm', ['--no-cache'], 'psalm-violation')
|
|
88
|
+
await runOptionalVendorTool('psalm', 'Psalm', ['--no-cache'], 'psalm-violation')
|
|
86
89
|
|
|
87
90
|
return reporter.result()
|
|
88
91
|
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { resolve } from 'node:path'
|
|
9
9
|
import { existsSync } from 'node:fs'
|
|
10
|
-
import { spawnSync } from 'node:child_process'
|
|
11
10
|
|
|
12
11
|
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
12
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
13
13
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
14
14
|
|
|
15
15
|
const LINT_TARGETS = ['npm/rules']
|
|
@@ -19,23 +19,25 @@ const LINT_TARGETS = ['npm/rules']
|
|
|
19
19
|
* @param {string} bin абсолютний шлях до бінарника
|
|
20
20
|
* @param {string[]} args аргументи
|
|
21
21
|
* @param {string} cwd робоча директорія
|
|
22
|
-
* @returns {{ status: number, output: string }} код завершення й обрізаний stdout+stderr
|
|
22
|
+
* @returns {Promise<{ status: number, output: string }>} код завершення й обрізаний stdout+stderr
|
|
23
23
|
*/
|
|
24
|
-
function runStep(bin, args, cwd) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
async function runStep(bin, args, cwd) {
|
|
25
|
+
let result
|
|
26
|
+
try {
|
|
27
|
+
result = await spawnAsync(bin, args, { cwd, env: process.env })
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return { status: 1, output: `Не вдалося запустити ${bin}: ${error.message}` }
|
|
28
30
|
}
|
|
29
31
|
const output = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim().slice(0, 2000)
|
|
30
|
-
return { status: result.
|
|
32
|
+
return { status: result.exitCode ?? 1, output }
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Detector rego/conftest_verify (read-only).
|
|
35
37
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону.
|
|
36
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат зі зібраними violations
|
|
38
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
37
39
|
*/
|
|
38
|
-
export function lint(ctx) {
|
|
40
|
+
export async function lint(ctx) {
|
|
39
41
|
const reporter = createViolationReporter(ctx)
|
|
40
42
|
const { fail } = reporter
|
|
41
43
|
const root = resolve(ctx.cwd)
|
|
@@ -46,7 +48,7 @@ export function lint(ctx) {
|
|
|
46
48
|
const conftest = resolveCmd('conftest')
|
|
47
49
|
if (!conftest) return reporter.result() // conftest відсутній → пропускаємо verify (старий код повертав 0)
|
|
48
50
|
|
|
49
|
-
const verifyRes = runStep(conftest, ['verify', ...targets.flatMap(t => ['-p', t])], root)
|
|
51
|
+
const verifyRes = await runStep(conftest, ['verify', ...targets.flatMap(t => ['-p', t])], root)
|
|
50
52
|
if (verifyRes.status !== 0) {
|
|
51
53
|
const verifySuffix = verifyRes.output ? `\n${verifyRes.output}` : ''
|
|
52
54
|
fail(`lint-rego: conftest verify — помилка (код ${verifyRes.status})${verifySuffix}`, 'conftest-verify-violation')
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync } from 'node:fs'
|
|
7
7
|
import { resolve } from 'node:path'
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
9
10
|
|
|
10
11
|
/** Full-режим (ctx.files undefined): корінь policy-дерева, якщо існує. */
|
|
11
12
|
export const FULL_TARGET = 'npm/rules'
|
|
@@ -44,13 +45,15 @@ export function resolveTargets(files, root) {
|
|
|
44
45
|
* @param {string} bin абсолютний шлях до бінарника
|
|
45
46
|
* @param {string[]} args аргументи
|
|
46
47
|
* @param {string} cwd робоча директорія
|
|
47
|
-
* @returns {{ status: number, output: string }} код завершення й обрізаний stdout+stderr
|
|
48
|
+
* @returns {Promise<{ status: number, output: string }>} код завершення й обрізаний stdout+stderr
|
|
48
49
|
*/
|
|
49
|
-
export function runStep(bin, args, cwd) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
export async function runStep(bin, args, cwd) {
|
|
51
|
+
let result
|
|
52
|
+
try {
|
|
53
|
+
result = await spawnAsync(bin, args, { cwd, env: process.env })
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return { status: 1, output: `Не вдалося запустити ${bin}: ${error.message}` }
|
|
53
56
|
}
|
|
54
57
|
const output = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim().slice(0, 2000)
|
|
55
|
-
return { status: result.
|
|
58
|
+
return { status: result.exitCode ?? 1, output }
|
|
56
59
|
}
|
|
@@ -14,9 +14,9 @@ import { resolveTargets, runStep } from '../lib/run-external-tool.mjs'
|
|
|
14
14
|
/**
|
|
15
15
|
* Detector rego/opa_check (read-only).
|
|
16
16
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону.
|
|
17
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат зі зібраними violations
|
|
17
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
18
18
|
*/
|
|
19
|
-
export function lint(ctx) {
|
|
19
|
+
export async function lint(ctx) {
|
|
20
20
|
const reporter = createViolationReporter(ctx)
|
|
21
21
|
const { fail } = reporter
|
|
22
22
|
const root = resolve(ctx.cwd)
|
|
@@ -25,7 +25,7 @@ export function lint(ctx) {
|
|
|
25
25
|
if (targets.length === 0) return reporter.result()
|
|
26
26
|
|
|
27
27
|
const opa = ensureTool('opa')
|
|
28
|
-
const opaRes = runStep(opa, ['check', '--strict', ...targets], root)
|
|
28
|
+
const opaRes = await runStep(opa, ['check', '--strict', ...targets], root)
|
|
29
29
|
if (opaRes.status !== 0) {
|
|
30
30
|
const opaSuffix = opaRes.output ? `\n${opaRes.output}` : ''
|
|
31
31
|
fail(`lint-rego: opa check --strict — помилка (код ${opaRes.status})${opaSuffix}`, 'opa-check-violation')
|
|
@@ -14,9 +14,9 @@ import { resolveTargets, runStep } from '../lib/run-external-tool.mjs'
|
|
|
14
14
|
/**
|
|
15
15
|
* Detector rego/regal (read-only).
|
|
16
16
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону.
|
|
17
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат зі зібраними violations
|
|
17
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
18
18
|
*/
|
|
19
|
-
export function lint(ctx) {
|
|
19
|
+
export async function lint(ctx) {
|
|
20
20
|
const reporter = createViolationReporter(ctx)
|
|
21
21
|
const { fail } = reporter
|
|
22
22
|
const root = resolve(ctx.cwd)
|
|
@@ -25,7 +25,7 @@ export function lint(ctx) {
|
|
|
25
25
|
if (targets.length === 0) return reporter.result()
|
|
26
26
|
|
|
27
27
|
const regal = ensureTool('regal')
|
|
28
|
-
const regalRes = runStep(regal, ['lint', ...targets], root)
|
|
28
|
+
const regalRes = await runStep(regal, ['lint', ...targets], root)
|
|
29
29
|
if (regalRes.status !== 0) {
|
|
30
30
|
const regalSuffix = regalRes.output ? `\n${regalRes.output}` : ''
|
|
31
31
|
fail(`lint-rego: regal lint — помилка (код ${regalRes.status})${regalSuffix}`, 'regal-lint-violation')
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* lint-поверхня security/scan: read-only detector секретів (`trufflehog` filesystem скан
|
|
3
3
|
* усього репо). Фіксу немає — детектор лише сигналить про знайдені секрети.
|
|
4
4
|
*/
|
|
5
|
-
import { spawnSync } from 'node:child_process'
|
|
6
|
-
|
|
7
5
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
8
6
|
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
7
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Detector security/scan: trufflehog filesystem скан (read-only). Якщо бінарника немає —
|
|
12
|
-
* скан пропускається (як і раніше при відсутності інструмента).
|
|
11
|
+
* скан пропускається (як і раніше при відсутності інструмента). Async (не блокує event loop) —
|
|
12
|
+
* детектор може виконуватись у parallel lane `detectAll()` (ADR 260716-1354).
|
|
13
13
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону
|
|
14
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат detector-а
|
|
14
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат detector-а
|
|
15
15
|
*/
|
|
16
|
-
export function lint(ctx) {
|
|
16
|
+
export async function lint(ctx) {
|
|
17
17
|
const reporter = createViolationReporter(ctx)
|
|
18
18
|
const { fail } = reporter
|
|
19
19
|
const cwd = ctx.cwd
|
|
@@ -26,7 +26,7 @@ export function lint(ctx) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const r =
|
|
29
|
+
const r = await spawnAsync(
|
|
30
30
|
trufflehog,
|
|
31
31
|
[
|
|
32
32
|
'filesystem',
|
|
@@ -37,12 +37,12 @@ export function lint(ctx) {
|
|
|
37
37
|
'--results=verified,unknown',
|
|
38
38
|
'--fail'
|
|
39
39
|
],
|
|
40
|
-
{ cwd
|
|
40
|
+
{ cwd }
|
|
41
41
|
)
|
|
42
|
-
if (r.
|
|
42
|
+
if (r.exitCode !== 0) {
|
|
43
43
|
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 4000)
|
|
44
44
|
const outSuffix = out ? `\n${out}` : ''
|
|
45
|
-
fail(`security/scan: trufflehog знайшов секрети (код ${r.
|
|
45
|
+
fail(`security/scan: trufflehog знайшов секрети (код ${r.exitCode})${outSuffix}`, 'secret-found')
|
|
46
46
|
}
|
|
47
47
|
return reporter.result()
|
|
48
48
|
}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* режимі), форматує їх і повертає лише фактично змінені. Запис permanent. Відсутній
|
|
8
8
|
* stylelint → no-op.
|
|
9
9
|
*/
|
|
10
|
-
import { spawnSync } from 'node:child_process'
|
|
11
10
|
import { readFileSync } from 'node:fs'
|
|
12
11
|
import { resolve } from 'node:path'
|
|
13
12
|
|
|
14
13
|
import { filterStyleFiles, resolveStylelint } from './main.mjs'
|
|
14
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Вміст файлу або null, якщо не читається.
|
|
@@ -31,12 +31,12 @@ function readOrNull(abs) {
|
|
|
31
31
|
* css/scss/vue через `git ls-files`.
|
|
32
32
|
* @param {string} cwd корінь
|
|
33
33
|
* @param {string[]|undefined} ctxFiles файли з контексту (дельта) або undefined (повний режим)
|
|
34
|
-
* @returns {string[]} posix-relative шляхи
|
|
34
|
+
* @returns {Promise<string[]>} posix-relative шляхи
|
|
35
35
|
*/
|
|
36
|
-
function listStyleFiles(cwd, ctxFiles) {
|
|
36
|
+
async function listStyleFiles(cwd, ctxFiles) {
|
|
37
37
|
if (ctxFiles !== undefined) return filterStyleFiles(ctxFiles)
|
|
38
|
-
const r =
|
|
39
|
-
if (r.
|
|
38
|
+
const r = await spawnAsync('git', ['ls-files', '-z', '--', '*.css', '*.scss', '*.vue'], { cwd })
|
|
39
|
+
if (r.exitCode !== 0) return []
|
|
40
40
|
return (r.stdout ?? '').split('\0').filter(Boolean)
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -46,15 +46,15 @@ export const patterns = [
|
|
|
46
46
|
id: 'style-stylelint-fix',
|
|
47
47
|
standalone: true, // §8 Phase 2: apply бере ctx.files (не violations), stylelint --fix сам ре-аналізує
|
|
48
48
|
test: violations => violations.some(v => v.reason === 'stylelint-violation'),
|
|
49
|
-
apply: (violations, ctx) => {
|
|
49
|
+
apply: async (violations, ctx) => {
|
|
50
50
|
const stylelint = resolveStylelint(ctx.cwd)
|
|
51
51
|
if (!stylelint) return { touchedFiles: [] }
|
|
52
|
-
const files = listStyleFiles(ctx.cwd, ctx.files)
|
|
52
|
+
const files = await listStyleFiles(ctx.cwd, ctx.files)
|
|
53
53
|
if (files.length === 0) return { touchedFiles: [] }
|
|
54
54
|
|
|
55
55
|
const abs = files.map(f => resolve(ctx.cwd, f))
|
|
56
56
|
const before = new Map(abs.map(a => [a, readOrNull(a)]))
|
|
57
|
-
|
|
57
|
+
await spawnAsync(stylelint, ['--fix', ...files], { cwd: ctx.cwd })
|
|
58
58
|
|
|
59
59
|
const touchedFiles = abs.filter(a => readOrNull(a) !== before.get(a))
|
|
60
60
|
for (const a of touchedFiles) ctx.recordWrite?.(a)
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Per-file (ctx.files) або весь проєкт (ctx.files === undefined). Якщо stylelint
|
|
4
4
|
* недоступний — крок пропускається (без npx-автовстановлення).
|
|
5
5
|
*/
|
|
6
|
-
import { spawnSync } from 'node:child_process'
|
|
7
6
|
import { existsSync } from 'node:fs'
|
|
8
7
|
import { join } from 'node:path'
|
|
9
8
|
|
|
10
9
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
11
10
|
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
11
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
12
12
|
|
|
13
13
|
const STYLE_EXT_RE = /\.(?:css|scss|vue)$/u
|
|
14
14
|
|
|
@@ -34,9 +34,9 @@ export function resolveStylelint(cwd) {
|
|
|
34
34
|
/**
|
|
35
35
|
* Detector style/lint (read-only).
|
|
36
36
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону (cwd, files)
|
|
37
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат зі зібраними violations
|
|
37
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
38
38
|
*/
|
|
39
|
-
export function lint(ctx) {
|
|
39
|
+
export async function lint(ctx) {
|
|
40
40
|
const reporter = createViolationReporter(ctx)
|
|
41
41
|
const { fail } = reporter
|
|
42
42
|
const cwd = ctx.cwd
|
|
@@ -58,11 +58,11 @@ export function lint(ctx) {
|
|
|
58
58
|
return reporter.result()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const r =
|
|
62
|
-
if (r.
|
|
61
|
+
const r = await spawnAsync(stylelint, targets, { cwd, shell: false })
|
|
62
|
+
if (r.exitCode !== 0) {
|
|
63
63
|
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
64
64
|
const outSuffix = out ? `\n${out}` : ''
|
|
65
|
-
fail(`lint-style: stylelint — порушення (код ${r.
|
|
65
|
+
fail(`lint-style: stylelint — порушення (код ${r.exitCode ?? 1}, style.mdc)${outSuffix}`, 'stylelint-violation')
|
|
66
66
|
}
|
|
67
67
|
return reporter.result()
|
|
68
68
|
}
|
|
@@ -40,7 +40,7 @@ export async function fixWorker(violations, ctx) {
|
|
|
40
40
|
const bin = resolveCmd('npx')
|
|
41
41
|
if (!bin) return { touchedFiles: [] }
|
|
42
42
|
|
|
43
|
-
const first = detectCspell(ctx.cwd, bin, ctx.files)
|
|
43
|
+
const first = await detectCspell(ctx.cwd, bin, ctx.files)
|
|
44
44
|
if (first.code === 0) return { touchedFiles: [] }
|
|
45
45
|
|
|
46
46
|
const words = unknownWords(first.out)
|