@7n/rules 1.5.1 → 1.7.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/bin/n-rules.js +83 -21
  3. package/package.json +1 -2
  4. package/rules/abie/main.mdc +0 -6
  5. package/rules/js/check/docs/main.md +1 -1
  6. package/rules/js/check/main.mjs +6 -10
  7. package/rules/js/main.mdc +0 -1
  8. package/rules/js/vscode_extensions/template/extensions.json.snippet.json +4 -1
  9. package/rules/npm-module/main.mdc +0 -2
  10. package/rules/php/tooling/docs/main.md +1 -1
  11. package/rules/php/tooling/main.mjs +2 -7
  12. package/rules/python/tooling/docs/main.md +1 -1
  13. package/rules/python/tooling/main.mjs +2 -7
  14. package/rules/rego/lib/docs/run-external-tool.md +1 -2
  15. package/rules/rego/lib/run-external-tool.mjs +4 -1
  16. package/rules/security/main.mdc +0 -1
  17. package/rules/style/main.mdc +0 -1
  18. package/rules/style/tooling/docs/main.md +1 -1
  19. package/rules/style/tooling/main.mjs +2 -7
  20. package/rules/tauri/release/release.mdc +1 -1
  21. package/rules/text/formatting/docs/main.md +1 -1
  22. package/rules/text/formatting/main.mjs +11 -11
  23. package/rules/text/main.mdc +0 -1
  24. package/scripts/docs/skills-cli.md +1 -1
  25. package/scripts/lib/acp-runner.mjs +26 -33
  26. package/scripts/lib/docs/acp-runner.md +5 -5
  27. package/scripts/lib/docs/mirror-parity.md +1 -1
  28. package/scripts/lib/mirror-parity.mjs +49 -16
  29. package/scripts/skills-cli.mjs +35 -26
  30. package/rules/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc +0 -19
  31. package/rules/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +0 -81
  32. package/rules/abie/clean_merged_ignore_branches/concern.json +0 -11
  33. package/rules/abie/clean_merged_ignore_branches/docs/fix-clean_merged_ignore_branches.md +0 -31
  34. package/rules/abie/clean_merged_ignore_branches/docs/index.md +0 -9
  35. package/rules/abie/clean_merged_ignore_branches/fix-clean_merged_ignore_branches.mjs +0 -8
  36. package/rules/abie/clean_merged_ignore_branches/template/clean-merged-branch.yml.snippet.yml +0 -9
  37. package/rules/docker/lint_docker_yml/concern.json +0 -12
  38. package/rules/docker/lint_docker_yml/docs/fix-lint_docker_yml.md +0 -31
  39. package/rules/docker/lint_docker_yml/docs/index.md +0 -9
  40. package/rules/docker/lint_docker_yml/fix-lint_docker_yml.mjs +0 -5
  41. package/rules/docker/lint_docker_yml/lint_docker_yml.mdc +0 -14
  42. package/rules/docker/lint_docker_yml/lint_docker_yml.rego +0 -79
  43. package/rules/docker/lint_docker_yml/template/lint-docker.yml.snippet.yml +0 -41
  44. package/rules/js/lint_js_yml/concern.json +0 -12
  45. package/rules/js/lint_js_yml/docs/fix-lint_js_yml.md +0 -28
  46. package/rules/js/lint_js_yml/docs/index.md +0 -9
  47. package/rules/js/lint_js_yml/fix-lint_js_yml.mjs +0 -5
  48. package/rules/js/lint_js_yml/lint_js_yml.mdc +0 -14
  49. package/rules/js/lint_js_yml/lint_js_yml.rego +0 -117
  50. package/rules/js/lint_js_yml/template/lint-js.yml.snippet.yml +0 -40
  51. package/rules/k8s/lint_k8s_yml/concern.json +0 -12
  52. package/rules/k8s/lint_k8s_yml/docs/fix-lint_k8s_yml.md +0 -30
  53. package/rules/k8s/lint_k8s_yml/docs/index.md +0 -9
  54. package/rules/k8s/lint_k8s_yml/fix-lint_k8s_yml.mjs +0 -5
  55. package/rules/k8s/lint_k8s_yml/lint_k8s_yml.rego +0 -57
  56. package/rules/k8s/lint_k8s_yml/template/lint-k8s.yml.snippet.yml +0 -43
  57. package/rules/npm-module/npm_publish_yml/concern.json +0 -13
  58. package/rules/npm-module/npm_publish_yml/docs/fix-npm_publish_yml.md +0 -28
  59. package/rules/npm-module/npm_publish_yml/docs/index.md +0 -9
  60. package/rules/npm-module/npm_publish_yml/fix-npm_publish_yml.mjs +0 -8
  61. package/rules/npm-module/npm_publish_yml/template/npm-publish.yml.snippet.yml +0 -49
  62. package/rules/php/lint_php_yml/concern.json +0 -12
  63. package/rules/php/lint_php_yml/docs/fix-lint_php_yml.md +0 -28
  64. package/rules/php/lint_php_yml/docs/index.md +0 -9
  65. package/rules/php/lint_php_yml/fix-lint_php_yml.mjs +0 -5
  66. package/rules/php/lint_php_yml/lint_php_yml.mdc +0 -23
  67. package/rules/php/lint_php_yml/lint_php_yml.rego +0 -34
  68. package/rules/php/lint_php_yml/template/lint-php.yml.snippet.yml +0 -47
  69. package/rules/python/lint_python_yml/concern.json +0 -12
  70. package/rules/python/lint_python_yml/docs/fix-lint_python_yml.md +0 -27
  71. package/rules/python/lint_python_yml/docs/index.md +0 -9
  72. package/rules/python/lint_python_yml/fix-lint_python_yml.mjs +0 -5
  73. package/rules/python/lint_python_yml/lint_python_yml.mdc +0 -12
  74. package/rules/python/lint_python_yml/lint_python_yml.rego +0 -68
  75. package/rules/python/lint_python_yml/template/lint-python.yml.snippet.yml +0 -41
  76. package/rules/rust/lint_rust_yml/concern.json +0 -14
  77. package/rules/rust/lint_rust_yml/docs/fix-lint_rust_yml.md +0 -28
  78. package/rules/rust/lint_rust_yml/docs/index.md +0 -9
  79. package/rules/rust/lint_rust_yml/fix-lint_rust_yml.mjs +0 -5
  80. package/rules/rust/lint_rust_yml/lint_rust_yml.mdc +0 -17
  81. package/rules/rust/lint_rust_yml/lint_rust_yml.rego +0 -79
  82. package/rules/rust/lint_rust_yml/template/lint-rust.yml.snippet.yml +0 -44
  83. package/rules/rust/toolchain_cache/concern.json +0 -14
  84. package/rules/rust/toolchain_cache/docs/fix-toolchain_cache.md +0 -35
  85. package/rules/rust/toolchain_cache/docs/index.md +0 -12
  86. package/rules/rust/toolchain_cache/docs/main.md +0 -57
  87. package/rules/rust/toolchain_cache/fix-toolchain_cache.mjs +0 -117
  88. package/rules/rust/toolchain_cache/main.mjs +0 -177
  89. package/rules/rust/toolchain_cache/toolchain_cache.mdc +0 -23
  90. package/rules/security/lint_security_yml/concern.json +0 -14
  91. package/rules/security/lint_security_yml/docs/fix-lint_security_yml.md +0 -31
  92. package/rules/security/lint_security_yml/docs/index.md +0 -9
  93. package/rules/security/lint_security_yml/fix-lint_security_yml.mjs +0 -8
  94. package/rules/security/lint_security_yml/lint_security_yml.mdc +0 -7
  95. package/rules/security/lint_security_yml/lint_security_yml.rego +0 -33
  96. package/rules/security/lint_security_yml/template/lint-security.yml.snippet.yml +0 -31
  97. package/rules/style/lint_style_yml/concern.json +0 -12
  98. package/rules/style/lint_style_yml/docs/fix-lint_style_yml.md +0 -31
  99. package/rules/style/lint_style_yml/docs/index.md +0 -9
  100. package/rules/style/lint_style_yml/fix-lint_style_yml.mjs +0 -5
  101. package/rules/style/lint_style_yml/lint_style_yml.mdc +0 -13
  102. package/rules/style/lint_style_yml/lint_style_yml.rego +0 -38
  103. package/rules/style/lint_style_yml/template/lint-style.yml.snippet.yml +0 -39
  104. package/rules/text/lint_text/concern.json +0 -11
  105. package/rules/text/lint_text/docs/fix-lint_text.md +0 -28
  106. package/rules/text/lint_text/docs/index.md +0 -9
  107. package/rules/text/lint_text/fix-lint_text.mjs +0 -5
  108. package/rules/text/lint_text/lint_text.mdc +0 -19
  109. package/rules/text/lint_text/lint_text.rego +0 -104
  110. package/rules/text/lint_text/template/lint-text.yml.snippet.yml +0 -61
@@ -1,117 +0,0 @@
1
- /** @see ./docs/fix-toolchain_cache.md */
2
-
3
- /**
4
- * T0-autofix для `rust/toolchain_cache` — детерміновано вставляє
5
- * `Swatinem/rust-cache@v2` одразу після кожного `dtolnay/rust-toolchain@…` кроку,
6
- * якому його бракує у своєму job-і, і дописує `with.workspaces` у Tauri-job-ах,
7
- * де Cargo.toml не в корені репо. Текстові splice-и (як `ga/workflows/fix-workflows.mjs`) —
8
- * зберігають коментарі/формат, мінімальний diff. Ідемпотентно: `scanToolchainSteps`
9
- * заново перевіряє стан файла на кожному прогоні.
10
- */
11
- import { applyToFiles } from '../../../scripts/utils/apply-to-files.mjs'
12
-
13
- import { MISSING_RUST_CACHE, MISSING_RUST_CACHE_WORKSPACES, scanToolchainSteps } from './main.mjs'
14
-
15
- /**
16
- * Індекс першого рядка після step-блоку, що починається на `stepLine`
17
- * (dash-колонка `dashCol`) — перший рядок з відступом не більшим за `dashCol`
18
- * (сусідній крок того самого рівня або dedent), або EOF.
19
- * @param {string[]} lines усі рядки
20
- * @param {number} stepLine індекс рядка кроку (`- uses: …`)
21
- * @param {number} dashCol колонка dash-а кроку
22
- * @returns {number} індекс вставки (кінець блоку кроку)
23
- */
24
- function stepBlockEnd(lines, stepLine, dashCol) {
25
- let j = stepLine + 1
26
- while (j < lines.length) {
27
- const line = lines[j]
28
- if (line.trim() !== '' && line.length - line.trimStart().length <= dashCol) break
29
- j++
30
- }
31
- return j
32
- }
33
-
34
- /**
35
- * Вставляє `Swatinem/rust-cache@v2` (з опційним `with.workspaces`) одразу після
36
- * кожного `dtolnay/rust-toolchain@…` кроку без cache-кроку в тому самому job-і.
37
- * @param {string} content вміст workflow-файла
38
- * @param {string} [workspaceDir] відносний шлях workspace-а для `with.workspaces` (опційно)
39
- * @returns {string|null} новий вміст або null, якщо нічого не змінилось
40
- */
41
- export function insertRustCache(content, workspaceDir) {
42
- const lines = content.split('\n')
43
- const missing = scanToolchainSteps(content).filter(s => !s.hasCache)
44
- if (missing.length === 0) return null
45
-
46
- /** @type {Array<{ at: number, text: string[] }>} */
47
- const inserts = []
48
- for (const step of missing) {
49
- const at = stepBlockEnd(lines, step.line, step.dashCol)
50
- const ind = ' '.repeat(step.dashCol)
51
- const text = [`${ind}- uses: Swatinem/rust-cache@v2`]
52
- if (workspaceDir && step.jobHasTauriAction) {
53
- text.push(`${ind} with:`, `${ind} workspaces: ${workspaceDir}`)
54
- }
55
- inserts.push({ at, text })
56
- }
57
- inserts.sort((a, b) => b.at - a.at) // згори вниз — індекси не зсуваються під час splice
58
- for (const ins of inserts) lines.splice(ins.at, 0, ...ins.text)
59
- return lines.join('\n')
60
- }
61
-
62
- /**
63
- * Дописує `with: workspaces: <dir>` у кожен уже наявний `Swatinem/rust-cache@…`
64
- * крок Tauri-job-а (`tauri-apps/tauri-action`), якому бракує `workspaces`.
65
- * @param {string} content вміст workflow-файла
66
- * @param {string} workspaceDir відносний шлях workspace-а
67
- * @returns {string|null} новий вміст або null, якщо нічого не змінилось
68
- */
69
- export function addCacheWorkspaces(content, workspaceDir) {
70
- const lines = content.split('\n')
71
- const targets = scanToolchainSteps(content).filter(s => s.hasCache && s.jobHasTauriAction && !s.cacheHasWorkspaces)
72
- if (targets.length === 0) return null
73
-
74
- /** @type {Array<{ at: number, text: string[] }>} */
75
- const inserts = []
76
- for (const step of targets) {
77
- const cacheLine = lines[step.cacheLine]
78
- const usesCol = cacheLine.indexOf('uses:')
79
- const ind = ' '.repeat(usesCol)
80
- const at = stepBlockEnd(lines, step.cacheLine, usesCol - 2)
81
- inserts.push({ at, text: [`${ind}with:`, `${ind} workspaces: ${workspaceDir}`] })
82
- }
83
- inserts.sort((a, b) => b.at - a.at)
84
- for (const ins of inserts) lines.splice(ins.at, 0, ...ins.text)
85
- return lines.join('\n')
86
- }
87
-
88
- /** @type {import('../../../scripts/lib/lint-surface/types.mjs').T0Pattern[]} */
89
- export const patterns = [
90
- {
91
- id: 'rust-toolchain-cache-insert',
92
- test: violations => violations.some(v => v.data?.kind === MISSING_RUST_CACHE && v.file),
93
- apply: (violations, ctx) => {
94
- const targets = violations.filter(v => v.data?.kind === MISSING_RUST_CACHE && v.file)
95
- const wsTargets = violations.filter(v => v.data?.kind === MISSING_RUST_CACHE_WORKSPACES)
96
- const workspaceDir = wsTargets.find(v => typeof v.data?.workspaceDir === 'string')?.data?.workspaceDir
97
- const touchedFiles = applyToFiles(targets, ctx, () => content => insertRustCache(content, workspaceDir))
98
- return touchedFiles.length > 0
99
- ? { touchedFiles, message: `Swatinem/rust-cache@v2 → ${touchedFiles.length} workflow(s)` }
100
- : { touchedFiles: [] }
101
- }
102
- },
103
- {
104
- id: 'rust-toolchain-cache-workspaces',
105
- test: violations => violations.some(v => v.data?.kind === MISSING_RUST_CACHE_WORKSPACES && v.file),
106
- apply: (violations, ctx) => {
107
- const targets = violations.filter(v => v.data?.kind === MISSING_RUST_CACHE_WORKSPACES && v.file)
108
- const touchedFiles = applyToFiles(targets, ctx, () => content => {
109
- const workspaceDir = targets.find(v => typeof v.data?.workspaceDir === 'string')?.data?.workspaceDir
110
- return workspaceDir ? addCacheWorkspaces(content, workspaceDir) : null
111
- })
112
- return touchedFiles.length > 0
113
- ? { touchedFiles, message: `with.workspaces → ${touchedFiles.length} workflow(s)` }
114
- : { touchedFiles: [] }
115
- }
116
- }
117
- ]
@@ -1,177 +0,0 @@
1
- /**
2
- * @see ./docs/main.md
3
- *
4
- * Read-only detector: у кожному `.github/workflows/*.yml` кожен job, що ставить
5
- * Rust toolchain через `dtolnay/rust-toolchain@stable`, повинен мати
6
- * `Swatinem/rust-cache@v2` десь пізніше у тому самому job-і (lint, coverage,
7
- * Tauri release/build — незалежно від job-а чи файлу; rust.mdc). Якщо job також
8
- * запускає `tauri-apps/tauri-action` і Cargo.toml лежить не в корені репо, а під
9
- * `src-tauri/`, кеш-крок повинен мати `with.workspaces` на цей каталог.
10
- *
11
- * Текстовий (не YAML-AST) аналіз — навмисно, як `ga/workflows/main.mjs`: мінімізує
12
- * diff і не залежить від того, чи canonical formatter зберігає коментарі при
13
- * round-trip через YAML-парсер. Job-межа визначається через indentation:
14
- * будь-який рядок з відступом меншим за відступ dash-а кроку означає вихід
15
- * зі step-list-а (наступний job або кінець `jobs:`).
16
- */
17
- import { existsSync } from 'node:fs'
18
- import { readdir, readFile } from 'node:fs/promises'
19
- import { join, relative } from 'node:path'
20
-
21
- import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
22
-
23
- export const MISSING_RUST_CACHE = 'missing-rust-cache'
24
- export const MISSING_RUST_CACHE_WORKSPACES = 'missing-rust-cache-workspaces'
25
-
26
- export const TOOLCHAIN_RE = /uses:\s*dtolnay\/rust-toolchain@/u
27
- export const CACHE_RE = /uses:\s*Swatinem\/rust-cache@/u
28
- const TAURI_ACTION_RE = /uses:\s*tauri-apps\/tauri-action@/u
29
- const WORKSPACES_KEY_RE = /^\s*workspaces\s*:/u
30
-
31
- /**
32
- * Відступ рядка (кількість пробілів перед першим непробільним символом).
33
- * @param {string} line рядок файла
34
- * @returns {number} кількість пробілів відступу
35
- */
36
- function indentOf(line) {
37
- return line.length - line.trimStart().length
38
- }
39
-
40
- /**
41
- * Дашова колонка кроку (`- uses: …`) з колонки `uses:`. Захист від негативного
42
- * значення для нетипового форматування (dash не на тому ж рядку).
43
- * @param {number} usesCol колонка підрядка `uses:`
44
- * @returns {number} колонка dash-а (не менше 0)
45
- */
46
- function dashColFor(usesCol) {
47
- return Math.max(usesCol - 2, 0)
48
- }
49
-
50
- /**
51
- * Один запис аналізу `dtolnay/rust-toolchain` кроку в межах його job-а (обмеженого
52
- * indentation-dedent-ом, без явного YAML-парсу job-структури).
53
- * @typedef {object} ToolchainStepScan
54
- * @property {number} line індекс рядка кроку `dtolnay/rust-toolchain@…`
55
- * @property {number} dashCol колонка dash-а кроку (рівень step-list-а job-а)
56
- * @property {boolean} hasCache чи є `Swatinem/rust-cache@…` пізніше в тому самому job-і
57
- * @property {number} cacheLine індекс рядка кеш-кроку (−1, якщо відсутній)
58
- * @property {boolean} cacheHasWorkspaces чи кеш-крок вже має ключ `workspaces`
59
- * @property {boolean} jobHasTauriAction чи job також викликає `tauri-apps/tauri-action`
60
- */
61
-
62
- /**
63
- * Сканує job від рядка ОДРАЗУ ПІСЛЯ toolchain-кроку до dedent-у: шукає перший
64
- * `Swatinem/rust-cache@…` крок і чи job також викликає `tauri-apps/tauri-action`.
65
- * @param {string[]} lines усі рядки файла
66
- * @param {number} fromLine рядок, з якого починати сканування (i + 1)
67
- * @param {number} dashCol колонка dash-а step-list-а job-а (межа dedent-у)
68
- * @returns {{hasCache: boolean, cacheLine: number, jobHasTauriAction: boolean}} результат сканування job-а
69
- */
70
- function scanJobForCache(lines, fromLine, dashCol) {
71
- let hasCache = false
72
- let cacheLine = -1
73
- let jobHasTauriAction = false
74
- for (let j = fromLine; j < lines.length; j++) {
75
- const line = lines[j]
76
- if (line.trim() === '') continue
77
- if (indentOf(line) < dashCol) break // dedent → вийшли зі step-list-а цього job-а
78
- if (!hasCache && CACHE_RE.test(line)) {
79
- hasCache = true
80
- cacheLine = j
81
- }
82
- if (TAURI_ACTION_RE.test(line)) jobHasTauriAction = true
83
- }
84
- return { hasCache, cacheLine, jobHasTauriAction }
85
- }
86
-
87
- /**
88
- * Чи кеш-крок (`cacheLine`) уже має ключ `with.workspaces` у своєму блоці (до dedent-у).
89
- * @param {string[]} lines усі рядки файла
90
- * @param {number} cacheLine рядок кеш-кроку
91
- * @param {number} dashCol колонка dash-а step-list-а job-а (межа dedent-у)
92
- * @returns {boolean} true — ключ `workspaces` уже є
93
- */
94
- function cacheStepHasWorkspaces(lines, cacheLine, dashCol) {
95
- for (let j = cacheLine + 1; j < lines.length; j++) {
96
- const line = lines[j]
97
- if (line.trim() === '') continue
98
- if (indentOf(line) < dashCol) break
99
- if (WORKSPACES_KEY_RE.test(line)) return true
100
- }
101
- return false
102
- }
103
-
104
- /**
105
- * Сканує вміст workflow-файла й повертає по одному запису на кожен
106
- * `dtolnay/rust-toolchain@…` крок, з інформацією про cache-крок і tauri-action
107
- * у тому самому job-і (обмежено indentation-dedent-ом).
108
- * @param {string} content вміст workflow-файла
109
- * @returns {ToolchainStepScan[]} записи аналізу
110
- */
111
- export function scanToolchainSteps(content) {
112
- const lines = content.split('\n')
113
- /** @type {ToolchainStepScan[]} */
114
- const out = []
115
- for (let i = 0; i < lines.length; i++) {
116
- const usesCol = lines[i].indexOf('uses:')
117
- if (usesCol === -1 || !TOOLCHAIN_RE.test(lines[i])) continue
118
- const dashCol = dashColFor(usesCol)
119
- const { hasCache, cacheLine, jobHasTauriAction } = scanJobForCache(lines, i + 1, dashCol)
120
- const cacheHasWorkspaces = hasCache && cacheStepHasWorkspaces(lines, cacheLine, dashCol)
121
- out.push({ line: i, dashCol, hasCache, cacheLine, cacheHasWorkspaces, jobHasTauriAction })
122
- }
123
- return out
124
- }
125
-
126
- /**
127
- * Каталог Rust-workspace-а для `Swatinem/rust-cache` `with.workspaces`, якщо
128
- * `Cargo.toml` не в корені репо, а під `src-tauri/` (типовий Tauri-layout).
129
- * `undefined`, якщо корінь репо вже є workspace-коренем (окремий крок не потрібен).
130
- * @param {string} cwd корінь проєкту
131
- * @returns {string|undefined} відносний шлях workspace-а або `undefined`
132
- */
133
- export function tauriWorkspaceDir(cwd) {
134
- if (existsSync(join(cwd, 'Cargo.toml'))) return
135
- return existsSync(join(cwd, 'src-tauri', 'Cargo.toml')) ? 'src-tauri' : undefined
136
- }
137
-
138
- /**
139
- * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінт-прогону
140
- * @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат перевірки
141
- */
142
- export async function lint(ctx) {
143
- const cwd = ctx.cwd
144
- const reporter = createViolationReporter(ctx)
145
- const wfDir = join(cwd, '.github', 'workflows')
146
- if (!existsSync(wfDir)) return reporter.result()
147
-
148
- const workspaceDir = tauriWorkspaceDir(cwd)
149
- const entries = await readdir(wfDir)
150
- const workflowFiles = entries.filter(f => f.endsWith('.yml') || f.endsWith('.yaml'))
151
-
152
- for (const name of workflowFiles) {
153
- const abs = join(wfDir, name)
154
- const rel = relative(cwd, abs)
155
- const content = await readFile(abs, 'utf8')
156
- for (const step of scanToolchainSteps(content)) {
157
- if (!step.hasCache) {
158
- reporter.fail(
159
- `${rel}: job зі \`dtolnay/rust-toolchain@stable\` потребує \`Swatinem/rust-cache@v2\` одразу після (rust.mdc)`,
160
- { reason: MISSING_RUST_CACHE, file: rel, data: { kind: MISSING_RUST_CACHE } }
161
- )
162
- continue
163
- }
164
- if (workspaceDir && step.jobHasTauriAction && !step.cacheHasWorkspaces) {
165
- reporter.fail(
166
- `${rel}: Swatinem/rust-cache@v2 у Tauri-job-і потребує \`with.workspaces: ${workspaceDir}\` (rust.mdc)`,
167
- {
168
- reason: MISSING_RUST_CACHE_WORKSPACES,
169
- file: rel,
170
- data: { kind: MISSING_RUST_CACHE_WORKSPACES, workspaceDir }
171
- }
172
- )
173
- }
174
- }
175
- }
176
- return reporter.result()
177
- }
@@ -1,23 +0,0 @@
1
- ## Rust-cache після rust-toolchain — у будь-якому workflow
2
-
3
- Concern: `rust/toolchain_cache` (JS-detector, `main.mjs` — не rego)
4
-
5
- Цільові файли: `.github/workflows/*.yml`, `.github/workflows/*.yaml` (кожен файл окремо)
6
-
7
- У кожному job-і, що ставить Rust toolchain через `dtolnay/rust-toolchain@stable`
8
- (або будь-яку іншу версію), одразу після цього кроку має бути `Swatinem/rust-cache@v2` —
9
- незалежно від того, lint це, coverage чи release/build job, що збирає Tauri-додаток
10
- через `tauri-apps/tauri-action`. Без кешу CI щоразу заново качає весь cargo registry.
11
-
12
- Це узагальнення перевірки `rust/lint_rust_yml` (яка звіряє канонічний
13
- `.github/workflows/lint-rust.yml` цілком) — той concern лишається specific до
14
- lint-workflow, цей — universal per-job перевірка для решти workflow-файлів
15
- (coverage, release, будь-який кастомний).
16
-
17
- Якщо job також викликає `tauri-apps/tauri-action`, а `Cargo.toml` лежить не в
18
- корені репо, а під `<ws>/src-tauri/` (типовий Tauri-layout) — крок
19
- `Swatinem/rust-cache@v2` має мати `with.workspaces: <ws>/src-tauri`.
20
-
21
- Автофікс (`fix-toolchain_cache.mjs`, T0, `fixability: config`) вставляє відсутній
22
- крок одразу після `dtolnay/rust-toolchain@…` (і `with.workspaces`, де потрібно)
23
- текстовим splice-ом — зберігає формат/коментарі, ідемпотентно.
@@ -1,14 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "fixability": "config",
4
- "policy": {
5
- "files": {
6
- "single": ".github/workflows/lint-security.yml",
7
- "required": true
8
- },
9
- "missingMessage": ".github/workflows/lint-security.yml не знайдено — створи за каноном security.mdc"
10
- },
11
- "requires": {
12
- "capability": "ci:github"
13
- }
14
- }
@@ -1,31 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-lint_security_yml.mjs
4
- resource: npm/rules/security/lint_security_yml/fix-lint_security_yml.mjs
5
- docgen:
6
- crc: cb66ccb7
7
- model: openai-codex/gpt-5.5
8
- tier: cloud-avg
9
- score: 100
10
- issues: judge:inaccurate:0.99
11
- judgeModel: openai-codex/gpt-5.4-mini
12
- ---
13
-
14
- ## Огляд
15
-
16
- `patterns` визначає межі пошуку в кодовій базі та свідомо оминає `.github` і `.git`, щоб перевірка не зачіпала службові каталоги. Правило працює в read-only режимі й не записує зміни у файлову систему або бази даних.
17
-
18
- ## Поведінка
19
-
20
- 1. `patterns` визначає правило автоматичного приведення workflow перевірки безпеки до еталонного шаблону.
21
-
22
- 2. Правило орієнтується на файл `.github/workflows/lint-security.yml`, щоб забезпечити наявність узгодженого процесу security lint у CI.
23
-
24
- 3. Під час підбору файлів для загальної обробки свідомо пропускаються службові шляхи `.github` і `.git`, щоб не аналізувати інфраструктурні каталоги як звичайний код.
25
-
26
- 4. Зміни не записуються напряму у файлову систему або зовнішні сховища: `patterns` лише описує доступне виправлення для подальшого застосування інструментом.
27
-
28
- ## Гарантії поведінки
29
-
30
- - Read-only: не виконує операцій запису (ФС/БД).
31
- - Свідомо пропускає шляхи: `.github`, `.git`.
@@ -1,9 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/security/lint_security_yml
4
- resource: npm/rules/security/lint_security_yml/
5
- ---
6
-
7
- | Файл | Тип |
8
- | ----------------------------------------------------- | --------- |
9
- | [fix-lint_security_yml.mjs](fix-lint_security_yml.md) | JS Module |
@@ -1,8 +0,0 @@
1
- import { createTemplateFixPattern } from '../../../scripts/lib/fix/template-deep-merge.mjs'
2
-
3
- export const patterns = [
4
- createTemplateFixPattern({
5
- id: 'security-lint_security_yml-template',
6
- targetPath: '.github/workflows/lint-security.yml'
7
- })
8
- ]
@@ -1,7 +0,0 @@
1
- ## Наявність кроку TruffleHog у CI workflow
2
-
3
- Rego-пакет: `security.lint_security_yml`
4
-
5
- Цільові файли: `.github/workflows/lint-security.yml`
6
-
7
- Перевіряє, що серед `uses:` у workflow присутній крок `trufflesecurity/trufflehog@main`. Очікуваний перелік action-refs (не-`actions/*`) береться з `--data` через [lint-security.yml.snippet.yml](./template/lint-security.yml.snippet.yml). Універсальні кроки (`actions/*`) перевіряє `ga.workflow_common`.
@@ -1,33 +0,0 @@
1
- # Перевірка `.github/workflows/lint-security.yml` (security.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "snippet": ... } }, побудоване
4
- # з template/lint-security.yml.snippet.yml. З нього збирається перелік
5
- # `uses:` action-refs security-job (виключаючи універсальні `actions/*`, які
6
- # валідує `ga.workflow_common`).
7
- #
8
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
9
- package security.lint_security_yml
10
-
11
- import rego.v1
12
-
13
- # Очікувані action-uses із template (не-`actions/*`).
14
- expected_uses_blob := concat("\n", [u |
15
- some step in data.template.snippet.jobs.security.steps
16
- u := object.get(step, "uses", "")
17
- u != ""
18
- not startswith(u, "actions/")
19
- ])
20
-
21
- # Усі `uses:` із input workflow.
22
- all_uses_text := concat("\n", [u |
23
- some job in object.get(input, "jobs", {})
24
- some step in object.get(job, "steps", [])
25
- u := object.get(step, "uses", "")
26
- u != ""
27
- ])
28
-
29
- deny contains msg if {
30
- expected_uses_blob != ""
31
- not contains(all_uses_text, expected_uses_blob)
32
- msg := sprintf("lint-security.yml: відсутній крок з uses %q (security.mdc)", [expected_uses_blob])
33
- }
@@ -1,31 +0,0 @@
1
- name: Lint Security
2
-
3
- on:
4
- push:
5
- branches:
6
- - dev
7
- - main
8
-
9
- pull_request:
10
- branches:
11
- - dev
12
- - main
13
-
14
- concurrency:
15
- group: ${{ github.ref }}-${{ github.workflow }}
16
- cancel-in-progress: true
17
-
18
- jobs:
19
- security:
20
- runs-on: ubuntu-latest
21
- permissions:
22
- contents: read
23
- steps:
24
- - uses: actions/checkout@v6
25
- with:
26
- persist-credentials: false
27
- fetch-depth: 0
28
-
29
- - uses: trufflesecurity/trufflehog@main
30
- with:
31
- extra_args: --results=verified,unknown
@@ -1,12 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "fixability": "config",
4
- "policy": {
5
- "files": {
6
- "single": ".github/workflows/lint-style.yml"
7
- }
8
- },
9
- "requires": {
10
- "capability": "ci:github"
11
- }
12
- }
@@ -1,31 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-lint_style_yml.mjs
4
- resource: npm/rules/style/lint_style_yml/fix-lint_style_yml.mjs
5
- docgen:
6
- crc: fc52d912
7
- model: openai-codex/gpt-5.5
8
- tier: cloud-avg
9
- score: 100
10
- issues: judge:inaccurate:0.99
11
- judgeModel: openai-codex/gpt-5.4-mini
12
- ---
13
-
14
- ## Огляд
15
-
16
- Публічна функція `patterns` надає шаблони для зовнішньої перевірки очікуваного стану коду. Модуль працює як read-only джерело правил: не змінює ФС чи БД і свідомо пропускає службові шляхи `.github` та `.git`.
17
-
18
- ## Поведінка
19
-
20
- 1. `patterns` визначає набір правил автоматичного виправлення для стандартного workflow перевірки стилю.
21
-
22
- 2. `patterns` спрямовує виправлення на файл `.github/workflows/lint-style.yml`, щоб підтримувати єдиний шаблон CI-перевірки стилю в проєкті.
23
-
24
- 3. `patterns` не виконує запис у файлову систему чи інші сховища самостійно, а лише описує очікувану зміну для зовнішнього механізму застосування.
25
-
26
- 4. Під час роботи свідомо не обробляються службові шляхи `.github` і `.git`, окрім цільового workflow-файлу, для якого визначено шаблонне виправлення.
27
-
28
- ## Гарантії поведінки
29
-
30
- - Read-only: не виконує операцій запису (ФС/БД).
31
- - Свідомо пропускає шляхи: `.github`, `.git`.
@@ -1,9 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/style/lint_style_yml
4
- resource: npm/rules/style/lint_style_yml/
5
- ---
6
-
7
- | Файл | Тип |
8
- | ----------------------------------------------- | --------- |
9
- | [fix-lint_style_yml.mjs](fix-lint_style_yml.md) | JS Module |
@@ -1,5 +0,0 @@
1
- import { createTemplateFixPattern } from '../../../scripts/lib/fix/template-deep-merge.mjs'
2
-
3
- export const patterns = [
4
- createTemplateFixPattern({ id: 'style-lint_style_yml-template', targetPath: '.github/workflows/lint-style.yml' })
5
- ]
@@ -1,13 +0,0 @@
1
- ## GitHub Actions workflow: lint-style.yml
2
-
3
- Rego-пакет: `style_lint.lint_style_yml`
4
-
5
- Цільовий файл: `.github/workflows/lint-style.yml`
6
-
7
- Перевіряє, що у workflow є крок `run`, який містить команду `n-rules lint style --no-fix` (substring-match по всіх кроках усіх jobs). Канонічний текст береться з template через `--data`.
8
-
9
- Канонічний template: [lint-style.yml.snippet.yml](./template/lint-style.yml.snippet.yml)
10
-
11
- **✓ Правильно** — крок `run: n-rules lint style --no-fix` присутній у jobs.stylelint.steps.
12
-
13
- **✗ Неправильно** — крок відсутній або містить лише `echo nothing` / `npx stylelint` без канонічного рядка.
@@ -1,38 +0,0 @@
1
- # Перевірка `lint-style.yml` (style.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "snippet": ... } }
4
- # Структура --data сформована з template/lint-style.yml.snippet.yml.
5
- # Маркер `run:` (npx stylelint substring) збирається з template's stylelint-job steps.
6
- # Універсальні workflow-перевірки — у `ga.workflow_common`.
7
- package style.lint_style_yml
8
-
9
- import rego.v1
10
-
11
- expected_run_blob := concat("\n", [r |
12
- some step in data.template.snippet.jobs.stylelint.steps
13
- r := object.get(step, "run", "")
14
- r != ""
15
- ])
16
-
17
- all_run_text := concat("\n", [run_text |
18
- some job in object.get(input, "jobs", {})
19
- some step in object.get(job, "steps", [])
20
- run_text := step_run_to_text(step)
21
- ])
22
-
23
- deny contains msg if {
24
- expected_run_blob != ""
25
- not contains(all_run_text, expected_run_blob)
26
- msg := sprintf("lint-style.yml: жоден крок run не містить %q (style.mdc)", [expected_run_blob])
27
- }
28
-
29
- deny contains msg if {
30
- contains(all_run_text, "bunx stylelint")
31
- msg := "lint-style.yml: знайдено bunx stylelint — використовуй n-rules lint style --no-fix (style.mdc)"
32
- }
33
-
34
- step_run_to_text(step) := step.run if is_string(step.run)
35
-
36
- else := concat("\n", [s | some s in step.run]) if is_array(step.run)
37
-
38
- else := ""
@@ -1,39 +0,0 @@
1
- name: StyleLint
2
-
3
- on:
4
- push:
5
- branches:
6
- - dev
7
- - main
8
- paths:
9
- - '**/*.css'
10
- - '**/*.scss'
11
- - '**/*.vue'
12
-
13
- pull_request:
14
- branches:
15
- - dev
16
- - main
17
- paths:
18
- - '**/*.css'
19
- - '**/*.scss'
20
- - '**/*.vue'
21
-
22
- concurrency:
23
- group: ${{ github.ref }}-${{ github.workflow }}
24
- cancel-in-progress: true
25
-
26
- jobs:
27
- stylelint:
28
- runs-on: ubuntu-latest
29
- permissions:
30
- contents: read
31
- steps:
32
- - uses: actions/checkout@v6
33
- with:
34
- persist-credentials: false
35
-
36
- - uses: ./.github/actions/setup-bun-deps
37
-
38
- - name: StyleLint
39
- run: bunx n-rules lint style --no-fix
@@ -1,11 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "policy": {
4
- "files": {
5
- "single": ".github/workflows/lint-text.yml"
6
- }
7
- },
8
- "requires": {
9
- "capability": "ci:github"
10
- }
11
- }
@@ -1,28 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-lint_text.mjs
4
- resource: npm/rules/text/lint_text/fix-lint_text.mjs
5
- docgen:
6
- crc: cefae829
7
- model: openai-codex/gpt-5.4-mini
8
- tier: cloud-min
9
- score: 100
10
- issues: judge:inaccurate:0.99
11
- judgeModel: openai-codex/gpt-5.4-mini
12
- ---
13
-
14
- ## Огляд
15
-
16
- `patterns` визначає, які текстові зміни вважаються придатними для узгодження з еталонною структурою workflow. Вона потрібна, щоб перевірка зосереджувалась на змісті потрібних файлів і не торкалась службових шляхів `.github` і `.git`.
17
-
18
- ## Поведінка
19
-
20
- 1. `patterns` формує набір правил для узгодження текстової перевірки з еталонною структурою workflow.
21
- 2. Підготовлює виправлення для цільового файлу `.github/workflows/lint-text.yml`.
22
- 3. Свідомо обходить службові шляхи `.github` і `.git`, щоб не зачіпати внутрішню інфраструктуру репозиторію.
23
- 4. Працює лише на читання: не змінює файлову систему і не виконує запис у БД.
24
-
25
- ## Гарантії поведінки
26
-
27
- - Read-only: не виконує операцій запису (ФС/БД).
28
- - Свідомо пропускає шляхи: `.github`, `.git`.