@7n/rules-ci-github 1.2.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 +15 -0
- package/package.json +49 -0
- package/rules/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc +19 -0
- package/rules/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +81 -0
- package/rules/abie/clean_merged_ignore_branches/concern.json +8 -0
- package/rules/abie/clean_merged_ignore_branches/docs/fix-clean_merged_ignore_branches.md +30 -0
- package/rules/abie/clean_merged_ignore_branches/docs/index.md +9 -0
- package/rules/abie/clean_merged_ignore_branches/fix-clean_merged_ignore_branches.mjs +8 -0
- package/rules/abie/clean_merged_ignore_branches/template/clean-merged-branch.yml.snippet.yml +9 -0
- package/rules/docker/lint_docker_yml/concern.json +11 -0
- package/rules/docker/lint_docker_yml/docs/fix-lint_docker_yml.md +30 -0
- package/rules/docker/lint_docker_yml/docs/index.md +9 -0
- package/rules/docker/lint_docker_yml/fix-lint_docker_yml.mjs +5 -0
- package/rules/docker/lint_docker_yml/lint_docker_yml.mdc +14 -0
- package/rules/docker/lint_docker_yml/lint_docker_yml.rego +79 -0
- package/rules/docker/lint_docker_yml/template/lint-docker.yml.snippet.yml +41 -0
- package/rules/ga/clean_ga_workflows/clean_ga_workflows.mdc +20 -0
- package/rules/ga/clean_ga_workflows/clean_ga_workflows.rego +112 -0
- package/rules/ga/clean_ga_workflows/concern.json +10 -0
- package/rules/ga/clean_ga_workflows/docs/fix-clean_ga_workflows.md +33 -0
- package/rules/ga/clean_ga_workflows/docs/index.md +9 -0
- package/rules/ga/clean_ga_workflows/fix-clean_ga_workflows.mjs +8 -0
- package/rules/ga/clean_ga_workflows/template/clean-ga-workflows.yml.snippet.yml +26 -0
- package/rules/ga/clean_merged_branch/clean_merged_branch.mdc +24 -0
- package/rules/ga/clean_merged_branch/clean_merged_branch.rego +163 -0
- package/rules/ga/clean_merged_branch/concern.json +10 -0
- package/rules/ga/clean_merged_branch/docs/fix-clean_merged_branch.md +27 -0
- package/rules/ga/clean_merged_branch/docs/index.md +9 -0
- package/rules/ga/clean_merged_branch/fix-clean_merged_branch.mjs +8 -0
- package/rules/ga/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +37 -0
- package/rules/ga/docs/index.md +11 -0
- package/rules/ga/git_ai/concern.json +11 -0
- package/rules/ga/git_ai/docs/fix-git_ai.md +30 -0
- package/rules/ga/git_ai/docs/index.md +9 -0
- package/rules/ga/git_ai/fix-git_ai.mjs +5 -0
- package/rules/ga/git_ai/git_ai.mdc +19 -0
- package/rules/ga/git_ai/git_ai.rego +76 -0
- package/rules/ga/git_ai/template/git-ai.yml.snippet.yml +30 -0
- package/rules/ga/lint_ga/concern.json +10 -0
- package/rules/ga/lint_ga/docs/fix-lint_ga.md +32 -0
- package/rules/ga/lint_ga/docs/index.md +9 -0
- package/rules/ga/lint_ga/fix-lint_ga.mjs +5 -0
- package/rules/ga/lint_ga/lint_ga.mdc +21 -0
- package/rules/ga/lint_ga/lint_ga.rego +132 -0
- package/rules/ga/lint_ga/template/lint-ga.yml.snippet.yml +41 -0
- package/rules/ga/main.json +1 -0
- package/rules/ga/main.mdc +17 -0
- package/rules/ga/vscode_extensions/concern.json +11 -0
- package/rules/ga/vscode_extensions/docs/fix-vscode_extensions.md +25 -0
- package/rules/ga/vscode_extensions/docs/index.md +11 -0
- package/rules/ga/vscode_extensions/fix-vscode_extensions.mjs +1 -0
- package/rules/ga/vscode_extensions/template/extensions.json.snippet.json +1 -0
- package/rules/ga/vscode_extensions/vscode_extensions.mdc +9 -0
- package/rules/ga/vscode_extensions/vscode_extensions.rego +18 -0
- package/rules/ga/vscode_settings/concern.json +11 -0
- package/rules/ga/vscode_settings/docs/fix-vscode_settings.md +26 -0
- package/rules/ga/vscode_settings/docs/index.md +9 -0
- package/rules/ga/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/ga/vscode_settings/template/settings.json.snippet.json +1 -0
- package/rules/ga/vscode_settings/vscode_settings.mdc +9 -0
- package/rules/ga/vscode_settings/vscode_settings.rego +22 -0
- package/rules/ga/workflow_common/concern.json +9 -0
- package/rules/ga/workflow_common/template/uses-min-versions.snippet.json +4 -0
- package/rules/ga/workflow_common/workflow_common.mdc +18 -0
- package/rules/ga/workflow_common/workflow_common.rego +288 -0
- package/rules/ga/workflows/concern.json +8 -0
- package/rules/ga/workflows/docs/fix-workflows.md +37 -0
- package/rules/ga/workflows/docs/main.md +40 -0
- package/rules/ga/workflows/fix-workflows.mjs +212 -0
- package/rules/ga/workflows/main.mjs +436 -0
- package/rules/ga/workflows/workflows.mdc +33 -0
- package/rules/ga/zizmor_yml/concern.json +11 -0
- package/rules/ga/zizmor_yml/docs/fix-zizmor_yml.md +28 -0
- package/rules/ga/zizmor_yml/docs/index.md +9 -0
- package/rules/ga/zizmor_yml/fix-zizmor_yml.mjs +3 -0
- package/rules/ga/zizmor_yml/template/zizmor.yml.snippet.yml +5 -0
- package/rules/ga/zizmor_yml/zizmor_yml.mdc +9 -0
- package/rules/ga/zizmor_yml/zizmor_yml.rego +27 -0
- package/rules/js/lint_js_yml/concern.json +11 -0
- package/rules/js/lint_js_yml/docs/fix-lint_js_yml.md +27 -0
- package/rules/js/lint_js_yml/docs/index.md +9 -0
- package/rules/js/lint_js_yml/fix-lint_js_yml.mjs +5 -0
- package/rules/js/lint_js_yml/lint_js_yml.mdc +14 -0
- package/rules/js/lint_js_yml/lint_js_yml.rego +117 -0
- package/rules/js/lint_js_yml/template/lint-js.yml.snippet.yml +40 -0
- package/rules/k8s/lint_k8s_yml/concern.json +11 -0
- package/rules/k8s/lint_k8s_yml/docs/fix-lint_k8s_yml.md +30 -0
- package/rules/k8s/lint_k8s_yml/docs/index.md +9 -0
- package/rules/k8s/lint_k8s_yml/fix-lint_k8s_yml.mjs +5 -0
- package/rules/k8s/lint_k8s_yml/lint_k8s_yml.rego +57 -0
- package/rules/k8s/lint_k8s_yml/template/lint-k8s.yml.snippet.yml +43 -0
- package/rules/npm-module/npm_publish_yml/concern.json +12 -0
- package/rules/npm-module/npm_publish_yml/docs/fix-npm_publish_yml.md +27 -0
- package/rules/npm-module/npm_publish_yml/docs/index.md +9 -0
- package/rules/npm-module/npm_publish_yml/fix-npm_publish_yml.mjs +8 -0
- package/rules/npm-module/npm_publish_yml/template/npm-publish.yml.snippet.yml +49 -0
- package/rules/php/lint_php_yml/concern.json +11 -0
- package/rules/php/lint_php_yml/docs/fix-lint_php_yml.md +27 -0
- package/rules/php/lint_php_yml/docs/index.md +9 -0
- package/rules/php/lint_php_yml/fix-lint_php_yml.mjs +5 -0
- package/rules/php/lint_php_yml/lint_php_yml.mdc +23 -0
- package/rules/php/lint_php_yml/lint_php_yml.rego +34 -0
- package/rules/php/lint_php_yml/template/lint-php.yml.snippet.yml +47 -0
- package/rules/python/lint_python_yml/concern.json +11 -0
- package/rules/python/lint_python_yml/docs/fix-lint_python_yml.md +26 -0
- package/rules/python/lint_python_yml/docs/index.md +9 -0
- package/rules/python/lint_python_yml/fix-lint_python_yml.mjs +5 -0
- package/rules/python/lint_python_yml/lint_python_yml.mdc +12 -0
- package/rules/python/lint_python_yml/lint_python_yml.rego +68 -0
- package/rules/python/lint_python_yml/template/lint-python.yml.snippet.yml +41 -0
- package/rules/rust/lint_rust_yml/concern.json +11 -0
- package/rules/rust/lint_rust_yml/docs/fix-lint_rust_yml.md +27 -0
- package/rules/rust/lint_rust_yml/docs/index.md +9 -0
- package/rules/rust/lint_rust_yml/fix-lint_rust_yml.mjs +5 -0
- package/rules/rust/lint_rust_yml/lint_rust_yml.mdc +17 -0
- package/rules/rust/lint_rust_yml/lint_rust_yml.rego +79 -0
- package/rules/rust/lint_rust_yml/template/lint-rust.yml.snippet.yml +44 -0
- package/rules/rust/toolchain_cache/concern.json +11 -0
- package/rules/rust/toolchain_cache/docs/fix-toolchain_cache.md +35 -0
- package/rules/rust/toolchain_cache/docs/index.md +12 -0
- package/rules/rust/toolchain_cache/docs/main.md +57 -0
- package/rules/rust/toolchain_cache/fix-toolchain_cache.mjs +117 -0
- package/rules/rust/toolchain_cache/main.mjs +177 -0
- package/rules/rust/toolchain_cache/toolchain_cache.mdc +23 -0
- package/rules/security/lint_security_yml/concern.json +11 -0
- package/rules/security/lint_security_yml/docs/fix-lint_security_yml.md +30 -0
- package/rules/security/lint_security_yml/docs/index.md +9 -0
- package/rules/security/lint_security_yml/fix-lint_security_yml.mjs +8 -0
- package/rules/security/lint_security_yml/lint_security_yml.mdc +7 -0
- package/rules/security/lint_security_yml/lint_security_yml.rego +33 -0
- package/rules/security/lint_security_yml/template/lint-security.yml.snippet.yml +31 -0
- package/rules/style/lint_style_yml/concern.json +11 -0
- package/rules/style/lint_style_yml/docs/fix-lint_style_yml.md +30 -0
- package/rules/style/lint_style_yml/docs/index.md +9 -0
- package/rules/style/lint_style_yml/fix-lint_style_yml.mjs +5 -0
- package/rules/style/lint_style_yml/lint_style_yml.mdc +13 -0
- package/rules/style/lint_style_yml/lint_style_yml.rego +38 -0
- package/rules/style/lint_style_yml/template/lint-style.yml.snippet.yml +39 -0
- package/rules/text/lint_text/concern.json +10 -0
- package/rules/text/lint_text/docs/fix-lint_text.md +27 -0
- package/rules/text/lint_text/docs/index.md +9 -0
- package/rules/text/lint_text/fix-lint_text.mjs +5 -0
- package/rules/text/lint_text/lint_text.mdc +19 -0
- package/rules/text/lint_text/lint_text.rego +104 -0
- package/rules/text/lint_text/template/lint-text.yml.snippet.yml +61 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.2.0] - 2026-07-16
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Mixin-концерни з ядра: lint_*_yml для js/python/docker/k8s/style/php/rust/security/text, npm_publish_yml, rust/toolchain_cache, abie/clean_merged_ignore_branches — GitHub-реалізація CI-lint намірів доменних правил
|
|
8
|
+
|
|
9
|
+
## [1.1.0] - 2026-07-15
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Перший реліз @7n/rules-ci-github: правило `ga` (канон GitHub Actions) винесено з ядра @7n/rules у плагін; capability `ci:github`
|
|
14
|
+
|
|
15
|
+
All notable changes to this project will be documented in this file.
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@7n/rules-ci-github",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "\u041f\u043b\u0430\u0433\u0456\u043d @7n/rules: \u043a\u0430\u043d\u043e\u043d GitHub Actions (.github/workflows) \u2014 \u043e\u0431\u043e\u0432'\u044f\u0437\u043a\u043e\u0432\u0456 workflow, zizmor, VS Code",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"github-actions",
|
|
7
|
+
"ci",
|
|
8
|
+
"lint",
|
|
9
|
+
"n-rules-plugin"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/nitra/7n-rules#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/nitra/7n-rules/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"author": "v@nitra.ai",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/nitra/7n-rules.git",
|
|
20
|
+
"directory": "plugins/ci-github"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"files": [
|
|
24
|
+
"rules",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"!**/*.test.mjs",
|
|
27
|
+
"!**/*_test.rego",
|
|
28
|
+
"!**/fixtures/**",
|
|
29
|
+
"!**/tests/**"
|
|
30
|
+
],
|
|
31
|
+
"n-rules": {
|
|
32
|
+
"capabilities": [
|
|
33
|
+
"ci:github"
|
|
34
|
+
],
|
|
35
|
+
"contributes": {
|
|
36
|
+
"rules": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@7n/rules": ">=1.2.0"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"bun": ">=1.3",
|
|
47
|
+
"node": ">=24"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## Rego: `ignore_branches` у `clean-merged-branch.yml`
|
|
2
|
+
|
|
3
|
+
Rego-пакет: `abie.clean_merged_ignore_branches`
|
|
4
|
+
|
|
5
|
+
Цільовий файл: `.github/workflows/clean-merged-branch.yml`.
|
|
6
|
+
|
|
7
|
+
Перевіряє, що у workflow-файлі є крок з `uses: phpdocker-io/github-actions-delete-abandoned-branches` і що його `with.ignore_branches` містить обидва токени `dev` та `ua` (case-insensitive, пробіли навколо токенів обрізаються). Токени зчитуються з template-файлу `data.template.snippet` — зміна канону автоматично змінює вимоги.
|
|
8
|
+
|
|
9
|
+
Канонічний snippet: [clean-merged-branch.yml.snippet.yml](./template/clean-merged-branch.yml.snippet.yml)
|
|
10
|
+
|
|
11
|
+
```yaml title=".github/workflows/clean-merged-branch.yml (фрагмент)"
|
|
12
|
+
- uses: phpdocker-io/github-actions-delete-abandoned-branches@v2
|
|
13
|
+
with:
|
|
14
|
+
ignore_branches: "dev,ua,main" # ✓ містить dev та ua
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
ignore_branches: "main" # ✗ не вистачає dev,ua
|
|
19
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Перевірка `clean-merged-branch.yml` для abie-проєктів (abie.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/clean-merged-branch.yml.snippet.yml.
|
|
5
|
+
# Action-маркер (`uses:` substring) і required branches (parsed з template's
|
|
6
|
+
# `ignore_branches`) читаються з template. ga.clean_merged_branch перевіряє
|
|
7
|
+
# повний канон workflow окремо; цей пакет — лише abie-specific шар.
|
|
8
|
+
package abie.clean_merged_ignore_branches
|
|
9
|
+
|
|
10
|
+
import rego.v1
|
|
11
|
+
|
|
12
|
+
# Експектації з template's step (першого з steps).
|
|
13
|
+
expected_step := step if some step in data.template.snippet.jobs.cleanup_old_branches.steps
|
|
14
|
+
|
|
15
|
+
target_action_marker := expected_step.uses
|
|
16
|
+
|
|
17
|
+
required_branches := parsed_ignore_tokens(expected_step.with.ignore_branches)
|
|
18
|
+
|
|
19
|
+
step_missing_msg := sprintf(
|
|
20
|
+
"clean-merged-branch.yml: не знайдено крок з uses: %s (abie.mdc)",
|
|
21
|
+
[target_action_marker],
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
ignore_branches_missing_msg := sprintf(
|
|
25
|
+
"clean-merged-branch.yml: не знайдено with.ignore_branches у кроці %s (abie.mdc)",
|
|
26
|
+
[target_action_marker],
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# ── deny ─────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
deny contains step_missing_msg if {
|
|
32
|
+
count(target_steps) == 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
deny contains ignore_branches_missing_msg if {
|
|
36
|
+
count(target_steps) > 0
|
|
37
|
+
not has_ignore_branches_value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
deny contains msg if {
|
|
41
|
+
count(target_steps) > 0
|
|
42
|
+
ignore_branches_value != ""
|
|
43
|
+
missing := required_branches - parsed_ignore_tokens(ignore_branches_value)
|
|
44
|
+
count(missing) > 0
|
|
45
|
+
msg := sprintf(
|
|
46
|
+
"clean-merged-branch.yml: ignore_branches має містити %v (зараз: %q; не вистачає: %v) (abie.mdc)",
|
|
47
|
+
[concat(",", sort(required_branches)), ignore_branches_value, concat(",", sort(missing))],
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# ── helpers ──────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
target_steps contains step if {
|
|
54
|
+
some job in object.get(input, "jobs", {})
|
|
55
|
+
some step in object.get(job, "steps", [])
|
|
56
|
+
uses := object.get(step, "uses", "")
|
|
57
|
+
is_string(uses)
|
|
58
|
+
contains(uses, target_action_marker)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
has_ignore_branches_value if {
|
|
62
|
+
some step in target_steps
|
|
63
|
+
v := object.get(object.get(step, "with", {}), "ignore_branches", null)
|
|
64
|
+
is_string(v)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
default ignore_branches_value := ""
|
|
68
|
+
|
|
69
|
+
ignore_branches_value := values[0] if {
|
|
70
|
+
values := [v |
|
|
71
|
+
some step in target_steps
|
|
72
|
+
v := object.get(object.get(step, "with", {}), "ignore_branches", null)
|
|
73
|
+
is_string(v)
|
|
74
|
+
]
|
|
75
|
+
count(values) > 0
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
parsed_ignore_tokens(value) := {lower(trim_space(part)) |
|
|
79
|
+
some part in split(value, ",")
|
|
80
|
+
trim_space(part) != ""
|
|
81
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: fix-clean_merged_ignore_branches.mjs
|
|
4
|
+
resource: plugins/ci-github/rules/abie/clean_merged_ignore_branches/fix-clean_merged_ignore_branches.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: f3646572
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
score: 100
|
|
9
|
+
issues: judge:inaccurate:0.99
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
`patterns` визначає набір шляхів репозиторію, які правило має враховувати під час перевірки. Воно свідомо не охоплює `.git` і `.github`, щоб не аналізувати службові дані Git та конфігурацію GitHub. Правило працює read-only: лише повідомляє про невідповідність очікуваній структурі, не змінюючи файли чи зовнішні сховища.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
1. `patterns` визначає правило виправлення, яке забезпечує наявність workflow для очищення merged branches.
|
|
20
|
+
|
|
21
|
+
2. Правило орієнтується на шаблонний стан файлу `.github/workflows/clean-merged-branch.yml`, щоб уніфікувати поведінку репозиторіїв щодо прибирання вже злитих гілок.
|
|
22
|
+
|
|
23
|
+
3. Під час перевірки свідомо не обходить службові шляхи `.github` і `.git`, окрім цільового workflow-файлу, який є предметом виправлення.
|
|
24
|
+
|
|
25
|
+
4. `patterns` лише описує очікуване виправлення й не виконує самостійного запису у файлову систему чи інші сховища.
|
|
26
|
+
|
|
27
|
+
## Гарантії поведінки
|
|
28
|
+
|
|
29
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
30
|
+
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Directory Index
|
|
3
|
+
title: npm/rules/abie/clean_merged_ignore_branches
|
|
4
|
+
resource: npm/rules/abie/clean_merged_ignore_branches/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
| Файл | Тип |
|
|
8
|
+
| --------------------------------------------------------------------------- | --------- |
|
|
9
|
+
| [fix-clean_merged_ignore_branches.mjs](fix-clean_merged_ignore_branches.md) | JS Module |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createTemplateFixPattern } from '@7n/rules/scripts/lib/fix/template-deep-merge.mjs'
|
|
2
|
+
|
|
3
|
+
export const patterns = [
|
|
4
|
+
createTemplateFixPattern({
|
|
5
|
+
id: 'abie-clean_merged_ignore_branches-template',
|
|
6
|
+
targetPath: '.github/workflows/clean-merged-branch.yml'
|
|
7
|
+
})
|
|
8
|
+
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# abie-specific шар поверх ga.clean_merged_branch:
|
|
2
|
+
# у `clean-merged-branch.yml` крок phpdocker-io/github-actions-delete-abandoned-branches
|
|
3
|
+
# має містити `ignore_branches: dev,ua` (обовʼязкові гілки для abie-проєктів).
|
|
4
|
+
jobs:
|
|
5
|
+
cleanup_old_branches:
|
|
6
|
+
steps:
|
|
7
|
+
- uses: phpdocker-io/github-actions-delete-abandoned-branches
|
|
8
|
+
with:
|
|
9
|
+
ignore_branches: dev,ua
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
|
|
3
|
+
"fixability": "config",
|
|
4
|
+
"policy": {
|
|
5
|
+
"files": {
|
|
6
|
+
"single": ".github/workflows/lint-docker.yml",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"missingMessage": ".github/workflows/lint-docker.yml не існує — створи за каноном правила (mixin @7n/rules-ci-github)"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: fix-lint_docker_yml.mjs
|
|
4
|
+
resource: plugins/ci-github/rules/docker/lint_docker_yml/fix-lint_docker_yml.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: cbc93b9d
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
score: 100
|
|
9
|
+
issues: judge:inaccurate:0.98
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
`patterns` визначає поведінку правила для обходу проєкту без змін у файловій системі чи зовнішніх сховищах. Службові директорії `.github` і `.git` свідомо не входять до перевірюваних шляхів, щоб правило працювало лише з релевантним кодом проєкту.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
1. `patterns` визначає правило автоматичного виправлення для workflow перевірки Docker.
|
|
20
|
+
|
|
21
|
+
2. `patterns` забезпечує наявність стандартного файлу `.github/workflows/lint-docker.yml`, щоб проєкт мав єдиний CI-контроль Docker-конфігурації.
|
|
22
|
+
|
|
23
|
+
3. `patterns` працює як read-only опис виправлення: сам модуль не змінює файлову систему чи зовнішні сховища.
|
|
24
|
+
|
|
25
|
+
4. Під час супровідного обходу шляхів свідомо не аналізуються `.github` і `.git`, щоб не змішувати службові директорії з основним кодом проєкту.
|
|
26
|
+
|
|
27
|
+
## Гарантії поведінки
|
|
28
|
+
|
|
29
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
30
|
+
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Directory Index
|
|
3
|
+
title: npm/rules/docker/lint_docker_yml
|
|
4
|
+
resource: npm/rules/docker/lint_docker_yml/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
| Файл | Тип |
|
|
8
|
+
| ------------------------------------------------- | --------- |
|
|
9
|
+
| [fix-lint_docker_yml.mjs](fix-lint_docker_yml.md) | JS Module |
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Перевірка `.github/workflows/lint-docker.yml`
|
|
2
|
+
|
|
3
|
+
Rego-пакет: `docker.lint_docker_yml`
|
|
4
|
+
|
|
5
|
+
Цільовий файл: `.github/workflows/lint-docker.yml`
|
|
6
|
+
|
|
7
|
+
Перевіряє, що CI-workflow lint-docker відповідає канонічному сніпету:
|
|
8
|
+
|
|
9
|
+
- `on.push.paths` містить усі три glob-маски: `**/Dockerfile`, `**/*.Dockerfile`, `**/*.dockerfile`
|
|
10
|
+
- присутні кроки `uses: actions/checkout@v6` та `uses: ./.github/actions/setup-bun-deps`
|
|
11
|
+
- крок install hadolint містить рядок із версією `v2.12.0` (substring-перевірка)
|
|
12
|
+
- крок lint містить `n-rules lint docker --no-fix`
|
|
13
|
+
|
|
14
|
+
Канонічний шаблон: [lint-docker.yml.snippet.yml](./template/lint-docker.yml.snippet.yml)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Перевірка `.github/workflows/lint-docker.yml` (docker.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/lint-docker.yml.snippet.yml.
|
|
5
|
+
# Path-маркери, hadolint версія (substring "v2.12.0" у run), setup-bun-deps
|
|
6
|
+
# composite, `n-rules lint docker --no-fix` substring — все читається з template's snippet.
|
|
7
|
+
# Універсальні workflow-перевірки — у `ga.workflow_common`.
|
|
8
|
+
package docker.lint_docker_yml
|
|
9
|
+
|
|
10
|
+
import rego.v1
|
|
11
|
+
|
|
12
|
+
# Очікувані літерали з template.
|
|
13
|
+
expected_paths := {p | some p in data.template.snippet.on.push.paths}
|
|
14
|
+
|
|
15
|
+
# Required uses set — з template's steps.
|
|
16
|
+
expected_uses_set contains u if {
|
|
17
|
+
some step in data.template.snippet.jobs["lint-docker"].steps
|
|
18
|
+
u := object.get(step, "uses", "")
|
|
19
|
+
u != ""
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Required run substrings — collected per-step з template.
|
|
23
|
+
expected_run_substrings contains r if {
|
|
24
|
+
some step in data.template.snippet.jobs["lint-docker"].steps
|
|
25
|
+
r := object.get(step, "run", "")
|
|
26
|
+
r != ""
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Аліаси на input.
|
|
30
|
+
all_step_uses contains u if {
|
|
31
|
+
some job in object.get(input, "jobs", {})
|
|
32
|
+
some step in object.get(job, "steps", [])
|
|
33
|
+
u := object.get(step, "uses", "")
|
|
34
|
+
u != ""
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
all_run_text := concat("\n", [run_text |
|
|
38
|
+
some job in object.get(input, "jobs", {})
|
|
39
|
+
some step in object.get(job, "steps", [])
|
|
40
|
+
run_text := step_run_to_text(step)
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
# conftest парсить YAML 1.1, тож канонічний `on:` без лапок стає булевим ключем
|
|
44
|
+
# `true` (як у `ga.lint_ga`). Тому читаємо через `input["true"]`.
|
|
45
|
+
push_paths_set := {p |
|
|
46
|
+
some p in object.get(object.get(object.get(input, "true", {}), "push", {}), "paths", [])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ── deny: on.push.paths subset-of ──────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
deny contains msg if {
|
|
52
|
+
some required in expected_paths
|
|
53
|
+
not required in push_paths_set
|
|
54
|
+
msg := sprintf("lint-docker.yml: on.push.paths має містити %q (docker.mdc)", [required])
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# ── deny: required uses present ────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
deny contains msg if {
|
|
60
|
+
some required_use in expected_uses_set
|
|
61
|
+
not required_use in all_step_uses
|
|
62
|
+
msg := sprintf("lint-docker.yml: відсутній крок `uses: %s` (docker.mdc)", [required_use])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# ── deny: required run substrings ──────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
deny contains msg if {
|
|
68
|
+
some required_run in expected_run_substrings
|
|
69
|
+
not contains(all_run_text, required_run)
|
|
70
|
+
msg := sprintf("lint-docker.yml: жоден крок run не містить %q (docker.mdc)", [required_run])
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# ── helpers ────────────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
step_run_to_text(step) := step.run if is_string(step.run)
|
|
76
|
+
|
|
77
|
+
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
|
78
|
+
|
|
79
|
+
else := ""
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Lint Docker
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- dev
|
|
7
|
+
- main
|
|
8
|
+
paths:
|
|
9
|
+
- '**/Dockerfile'
|
|
10
|
+
- '**/*.Dockerfile'
|
|
11
|
+
- '**/*.dockerfile'
|
|
12
|
+
|
|
13
|
+
pull_request:
|
|
14
|
+
branches:
|
|
15
|
+
- dev
|
|
16
|
+
- main
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
lint-docker:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
permissions:
|
|
26
|
+
contents: read
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v6
|
|
29
|
+
with:
|
|
30
|
+
persist-credentials: false
|
|
31
|
+
|
|
32
|
+
- name: Install hadolint
|
|
33
|
+
run: |
|
|
34
|
+
curl -sSL -o /tmp/hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64
|
|
35
|
+
chmod +x /tmp/hadolint
|
|
36
|
+
sudo mv /tmp/hadolint /usr/local/bin/hadolint
|
|
37
|
+
|
|
38
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
39
|
+
|
|
40
|
+
- name: Lint Docker
|
|
41
|
+
run: bunx n-rules lint docker --no-fix
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Структура `clean-ga-workflows.yml` — видалення завершених workflow runs
|
|
2
|
+
|
|
3
|
+
Rego-пакет: `ga.clean_ga_workflows`
|
|
4
|
+
|
|
5
|
+
**Цільовий файл:** `.github/workflows/clean-ga-workflows.yml`
|
|
6
|
+
|
|
7
|
+
### Що перевіряється
|
|
8
|
+
|
|
9
|
+
- `name` — точна відповідність значенню з template
|
|
10
|
+
- `on.schedule[].cron` — має містити cron із template (`0 1 16 * *`)
|
|
11
|
+
- `on.workflow_dispatch` — має бути об'єктом `{}`
|
|
12
|
+
- `jobs.cleanup_old_workflows` — job має існувати
|
|
13
|
+
- `jobs.cleanup_old_workflows.runs-on` — відповідно до template (`ubuntu-latest`)
|
|
14
|
+
- `jobs.cleanup_old_workflows.permissions` — `actions: write`, `contents: read`
|
|
15
|
+
- `steps[0].name` і `steps[0].uses` — відповідно до template (`dmvict/clean-workflow-runs@v1`)
|
|
16
|
+
- `steps[0].with` — `token`, `save_period`, `save_min_runs_number` як у template
|
|
17
|
+
|
|
18
|
+
**Pin-aware `uses`:** SHA-пін того самого action (`owner/action@<40-hex SHA>`, з тег-коментарем `# vX` чи без) задовольняє канонічний тег із template. Якщо в репо вже SHA-пін (zizmor-політика ref-pin) — НЕ замінюй його тегом.
|
|
19
|
+
|
|
20
|
+
Канон: [clean-ga-workflows.yml.snippet.yml](./template/clean-ga-workflows.yml.snippet.yml)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Перевірка `.github/workflows/clean-ga-workflows.yml` (ga.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/clean-ga-workflows.yml.snippet.yml
|
|
5
|
+
# (повний YAML канон). Path-and-value перевірки — у цьому rego (per-concern
|
|
6
|
+
# field-by-field з .data.template.snippet.<path>); жодних inline literals.
|
|
7
|
+
package ga.clean_ga_workflows
|
|
8
|
+
|
|
9
|
+
import rego.v1
|
|
10
|
+
|
|
11
|
+
# ── Аліаси на input ────────────────────────────────────────────────────────
|
|
12
|
+
# GHA YAML quirk: ключ `on:` — YAML 1.1 boolean `true`, у conftest серіалізується
|
|
13
|
+
# як рядковий ключ "true". Template (через --data JSON) має ключ "on".
|
|
14
|
+
|
|
15
|
+
gha_on := input["true"]
|
|
16
|
+
|
|
17
|
+
step0 := input.jobs.cleanup_old_workflows.steps[0]
|
|
18
|
+
|
|
19
|
+
# Експектації з template.
|
|
20
|
+
expected_name := data.template.snippet.name
|
|
21
|
+
|
|
22
|
+
expected_cron := data.template.snippet.on.schedule[0].cron
|
|
23
|
+
|
|
24
|
+
expected_step0 := data.template.snippet.jobs.cleanup_old_workflows.steps[0]
|
|
25
|
+
|
|
26
|
+
expected_perms := data.template.snippet.jobs.cleanup_old_workflows.permissions
|
|
27
|
+
|
|
28
|
+
expected_runs_on := data.template.snippet.jobs.cleanup_old_workflows["runs-on"]
|
|
29
|
+
|
|
30
|
+
# ── deny rules ─────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
deny contains msg if {
|
|
33
|
+
input.name != expected_name
|
|
34
|
+
msg := sprintf("clean-ga-workflows.yml: name має бути %q (ga.mdc)", [expected_name])
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
deny contains msg if {
|
|
38
|
+
not has_expected_cron
|
|
39
|
+
msg := sprintf("clean-ga-workflows.yml: on.schedule має містити cron: '%s' (ga.mdc)", [expected_cron])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
deny contains msg if {
|
|
43
|
+
not is_object(object.get(gha_on, "workflow_dispatch", null))
|
|
44
|
+
msg := "clean-ga-workflows.yml: має бути workflow_dispatch: {} (ga.mdc)"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
deny contains msg if {
|
|
48
|
+
not input.jobs.cleanup_old_workflows
|
|
49
|
+
msg := "clean-ga-workflows.yml: jobs.cleanup_old_workflows відсутній (ga.mdc)"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
deny contains msg if {
|
|
53
|
+
job := input.jobs.cleanup_old_workflows
|
|
54
|
+
job["runs-on"] != expected_runs_on
|
|
55
|
+
msg := sprintf("clean-ga-workflows.yml: runs-on має бути %s (ga.mdc)", [expected_runs_on])
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
deny contains msg if {
|
|
59
|
+
perms := input.jobs.cleanup_old_workflows.permissions
|
|
60
|
+
not perms_match(perms, expected_perms)
|
|
61
|
+
msg := "clean-ga-workflows.yml: permissions мають бути actions: write, contents: read (ga.mdc)"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
deny contains msg if {
|
|
65
|
+
step0.name != expected_step0.name
|
|
66
|
+
msg := sprintf("clean-ga-workflows.yml: перший крок має мати name: %s (ga.mdc)", [expected_step0.name])
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
deny contains msg if {
|
|
70
|
+
actual := step0.uses
|
|
71
|
+
not uses_satisfies(actual, expected_step0.uses)
|
|
72
|
+
msg := sprintf("clean-ga-workflows.yml: перший крок має uses: %s (ga.mdc)", [expected_step0.uses])
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
deny contains msg if {
|
|
76
|
+
not step0_with_canonical
|
|
77
|
+
msg := "clean-ga-workflows.yml: with має містити token/save_period/save_min_runs_number як у template (ga.mdc)"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
deny contains msg if {
|
|
81
|
+
step0.with.save_period != expected_step0.with.save_period
|
|
82
|
+
msg := sprintf("clean-ga-workflows.yml: with.save_period має бути %d (ga.mdc)", [expected_step0.with.save_period])
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# ── helpers ────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
# `uses:` з input задовольняє канонічний `owner/action@tag`: точний збіг…
|
|
88
|
+
uses_satisfies(actual, expected) if actual == expected
|
|
89
|
+
|
|
90
|
+
# …або той самий action-slug і ref — повний 40-hex commit SHA (zizmor ref-pin).
|
|
91
|
+
# SHA-пін відповідної версії задовольняє вимогу тега — не даунгрейдимо до тега.
|
|
92
|
+
uses_satisfies(actual, expected) if {
|
|
93
|
+
slug := split(expected, "@")[0]
|
|
94
|
+
startswith(actual, concat("", [slug, "@"]))
|
|
95
|
+
parts := split(actual, "@")
|
|
96
|
+
regex.match(`^[0-9a-fA-F]{40}$`, parts[count(parts) - 1])
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
has_expected_cron if {
|
|
100
|
+
gha_on.schedule[_].cron == expected_cron
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
perms_match(actual, expected) if {
|
|
104
|
+
actual.actions == expected.actions
|
|
105
|
+
actual.contents == expected.contents
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
step0_with_canonical if {
|
|
109
|
+
step0.with.token == expected_step0.with.token
|
|
110
|
+
step0.with.save_period == expected_step0.with.save_period
|
|
111
|
+
step0.with.save_min_runs_number == expected_step0.with.save_min_runs_number
|
|
112
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
|
|
3
|
+
"policy": {
|
|
4
|
+
"files": {
|
|
5
|
+
"single": ".github/workflows/clean-ga-workflows.yml",
|
|
6
|
+
"required": true
|
|
7
|
+
},
|
|
8
|
+
"missingMessage": ".github/workflows/clean-ga-workflows.yml не існує — створи за каноном ga.mdc"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: fix-clean_ga_workflows.mjs
|
|
4
|
+
resource: plugins/ci-github/rules/ga/clean_ga_workflows/fix-clean_ga_workflows.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: f149bf34
|
|
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` пропускаються, щоб службові каталоги репозиторію не змішувалися з робочим кодом.
|
|
17
|
+
|
|
18
|
+
Правило працює read-only: не записує у файлову систему чи бази даних.
|
|
19
|
+
|
|
20
|
+
## Поведінка
|
|
21
|
+
|
|
22
|
+
1. `patterns` визначає правило автоматичного виправлення для workflow очищення GitHub Actions.
|
|
23
|
+
|
|
24
|
+
2. Правило гарантує наявність очікуваного файлу `.github/workflows/clean-ga-workflows.yml` на основі затвердженого шаблону.
|
|
25
|
+
|
|
26
|
+
3. Виправлення працює як read-only опис дії: саме по собі не записує зміни у файлову систему чи зовнішні сховища.
|
|
27
|
+
|
|
28
|
+
4. Під час застосування загальних перевірок свідомо не розглядаються службові шляхи `.github` і `.git`, щоб не аналізувати інфраструктурні каталоги як звичайний код.
|
|
29
|
+
|
|
30
|
+
## Гарантії поведінки
|
|
31
|
+
|
|
32
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
33
|
+
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Directory Index
|
|
3
|
+
title: plugins/ci-github/rules/ga/clean_ga_workflows
|
|
4
|
+
resource: plugins/ci-github/rules/ga/clean_ga_workflows/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
| Файл | Тип |
|
|
8
|
+
| ------------------------------------------------------- | --------- |
|
|
9
|
+
| [fix-clean_ga_workflows.mjs](fix-clean_ga_workflows.md) | JS Module |
|