@nitra/cursor 1.8.206 → 1.8.208
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 +36 -0
- package/mdc/js-run.mdc +49 -2
- package/package.json +1 -1
- package/policy/abie/health_check_policy/health_check_policy.rego +73 -0
- package/policy/abie/http_route_base/http_route_base.rego +45 -0
- package/policy/adr/settings_json/settings_json.rego +31 -0
- package/policy/adr/settings_local_json/settings_local_json.rego +28 -0
- package/policy/bun/bunfig/bunfig.rego +33 -0
- package/policy/bun/package_json/package_json.rego +94 -0
- package/policy/capacitor/package_json/package_json.rego +45 -0
- package/policy/ga/clean_ga_workflows/clean_ga_workflows.rego +0 -26
- package/policy/ga/clean_merged_branch/clean_merged_branch.rego +0 -25
- package/policy/ga/git_ai/git_ai.rego +0 -26
- package/policy/ga/lint_ga/lint_ga.rego +0 -26
- package/policy/ga/workflow_common/workflow_common.rego +161 -0
- package/policy/graphql/package_json/package_json.rego +35 -0
- package/policy/hasura/svc_hl/svc_hl.rego +27 -0
- package/policy/image_compress/package_json/package_json.rego +94 -0
- package/policy/js_bun_db/package_json/package_json.rego +28 -0
- package/policy/js_lint/lint_js_yml/lint_js_yml.rego +98 -0
- package/policy/js_lint/package_json/package_json.rego +137 -0
- package/policy/js_mssql/package_json/package_json.rego +57 -0
- package/policy/js_run/configmap/configmap.rego +45 -0
- package/policy/js_run/jsconfig/jsconfig.rego +66 -0
- package/policy/js_run/package_json/package_json.rego +31 -0
- package/policy/k8s/manifest/manifest.rego +130 -0
- package/policy/npm_module/emit_types_config/emit_types_config.rego +37 -0
- package/policy/npm_module/npm_package_json/npm_package_json.rego +55 -0
- package/policy/npm_module/npm_publish_yml/npm_publish_yml.rego +79 -0
- package/policy/npm_module/root_package_json/root_package_json.rego +28 -0
- package/policy/php/lint_php_yml/lint_php_yml.rego +32 -0
- package/policy/php/package_json/package_json.rego +19 -0
- package/policy/style_lint/lint_style_yml/lint_style_yml.rego +35 -0
- package/policy/style_lint/package_json/package_json.rego +49 -0
- package/policy/text/cspell/cspell.rego +91 -0
- package/policy/text/markdownlint/markdownlint.rego +21 -0
- package/policy/text/oxfmtrc/oxfmtrc.rego +90 -0
- package/policy/text/package_json/package_json.rego +88 -0
- package/policy/vue/package_json/package_json.rego +54 -0
- package/scripts/check-adr.mjs +3 -2
- package/scripts/check-bun.mjs +21 -117
- package/scripts/check-graphql.mjs +6 -45
- package/scripts/check-hasura.mjs +2 -3
- package/scripts/check-image-avif.mjs +3 -3
- package/scripts/check-image-compress.mjs +25 -132
- package/scripts/check-js-bun-db.mjs +3 -50
- package/scripts/check-js-run.mjs +84 -86
- package/scripts/check-k8s.mjs +4 -4
- package/scripts/check-npm-module.mjs +17 -8
- package/scripts/check-php.mjs +16 -51
- package/scripts/check-style-lint.mjs +28 -52
- package/scripts/check-text.mjs +47 -219
- package/scripts/check-vue.mjs +3 -16
- package/scripts/lint-conftest.mjs +351 -0
- package/scripts/lint-ga.mjs +39 -2
- package/scripts/run-shellcheck-text.mjs +2 -2
- package/scripts/utils/conn-file-rules.mjs +170 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Порт перевірки версії `mssql` з `npm/scripts/check-js-mssql.mjs` (js-mssql.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально, для будь-якого `package.json`):
|
|
4
|
+
# conftest test path/to/package.json -p npm/policy/js_mssql \
|
|
5
|
+
# --namespace js_mssql.package_json
|
|
6
|
+
#
|
|
7
|
+
# Перевіряє: якщо `dependencies.mssql` присутній, версія має бути >= 12.5.0.
|
|
8
|
+
# Підтримує `^12.5.0`, `>=12.5.0`, `12.5.0`, `workspace:*` (трактується як OK).
|
|
9
|
+
#
|
|
10
|
+
# AST-скан коду на per-request `new sql.ConnectionPool(...)` всередині функцій
|
|
11
|
+
# (потребує парсингу `.js` / `.ts` через oxc-parser), а також full-semver
|
|
12
|
+
# (`major.minor.patch` triple-compare у `check-js-mssql.mjs`) лишаються у JS:
|
|
13
|
+
# JS-перевірка authoritative, ця Rego — швидкий gate для одиничного `package.json`.
|
|
14
|
+
#
|
|
15
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
16
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
17
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
18
|
+
package js_mssql.package_json
|
|
19
|
+
|
|
20
|
+
import rego.v1
|
|
21
|
+
|
|
22
|
+
deny contains msg if {
|
|
23
|
+
range := object.get(object.get(input, "dependencies", {}), "mssql", "")
|
|
24
|
+
range != ""
|
|
25
|
+
not mssql_version_meets_min(range)
|
|
26
|
+
msg := sprintf("dependencies.mssql має бути >= 12.5.0 (зараз %q) (js-mssql.mdc)", [range])
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Мінімум — 12.5.0 (js-mssql.mdc). `workspace:*` трактуємо як OK (узгоджено з JS).
|
|
30
|
+
mssql_version_meets_min(range) if startswith(trim_space(range), "workspace:")
|
|
31
|
+
|
|
32
|
+
mssql_version_meets_min(range) if {
|
|
33
|
+
parts := split_to_numbers(range)
|
|
34
|
+
count(parts) >= 3
|
|
35
|
+
parts[0] > 12
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
mssql_version_meets_min(range) if {
|
|
39
|
+
parts := split_to_numbers(range)
|
|
40
|
+
count(parts) >= 3
|
|
41
|
+
parts[0] == 12
|
|
42
|
+
parts[1] > 5
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
mssql_version_meets_min(range) if {
|
|
46
|
+
parts := split_to_numbers(range)
|
|
47
|
+
count(parts) >= 3
|
|
48
|
+
parts[0] == 12
|
|
49
|
+
parts[1] == 5
|
|
50
|
+
parts[2] >= 0
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
split_to_numbers(spec) := nums if {
|
|
54
|
+
tokens := regex.split(`\D+`, spec)
|
|
55
|
+
non_empty := [t | some t in tokens; t != ""]
|
|
56
|
+
nums := [n | some t in non_empty; n := to_number(t)]
|
|
57
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Порт перевірки `k8s/base/configmap.yaml` з `npm/scripts/check-js-run.mjs`
|
|
2
|
+
# (js-run.mdc) — `OTEL_RESOURCE_ATTRIBUTES` має містити `service.name=` і
|
|
3
|
+
# `service.namespace=`.
|
|
4
|
+
#
|
|
5
|
+
# Запуск (локально):
|
|
6
|
+
# conftest test path/to/k8s/base/configmap.yaml -p npm/policy/js_run \
|
|
7
|
+
# --namespace js_run.configmap
|
|
8
|
+
#
|
|
9
|
+
# Відповідність імені ConfigMap імені Deployment (cross-file) — у JS і `check-k8s.mjs`.
|
|
10
|
+
#
|
|
11
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
12
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
13
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
14
|
+
package js_run.configmap
|
|
15
|
+
|
|
16
|
+
import rego.v1
|
|
17
|
+
|
|
18
|
+
# Шаблони повідомлень — через `concat` для regal style/line-length.
|
|
19
|
+
otel_service_name_template := concat(" ", [
|
|
20
|
+
"ConfigMap %q: OTEL_RESOURCE_ATTRIBUTES має містити",
|
|
21
|
+
"`service.name=` (js-run.mdc)",
|
|
22
|
+
])
|
|
23
|
+
|
|
24
|
+
otel_service_namespace_template := concat(" ", [
|
|
25
|
+
"ConfigMap %q: OTEL_RESOURCE_ATTRIBUTES має містити",
|
|
26
|
+
"`service.namespace=` (js-run.mdc)",
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
deny contains msg if {
|
|
30
|
+
input.kind == "ConfigMap"
|
|
31
|
+
otel := object.get(object.get(input, "data", {}), "OTEL_RESOURCE_ATTRIBUTES", "")
|
|
32
|
+
otel != ""
|
|
33
|
+
not contains(otel, "service.name=")
|
|
34
|
+
msg := sprintf(otel_service_name_template, [cm_name])
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
deny contains msg if {
|
|
38
|
+
input.kind == "ConfigMap"
|
|
39
|
+
otel := object.get(object.get(input, "data", {}), "OTEL_RESOURCE_ATTRIBUTES", "")
|
|
40
|
+
otel != ""
|
|
41
|
+
not contains(otel, "service.namespace=")
|
|
42
|
+
msg := sprintf(otel_service_namespace_template, [cm_name])
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
cm_name := object.get(object.get(input, "metadata", {}), "name", "?")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Порт перевірки `jsconfig.json` з `npm/scripts/check-js-run.mjs` (js-run.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально, у backend-пакеті з каталогом `src/`):
|
|
4
|
+
# conftest test path/to/jsconfig.json -p npm/policy/js_run \
|
|
5
|
+
# --namespace js_run.jsconfig
|
|
6
|
+
#
|
|
7
|
+
# Перевіряє: `compilerOptions.{lib, module, moduleResolution, target, checkJs}` і
|
|
8
|
+
# `include` мають канонічні значення (js-run.mdc).
|
|
9
|
+
#
|
|
10
|
+
# FS-перевірка (наявність каталогу `src/` у пакеті, наявність самого `jsconfig.json`)
|
|
11
|
+
# і вибір файлу-кандидата — у JS.
|
|
12
|
+
#
|
|
13
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
14
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
15
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
16
|
+
package js_run.jsconfig
|
|
17
|
+
|
|
18
|
+
import rego.v1
|
|
19
|
+
|
|
20
|
+
# ── deny: compilerOptions ──────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
deny contains msg if {
|
|
23
|
+
co := object.get(input, "compilerOptions", {})
|
|
24
|
+
not is_array(object.get(co, "lib", null))
|
|
25
|
+
msg := "jsconfig.json: compilerOptions.lib має бути [\"esnext\"] (js-run.mdc)"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
deny contains msg if {
|
|
29
|
+
co := object.get(input, "compilerOptions", {})
|
|
30
|
+
is_array(co.lib)
|
|
31
|
+
{l | some l in co.lib} != {"esnext"}
|
|
32
|
+
msg := "jsconfig.json: compilerOptions.lib має бути [\"esnext\"] (js-run.mdc)"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
deny contains msg if {
|
|
36
|
+
object.get(object.get(input, "compilerOptions", {}), "module", null) != "NodeNext"
|
|
37
|
+
msg := "jsconfig.json: compilerOptions.module має бути \"NodeNext\" (js-run.mdc)"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
deny contains msg if {
|
|
41
|
+
object.get(object.get(input, "compilerOptions", {}), "moduleResolution", null) != "NodeNext"
|
|
42
|
+
msg := "jsconfig.json: compilerOptions.moduleResolution має бути \"NodeNext\" (js-run.mdc)"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
deny contains msg if {
|
|
46
|
+
object.get(object.get(input, "compilerOptions", {}), "target", null) != "esnext"
|
|
47
|
+
msg := "jsconfig.json: compilerOptions.target має бути \"esnext\" (js-run.mdc)"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
deny contains msg if {
|
|
51
|
+
object.get(object.get(input, "compilerOptions", {}), "checkJs", null) != false
|
|
52
|
+
msg := "jsconfig.json: compilerOptions.checkJs має бути false (js-run.mdc)"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ── deny: include ──────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
deny contains msg if {
|
|
58
|
+
not is_array(object.get(input, "include", null))
|
|
59
|
+
msg := "jsconfig.json: include має бути [\"src/**/*\"] (js-run.mdc)"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
deny contains msg if {
|
|
63
|
+
is_array(input.include)
|
|
64
|
+
{p | some p in input.include} != {"src/**/*"}
|
|
65
|
+
msg := "jsconfig.json: include має бути [\"src/**/*\"] (js-run.mdc)"
|
|
66
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Порт перевірки залежностей `package.json` з `npm/scripts/check-js-run.mjs`
|
|
2
|
+
# (js-run.mdc) — заборона `bunyan` / `@nitra/bunyan`.
|
|
3
|
+
#
|
|
4
|
+
# Запуск (локально, для будь-якого `package.json` у дереві):
|
|
5
|
+
# conftest test path/to/package.json -p npm/policy/js_run \
|
|
6
|
+
# --namespace js_run.package_json
|
|
7
|
+
#
|
|
8
|
+
# AST-скан коду на імпорти `bunyan` / `process.env` без `checkEnv`,
|
|
9
|
+
# `new Promise(resolve => setTimeout(resolve, ...))`, обмеження `#conn/*`-аліасів —
|
|
10
|
+
# у JS (потребує парсингу `.js` / `.ts` через oxc-parser).
|
|
11
|
+
#
|
|
12
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
13
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
14
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
15
|
+
package js_run.package_json
|
|
16
|
+
|
|
17
|
+
import rego.v1
|
|
18
|
+
|
|
19
|
+
forbidden_packages := {"bunyan", "@nitra/bunyan"}
|
|
20
|
+
|
|
21
|
+
deny contains msg if {
|
|
22
|
+
some pkg_name in forbidden_packages
|
|
23
|
+
pkg_name in object.keys(object.get(input, "dependencies", {}))
|
|
24
|
+
msg := sprintf("dependencies містить %q — використовуй стандартні логери (js-run.mdc)", [pkg_name])
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
deny contains msg if {
|
|
28
|
+
some pkg_name in forbidden_packages
|
|
29
|
+
pkg_name in object.keys(object.get(input, "devDependencies", {}))
|
|
30
|
+
msg := sprintf("devDependencies містить %q — використовуй стандартні логери (js-run.mdc)", [pkg_name])
|
|
31
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Порт пер-документних структурних перевірок з `npm/scripts/check-k8s.mjs`
|
|
2
|
+
# (k8s.mdc). Цей пакет описує лише ті правила, що дивляться на ОДИН манифест
|
|
3
|
+
# (один YAML-документ): conftest за замовчуванням розрізає файли по `---` і
|
|
4
|
+
# запускає policy на кожен документ окремо.
|
|
5
|
+
#
|
|
6
|
+
# Запуск (локально, по одному файлу або по дереву):
|
|
7
|
+
# conftest test path/to/k8s/manifest.yaml -p npm/policy/k8s \
|
|
8
|
+
# --namespace k8s.manifest
|
|
9
|
+
#
|
|
10
|
+
# Перевіряє:
|
|
11
|
+
# - `kind: Ingress` заборонено (потрібен перехід на Gateway API);
|
|
12
|
+
# - `apiVersion: autoscaling/v1` заборонено (HPA → autoscaling/v2);
|
|
13
|
+
# - `kind: Service` без `cloud.google.com/neg` /
|
|
14
|
+
# `cloud.google.com/backend-config` в `metadata.annotations` (k8s.mdc);
|
|
15
|
+
# - `kind: Deployment` — у кожного контейнера спільно `containers` +
|
|
16
|
+
# `initContainers` має бути `resources.requests.cpu` (рядок на кшталт
|
|
17
|
+
# `"500m"` чи число), без порожнього значення.
|
|
18
|
+
#
|
|
19
|
+
# CROSS-FILE логіка (Kustomize-резолюція ресурсів, парність svc.yaml/svc-hl.yaml,
|
|
20
|
+
# HPA/PDB/topologySpreadConstraints за каталогом, BackendConfig-сепарація,
|
|
21
|
+
# yaml-language-server schema modeline, namespace-перевірки за деревом
|
|
22
|
+
# `…/k8s/base/`) лишається у `check-k8s.mjs`: вона потребує файлової системи.
|
|
23
|
+
#
|
|
24
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
25
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
26
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
27
|
+
package k8s.manifest
|
|
28
|
+
|
|
29
|
+
import rego.v1
|
|
30
|
+
|
|
31
|
+
default_cpu_request := "0.5"
|
|
32
|
+
|
|
33
|
+
forbidden_service_annotations := {
|
|
34
|
+
"cloud.google.com/neg",
|
|
35
|
+
"cloud.google.com/backend-config",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
ingress_template := concat(" ", [
|
|
39
|
+
"знайдено kind: Ingress — заміни на Gateway API:",
|
|
40
|
+
"HTTPRoute (hr.yaml), HealthCheckPolicy (hc.yaml) (k8s.mdc)",
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
autoscaling_v1_template := concat(" ", [
|
|
44
|
+
"знайдено apiVersion: autoscaling/v1 (kind: %s) —",
|
|
45
|
+
"мігруй на autoscaling/v2 (k8s.mdc)",
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
cpu_missing_template := concat(" ", [
|
|
49
|
+
"Deployment %q, контейнер %q: відсутнє resources.requests.cpu —",
|
|
50
|
+
"додай (за замовчуванням %s) (k8s.mdc)",
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
cpu_empty_template := concat(" ", [
|
|
54
|
+
"Deployment %q, контейнер %q: resources.requests.cpu має бути непорожнім",
|
|
55
|
+
"значенням (наприклад \"500m\") (зараз: %v) (k8s.mdc)",
|
|
56
|
+
])
|
|
57
|
+
|
|
58
|
+
# ── deny: заборонені kind/apiVersion ──────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
deny contains ingress_template if {
|
|
61
|
+
input.kind == "Ingress"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
deny contains msg if {
|
|
65
|
+
input.apiVersion == "autoscaling/v1"
|
|
66
|
+
msg := sprintf(autoscaling_v1_template, [object.get(input, "kind", "<no-kind>")])
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# ── deny: заборонені анотації Service ─────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
deny contains msg if {
|
|
72
|
+
input.kind == "Service"
|
|
73
|
+
annotations := object.get(object.get(input, "metadata", {}), "annotations", {})
|
|
74
|
+
some forbidden_key in forbidden_service_annotations
|
|
75
|
+
forbidden_key in object.keys(annotations)
|
|
76
|
+
msg := sprintf("Service %q: видали анотацію %q (k8s.mdc)", [input.metadata.name, forbidden_key])
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ── deny: Deployment — у кожного контейнера resources.requests.cpu ────────
|
|
80
|
+
#
|
|
81
|
+
# Дві гілки: відсутнє/null поле cpu (повідомлення про додавання) і явно
|
|
82
|
+
# присутнє, але порожнє/невалідне значення (повідомлення з підставленим value).
|
|
83
|
+
|
|
84
|
+
deny contains msg if {
|
|
85
|
+
input.kind == "Deployment"
|
|
86
|
+
some container in deployment_all_containers
|
|
87
|
+
not has_non_empty_cpu_request(container)
|
|
88
|
+
not has_cpu_field(container)
|
|
89
|
+
msg := sprintf(cpu_missing_template, [deployment_name, container.name, default_cpu_request])
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
deny contains msg if {
|
|
93
|
+
input.kind == "Deployment"
|
|
94
|
+
some container in deployment_all_containers
|
|
95
|
+
not has_non_empty_cpu_request(container)
|
|
96
|
+
has_cpu_field(container)
|
|
97
|
+
cpu := container.resources.requests.cpu
|
|
98
|
+
msg := sprintf(cpu_empty_template, [deployment_name, container.name, cpu])
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# ── helpers ────────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
deployment_name := object.get(object.get(input, "metadata", {}), "name", "<no-name>")
|
|
104
|
+
|
|
105
|
+
# Усі контейнери (звичайні + ініт) Deployment-а — для перевірки CPU.
|
|
106
|
+
deployment_all_containers contains container if {
|
|
107
|
+
some container in object.get(object.get(input.spec.template, "spec", {}), "containers", [])
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
deployment_all_containers contains container if {
|
|
111
|
+
some container in object.get(object.get(input.spec.template, "spec", {}), "initContainers", [])
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Чи у контейнера є непорожнє resources.requests.cpu (рядок або число > 0).
|
|
115
|
+
has_non_empty_cpu_request(container) if {
|
|
116
|
+
cpu := container.resources.requests.cpu
|
|
117
|
+
is_string(cpu)
|
|
118
|
+
trim_space(cpu) != ""
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
has_non_empty_cpu_request(container) if {
|
|
122
|
+
cpu := container.resources.requests.cpu
|
|
123
|
+
is_number(cpu)
|
|
124
|
+
cpu > 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Чи у контейнера в реальності присутнє поле resources.requests.cpu (хай і порожнє).
|
|
128
|
+
has_cpu_field(container) if {
|
|
129
|
+
_ := container.resources.requests.cpu
|
|
130
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Порт перевірок `npm/tsconfig.emit-types.json` з `npm/scripts/check-npm-module.mjs`
|
|
2
|
+
# (npm-module.mdc).
|
|
3
|
+
#
|
|
4
|
+
# Запуск (локально):
|
|
5
|
+
# conftest test npm/tsconfig.emit-types.json -p npm/policy/npm_module \
|
|
6
|
+
# --namespace npm_module.emit_types_config
|
|
7
|
+
#
|
|
8
|
+
# Перевіряє: `compilerOptions.{allowJs, declaration, emitDeclarationOnly, outDir,
|
|
9
|
+
# skipLibCheck}` мають канонічні значення (true/true/true/"types"/true). FS-перевірки
|
|
10
|
+
# (наявність самого `tsconfig.emit-types.json`, активність layout-варіанта) — у JS.
|
|
11
|
+
#
|
|
12
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
13
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
14
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
15
|
+
package npm_module.emit_types_config
|
|
16
|
+
|
|
17
|
+
import rego.v1
|
|
18
|
+
|
|
19
|
+
required_compiler_options := {
|
|
20
|
+
"allowJs": true,
|
|
21
|
+
"declaration": true,
|
|
22
|
+
"emitDeclarationOnly": true,
|
|
23
|
+
"outDir": "types",
|
|
24
|
+
"skipLibCheck": true,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
deny contains msg if {
|
|
28
|
+
not is_object(object.get(input, "compilerOptions", null))
|
|
29
|
+
msg := "npm/tsconfig.emit-types.json: відсутній compilerOptions (npm-module.mdc)"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
deny contains msg if {
|
|
33
|
+
is_object(input.compilerOptions)
|
|
34
|
+
some key, expected in required_compiler_options
|
|
35
|
+
object.get(input.compilerOptions, key, null) != expected
|
|
36
|
+
msg := sprintf("npm/tsconfig.emit-types.json: compilerOptions.%s має бути %v (npm-module.mdc)", [key, expected])
|
|
37
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Порт перевірок `npm/package.json` з `npm/scripts/check-npm-module.mjs`
|
|
2
|
+
# (npm-module.mdc).
|
|
3
|
+
#
|
|
4
|
+
# Запуск (локально):
|
|
5
|
+
# conftest test npm/package.json -p npm/policy/npm_module \
|
|
6
|
+
# --namespace npm_module.npm_package_json
|
|
7
|
+
#
|
|
8
|
+
# Перевіряє: поле `types` має будь-який з двох канонічних патернів:
|
|
9
|
+
# - `./types/index.d.ts` (layout `npm/src` з `.js`); або
|
|
10
|
+
# - `./types/<…>.d.ts` чи `.d.mts` (layout `tsconfig.emit-types.json`).
|
|
11
|
+
#
|
|
12
|
+
# Масив `files` має містити `"types"`. Те, який саме layout активний (зокрема
|
|
13
|
+
# наявність `.js` під `npm/src`), а також існування файлу зі шляху `types` —
|
|
14
|
+
# у JS-перевірці (`check-npm-module.mjs`).
|
|
15
|
+
#
|
|
16
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
17
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
18
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
19
|
+
package npm_module.npm_package_json
|
|
20
|
+
|
|
21
|
+
import rego.v1
|
|
22
|
+
|
|
23
|
+
# Шаблон повідомлення про неканонічне поле `types` — через `concat` для
|
|
24
|
+
# regal style/line-length.
|
|
25
|
+
types_field_template := concat(" ", [
|
|
26
|
+
"npm/package.json: поле \"types\" має бути \"./types/index.d.ts\"",
|
|
27
|
+
"або \"./types/<…>.d.ts|.d.mts\" (зараз: %v) (npm-module.mdc)",
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
# ── deny: types ────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
deny contains msg if {
|
|
33
|
+
types_field := object.get(input, "types", "")
|
|
34
|
+
not valid_types_field(types_field)
|
|
35
|
+
msg := sprintf(types_field_template, [types_field])
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# ── deny: files має містити "types" ───────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
deny contains msg if {
|
|
41
|
+
not is_array(object.get(input, "files", null))
|
|
42
|
+
msg := "npm/package.json: масив \"files\" відсутній — має містити \"types\" (npm-module.mdc)"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
deny contains msg if {
|
|
46
|
+
is_array(input.files)
|
|
47
|
+
not "types" in {f | some f in input.files}
|
|
48
|
+
msg := "npm/package.json: масив \"files\" має містити \"types\" (npm-module.mdc)"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# ── helpers ────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
valid_types_field("./types/index.d.ts")
|
|
54
|
+
|
|
55
|
+
valid_types_field(t) if regex.match(`^\./types/.+\.d\.(ts|mts)$`, t)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Порт перевірок `.github/workflows/npm-publish.yml` з `npm/scripts/check-npm-module.mjs`
|
|
2
|
+
# (npm-module.mdc).
|
|
3
|
+
#
|
|
4
|
+
# Запуск (локально):
|
|
5
|
+
# conftest test .github/workflows/npm-publish.yml -p npm/policy/npm_module \
|
|
6
|
+
# --namespace npm_module.npm_publish_yml
|
|
7
|
+
#
|
|
8
|
+
# Перевіряє: `on.push.paths` містить glob з `npm/**`, `on.push.branches` містить
|
|
9
|
+
# `main`, у jobs є `permissions.id-token: write` (OIDC), є крок з
|
|
10
|
+
# `uses: JS-DevTools/npm-publish` і `with.package: npm/package.json`.
|
|
11
|
+
#
|
|
12
|
+
# Універсальні workflow-перевірки (concurrency, заборонені setup-bun/cache/install,
|
|
13
|
+
# shell line-continuation) — у `ga.workflow_common`.
|
|
14
|
+
#
|
|
15
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
16
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
17
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
18
|
+
package npm_module.npm_publish_yml
|
|
19
|
+
|
|
20
|
+
import rego.v1
|
|
21
|
+
|
|
22
|
+
# YAML 1.1 quirk: ключ `on:` → boolean true → у конфтесті ключ "true".
|
|
23
|
+
gha_on := input["true"]
|
|
24
|
+
|
|
25
|
+
# Шаблон повідомлення про відсутній JS-DevTools/npm-publish крок — через `concat`
|
|
26
|
+
# для regal style/line-length.
|
|
27
|
+
npm_publish_step_template := concat(" ", [
|
|
28
|
+
"npm-publish.yml: очікується `uses: JS-DevTools/npm-publish`",
|
|
29
|
+
"з `with.package: npm/package.json` (npm-module.mdc)",
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
# ── deny: paths/branches ──────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
deny contains msg if {
|
|
35
|
+
not push_paths_have_npm_glob
|
|
36
|
+
msg := "npm-publish.yml: у on.push.paths має бути `npm/**` (npm-module.mdc)"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
deny contains msg if {
|
|
40
|
+
not push_branches_have_main
|
|
41
|
+
msg := "npm-publish.yml: on.push.branches має містити `main` (npm-module.mdc)"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# ── deny: id-token: write у permissions хоч одного job ────────────────────
|
|
45
|
+
|
|
46
|
+
deny contains msg if {
|
|
47
|
+
not any_job_has_id_token_write
|
|
48
|
+
msg := "npm-publish.yml: permissions має містити `id-token: write` (OIDC) (npm-module.mdc)"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# ── deny: крок з uses JS-DevTools/npm-publish та with.package ─────────────
|
|
52
|
+
|
|
53
|
+
deny contains npm_publish_step_template if {
|
|
54
|
+
not has_npm_publish_step
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# ── helpers ────────────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
push_paths_have_npm_glob if {
|
|
60
|
+
some p in gha_on.push.paths
|
|
61
|
+
is_string(p)
|
|
62
|
+
contains(p, "npm/**")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
push_branches_have_main if {
|
|
66
|
+
"main" in {b | some b in gha_on.push.branches}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
any_job_has_id_token_write if {
|
|
70
|
+
some job in object.get(input, "jobs", {})
|
|
71
|
+
job.permissions["id-token"] == "write"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
has_npm_publish_step if {
|
|
75
|
+
some job in object.get(input, "jobs", {})
|
|
76
|
+
some step in object.get(job, "steps", [])
|
|
77
|
+
contains(object.get(step, "uses", ""), "JS-DevTools/npm-publish")
|
|
78
|
+
step.with.package == "npm/package.json"
|
|
79
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Порт перевірки кореневого `package.json` з `npm/scripts/check-npm-module.mjs`
|
|
2
|
+
# (npm-module.mdc) — масив `workspaces` має містити "npm".
|
|
3
|
+
#
|
|
4
|
+
# Запуск (локально):
|
|
5
|
+
# conftest test package.json -p npm/policy/npm_module \
|
|
6
|
+
# --namespace npm_module.root_package_json
|
|
7
|
+
#
|
|
8
|
+
# Решта кореневих `package.json`-перевірок (заборонені поля, devDeps лише @nitra/*)
|
|
9
|
+
# — у `bun.package_json`. FS-перевірки (наявність каталогу `npm/`,
|
|
10
|
+
# `npm/package.json`) — у JS.
|
|
11
|
+
#
|
|
12
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
13
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
14
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
15
|
+
package npm_module.root_package_json
|
|
16
|
+
|
|
17
|
+
import rego.v1
|
|
18
|
+
|
|
19
|
+
deny contains msg if {
|
|
20
|
+
not is_array(object.get(input, "workspaces", null))
|
|
21
|
+
msg := "package.json: масив workspaces відсутній — має містити \"npm\" (npm-module.mdc)"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
deny contains msg if {
|
|
25
|
+
is_array(input.workspaces)
|
|
26
|
+
not "npm" in {w | some w in input.workspaces}
|
|
27
|
+
msg := "package.json: workspaces має містити \"npm\" (npm-module.mdc)"
|
|
28
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Порт перевірки `lint-php.yml` з `npm/scripts/check-php.mjs` (php.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально):
|
|
4
|
+
# conftest test .github/workflows/lint-php.yml -p npm/policy/php \
|
|
5
|
+
# --namespace php.lint_php_yml
|
|
6
|
+
#
|
|
7
|
+
# Перевіряє: хоча б один крок `run` містить `bun run lint-php`. Універсальні
|
|
8
|
+
# workflow-перевірки — у `ga.workflow_common`.
|
|
9
|
+
#
|
|
10
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
11
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
12
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
13
|
+
package php.lint_php_yml
|
|
14
|
+
|
|
15
|
+
import rego.v1
|
|
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
|
+
not contains(all_run_text, "bun run lint-php")
|
|
25
|
+
msg := "lint-php.yml: жоден крок run не містить `bun run lint-php` (php.mdc)"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
step_run_to_text(step) := step.run if is_string(step.run)
|
|
29
|
+
|
|
30
|
+
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
|
31
|
+
|
|
32
|
+
else := ""
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Порт перевірки `package.json` з `npm/scripts/check-php.mjs` (php.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально):
|
|
4
|
+
# conftest test package.json -p npm/policy/php --namespace php.package_json
|
|
5
|
+
#
|
|
6
|
+
# Перевіряє: наявність скрипта `lint-php`. FS-перевірки (`composer.json`, наявність
|
|
7
|
+
# `package.json` як такого) — у JS.
|
|
8
|
+
#
|
|
9
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
10
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
11
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
12
|
+
package php.package_json
|
|
13
|
+
|
|
14
|
+
import rego.v1
|
|
15
|
+
|
|
16
|
+
deny contains msg if {
|
|
17
|
+
not object.get(object.get(input, "scripts", {}), "lint-php", false)
|
|
18
|
+
msg := "package.json: додай скрипт \"lint-php\" (php.mdc)"
|
|
19
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Порт перевірки `lint-style.yml` з `npm/scripts/check-style-lint.mjs` (style-lint.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Запуск (локально):
|
|
4
|
+
# conftest test .github/workflows/lint-style.yml -p npm/policy/style_lint \
|
|
5
|
+
# --namespace style_lint.lint_style_yml
|
|
6
|
+
#
|
|
7
|
+
# Перевіряє: хоча б один крок `run` містить `npx stylelint` (саме через npx, не
|
|
8
|
+
# `bun run lint-style`). Універсальні workflow-перевірки (concurrency, заборонені
|
|
9
|
+
# setup-bun/cache/install) — у `ga.workflow_common`.
|
|
10
|
+
#
|
|
11
|
+
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
12
|
+
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
13
|
+
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
14
|
+
package style_lint.lint_style_yml
|
|
15
|
+
|
|
16
|
+
import rego.v1
|
|
17
|
+
|
|
18
|
+
# Усі тексти `run:` зі steps усіх jobs, склеєні в один blob — для substring-перевірки.
|
|
19
|
+
all_run_text := concat("\n", [run_text |
|
|
20
|
+
some job in object.get(input, "jobs", {})
|
|
21
|
+
some step in object.get(job, "steps", [])
|
|
22
|
+
run_text := step_run_to_text(step)
|
|
23
|
+
])
|
|
24
|
+
|
|
25
|
+
deny contains msg if {
|
|
26
|
+
not contains(all_run_text, "npx stylelint")
|
|
27
|
+
msg := "lint-style.yml: жоден крок run не містить `npx stylelint` (style-lint.mdc)"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Текст `run:` як один рядок: підтримує string і array форми (YAML).
|
|
31
|
+
step_run_to_text(step) := step.run if is_string(step.run)
|
|
32
|
+
|
|
33
|
+
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
|
34
|
+
|
|
35
|
+
else := ""
|