T-0.3 ServiceDefinition schema + renderer contract + examples (R-GITOPS-02)
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
1 parent
253b6600f4
commit
eccc13bb3c
6 files changed
+585
-4
No files matched your search
+77
-2
@@ -1,3 +1,78 @@
|
||||
# schemas
|
||||
# schemas — the ServiceDefinition contract
|
||||
|
||||
_Placeholder — populated in Phase 0. See ../home-network-k3s (read-only spec)._
|
||||
This directory holds the **ServiceDefinition** interface — the highest-traffic contract in the
|
||||
platform (spec `agents/coordination-protocol.md` §2). Onboarding a service is adding/editing one
|
||||
ServiceDefinition under [`../catalog/`](../catalog/); the platform compiles it into concrete
|
||||
resources. Operators declare **what**; the platform provides the **how**.
|
||||
|
||||
**Source of truth:** the read-only spec
|
||||
[`docs/13-service-catalog.md`](../../home-network-k3s/docs/13-service-catalog.md). This schema matches
|
||||
docs/13 exactly. Do not diverge from it here — escalate spec problems, don't fork the contract.
|
||||
|
||||
## Files
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `servicedefinition.schema.json` | Formal JSON Schema (draft 2020-12) for a ServiceDefinition. Enforces enums, required fields, patterns, and cross-field invariants. |
|
||||
| `renderer-contract.md` | Authoritative field → rendered-resource mapping, with requirement IDs. The contract other workstreams consume. |
|
||||
|
||||
**Schema version:** 1.0.0 (in the schema `description`). Treat any change as an interface change:
|
||||
propose on the task board, update dependent renderers/tests in the same change, never silently break a
|
||||
consumer (coordination-protocol §2).
|
||||
|
||||
## Required vs. defaulted fields
|
||||
- **Required:** `name`, `source` (with `source.image` for `kind: container`, `source.vmTemplate` for
|
||||
`kind: vm`).
|
||||
- **Everything else is optional and carries a default** matching docs/13's "default posture"
|
||||
(`kind: container`, `exposure: internal`, `egress: internet`, `auth.mode: forward-auth`,
|
||||
`update.channel: stable`, `update.autoRollbackOnFailedHealth: true`, `observability.metrics: true`,
|
||||
`dependencies: []` ⇒ DNS-only). A renderer MUST materialize defaults before rendering — see
|
||||
`renderer-contract.md` §"Default posture".
|
||||
|
||||
## Cross-field rules the schema enforces
|
||||
- `kind: vm` ⇒ `source.vmTemplate` required; otherwise `source.image` required.
|
||||
- `auth.mode: oidc | forward-auth` ⇒ `auth.groups` present and non-empty (R-IDP-06 — access is "in an
|
||||
authorized group," not merely authenticated).
|
||||
- `ingressRoutes[].host` must match `<label>.home.keithjackson.dev`.
|
||||
- `storage[].class ∈ {longhorn, bulk}`; `exposure ∈ {internal, public}`; `egress ∈ {internet, vpn}`;
|
||||
`auth.mode ∈ {oidc, forward-auth, native, none}`.
|
||||
- `additionalProperties: false` everywhere — unknown keys are rejected (catches typos in review/CI).
|
||||
|
||||
## Validate examples against the schema — L1, no cluster (R-TEST-02)
|
||||
|
||||
Reproducible, single command, no cluster required. Canonical tool: **check-jsonschema** (YAML-native,
|
||||
pins the schema file, pin the tool version for determinism):
|
||||
|
||||
```bash
|
||||
# one-time (pin the version for reproducibility)
|
||||
pip install check-jsonschema==0.38.0
|
||||
|
||||
# validate every catalog entry against the contract
|
||||
check-jsonschema --schemafile schemas/servicedefinition.schema.json catalog/*.yaml
|
||||
# -> "ok -- validation done"
|
||||
```
|
||||
|
||||
Fallback with no extra tool (Python `jsonschema` + `pyyaml` only):
|
||||
|
||||
```bash
|
||||
python3 - <<'PY'
|
||||
import json, yaml, glob, sys
|
||||
from jsonschema import Draft202012Validator
|
||||
schema = json.load(open('schemas/servicedefinition.schema.json'))
|
||||
Draft202012Validator.check_schema(schema)
|
||||
v = Draft202012Validator(schema); bad = False
|
||||
for f in sorted(glob.glob('catalog/*.yaml')):
|
||||
errs = sorted(v.iter_errors(yaml.safe_load(open(f))), key=lambda e: list(e.path))
|
||||
print(('PASS ' if not errs else 'FAIL ') + f)
|
||||
for e in errs: print(' ', list(e.path), e.message); bad = True
|
||||
sys.exit(1 if bad else 0)
|
||||
PY
|
||||
```
|
||||
|
||||
Both are pure manifest/schema checks (L0/L1 in spec `docs/14`, table row "L1 Rendering") — they run in
|
||||
CI with no cluster and are wired into the `.gitea/` schema-validation gate by WS-TEST.
|
||||
|
||||
## See also
|
||||
- `renderer-contract.md` — what each field renders into (Deployment/VM, PVC, CiliumNetworkPolicy,
|
||||
egress steering, HTTPRoute/Certificate/DNS, ServiceMonitor/alerts, ImagePolicy, Keycloak/oauth2-proxy).
|
||||
- Example ServiceDefinitions: [`../catalog/pihole.yaml`](../catalog/pihole.yaml),
|
||||
[`../catalog/keycloak.yaml`](../catalog/keycloak.yaml).
|
||||
Reference in new issue
Block a user