@nitra/cursor 1.9.17 → 1.9.19
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 +39 -0
- package/bin/auto-skills.md +2 -0
- package/mdc/abie.mdc +21 -249
- package/mdc/docker.mdc +2 -19
- package/mdc/hasura.mdc +1 -1
- package/mdc/k8s.mdc +2 -2
- package/package.json +1 -1
- package/policy/abie/base_deployment_preem/base_deployment_preem.rego +2 -2
- package/policy/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +2 -2
- package/policy/abie/clean_merged_ignore_branches/clean_merged_ignore_branches_test.rego +5 -5
- package/policy/docker/lint_docker_yml/lint_docker_yml.rego +91 -0
- package/policy/docker/lint_docker_yml/lint_docker_yml_test.rego +104 -0
- package/policy/docker/package_json/package_json.rego +35 -0
- package/policy/docker/package_json/package_json_test.rego +42 -0
- package/scripts/check-abie.mjs +73 -933
- package/scripts/check-hasura.mjs +8 -14
- package/scripts/check-k8s.mjs +1 -18
- package/scripts/lint-conftest.mjs +10 -1
- package/skills/abie-clean/SKILL.md +138 -0
- package/skills/abie-kustomize/SKILL.md +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Перевірка `.github/workflows/lint-docker.yml` (docker.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально):
|
|
4
|
+
# conftest test .github/workflows/lint-docker.yml -p npm/policy/docker/lint_docker_yml \
|
|
5
|
+
# --namespace docker.lint_docker_yml
|
|
6
|
+
#
|
|
7
|
+
# Canonical (docker.mdc):
|
|
8
|
+
# - `on.push.paths` містить glob-и для Dockerfile (`**/Dockerfile`, `**/*.Dockerfile`,
|
|
9
|
+
# `**/*.dockerfile`);
|
|
10
|
+
# - крок `Install hadolint` з URL версії `v2.12.0` (узгоджено з `HADOLINT_IMAGE`
|
|
11
|
+
# у `npm/scripts/utils/docker-hadolint.mjs`);
|
|
12
|
+
# - крок `uses: ./.github/actions/setup-bun-deps` (canonical composite per ga.mdc;
|
|
13
|
+
# прямі `oxen-sh/setup-bun`/`actions/cache`/`bun install` заборонено через
|
|
14
|
+
# `ga.workflow_common`);
|
|
15
|
+
# - крок `run: bun run lint-docker`.
|
|
16
|
+
#
|
|
17
|
+
# Універсальні workflow-перевірки (concurrency, заборонені setup-bun/cache/install,
|
|
18
|
+
# shell line-continuation) — у `ga.workflow_common`.
|
|
19
|
+
#
|
|
20
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
21
|
+
package docker.lint_docker_yml
|
|
22
|
+
|
|
23
|
+
import rego.v1
|
|
24
|
+
|
|
25
|
+
required_push_paths := {"**/Dockerfile", "**/*.Dockerfile", "**/*.dockerfile"}
|
|
26
|
+
required_hadolint_version := "v2.12.0"
|
|
27
|
+
canonical_setup_bun_action := "./.github/actions/setup-bun-deps"
|
|
28
|
+
|
|
29
|
+
# Усі тексти `uses:` зі steps усіх jobs (incremental set rule per regal:
|
|
30
|
+
# prefer-set-or-object-rule — це краще за comprehension).
|
|
31
|
+
all_step_uses contains u if {
|
|
32
|
+
some job in object.get(input, "jobs", {})
|
|
33
|
+
some step in object.get(job, "steps", [])
|
|
34
|
+
u := object.get(step, "uses", "")
|
|
35
|
+
u != ""
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
all_run_text := concat("\n", [run_text |
|
|
39
|
+
some job in object.get(input, "jobs", {})
|
|
40
|
+
some step in object.get(job, "steps", [])
|
|
41
|
+
run_text := step_run_to_text(step)
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
# Множина значень `on.push.paths` (підтримує `on: { push: { paths: [...] } }`).
|
|
45
|
+
push_paths_set := {p |
|
|
46
|
+
some p in object.get(object.get(object.get(input, "on", {}), "push", {}), "paths", [])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ── deny: on.push.paths ──────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
deny contains msg if {
|
|
52
|
+
some required in required_push_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: hadolint install version ───────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
deny contains msg if {
|
|
60
|
+
not contains(all_run_text, required_hadolint_version)
|
|
61
|
+
msg := sprintf(
|
|
62
|
+
"lint-docker.yml: крок hadolint install має містити версію %q (узгоджено з HADOLINT_IMAGE) (docker.mdc)",
|
|
63
|
+
[required_hadolint_version],
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# ── deny: setup-bun-deps composite ───────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
deny contains msg if {
|
|
70
|
+
not canonical_setup_bun_action in all_step_uses
|
|
71
|
+
msg := concat(" ", [
|
|
72
|
+
"lint-docker.yml: відсутній крок",
|
|
73
|
+
"`uses: ./.github/actions/setup-bun-deps` (canonical composite per ga.mdc) (docker.mdc)",
|
|
74
|
+
])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# ── deny: bun run lint-docker ────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
deny contains msg if {
|
|
80
|
+
not contains(all_run_text, "bun run lint-docker")
|
|
81
|
+
msg := "lint-docker.yml: жоден крок run не містить `bun run lint-docker` (docker.mdc)"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# ── helpers ──────────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
# Текст `run:` як один рядок: підтримує string і array форми (YAML).
|
|
87
|
+
step_run_to_text(step) := step.run if is_string(step.run)
|
|
88
|
+
|
|
89
|
+
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
|
90
|
+
|
|
91
|
+
else := ""
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Тести для `docker.lint_docker_yml`. Запуск:
|
|
2
|
+
# conftest verify -p npm/policy/docker/lint_docker_yml
|
|
3
|
+
package docker.lint_docker_yml_test
|
|
4
|
+
|
|
5
|
+
import rego.v1
|
|
6
|
+
|
|
7
|
+
import data.docker.lint_docker_yml
|
|
8
|
+
|
|
9
|
+
hadolint_install_run := concat("", [
|
|
10
|
+
"curl -sSL -o /tmp/hadolint",
|
|
11
|
+
" https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64",
|
|
12
|
+
])
|
|
13
|
+
|
|
14
|
+
valid_wf := {
|
|
15
|
+
"name": "Lint Docker",
|
|
16
|
+
"on": {"push": {
|
|
17
|
+
"branches": ["dev", "main"],
|
|
18
|
+
"paths": ["**/Dockerfile", "**/*.Dockerfile", "**/*.dockerfile"],
|
|
19
|
+
}},
|
|
20
|
+
"jobs": {"lint-docker": {"steps": [
|
|
21
|
+
{"uses": "actions/checkout@v6"},
|
|
22
|
+
{"name": "Install hadolint", "run": hadolint_install_run},
|
|
23
|
+
{"uses": "./.github/actions/setup-bun-deps"},
|
|
24
|
+
{"name": "Lint Docker", "run": "bun run lint-docker"},
|
|
25
|
+
]}},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# ── happy path ────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
test_allow_canonical if {
|
|
31
|
+
count(lint_docker_yml.deny) == 0 with input as valid_wf
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# ── deny: on.push.paths ──────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
test_deny_missing_path_dockerfile if {
|
|
37
|
+
wf := json.patch(
|
|
38
|
+
valid_wf,
|
|
39
|
+
[{"op": "replace", "path": "/on/push/paths", "value": ["**/*.Dockerfile", "**/*.dockerfile"]}],
|
|
40
|
+
)
|
|
41
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
test_deny_missing_paths_field if {
|
|
45
|
+
wf := json.patch(valid_wf, [{"op": "remove", "path": "/on/push/paths"}])
|
|
46
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ── deny: hadolint version ──────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
test_deny_wrong_hadolint_version if {
|
|
52
|
+
wrong_version_run := concat("", [
|
|
53
|
+
"curl -sSL",
|
|
54
|
+
" https://github.com/hadolint/hadolint/releases/download/v2.11.0/hadolint-Linux-x86_64",
|
|
55
|
+
])
|
|
56
|
+
wf := json.patch(valid_wf, [{
|
|
57
|
+
"op": "replace",
|
|
58
|
+
"path": "/jobs/lint-docker/steps/1/run",
|
|
59
|
+
"value": wrong_version_run,
|
|
60
|
+
}])
|
|
61
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
test_deny_no_hadolint_install if {
|
|
65
|
+
wf := json.patch(valid_wf, [{
|
|
66
|
+
"op": "replace",
|
|
67
|
+
"path": "/jobs/lint-docker/steps/1",
|
|
68
|
+
"value": {"name": "Noop", "run": "echo ok"},
|
|
69
|
+
}])
|
|
70
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# ── deny: composite setup-bun-deps ──────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
test_deny_inline_setup_bun_instead_of_composite if {
|
|
76
|
+
# Старий канон (НЕПРАВИЛЬНО per ga.mdc): пряме `oven-sh/setup-bun` замість composite.
|
|
77
|
+
wf := json.patch(valid_wf, [{
|
|
78
|
+
"op": "replace",
|
|
79
|
+
"path": "/jobs/lint-docker/steps/2",
|
|
80
|
+
"value": {"uses": "oven-sh/setup-bun@v2"},
|
|
81
|
+
}])
|
|
82
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
test_deny_no_setup_step if {
|
|
86
|
+
wf := json.patch(valid_wf, [{"op": "remove", "path": "/jobs/lint-docker/steps/2"}])
|
|
87
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# ── deny: bun run lint-docker ──────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
test_deny_missing_lint_docker_run if {
|
|
93
|
+
wf := json.patch(valid_wf, [{
|
|
94
|
+
"op": "replace",
|
|
95
|
+
"path": "/jobs/lint-docker/steps/3/run",
|
|
96
|
+
"value": "echo noop",
|
|
97
|
+
}])
|
|
98
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
test_deny_no_run_steps_at_all if {
|
|
102
|
+
wf := json.patch(valid_wf, [{"op": "replace", "path": "/jobs/lint-docker/steps", "value": []}])
|
|
103
|
+
count(lint_docker_yml.deny) > 0 with input as wf
|
|
104
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Перевірка `package.json` для docker (docker.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально):
|
|
4
|
+
# conftest test package.json -p npm/policy/docker/package_json \
|
|
5
|
+
# --namespace docker.package_json
|
|
6
|
+
#
|
|
7
|
+
# Canonical (docker.mdc): якщо у проєкті є правило `docker` (у `.n-cursor.json`),
|
|
8
|
+
# у кореневому `package.json` має бути канонічний `scripts.lint-docker`.
|
|
9
|
+
#
|
|
10
|
+
# Цей пакет перевіряє ЛИШЕ зміст значення `scripts.lint-docker`, якщо ключ
|
|
11
|
+
# присутній. Умовну обовʼязковість (правило `docker` у `.n-cursor.json` →
|
|
12
|
+
# `scripts.lint-docker` ЗОБОВ'ЯЗАНИЙ існувати) перевіряє `check-bun.mjs` через
|
|
13
|
+
# cross-file логіку (читає `.n-cursor.json` і `package.json`). Тут rego видно
|
|
14
|
+
# лише один документ, тому без `.n-cursor.json`-контексту вимагати наявність
|
|
15
|
+
# `scripts.lint-docker` означало б false-positive порушення для проєктів без docker.
|
|
16
|
+
#
|
|
17
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
18
|
+
package docker.package_json
|
|
19
|
+
|
|
20
|
+
import rego.v1
|
|
21
|
+
|
|
22
|
+
canonical_lint_docker := "bun ./npm/scripts/run-docker.mjs"
|
|
23
|
+
|
|
24
|
+
lint_docker_template := concat(" ", [
|
|
25
|
+
"package.json: scripts.lint-docker має бути %q",
|
|
26
|
+
"(зараз: %q) (docker.mdc)",
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
deny contains msg if {
|
|
30
|
+
scripts := object.get(input, "scripts", {})
|
|
31
|
+
lint_docker := object.get(scripts, "lint-docker", "")
|
|
32
|
+
lint_docker != ""
|
|
33
|
+
trim_space(lint_docker) != canonical_lint_docker
|
|
34
|
+
msg := sprintf(lint_docker_template, [canonical_lint_docker, lint_docker])
|
|
35
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Тести для `docker.package_json`. Запуск:
|
|
2
|
+
# conftest verify -p npm/policy/docker/package_json
|
|
3
|
+
package docker.package_json_test
|
|
4
|
+
|
|
5
|
+
import rego.v1
|
|
6
|
+
|
|
7
|
+
import data.docker.package_json
|
|
8
|
+
|
|
9
|
+
canonical_lint_docker := "bun ./npm/scripts/run-docker.mjs"
|
|
10
|
+
|
|
11
|
+
# ── happy path ────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
test_allow_canonical if {
|
|
14
|
+
pkg := {"scripts": {"lint-docker": canonical_lint_docker}}
|
|
15
|
+
count(package_json.deny) == 0 with input as pkg
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
test_allow_lint_docker_absent if {
|
|
19
|
+
# rego не вимагає наявність — cross-file умовно вимагає `check-bun.mjs`.
|
|
20
|
+
count(package_json.deny) == 0 with input as {"scripts": {}}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
test_allow_no_scripts_at_all if {
|
|
24
|
+
count(package_json.deny) == 0 with input as {"name": "x"}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test_allow_with_extra_whitespace if {
|
|
28
|
+
pkg := {"scripts": {"lint-docker": concat("", [" ", canonical_lint_docker, " "])}}
|
|
29
|
+
count(package_json.deny) == 0 with input as pkg
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# ── deny ──────────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
test_deny_lint_docker_wrong_value if {
|
|
35
|
+
pkg := {"scripts": {"lint-docker": "hadolint Dockerfile"}}
|
|
36
|
+
count(package_json.deny) > 0 with input as pkg
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
test_deny_lint_docker_old_npx_form if {
|
|
40
|
+
pkg := {"scripts": {"lint-docker": "npx hadolint ."}}
|
|
41
|
+
count(package_json.deny) > 0 with input as pkg
|
|
42
|
+
}
|