@nitra/cursor 12.8.5 → 12.8.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 +12 -0
- package/bin/n-cursor.js +5 -5
- package/package.json +1 -1
- package/rules/abie/js/http_route_base.mdc +25 -0
- package/rules/abie/js/ua_http_route.mdc +1 -1
- package/rules/abie/main.mdc +12 -0
- package/rules/adr/js/hooks.mdc +32 -0
- package/rules/adr/js/madr_format.mdc +96 -0
- package/rules/adr/js/settings_policy.mdc +34 -0
- package/rules/adr/main.mdc +13 -95
- package/rules/bun/js/bunfig.mdc +12 -0
- package/rules/bun/js/layout.mdc +60 -0
- package/rules/bun/js/lint.mdc +9 -0
- package/rules/bun/js/package_json.mdc +19 -0
- package/rules/bun/main.mdc +9 -61
- package/rules/capacitor/js/ios_spm.mdc +69 -0
- package/rules/capacitor/js/version.mdc +29 -0
- package/rules/capacitor/main.mdc +8 -22
- package/rules/changelog/js/agent-workflow.mdc +15 -0
- package/rules/changelog/js/changelog-format.mdc +33 -0
- package/rules/changelog/js/comparison-models.mdc +40 -0
- package/rules/changelog/main.mdc +4 -98
- package/rules/ci4/js/marksman_config.mdc +31 -0
- package/rules/ci4/js/vscode_extensions.mdc +33 -0
- package/rules/ci4/main.mdc +14 -14
- package/rules/docker/js/compile.mdc +44 -0
- package/rules/docker/js/hadolint.mdc +50 -0
- package/rules/docker/js/mirror.mdc +13 -0
- package/rules/docker/js/multistage.mdc +13 -0
- package/rules/docker/js/native-addon.mdc +43 -0
- package/rules/docker/js/nginx-tag.mdc +7 -0
- package/rules/docker/js/nginx-user.mdc +37 -0
- package/rules/docker/js/non-root.mdc +39 -0
- package/rules/docker/main.mdc +15 -196
- package/rules/ga/js/lint_toolchain.mdc +15 -0
- package/rules/ga/js/required_workflows.mdc +35 -0
- package/rules/ga/js/vscode.mdc +17 -0
- package/rules/ga/js/workflow_common.mdc +108 -0
- package/rules/ga/js/workflows.mdc +32 -0
- package/rules/ga/js/zizmor.mdc +7 -0
- package/rules/ga/main.mdc +17 -125
- package/rules/graphql/js/tooling.mdc +13 -0
- package/rules/graphql/js/vscode_extensions.mdc +13 -0
- package/rules/graphql/main.mdc +3 -22
- package/rules/hasura/js/internal_urls.mdc +27 -0
- package/rules/hasura/js/migrations.mdc +13 -0
- package/rules/hasura/js/svc_hl.mdc +17 -0
- package/rules/hasura/main.mdc +8 -30
- package/rules/image-avif/js/avif_generation.mdc +26 -0
- package/rules/image-avif/js/package_json_optout.mdc +21 -0
- package/rules/image-avif/main.mdc +7 -34
- package/rules/image-compress/js/package_json.mdc +7 -0
- package/rules/image-compress/js/package_setup.mdc +13 -0
- package/rules/image-compress/main.mdc +4 -12
- package/rules/js/docs/index.md +3 -3
- package/rules/js/js/dep-policy.mdc +17 -0
- package/rules/js/js/eslint-config.mdc +28 -0
- package/rules/js/js/extensions.mdc +8 -0
- package/rules/js/js/file-extensions.mdc +12 -0
- package/rules/js/js/for-in.mdc +26 -0
- package/rules/js/js/jscpd.mdc +42 -0
- package/rules/js/js/knip.mdc +15 -0
- package/rules/js/js/lint-js-workflow.mdc +58 -0
- package/rules/js/js/oxlintrc.mdc +20 -0
- package/rules/js/js/package-json.mdc +31 -0
- package/rules/js/js/tests.mdc +9 -0
- package/rules/js/js/utils-lib-structure.mdc +15 -0
- package/rules/js/main.mdc +21 -214
- package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
- package/rules/js-bun-db/js/connection.mdc +42 -0
- package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
- package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
- package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
- package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
- package/rules/js-bun-db/js/query-safety.mdc +117 -0
- package/rules/js-bun-db/js/sql-array.mdc +88 -0
- package/rules/js-bun-db/js/unsafe.mdc +65 -0
- package/rules/js-bun-db/main.mdc +15 -605
- package/rules/js-bun-redis/js/imports.mdc +47 -0
- package/rules/js-bun-redis/js/package_json.mdc +44 -0
- package/rules/js-bun-redis/main.mdc +3 -11
- package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
- package/rules/js-mssql/js/mssql-pool.mdc +56 -0
- package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
- package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
- package/rules/js-mssql/js/mssql-version.mdc +7 -0
- package/rules/js-mssql/main.mdc +10 -198
- package/rules/js-run/js/check-env.mdc +35 -0
- package/rules/js-run/js/conn-aliases.mdc +109 -0
- package/rules/js-run/js/jsconfig.mdc +20 -0
- package/rules/js-run/js/otel-configmap.mdc +6 -0
- package/rules/js-run/js/pino.mdc +6 -0
- package/rules/js-run/js/project-structure.mdc +11 -0
- package/rules/js-run/js/runtime.mdc +14 -0
- package/rules/js-run/js/scope.mdc +11 -0
- package/rules/js-run/js/settimeout.mdc +11 -0
- package/rules/js-run/js/temporal.mdc +5 -0
- package/rules/js-run/main.mdc +16 -218
- package/rules/k8s/js/configmap.mdc +41 -0
- package/rules/k8s/js/deployment_resources.mdc +49 -0
- package/rules/k8s/js/hasura_httproute.mdc +91 -0
- package/rules/k8s/js/hpa_apiversion.mdc +27 -0
- package/rules/k8s/js/ingress_gateway.mdc +16 -0
- package/rules/k8s/js/kustomize_structure.mdc +144 -0
- package/rules/k8s/js/lint_k8s.mdc +72 -0
- package/rules/k8s/js/multidoc_yaml.mdc +5 -0
- package/rules/k8s/js/network_policy.mdc +136 -0
- package/rules/k8s/js/schema_modeline.mdc +57 -0
- package/rules/k8s/js/service.mdc +44 -0
- package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
- package/rules/k8s/main.mdc +30 -843
- package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
- package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
- package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
- package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
- package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
- package/rules/nginx-default-tpl/main.mdc +6 -112
- package/rules/npm-module/js/docs/index.md +5 -5
- package/rules/npm-module/js/docs/rule_meta.md +6 -6
- package/rules/npm-module/js/docs/skill_meta.md +8 -8
- package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
- package/rules/npm-module/js/package_structure.mdc +62 -0
- package/rules/npm-module/js/rule_meta.mdc +11 -0
- package/rules/npm-module/js/skill_meta.mdc +11 -0
- package/rules/npm-module/main.mdc +10 -55
- package/rules/php/js/lint_php_yml.mdc +12 -0
- package/rules/php/js/tooling.mdc +66 -0
- package/rules/php/main.mdc +7 -66
- package/rules/python/js/lint_python_yml.mdc +23 -0
- package/rules/python/js/pyproject_toml.mdc +32 -0
- package/rules/python/js/tooling.mdc +23 -0
- package/rules/python/main.mdc +9 -33
- package/rules/rego/js/rego-lint.mdc +31 -0
- package/rules/rego/js/vscode_extensions.mdc +11 -0
- package/rules/rego/js/vscode_settings.mdc +13 -0
- package/rules/rego/main.mdc +8 -24
- package/rules/rust/js/coverage.mdc +28 -0
- package/rules/rust/js/lint.mdc +22 -0
- package/rules/rust/js/tauri_composition.mdc +8 -0
- package/rules/rust/js/vscode_extensions.mdc +12 -0
- package/rules/rust/main.mdc +8 -38
- package/rules/security/js/rego_policies.mdc +15 -0
- package/rules/security/js/sample_secret.mdc +19 -0
- package/rules/security/js/trufflehog.mdc +21 -0
- package/rules/security/main.mdc +7 -35
- package/rules/style/js/admin-table.mdc +88 -0
- package/rules/style/js/colors.mdc +21 -0
- package/rules/style/js/gap.mdc +22 -0
- package/rules/style/js/quasar-fixes.mdc +32 -0
- package/rules/style/js/quasar.mdc +7 -0
- package/rules/style/js/tooling.mdc +85 -0
- package/rules/style/main.mdc +13 -253
- package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
- package/rules/tauri/js/tool_surface.mdc +21 -0
- package/rules/tauri/js/tooling.mdc +25 -0
- package/rules/tauri/main.mdc +8 -78
- package/rules/test/js/cargo_mutants_config.mdc +18 -0
- package/rules/test/js/docs/index.md +7 -7
- package/rules/test/js/location.mdc +52 -0
- package/rules/test/js/no-console-store-restore.mdc +11 -0
- package/rules/test/js/no-process-chdir.mdc +15 -0
- package/rules/test/js/no-relative-fs-path.mdc +22 -0
- package/rules/test/js/sandbox-aware-test.mdc +28 -0
- package/rules/test/js/stryker_config.mdc +26 -0
- package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
- package/rules/test/main.mdc +18 -184
- package/rules/text/js/ci-lint-text.mdc +15 -0
- package/rules/text/js/cspell.mdc +81 -0
- package/rules/text/js/dotenv-linter.mdc +16 -0
- package/rules/text/js/forbidden-prettier.mdc +13 -0
- package/rules/text/js/markdownlint.mdc +25 -0
- package/rules/text/js/oxfmt.mdc +35 -0
- package/rules/text/js/package-json.mdc +26 -0
- package/rules/text/js/shellcheck.mdc +18 -0
- package/rules/text/js/v8r.mdc +23 -0
- package/rules/text/js/vscode.mdc +86 -0
- package/rules/text/main.mdc +20 -237
- package/rules/vue/js/composition-api.mdc +82 -0
- package/rules/vue/js/nheader-layout.mdc +171 -0
- package/rules/vue/js/node-imports.mdc +25 -0
- package/rules/vue/js/quasar-ui.mdc +32 -0
- package/rules/vue/js/structure.mdc +101 -0
- package/rules/vue/js/testing.mdc +32 -0
- package/rules/vue/js/tfm-translations.mdc +26 -0
- package/rules/vue/js/vite-config.mdc +126 -0
- package/rules/vue/js/vite-env.mdc +55 -0
- package/rules/vue/js/vue-imports.mdc +25 -0
- package/rules/vue/main.mdc +16 -640
- package/scripts/auto-rules.mjs +6 -6
- package/scripts/auto-skills.mjs +3 -3
- package/scripts/docs/auto-rules.md +17 -31
- package/scripts/docs/auto-skills.md +18 -163
- package/scripts/docs/index.md +16 -16
- package/scripts/lib/docs/index.md +36 -36
- package/scripts/lib/docs/mirror-parity.md +7 -7
- package/scripts/lib/docs/rule-meta.md +12 -12
- package/scripts/lib/docs/skill-meta.md +9 -9
- package/scripts/lib/docs/worktree-notice.md +10 -8
- package/scripts/lib/rule-meta.mjs +6 -6
- package/scripts/lib/skill-meta.mjs +6 -6
- package/scripts/lib/worktree-notice.mjs +2 -2
- package/scripts/utils/docs/index.md +14 -14
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## HorizontalPodAutoscaler: `autoscaling/v2`
|
|
2
|
+
|
|
3
|
+
У manifest-файлах під **`k8s`** заборонено **`apiVersion: autoscaling/v1`** (legacy HPA з єдиною метрикою CPU). Мігруй **HorizontalPodAutoscaler** на **`autoscaling/v2`**: поле **`spec.metrics`** (замість **`spec.targetCPUUtilizationPercentage`**) з **`type: Resource`** і **`target.type: Utilization`** / **`AverageUtilization`**. `check k8s` падає на будь-якому документі з **`apiVersion: autoscaling/v1`**.
|
|
4
|
+
|
|
5
|
+
Ресурси **batch** (наприклад **CronJob**, **Job**): застаріле **`apiVersion: batch/v1beta1`** у файлах під **`k8s`** під час `check k8s` переписується на **`apiVersion: batch/v1`**.
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/horizontalpodautoscaler-autoscaling-v2.json
|
|
9
|
+
apiVersion: autoscaling/v2
|
|
10
|
+
kind: HorizontalPodAutoscaler
|
|
11
|
+
metadata:
|
|
12
|
+
name: app
|
|
13
|
+
spec:
|
|
14
|
+
scaleTargetRef:
|
|
15
|
+
apiVersion: apps/v1
|
|
16
|
+
kind: Deployment
|
|
17
|
+
name: app
|
|
18
|
+
minReplicas: 1
|
|
19
|
+
maxReplicas: 5
|
|
20
|
+
metrics:
|
|
21
|
+
- type: Resource
|
|
22
|
+
resource:
|
|
23
|
+
name: cpu
|
|
24
|
+
target:
|
|
25
|
+
type: Utilization
|
|
26
|
+
averageUtilization: 70
|
|
27
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Ingress → Gateway API (GKE)
|
|
2
|
+
|
|
3
|
+
Якщо в дереві **`k8s`** трапляється маніфест з **`kind: Ingress`**, його потрібно **замінити на Gateway API**, а не залишати Ingress. **`check k8s`:** заборонено **`kind: Ingress`**.
|
|
4
|
+
|
|
5
|
+
1. **HTTPRoute** — окремий файл **`hr.yaml`** (або узгоджене ім'я в команді), **`kind: HTTPRoute`**, `apiVersion` з групи **`gateway.networking.k8s.io`**.
|
|
6
|
+
|
|
7
|
+
2. **HealthCheckPolicy (GKE)** — окремий файл **`hc.yaml`**:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
apiVersion: networking.gke.io/v1
|
|
11
|
+
kind: HealthCheckPolicy
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Для `$schema` у першому рядку — приклад **HealthCheckPolicy** у розділі «Визначення схеми YAML» (datree CRDs-catalog).
|
|
15
|
+
|
|
16
|
+
**`spec.targetRef`** (типово **`kind: Service`**) має вказувати на **headless** сервіс — ім'я з суфіксом **`-hl`** (div. **«Service: `svc.yaml` і `svc-hl.yaml`»**).
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
## Kustomize: структура каталогів (`base` / overlays)
|
|
2
|
+
|
|
3
|
+
Трансформуй дерева **`**/k8s`**, щоб **винести спільне** через [Kustomize](https://kustomize.io/): один канонічний **`base`** і тонкі **overlays** для інших середовищ.
|
|
4
|
+
|
|
5
|
+
### Джерело правди — середовище dev
|
|
6
|
+
|
|
7
|
+
- За основу бери **все, що відповідає середовищу dev** (як воно має виглядати в кластері для dev).
|
|
8
|
+
- У **такому вигляді** цей набір стає каталогом **`base`**: спільні маніфести без окремої директорії **`dev/`**.
|
|
9
|
+
- Окремої директорії **`dev`** **не повинно існувати**: за середовище **dev** відповідає **`base`**.
|
|
10
|
+
|
|
11
|
+
### Overlays (не-dev)
|
|
12
|
+
|
|
13
|
+
- У каталозі кожного іншого середовища (наприклад **`ua/`**, **`prod/`**) — мінімум файлів: типово лише **`kustomization.yaml`** і ресурси, **необхідні лише для цього overlay**.
|
|
14
|
+
- Відмінності від dev вносяться **оверрайдами** (patches, `images`, `replicas`, `configMapGenerator` тощо), а не копіюванням повного дерева з `base`.
|
|
15
|
+
|
|
16
|
+
### Namespace
|
|
17
|
+
|
|
18
|
+
- **`base/kustomization.yaml`:** поле **`namespace:`** має бути **непорожнім** (перевіряє **check k8s**).
|
|
19
|
+
- **Коли `metadata.namespace` обов'язковий у файлі:** YAML під **`k8s`** — непорожній **`metadata.namespace`** для namespaced **kind** (винятки — кластерні **kind**, перелік **`CLUSTER_SCOPED_KINDS`** у **`rules/k8s/fix.mjs`**).
|
|
20
|
+
- **Не додавай** окремі **patches** Kustomize, які лише змінюють **namespace**.
|
|
21
|
+
|
|
22
|
+
### Рядки, що змінюються між середовищами
|
|
23
|
+
|
|
24
|
+
У manifest-файлах у **`base`** для полів, які **будуть відрізнятися** в інших середовищах, на **тому самому рядку** додай коментар:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
image: my-app:dev-tag # буде замінено через kustomize
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Зміна image — через `images:`, не через `patches[]`
|
|
31
|
+
|
|
32
|
+
Підміну image у Pod-шаблоні Deployment в overlay роби директивою `images:`, а не JSON6902-патчем `op: replace` на `/spec/template/spec/containers/<N>/image`.
|
|
33
|
+
|
|
34
|
+
- У **`name`** — те, що **дослівно** стоїть у `image:` у base **без тегу**.
|
|
35
|
+
- **`newName`** — кінцеве ім'я образу; **`newTag`** — тег для прода.
|
|
36
|
+
- **`digest`** (`@sha256:…`) у `name` / `newName` не чіпай.
|
|
37
|
+
|
|
38
|
+
```yaml title="k8s/prod/kustomization.yaml (фрагмент)"
|
|
39
|
+
images:
|
|
40
|
+
- name: europe-west4-docker.pkg.dev/abie-ua/c/apply-on-invoice-discount
|
|
41
|
+
newName: europe-west4-docker.pkg.dev/abie-ua/c/apply-on-invoice-discount
|
|
42
|
+
newTag: v2025-04-29
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**`check k8s` автоматично** для кожного `kustomization.yaml`:
|
|
46
|
+
|
|
47
|
+
1. конвертує кожну JSON6902-операцію `op: replace` на `/spec/template/spec/containers/<N>/image` у запис `images:`;
|
|
48
|
+
2. чистить існуючий блок `images:` — зрізає `:tag` з `name` і видаляє `newTag`, який збігається з відрізаним тегом.
|
|
49
|
+
|
|
50
|
+
### Міграція зі старої структури
|
|
51
|
+
|
|
52
|
+
Після перенесення у **`base`** та overlays і перевірки (**`check k8s`**, **`lint-k8s`**) **видали** застарілі файли та директорії, що замінені новою схемою.
|
|
53
|
+
|
|
54
|
+
### `patches[].target`: лише `kind` і `name`
|
|
55
|
+
|
|
56
|
+
У `patches[].target` залишай **тільки** **`kind`** і **`name`** — поля **`group`** і **`version`** прибирай.
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
# ❌ зайві group / version
|
|
60
|
+
patches:
|
|
61
|
+
- target:
|
|
62
|
+
group: gateway.networking.k8s.io
|
|
63
|
+
version: v1beta1
|
|
64
|
+
kind: Gateway
|
|
65
|
+
name: gw
|
|
66
|
+
|
|
67
|
+
# ✅
|
|
68
|
+
patches:
|
|
69
|
+
- target:
|
|
70
|
+
kind: Gateway
|
|
71
|
+
name: gw
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Виняток:** залишай `group` / `version`, лише якщо в дереві overlay реально співіснують ресурси з однаковими `kind`+`name`, але різними API-групами/версіями.
|
|
75
|
+
|
|
76
|
+
### Структурний сорт `patches[]` і inline JSON6902
|
|
77
|
+
|
|
78
|
+
`patches[]` у `kustomization.yaml` має бути відсортовано за tuple **`target.kind` → `target.name` → `target.namespace` → `path`** (`localeCompare('en', { sensitivity: 'base' })`).
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
# ❌ atlas йде перед apruv
|
|
82
|
+
patches:
|
|
83
|
+
- target:
|
|
84
|
+
kind: ReferenceGrant
|
|
85
|
+
name: atlas-to-base
|
|
86
|
+
- target:
|
|
87
|
+
kind: ReferenceGrant
|
|
88
|
+
name: apruv-to-base
|
|
89
|
+
|
|
90
|
+
# ✅
|
|
91
|
+
patches:
|
|
92
|
+
- target:
|
|
93
|
+
kind: ReferenceGrant
|
|
94
|
+
name: apruv-to-base
|
|
95
|
+
- target:
|
|
96
|
+
kind: ReferenceGrant
|
|
97
|
+
name: atlas-to-base
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Усередині кожного inline `patches[i].patch` операції теж сортуються за **`path`**, **але лише** коли набір «безпечний»: усі ops — `add` / `replace` і всі `path` попарно дизʼюнктні. Інакше порядок не чіпається.
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
# ❌ minReplicas перед maxReplicas (за алфавітом max < min)
|
|
104
|
+
patch: |-
|
|
105
|
+
- op: add
|
|
106
|
+
path: /spec/minReplicas
|
|
107
|
+
value: 2
|
|
108
|
+
- op: replace
|
|
109
|
+
path: /spec/maxReplicas
|
|
110
|
+
value: 10
|
|
111
|
+
|
|
112
|
+
# ✅
|
|
113
|
+
patch: |-
|
|
114
|
+
- op: replace
|
|
115
|
+
path: /spec/maxReplicas
|
|
116
|
+
value: 10
|
|
117
|
+
- op: add
|
|
118
|
+
path: /spec/minReplicas
|
|
119
|
+
value: 2
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Порядок `resources`
|
|
123
|
+
|
|
124
|
+
Елементи **`resources:`** (лише непорожні рядки) мають бути **відсортовані за алфавітом (англ. локаль, як `localeCompare('en')` у `rules/k8s/fix.mjs`)**. Поля **`bases`**, **`components`**, **`crds`** цією перевіркою **не** впорядковуються.
|
|
125
|
+
|
|
126
|
+
### Локальні шляхи в `kustomization.yaml`
|
|
127
|
+
|
|
128
|
+
Кожен запис без `://` (remote) з `resources` / `bases` / `components` / `crds`, `patchesStrategicMerge`, `patches[].path`, `patchesJson6902[].path`, `configurations[]`, `replacements[].path` має вказувати на **існуючий** у репозиторії файл (`.yaml` / `.yml`) або **каталог**; биті посилання — помилка **`check k8s`**.
|
|
129
|
+
|
|
130
|
+
### JSON patch у kustomization: `op: replace`
|
|
131
|
+
|
|
132
|
+
Де можливо, змінюй ресурс через **`op: replace`** (одна операція на `path`), а не пару **`remove` + `add`** на той самий шлях.
|
|
133
|
+
|
|
134
|
+
```yaml title="overlay/kustomization.yaml (фрагмент)"
|
|
135
|
+
patches:
|
|
136
|
+
- target:
|
|
137
|
+
kind: Deployment
|
|
138
|
+
name: x
|
|
139
|
+
patch: |-
|
|
140
|
+
- op: replace
|
|
141
|
+
path: /spec/template/spec/nodeSelector
|
|
142
|
+
value:
|
|
143
|
+
preem: "false"
|
|
144
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
## lint-k8s: kubeconform і kubescape
|
|
2
|
+
|
|
3
|
+
Окремо від modeline `$schema` у редакторі варто ганяти CLI-лінтери (**kubeconform** і **kubescape**) по тих самих деревах **`…/k8s`**.
|
|
4
|
+
|
|
5
|
+
**Залежності:** виконувані файли kubeconform, kubescape і kubectl у **PATH** (kustomize використовуємо як вшиту підкоманду **`kubectl kustomize`** — окремий бінарник `kustomize` не потрібен); не додавай їх у **devDependencies**.
|
|
6
|
+
|
|
7
|
+
**Версія Kubernetes для kubeconform** — **`-kubernetes-version 1.33.9`** (semver без префікса `v`; набір схем **`v1.33.9-standalone-strict`**). Для CRD додатково підключай реєстр [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog) другим **`-schema-location`**. За потреби **`-ignore-missing-schemas`**.
|
|
8
|
+
|
|
9
|
+
**kubescape** — вхід через зібраний kustomize-маніфест: для кожного dir-у з `kustomization.yaml` (`kind: Kustomization`; **`kind: Component`** пропускається) `lint-k8s` виконує **`kubectl kustomize <dir>`** і передає stdout у **`kubescape scan <tmp-file>`** з порогом **`--severity-threshold high`**. Маніфест проходить через тимчасовий файл, бо **`kubescape scan` у v4.x не читає stdin**. Якщо в дереві **`…/k8s`** немає жодного `kustomization.yaml` — fallback на dir-скан **`kubescape scan <каталог-k8s>`**. У kubescape немає прапорця **`-kubernetes-version`**.
|
|
10
|
+
|
|
11
|
+
Лінт запускається через правило **`n-cursor lint k8s`** (реалізація — **`npm/rules/k8s/js/lint.mjs`**). Окремий `package.json`-скрипт `lint-k8s` не потрібен.
|
|
12
|
+
|
|
13
|
+
### Винятки kubescape: `.kubescape-exceptions.json`
|
|
14
|
+
|
|
15
|
+
Якщо в **корені проєкту** є файл **`.kubescape-exceptions.json`** — `lint-k8s` автоматично передає його в `kubescape scan` через **`--exceptions`** ([postureExceptionPolicy](https://github.com/kubescape/kubescape/blob/master/docs/exceptions.md)).
|
|
16
|
+
|
|
17
|
+
Канонічний кейс — **C-0012** (`Applications credentials in configuration files`, High): control тригериться на **ім'я** env, що містить підрядок `secret`/`password`/`key`/`token`, а **не** на значення. Точкове виключення для ConfigMap із цим env: [.kubescape-exceptions.json.snippet.json](./templates/kubescape_exceptions/.kubescape-exceptions.json.snippet.json)
|
|
18
|
+
|
|
19
|
+
Виключай контрольно, а не глобально (не додавай винятки без `attributes.name`/`labels`).
|
|
20
|
+
|
|
21
|
+
### GitHub Actions: `lint-k8s.yml`
|
|
22
|
+
|
|
23
|
+
Додай workflow **`.github/workflows/lint-k8s.yml`** (гілки **`dev`** і **`main`**, лише **`.yml`**). Після **`checkout`** використовуй локальний composite **`setup-bun-deps`**. Встановлення kubeconform / kubescape — окремі кроки. kustomize не встановлюємо окремо — `kubectl kustomize` вже на github-hosted runner'ах.
|
|
24
|
+
|
|
25
|
+
```yaml title=".github/workflows/lint-k8s.yml"
|
|
26
|
+
name: Lint K8s
|
|
27
|
+
|
|
28
|
+
on:
|
|
29
|
+
push:
|
|
30
|
+
branches:
|
|
31
|
+
- dev
|
|
32
|
+
- main
|
|
33
|
+
paths:
|
|
34
|
+
- '**/k8s/**/*.yaml'
|
|
35
|
+
|
|
36
|
+
pull_request:
|
|
37
|
+
branches:
|
|
38
|
+
- dev
|
|
39
|
+
- main
|
|
40
|
+
|
|
41
|
+
concurrency:
|
|
42
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
43
|
+
cancel-in-progress: true
|
|
44
|
+
|
|
45
|
+
jobs:
|
|
46
|
+
lint-k8s:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
permissions:
|
|
49
|
+
contents: read
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v6
|
|
52
|
+
with:
|
|
53
|
+
persist-credentials: false
|
|
54
|
+
|
|
55
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
56
|
+
|
|
57
|
+
- name: Install kubeconform
|
|
58
|
+
run: |
|
|
59
|
+
curl -sSL "https://github.com/yannh/kubeconform/releases/download/v0.7.0/kubeconform-linux-amd64.tar.gz" | tar xz
|
|
60
|
+
sudo mv kubeconform /usr/local/bin/
|
|
61
|
+
|
|
62
|
+
- name: Install kubescape
|
|
63
|
+
run: |
|
|
64
|
+
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
|
|
65
|
+
echo "$HOME/.kubescape/bin" >> $GITHUB_PATH
|
|
66
|
+
|
|
67
|
+
# kustomize не встановлюємо окремо — використовуємо вбудовану підкоманду `kubectl kustomize`
|
|
68
|
+
# (kubectl уже доступний на github-hosted runner'ах: https://github.com/actions/runner-images).
|
|
69
|
+
|
|
70
|
+
- name: Lint K8s
|
|
71
|
+
run: n-cursor lint k8s --read-only
|
|
72
|
+
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
## Багатодокументні YAML
|
|
2
|
+
|
|
3
|
+
Одна схема на файл; скрипт звіряє **перший** документ (до наступного `---`). Інші `kind` у тому ж файлі — розділи файли або узгодь у рев'ю.
|
|
4
|
+
|
|
5
|
+
**Розширення:** усі маніфести під **`k8s`**, включно з **`kustomization.yaml`**, — лише **`.yaml`** (розширення **`.yml`** не використовуй).
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
## NetworkPolicy: канон egress/ingress
|
|
2
|
+
|
|
3
|
+
Для **кожного** workload (**Deployment**, **StatefulSet**, **DaemonSet**, **Job**, **CronJob**) під `k8s` обов'язковий **NetworkPolicy** у **`base/networkpolicy.yaml`** поруч з workload-маніфестом (multi-doc через `---`, якщо workload-ів кілька). `metadata.name` NetworkPolicy **= `metadata.name`** workload; `spec.podSelector.matchLabels.app` **= мітка `app`** з `spec.selector.matchLabels` workload. Відсутні документи **`check k8s`** створює автоматично і додає `networkpolicy.yaml` у `base/kustomization.yaml` `resources:`.
|
|
4
|
+
|
|
5
|
+
Два **повних** snippet-файли (JS-генератор/rego обирають один за `kind` workload-у через анотацію `metadata.annotations['nitra.dev/workload-kind']`):
|
|
6
|
+
- [deployment.snippet.yaml](./policy/network_policy/template/deployment.snippet.yaml) — для `Deployment`/`Job`/`CronJob`/`DaemonSet`
|
|
7
|
+
- [stateful-set.snippet.yaml](./policy/network_policy/template/stateful-set.snippet.yaml) — для `StatefulSet` (містить deployment-канон + intra-replica правила)
|
|
8
|
+
|
|
9
|
+
### Канонічний `base/networkpolicy.yaml`
|
|
10
|
+
|
|
11
|
+
`networking.k8s.io/v1`, `NetworkPolicy`, **без** `metadata.namespace` (namespace додає `base/kustomization.yaml`).
|
|
12
|
+
|
|
13
|
+
**Ingress:** `from.podSelector: {}` (інші Pod у namespace).
|
|
14
|
+
|
|
15
|
+
**Egress (усі workload-и):**
|
|
16
|
+
- kube-dns через `kube-system` namespaceSelector (UDP/TCP 53);
|
|
17
|
+
- link-local DNS `169.254.0.0/16` (UDP/TCP 53, GKE NodeLocal DNSCache);
|
|
18
|
+
- **TCP 80 і 443** на `0.0.0.0/0` (HTTP/HTTPS назовні);
|
|
19
|
+
- **in-cluster** — `to.namespaceSelector: {}` з **явним списком TCP-портів** (`80, 443, 5432, 3306, 1433, 6379, 8080, 4222, 4317, 4318`).
|
|
20
|
+
|
|
21
|
+
**StatefulSet** додатково має egress/ingress `to/from.podSelector: {}` для intra-replica реплікації.
|
|
22
|
+
|
|
23
|
+
Заборонено: `egress: [{}]`; `to.namespaceSelector: {}` без `ports:` (catch-all).
|
|
24
|
+
|
|
25
|
+
```yaml title="k8s/base/networkpolicy.yaml"
|
|
26
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/networkpolicy-networking-v1.json
|
|
27
|
+
apiVersion: networking.k8s.io/v1
|
|
28
|
+
kind: NetworkPolicy
|
|
29
|
+
metadata:
|
|
30
|
+
name: backend-api
|
|
31
|
+
annotations:
|
|
32
|
+
nitra.dev/workload-kind: Deployment
|
|
33
|
+
spec:
|
|
34
|
+
podSelector:
|
|
35
|
+
matchLabels:
|
|
36
|
+
app: backend-api
|
|
37
|
+
policyTypes:
|
|
38
|
+
- Ingress
|
|
39
|
+
- Egress
|
|
40
|
+
ingress:
|
|
41
|
+
- from:
|
|
42
|
+
- podSelector: {}
|
|
43
|
+
egress:
|
|
44
|
+
- to:
|
|
45
|
+
- namespaceSelector:
|
|
46
|
+
matchLabels:
|
|
47
|
+
kubernetes.io/metadata.name: kube-system
|
|
48
|
+
podSelector:
|
|
49
|
+
matchLabels:
|
|
50
|
+
k8s-app: kube-dns
|
|
51
|
+
ports:
|
|
52
|
+
- protocol: UDP
|
|
53
|
+
port: 53
|
|
54
|
+
- protocol: TCP
|
|
55
|
+
port: 53
|
|
56
|
+
- to:
|
|
57
|
+
- ipBlock:
|
|
58
|
+
cidr: 169.254.0.0/16
|
|
59
|
+
ports:
|
|
60
|
+
- protocol: UDP
|
|
61
|
+
port: 53
|
|
62
|
+
- protocol: TCP
|
|
63
|
+
port: 53
|
|
64
|
+
- to:
|
|
65
|
+
- ipBlock:
|
|
66
|
+
cidr: 0.0.0.0/0
|
|
67
|
+
ports:
|
|
68
|
+
- protocol: TCP
|
|
69
|
+
port: 80
|
|
70
|
+
- protocol: TCP
|
|
71
|
+
port: 443
|
|
72
|
+
- to:
|
|
73
|
+
- namespaceSelector: {}
|
|
74
|
+
ports:
|
|
75
|
+
- protocol: TCP
|
|
76
|
+
port: 80
|
|
77
|
+
- protocol: TCP
|
|
78
|
+
port: 443
|
|
79
|
+
- protocol: TCP
|
|
80
|
+
port: 5432
|
|
81
|
+
- protocol: TCP
|
|
82
|
+
port: 3306
|
|
83
|
+
- protocol: TCP
|
|
84
|
+
port: 1433
|
|
85
|
+
- protocol: TCP
|
|
86
|
+
port: 6379
|
|
87
|
+
- protocol: TCP
|
|
88
|
+
port: 8080
|
|
89
|
+
- protocol: TCP
|
|
90
|
+
port: 4222
|
|
91
|
+
- protocol: TCP
|
|
92
|
+
port: 4317
|
|
93
|
+
- protocol: TCP
|
|
94
|
+
port: 4318
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### HTTPRoute → NetworkPolicy ingress (GCLB + Envoy)
|
|
98
|
+
|
|
99
|
+
Якщо в каталозі workload є **`HTTPRoute`** (Gateway API) з **`backendRef`** на **`<workload>-hl`** Service, **`check k8s`** автоматично додає в NetworkPolicy цього workload **ingress-правило** з фіксованим набором CIDR-ів і **TCP-портами з `backendRefs[].port`** (дедуп, відсортовано за зростанням).
|
|
100
|
+
|
|
101
|
+
Без цього правила трафік від **GKE Gateway** (Envoy proxy-only subnet, наприклад `10.10.0.0/23`) і **Google health checks** блокується базовим NetworkPolicy.
|
|
102
|
+
|
|
103
|
+
CIDR-набір зафіксовано:
|
|
104
|
+
- `35.191.0.0/16` — GCP HC global
|
|
105
|
+
- `130.211.0.0/22` — GCP HC global (legacy)
|
|
106
|
+
- `10.0.0.0/8` — широкий range, покриває proxy-only subnets усіх регіонів GKE
|
|
107
|
+
|
|
108
|
+
```yaml title="k8s/base/networkpolicy.yaml — workload з HTTPRoute (з GCLB ingress)"
|
|
109
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/networkpolicy-networking-v1.json
|
|
110
|
+
apiVersion: networking.k8s.io/v1
|
|
111
|
+
kind: NetworkPolicy
|
|
112
|
+
metadata:
|
|
113
|
+
name: backend-api
|
|
114
|
+
annotations:
|
|
115
|
+
nitra.dev/workload-kind: Deployment
|
|
116
|
+
spec:
|
|
117
|
+
podSelector:
|
|
118
|
+
matchLabels:
|
|
119
|
+
app: backend-api
|
|
120
|
+
policyTypes:
|
|
121
|
+
- Ingress
|
|
122
|
+
- Egress
|
|
123
|
+
ingress:
|
|
124
|
+
- from:
|
|
125
|
+
- podSelector: {}
|
|
126
|
+
- from: # auto-added by check k8s for HTTPRoute-paired workloads
|
|
127
|
+
- ipBlock: { cidr: 35.191.0.0/16 }
|
|
128
|
+
- ipBlock: { cidr: 130.211.0.0/22 }
|
|
129
|
+
- ipBlock: { cidr: 10.0.0.0/8 }
|
|
130
|
+
ports:
|
|
131
|
+
- { protocol: TCP, port: 8080 }
|
|
132
|
+
egress:
|
|
133
|
+
# ... (ідентично до базового прикладу вище)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Алгоритм: функція `collectHttpRouteIngressForWorkload` у **`rules/k8s/js/manifests.mjs`**.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
## Визначення схеми YAML (канон `yaml-language-server: $schema`)
|
|
2
|
+
|
|
3
|
+
Для кожного файлу `*.yaml`, у шляху якого є сегмент директорії **`k8s`**, якщо існує **публічна** схема — **перший рядок** — коментар-директива для [YAML Language Server](https://github.com/redhat-developer/yaml-language-server) з URL за `https://`:
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
# yaml-language-server: $schema=https://...
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Далі — вміст маніфесту без зайвого порожнього рядка між коментарем і YAML.
|
|
10
|
+
|
|
11
|
+
**Modeline — опційний:** якщо для конкретного поєднання `apiVersion`/`kind` **немає** надійної публічної схеми (yannh/datree/schemastore не покривають), залиш файл **без** рядка `# yaml-language-server: $schema=…`. **Заборонено** ставити `$schema=file:…` як заглушку.
|
|
12
|
+
|
|
13
|
+
**Виняток — modeline заборонено:** `apiVersion: alb.yc.io/v1alpha1`, `kind: HttpBackendGroup` (Yandex ALB) — рядка **`# yaml-language-server: $schema=…`** у файлі **не** має бути. Перший рядок — одразу YAML (`apiVersion:` тощо). Перевірка — **`rules/k8s/fix.mjs`**.
|
|
14
|
+
|
|
15
|
+
### Правила визначення URL схеми
|
|
16
|
+
|
|
17
|
+
Орієнтир — **перший документ** (до наступного `---`).
|
|
18
|
+
|
|
19
|
+
1. **Ім'я** `kustomization.yaml` → `https://json.schemastore.org/kustomization.json`.
|
|
20
|
+
|
|
21
|
+
2. **`apiVersion: v1`** → yannh, PIN набору схем **`v1.33.9-standalone-strict`**, ref репозиторію для raw URL — **`master`**:
|
|
22
|
+
`https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-v1.json`
|
|
23
|
+
`<kind>`: літери в нижньому регістрі без роздільників між CamelCase (наприклад `Service` → `service`).
|
|
24
|
+
|
|
25
|
+
**`kind: Secret`** і **`type: kubernetes.io/basic-auth`** — той самий шаблон, **`secret-v1.json`**:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/secret-v1.json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
3. **`apiVersion: group/version`** і **group** у **`YANNH_GROUPS`** у скрипті → yannh:
|
|
32
|
+
`https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-<group-частина>-<version>.json`
|
|
33
|
+
де **`<group-частина>`** — **перший сегмент** `group` до першої крапки: для груп без крапок збігається з усією group (`apps/v1` + `Deployment` → `deployment-apps-v1.json`); для `*.k8s.io` / `*.apiserver.k8s.io` — лише префікс до `.k8s.io` (`networking.k8s.io/v1` + `Ingress` → `ingress-networking-v1.json`; `networking.k8s.io/v1` + `NetworkPolicy` → `networkpolicy-networking-v1.json`; `rbac.authorization.k8s.io/v1` + `ClusterRole` → `clusterrole-rbac-v1.json`; `flowcontrol.apiserver.k8s.io/v1` + `FlowSchema` → `flowschema-flowcontrol-v1.json`). У yannh **немає** файлів з фрагментом `-k8s-io-` у назві.
|
|
34
|
+
|
|
35
|
+
4. **Інакше** (CRD тощо) → [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog). Типово для `$schema` у редакторі — **GitHub Pages**:
|
|
36
|
+
`https://datreeio.github.io/CRDs-catalog/<group>/<kind>_<version>.json`
|
|
37
|
+
(`<kind>` — лише літери та цифри в нижньому регістрі, без роздільників між CamelCase.)
|
|
38
|
+
|
|
39
|
+
**Виняток — `InfisicalSecret`:** `apiVersion: secrets.infisical.com/v1alpha1`, `kind: InfisicalSecret` — канонічний modeline через **raw** на гілці **`main`**:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/secrets.infisical.com/infisicalsecret_v1alpha1.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Приклад (Gateway API):** `apiVersion: gateway.networking.k8s.io/v1`, `kind: HTTPRoute`:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
# yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/gateway.networking.k8s.io/httproute_v1beta1.json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Приклад (GKE):** `apiVersion: networking.gke.io/v1`, `kind: HealthCheckPolicy`:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
# yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
5. **Немає надійного публічного URL** — не вигадуй URL і **не** використовуй `$schema=file:…`. Залиш файл **без** рядка `# yaml-language-server: $schema=…` зовсім.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
## Service: заборонені анотації GKE
|
|
2
|
+
|
|
3
|
+
У **`kind: Service`** не додавай у **`metadata.annotations`** **`cloud.google.com/neg`** і **`cloud.google.com/backend-config`** (legacy під Ingress / старе балансування GKE). **check k8s** падає, якщо ключ є.
|
|
4
|
+
|
|
5
|
+
## Service: `svc.yaml` і `svc-hl.yaml` (Gateway API)
|
|
6
|
+
|
|
7
|
+
Пара файлів для кластерного й headless **Service**: **`svc.yaml`** + **`svc-hl.yaml`** в одному каталозі, **`spec.type: ClusterIP`** / **`clusterIP: None`**, імена **`-hl`**, узгодженість пар, маршрути **`gateway.networking.k8s.io`** (**HTTPRoute**, **GRPCRoute**, **TCPRoute**, **TLSRoute**, **UDPRoute**) — **backendRef** лише на сервіси з суфіксом **`-hl`**; якщо **kustomization** посилається на **`svc.yaml`**, у **тому ж** **`kustomization.yaml`** має бути посилання на sibling **`svc-hl.yaml`**. Скрипт **не** створює файли — додай **`svc-hl.yaml`** вручну (копія з правками **name** / **clusterIP**).
|
|
8
|
+
|
|
9
|
+
**Точні умови та повідомлення `fail`** — верхній JSDoc **`npm/scripts/rules/k8s/fix.mjs`**.
|
|
10
|
+
|
|
11
|
+
### Gateway API: не дублюй namespace у `backendRef`
|
|
12
|
+
|
|
13
|
+
У маршрутах Gateway API (**HTTPRoute**, **GRPCRoute**, **TCPRoute**, **TLSRoute**, **UDPRoute**) у `spec.rules[*].backendRefs[*]` **не** додавай поле **`namespace`**, якщо його значення збігається з **`metadata.namespace`** самого маршруту. **`check k8s`** падає на такому збігу.
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
# ❌ погано — namespace дублює metadata.namespace маршруту
|
|
17
|
+
apiVersion: gateway.networking.k8s.io/v1
|
|
18
|
+
kind: HTTPRoute
|
|
19
|
+
metadata:
|
|
20
|
+
name: admin-site
|
|
21
|
+
namespace: dev-b2b
|
|
22
|
+
spec:
|
|
23
|
+
rules:
|
|
24
|
+
- backendRefs:
|
|
25
|
+
- name: auth-hl
|
|
26
|
+
namespace: dev-b2b # ← прибери
|
|
27
|
+
port: 8080
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
# ✅ добре — namespace лише в metadata
|
|
32
|
+
apiVersion: gateway.networking.k8s.io/v1
|
|
33
|
+
kind: HTTPRoute
|
|
34
|
+
metadata:
|
|
35
|
+
name: admin-site
|
|
36
|
+
namespace: dev-b2b
|
|
37
|
+
spec:
|
|
38
|
+
rules:
|
|
39
|
+
- backendRefs:
|
|
40
|
+
- name: auth-hl
|
|
41
|
+
port: 8080
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Якщо backend **дійсно** живе в іншому namespace — поле **`namespace`** у `backendRef` обов'язкове (і потрібен `ReferenceGrant` у тому namespace); правило цього випадку не торкається.
|