@7n/rules-ci-github 1.2.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.1] - 2026-07-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- ga/workflows: `runConftestBatch` викликається з `await` — ядро зробило його async у @7n/rules 1.14 (#109), без await детектор падав «violations is not iterable» і валив увесь lint-прогін
|
|
8
|
+
|
|
9
|
+
## [1.3.0] - 2026-07-17
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- ga/workflow_common: дозволено режим release-серіалізації concurrency — статичний group + cancel-in-progress: false
|
|
14
|
+
|
|
3
15
|
## [1.2.2] - 2026-07-16
|
|
4
16
|
|
|
5
17
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@7n/rules-ci-github",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
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
5
|
"keywords": [
|
|
6
6
|
"github-actions",
|
|
@@ -6,7 +6,10 @@ Rego-пакет: `ga.workflow_common`
|
|
|
6
6
|
|
|
7
7
|
### Що перевіряється
|
|
8
8
|
|
|
9
|
-
- **concurrency** — обов'язкова наявність блоку;
|
|
9
|
+
- **concurrency** — обов'язкова наявність блоку; два допустимі режими:
|
|
10
|
+
- канонічний CI: `group` = `${{ github.ref }}-${{ github.workflow }}` + `cancel-in-progress: true`
|
|
11
|
+
- release-серіалізація: статичний `group` (без `${{ }}`-виразів, глобальний lock) + `cancel-in-progress: false` — для workflow, що піднімають версію/тег/CHANGELOG і не можуть бути скасовані на півдорозі; відсутній `cancel-in-progress` = `false` (семантика GitHub)
|
|
12
|
+
- змішані комбінації (статичний `group` + `true`, per-ref `group` + `false`) — заборонені
|
|
10
13
|
- **Заборонені кроки** — `oven-sh/setup-bun`, `actions/cache`, `bun install` у будь-якому `uses:`/`run:` (мають бути інкапсульовані у composite `setup-bun-deps`)
|
|
11
14
|
- **Порядок кроків** — якщо є `setup-bun-deps`, перед ним обов'язковий `actions/checkout@`
|
|
12
15
|
- **Shell-продовження** — `\` перед переносом рядка у `run:` заборонено; треба `run: >-`
|
|
@@ -18,6 +18,10 @@ import rego.v1
|
|
|
18
18
|
|
|
19
19
|
expected_concurrency_group := concat("", ["$", "{{ github.ref }}-$", "{{ github.workflow }}"])
|
|
20
20
|
|
|
21
|
+
# Маркер GitHub-виразу `${{` — через concat (та сама причина, що й у
|
|
22
|
+
# expected_concurrency_group): без сирого літерала в rego-джерелі.
|
|
23
|
+
gh_expr_marker := concat("", ["$", "{{"])
|
|
24
|
+
|
|
21
25
|
# Локальні composite setup-bun-deps (ga.mdc) — два варіанти шляху:
|
|
22
26
|
# `.github/actions/...` (cursor-репо) і `npm/github-actions/...` (npm-пакет dev-локально).
|
|
23
27
|
local_setup_bun_markers := {
|
|
@@ -45,6 +49,16 @@ concurrency_missing_template := concat(" ", [
|
|
|
45
49
|
"додай concurrency.group: %s і cancel-in-progress: true (ga.mdc)",
|
|
46
50
|
])
|
|
47
51
|
|
|
52
|
+
concurrency_group_template := concat(" ", [
|
|
53
|
+
"concurrency.group має бути %s,",
|
|
54
|
+
"або статичний рядок-lock для release-серіалізації (ga.mdc)",
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
concurrency_release_cancel_template := concat(" ", [
|
|
58
|
+
"статичний concurrency.group — release-серіалізація: скасування на півдорозі",
|
|
59
|
+
"лишає репо в неконсистентному стані, тому cancel-in-progress: false (ga.mdc)",
|
|
60
|
+
])
|
|
61
|
+
|
|
48
62
|
shell_continuation_template := concat(" ", [
|
|
49
63
|
"jobs.%s.steps[%d]: у run заборонено продовження рядків через зворотний сліш;",
|
|
50
64
|
"оформи як folded block (run: >-) (ga.mdc)",
|
|
@@ -147,6 +161,14 @@ deny contains msg if {
|
|
|
147
161
|
# Дублює окремі per-workflow перевірки для clean-ga-workflows / clean-merged-branch /
|
|
148
162
|
# lint-ga / git-ai, але вкриває й решту workflow-файлів (apply-k8s, lint-js, …),
|
|
149
163
|
# для яких поки немає виділеної polysi.
|
|
164
|
+
#
|
|
165
|
+
# Допустимі рівно два когерентні режими:
|
|
166
|
+
# 1. канонічний CI: per-ref group + cancel-in-progress: true;
|
|
167
|
+
# 2. release-серіалізація: статичний group (глобальний lock, без `${{ }}`-виразів)
|
|
168
|
+
# + cancel-in-progress: false — для workflow, що піднімають версію/тег і не
|
|
169
|
+
# можуть бути скасовані на півдорозі (per-ref lock не захищає від двох
|
|
170
|
+
# одночасних push-подій, які обидві піднімають версію).
|
|
171
|
+
# Змішані комбінації (статичний group + true, per-ref + false) — заборонені.
|
|
150
172
|
|
|
151
173
|
deny contains msg if {
|
|
152
174
|
# `object.get(…, default)` повертає `false` коли ключа немає — інакше `not is_object(…)`
|
|
@@ -157,16 +179,25 @@ deny contains msg if {
|
|
|
157
179
|
|
|
158
180
|
deny contains msg if {
|
|
159
181
|
is_object(object.get(input, "concurrency", false))
|
|
160
|
-
input.concurrency
|
|
161
|
-
|
|
182
|
+
group := object.get(input.concurrency, "group", "")
|
|
183
|
+
group != expected_concurrency_group
|
|
184
|
+
not is_release_lock_group(group)
|
|
185
|
+
msg := sprintf(concurrency_group_template, [expected_concurrency_group])
|
|
162
186
|
}
|
|
163
187
|
|
|
164
188
|
deny contains msg if {
|
|
165
189
|
is_object(object.get(input, "concurrency", false))
|
|
166
|
-
input.concurrency
|
|
190
|
+
input.concurrency.group == expected_concurrency_group
|
|
191
|
+
object.get(input.concurrency, "cancel-in-progress", false) != true
|
|
167
192
|
msg := "concurrency.cancel-in-progress має бути true (ga.mdc)"
|
|
168
193
|
}
|
|
169
194
|
|
|
195
|
+
deny contains concurrency_release_cancel_template if {
|
|
196
|
+
is_object(object.get(input, "concurrency", false))
|
|
197
|
+
is_release_lock_group(object.get(input.concurrency, "group", ""))
|
|
198
|
+
object.get(input.concurrency, "cancel-in-progress", false) != false
|
|
199
|
+
}
|
|
200
|
+
|
|
170
201
|
# ── deny: мінімальні версії marketplace actions у `uses:` ─────────────────
|
|
171
202
|
#
|
|
172
203
|
# Канон — `template/uses-min-versions.snippet.json` (через --data).
|
|
@@ -191,6 +222,14 @@ deny contains msg if {
|
|
|
191
222
|
|
|
192
223
|
# ── helpers ────────────────────────────────────────────────────────────────
|
|
193
224
|
|
|
225
|
+
# Статичний непорожній group без `${{ }}`-виразів — глобальний lock
|
|
226
|
+
# (режим release-серіалізації concurrency).
|
|
227
|
+
is_release_lock_group(group) if {
|
|
228
|
+
is_string(group)
|
|
229
|
+
group != ""
|
|
230
|
+
not contains(group, gh_expr_marker)
|
|
231
|
+
}
|
|
232
|
+
|
|
194
233
|
# Об'єднаний рядок `uses` + `run` для одного кроку — для substring-пошуку
|
|
195
234
|
# заборонених патернів. `run` може бути рядком або масивом рядків (YAML).
|
|
196
235
|
step_uses_or_run_blob(step) := blob if {
|
|
@@ -331,7 +331,7 @@ async function runAllGaRego(wfDir, ymlWorkflows, cwd, pass, fail) {
|
|
|
331
331
|
const concernDir = join(GA_POLICY_DIR, target.policyDirRel.split('/', 2)[1])
|
|
332
332
|
const tpl = await loadTemplate(concernDir)
|
|
333
333
|
const templateData = tpl[basename(target.workflow)]
|
|
334
|
-
const violations = runConftestBatch({
|
|
334
|
+
const violations = await runConftestBatch({
|
|
335
335
|
policyDirRel: target.policyDirRel,
|
|
336
336
|
// Правило живе у плагіні поза вбудованим rules/ ядра — резолвимо policy-теку від себе.
|
|
337
337
|
policyDirAbs: concernDir,
|
|
@@ -351,7 +351,7 @@ async function runAllGaRego(wfDir, ymlWorkflows, cwd, pass, fail) {
|
|
|
351
351
|
const workflowCommonDir = join(GA_POLICY_DIR, 'workflow_common')
|
|
352
352
|
const workflowCommonTpl = await loadTemplate(workflowCommonDir)
|
|
353
353
|
const usesMinVersionsSnippet = workflowCommonTpl['uses-min-versions']?.snippet
|
|
354
|
-
const violations = runConftestBatch({
|
|
354
|
+
const violations = await runConftestBatch({
|
|
355
355
|
policyDirRel: 'ga/workflow_common',
|
|
356
356
|
policyDirAbs: workflowCommonDir,
|
|
357
357
|
namespace: 'ga.workflow_common',
|