Some checks are pending
Run Check Script / check (pull_request) Waiting to run
The CRD previously accepted any string for `score.type`, so typos like `"pdoman"` or `"PodmnV0"` would be persisted by the apiserver and only surface on-device as agent-side deserialize warnings. That class of failure is distasteful and hard to debug. Replace the auto-derived schema for `ScorePayload` with a hand-rolled one that keeps the same visible shape but adds two apiserver-level guardrails: - `score.type` gets `minLength: 1` and an `x-kubernetes-validations` CEL rule requiring it to match `^[A-Za-z_][A-Za-z0-9_]*$` — a valid Rust identifier, since score variants *are* Rust struct names in `harmony::modules::podman::IotScore`. Message points operators at the concrete example `PodmanV0`. - `score.data` still carries only `x-kubernetes-preserve-unknown- fields: true`. The rule validates the discriminator's *shape*, not its *value*, so v0.3+ variants (OkdApplyV0, KubectlApplyV0) don't require an operator release — preserves ROADMAP §6.1's generic-router design. The `x-kubernetes-preserve-unknown-fields` extension stays scoped to `score.data` alone; every other field in the CRD has a strict schema, exactly one preserve-unknown-fields marker and exactly one validations block in the whole document. Smoke test extended: phase 2b applies a CR with `score.type: "has spaces"` and asserts the apiserver rejects it with the CEL message before the operator ever sees it. Positive phases (kubectl apply -> NATS KV put -> status observed -> delete -> KV key removed) still PASS end-to-end. Matches the `preserve_arbitrary` pattern used by ArgoCD (`Application.spec.source.helm.valuesObject`) and Flux (`HelmRelease.spec.values`), both of which similarly use narrow preserve-unknown-fields on a payload field without coupling the CRD to their variant catalog.
72 lines
1.9 KiB
YAML
72 lines
1.9 KiB
YAML
apiVersion: apiextensions.k8s.io/v1
|
|
kind: CustomResourceDefinition
|
|
metadata:
|
|
name: deployments.iot.nationtech.io
|
|
spec:
|
|
group: iot.nationtech.io
|
|
names:
|
|
categories: []
|
|
kind: Deployment
|
|
plural: deployments
|
|
shortNames:
|
|
- iotdep
|
|
singular: deployment
|
|
scope: Namespaced
|
|
versions:
|
|
- additionalPrinterColumns: []
|
|
name: v1alpha1
|
|
schema:
|
|
openAPIV3Schema:
|
|
description: Auto-generated derived type for DeploymentSpec via `CustomResource`
|
|
properties:
|
|
spec:
|
|
properties:
|
|
rollout:
|
|
properties:
|
|
strategy:
|
|
enum:
|
|
- Immediate
|
|
type: string
|
|
required:
|
|
- strategy
|
|
type: object
|
|
score:
|
|
properties:
|
|
data:
|
|
x-kubernetes-preserve-unknown-fields: true
|
|
type:
|
|
minLength: 1
|
|
type: string
|
|
required:
|
|
- data
|
|
- type
|
|
type: object
|
|
x-kubernetes-validations:
|
|
- message: score.type must be a valid Rust identifier matching the struct name of the score variant (e.g. PodmanV0)
|
|
rule: self.type.matches('^[A-Za-z_][A-Za-z0-9_]*$')
|
|
targetDevices:
|
|
items:
|
|
type: string
|
|
type: array
|
|
required:
|
|
- rollout
|
|
- score
|
|
- targetDevices
|
|
type: object
|
|
status:
|
|
nullable: true
|
|
properties:
|
|
observedScoreString:
|
|
nullable: true
|
|
type: string
|
|
type: object
|
|
required:
|
|
- spec
|
|
title: Deployment
|
|
type: object
|
|
served: true
|
|
storage: true
|
|
subresources:
|
|
status: {}
|
|
|