@7n/rules-ci-github 1.9.6 → 1.9.7

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.9.7] - 2026-07-25
4
+
5
+ ### Changed
6
+
7
+ - Оптимізовано path-фільтри lint workflow для pull request
8
+
3
9
  ## [1.9.6] - 2026-07-24
4
10
 
5
11
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/rules-ci-github",
3
- "version": "1.9.6",
3
+ "version": "1.9.7",
4
4
  "description": "Плагін @7n/rules: канон GitHub Actions (.github/workflows) — обов'язкові workflow, zizmor, VS Code",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -10,6 +10,7 @@ Rego-пакет: `ga.lint_ga`
10
10
  - `on.push.branches` — superset: містить `dev` і `main`
11
11
  - `on.pull_request.branches` — superset: містить `dev` і `main`
12
12
  - `on.push.paths` — superset: містить `.github/actions/**` і `.github/workflows/**`
13
+ - `on.pull_request.paths` — superset: містить `.github/actions/**` і `.github/workflows/**`
13
14
  - `jobs.lint-ga` — job має існувати
14
15
  - `jobs.lint-ga.runs-on` — за template (`ubuntu-latest`)
15
16
  - `jobs.lint-ga.permissions.contents` — `read`
@@ -8,7 +8,9 @@ import rego.v1
8
8
 
9
9
  # ── Аліаси ─────────────────────────────────────────────────────────────────
10
10
 
11
- gha_on := input["true"]
11
+ # Conftest поточних версій читає YAML 1.2 (`on`), але старі версії віддавали
12
+ # YAML 1.1 boolean-key (`true`). Приймаємо обидві форми, щоб policy не мовчала.
13
+ gha_on := object.get(input, "on", object.get(input, "true", {}))
12
14
 
13
15
  job := input.jobs["lint-ga"]
14
16
 
@@ -26,6 +28,10 @@ expected_pr_branches := {b | some b in data.template.snippet.on.pull_request.bra
26
28
 
27
29
  expected_push_paths := {p | some p in data.template.snippet.on.push.paths}
28
30
 
31
+ expected_pr_paths := {p | some p in data.template.snippet.on.pull_request.paths}
32
+
33
+ actual_pr_paths := object.get(object.get(gha_on, "pull_request", {}), "paths", [])
34
+
29
35
  expected_runs_on := data.template.snippet.jobs["lint-ga"]["runs-on"]
30
36
 
31
37
  expected_perms := data.template.snippet.jobs["lint-ga"].permissions
@@ -66,6 +72,11 @@ deny contains msg if {
66
72
  msg := "lint-ga.yml: on.push.paths має містити .github/actions/** і .github/workflows/** (ga.mdc)"
67
73
  }
68
74
 
75
+ deny contains msg if {
76
+ not paths_superset_of(actual_pr_paths, expected_pr_paths)
77
+ msg := "lint-ga.yml: on.pull_request.paths має містити .github/actions/** і .github/workflows/** (ga.mdc)"
78
+ }
79
+
69
80
  deny contains msg if {
70
81
  not job
71
82
  msg := "lint-ga.yml: jobs.lint-ga відсутній (ga.mdc)"
@@ -12,6 +12,9 @@ on:
12
12
  branches:
13
13
  - dev
14
14
  - main
15
+ paths:
16
+ - '.github/actions/**'
17
+ - '.github/workflows/**'
15
18
 
16
19
  concurrency:
17
20
  group: ${{ github.ref }}-${{ github.workflow }}
@@ -16,6 +16,14 @@ package js.lint_js_yml
16
16
 
17
17
  import rego.v1
18
18
 
19
+ # Conftest поточних версій читає YAML 1.2 (`on`), але старі версії віддавали
20
+ # YAML 1.1 boolean-key (`true`). Приймаємо обидві форми, щоб policy не мовчала.
21
+ gha_on := object.get(input, "on", object.get(input, "true", {}))
22
+
23
+ expected_pr_paths := {p | some p in data.template.snippet.on.pull_request.paths}
24
+
25
+ actual_pr_paths := object.get(object.get(gha_on, "pull_request", {}), "paths", [])
26
+
19
27
  # Required `uses:` зі template — фільтруємо тільки кроки з uses.
20
28
  expected_uses_set contains u if {
21
29
  some step in data.template.snippet.jobs.eslint.steps
@@ -58,6 +66,11 @@ deny contains msg if {
58
66
  msg := sprintf("lint-js.yml: відсутній крок uses: %s (js.mdc)", [required_use])
59
67
  }
60
68
 
69
+ deny contains msg if {
70
+ not paths_superset_of(actual_pr_paths, expected_pr_paths)
71
+ msg := "lint-js.yml: on.pull_request.paths має містити очікувані glob-и (js.mdc)"
72
+ }
73
+
61
74
  # ── deny: required run substrings ───────────────────────────────────────
62
75
 
63
76
  deny contains msg if {
@@ -110,6 +123,10 @@ has_use_satisfying(required) if {
110
123
  uses_satisfies(u, required)
111
124
  }
112
125
 
126
+ paths_superset_of(actual, expected) if {
127
+ expected & {p | some p in actual} == expected
128
+ }
129
+
113
130
  step_run_text(step) := step.run if is_string(step.run)
114
131
 
115
132
  else := concat("\n", [s | some s in step.run]) if is_array(step.run)
@@ -14,11 +14,22 @@ on:
14
14
  - '**/*.tsx'
15
15
  - '**/*.vue'
16
16
  - '**/eslint.config.*'
17
+ - '**/.oxlintrc.json'
17
18
 
18
19
  pull_request:
19
20
  branches:
20
21
  - dev
21
22
  - main
23
+ paths:
24
+ - '**/*.js'
25
+ - '**/*.mjs'
26
+ - '**/*.cjs'
27
+ - '**/*.jsx'
28
+ - '**/*.ts'
29
+ - '**/*.tsx'
30
+ - '**/*.vue'
31
+ - '**/eslint.config.*'
32
+ - '**/.oxlintrc.json'
22
33
 
23
34
  concurrency:
24
35
  group: ${{ github.ref }}-${{ github.workflow }}
@@ -14,6 +14,14 @@ package python.lint_python_yml
14
14
 
15
15
  import rego.v1
16
16
 
17
+ # Conftest поточних версій читає YAML 1.2 (`on`), але старі версії віддавали
18
+ # YAML 1.1 boolean-key (`true`). Приймаємо обидві форми, щоб policy не мовчала.
19
+ gha_on := object.get(input, "on", object.get(input, "true", {}))
20
+
21
+ expected_pr_paths := {p | some p in data.template.snippet.on.pull_request.paths}
22
+
23
+ actual_pr_paths := object.get(object.get(gha_on, "pull_request", {}), "paths", [])
24
+
17
25
  # Усі `uses` з канону workflow (по всіх job'ах template).
18
26
  expected_uses contains u if {
19
27
  some job in data.template.snippet.jobs
@@ -43,6 +51,11 @@ deny contains msg if {
43
51
  msg := sprintf("lint-python.yml: відсутній step з `uses: %s` (python.mdc)", [required_use])
44
52
  }
45
53
 
54
+ deny contains msg if {
55
+ not paths_superset_of(actual_pr_paths, expected_pr_paths)
56
+ msg := "lint-python.yml: on.pull_request.paths має містити очікувані glob-и (python.mdc)"
57
+ }
58
+
46
59
  deny contains msg if {
47
60
  msg := "lint-python.yml: actions/checkout@v6 потребує `with: persist-credentials: false` (python.mdc)"
48
61
  some job in object.get(input, "jobs", {})
@@ -66,3 +79,7 @@ step_run_to_text(step) := step.run if is_string(step.run)
66
79
  else := concat("\n", [s | some s in step.run]) if is_array(step.run)
67
80
 
68
81
  else := ""
82
+
83
+ paths_superset_of(actual, expected) if {
84
+ expected & {p | some p in actual} == expected
85
+ }
@@ -15,6 +15,11 @@ on:
15
15
  branches:
16
16
  - dev
17
17
  - main
18
+ paths:
19
+ - '**/*.py'
20
+ - 'pyproject.toml'
21
+ - 'uv.lock'
22
+ - '.github/workflows/lint-python.yml'
18
23
 
19
24
  concurrency:
20
25
  group: ${{ github.ref }}-${{ github.workflow }}
@@ -12,6 +12,14 @@ package rust.lint_rust_yml
12
12
 
13
13
  import rego.v1
14
14
 
15
+ # Conftest поточних версій читає YAML 1.2 (`on`), але старі версії віддавали
16
+ # YAML 1.1 boolean-key (`true`). Приймаємо обидві форми, щоб policy не мовчала.
17
+ gha_on := object.get(input, "on", object.get(input, "true", {}))
18
+
19
+ expected_pr_paths := {p | some p in data.template.snippet.on.pull_request.paths}
20
+
21
+ actual_pr_paths := object.get(object.get(gha_on, "pull_request", {}), "paths", [])
22
+
15
23
  # Усі `uses` з канону workflow.
16
24
  expected_uses contains u if {
17
25
  some step in data.template.snippet.jobs.lint.steps
@@ -46,6 +54,11 @@ deny contains msg if {
46
54
  msg := sprintf("lint-rust.yml: відсутній step з `uses: %s` (rust.mdc)", [required_use])
47
55
  }
48
56
 
57
+ deny contains msg if {
58
+ not paths_superset_of(actual_pr_paths, expected_pr_paths)
59
+ msg := "lint-rust.yml: on.pull_request.paths має містити очікувані glob-и (rust.mdc)"
60
+ }
61
+
49
62
  deny contains msg if {
50
63
  some step in data.template.snippet.jobs.lint.steps
51
64
  expected_run := object.get(step, "run", "")
@@ -77,3 +90,7 @@ step_run_to_text(step) := step.run if is_string(step.run)
77
90
  else := concat("\n", [s | some s in step.run]) if is_array(step.run)
78
91
 
79
92
  else := ""
93
+
94
+ paths_superset_of(actual, expected) if {
95
+ expected & {p | some p in actual} == expected
96
+ }
@@ -16,6 +16,12 @@ on:
16
16
  branches:
17
17
  - dev
18
18
  - main
19
+ paths:
20
+ - '**/*.rs'
21
+ - '**/Cargo.toml'
22
+ - '**/Cargo.lock'
23
+ - '**/rustfmt.toml'
24
+ - '**/clippy.toml'
19
25
 
20
26
  concurrency:
21
27
  group: ${{ github.ref }}-${{ github.workflow }}
@@ -8,7 +8,7 @@ Rego-пакет: `text.lint_text`
8
8
 
9
9
  - `name` — має бути `"Lint Text"`
10
10
  - `on.push.branches` та `on.pull_request.branches` — мають містити `dev` і `main`
11
- - `on.push.paths` — має бути надмножиною канонічних glob-ів (усі текстові розширення)
11
+ - `on.push.paths` та `on.pull_request.paths` мають бути надмножиною канонічних glob-ів (усі текстові розширення)
12
12
  - `jobs.text` — job обов'язковий
13
13
  - `jobs.text.runs-on` — має бути `ubuntu-latest`
14
14
  - `jobs.text.permissions.contents` — має бути `read`
@@ -15,13 +15,17 @@ expected_pr_branches := {b | some b in data.template.snippet.on.pull_request.bra
15
15
 
16
16
  expected_push_paths := {p | some p in data.template.snippet.on.push.paths}
17
17
 
18
+ expected_pr_paths := {p | some p in data.template.snippet.on.pull_request.paths}
19
+
20
+ actual_pr_paths := object.get(object.get(gha_on, "pull_request", {}), "paths", [])
21
+
18
22
  expected_runs_on := data.template.snippet.jobs.text["runs-on"]
19
23
 
20
24
  expected_perms := data.template.snippet.jobs.text.permissions
21
25
 
22
- # conftest парсить YAML 1.1, де канонічний `on:` без лапок стає булевим ключем
23
- # `true` (як у `ga.lint_ga`). Тому читаємо on-блок через `input["true"]`.
24
- gha_on := input["true"]
26
+ # Conftest поточних версій читає YAML 1.2 (`on`), але старі версії віддавали
27
+ # YAML 1.1 boolean-key (`true`). Приймаємо обидві форми, щоб policy не мовчала.
28
+ gha_on := object.get(input, "on", object.get(input, "true", {}))
25
29
 
26
30
  job := input.jobs.text
27
31
 
@@ -63,6 +67,11 @@ deny contains msg if {
63
67
  msg := "lint-text.yml: on.push.paths має містити очікувані glob-и (text.mdc)"
64
68
  }
65
69
 
70
+ deny contains msg if {
71
+ not paths_superset_of(actual_pr_paths, expected_pr_paths)
72
+ msg := "lint-text.yml: on.pull_request.paths має містити очікувані glob-и (text.mdc)"
73
+ }
74
+
66
75
  deny contains msg if {
67
76
  not job
68
77
  msg := "lint-text.yml: jobs.text відсутній (text.mdc)"
@@ -32,6 +32,28 @@ on:
32
32
  branches:
33
33
  - dev
34
34
  - main
35
+ paths:
36
+ - '**/*.js'
37
+ - '**/*.ts'
38
+ - '**/*.vue'
39
+ - '**/*.html'
40
+ - '**/*.css'
41
+ - '**/*.scss'
42
+ - '**/*.less'
43
+ - '**/*.json'
44
+ - '**/*.jsonc'
45
+ - '**/*.yaml'
46
+ - '**/*.yml'
47
+ - '**/*.toml'
48
+ - '**/*.xml'
49
+ - '**/*.md'
50
+ - '**/*.mdc'
51
+ - '**/*.mdс'
52
+ - '**/*.txt'
53
+ - '**/*.go'
54
+ - '**/*.py'
55
+ - '**/*.php'
56
+ - '**/*.sh'
35
57
 
36
58
  concurrency:
37
59
  group: ${{ github.ref }}-${{ github.workflow }}