flux-schema

Flux CLI plugin for Kubernetes schema extraction and manifests validation.
[!NOTE]
This repository is in early development and the plugin system is not yet available in a stable release of Flux.
The instructions for installing and using the plugin will be added here when RFC-0013
has been implemented and released in Flux 2.9 or later.
Available Commands
flux-schema extract crd [files...]: Extract JSON Schema from Kubernetes CRD YAMLs
-d, --output-dir: Directory to write JSON Schema files to (mutually exclusive with --output-archive)
-a, --output-archive: Path to write a gzipped tar archive of JSON Schema files to
-f, --output-format: Go template for output file paths (default: {{ .Group }}/{{ .Kind }}_{{ .Version }}.json)
flux-schema extract k8s [swagger-file]: Extract JSON Schema from a Kubernetes OpenAPI v2 swagger document
--version X.Y.Z: Fetch the swagger from kubernetes/kubernetes for the given release tag (mutually exclusive with a swagger file)
-d, --output-dir, -f, --output-format: same as extract crd
flux-schema validate [paths...]: Validate Kubernetes manifests against JSON Schemas
--schema-location: Template URL or file path for schemas (repeatable, tried in order)
--skip-missing-schemas: Skip documents for which no schema can be found
-v, --verbose: Print a line for every document, including valid and skipped
The extract crd command reads Kubernetes CustomResourceDefinition YAML and writes one JSON Schema file per CRD version.
The input can be a bare CRD, a List of CRDs, or a multi-document YAML stream.
Generate schemas for every CRD installed in a cluster, using the
per-group-directory layout:
kubectl get crds -o yaml | flux-schema extract crd /dev/stdin -d ./schemas
You can supply -f, --output-format with a Go template to change the layout, e.g. the
kubeconform/kubeval flat layout:
flux-schema extract crd crds.yaml -f '{{ .Kind }}-{{ .GroupPrefix }}-{{ .Version }}.json'
The output is compatible with kubeconform and kubeval, making this command a drop-in replacement for kubeconform's
openapi2jsonschema.py script.
To bundle the schemas into a gzipped tar archive instead of writing to a directory,
use -a, --output-archive:
kustomize build config/crd | flux-schema extract crd /dev/stdin -a dist/crd-schemas.tar.gz
The archive path must end in .tar.gz or .tgz, and its parent directory is created if missing.
-f, --output-format still controls the entry paths inside the archive, so a nested template produces
subdirectories within the tarball.
Supported template variables (all lowercased at render time):
| Variable |
Example |
.Group |
source.toolkit.fluxcd.io |
.GroupPrefix |
source |
.Kind |
gitrepository |
.Version |
v1 |
An empty .Group (Kubernetes core API, e.g. apiVersion: v1) is normalized to core, and .GroupPrefix
is derived from .Group when unset. So a core Pod renders as core/pod_v1.json with the default template
and resolves to the same path when validate looks up its schema.
Note that the generated schemas apply the following OpenAPI → JSON Schema transformations:
- Objects with
properties are closed with additionalProperties: false, except under nodes
marked with x-kubernetes-preserve-unknown-fields: true, which stay open so free-form maps validate correctly.
- Integer-or-string fields are rewritten to
oneOf: [{type: string}, {type: integer}]. Both the
legacy format: int-or-string and the structural x-kubernetes-int-or-string: true forms are recognized.
The extract k8s command reads a Kubernetes OpenAPI v2 swagger document and writes
one JSON Schema file per kind listed under x-kubernetes-group-version-kind. Helper
types (e.g. PodSpec, ObjectMeta) are not emitted as standalone files — they are
inlined into the kinds that reference them.
Fetch the upstream swagger for a Kubernetes release and generate schemas:
flux-schema extract k8s --version 1.35.0 -d ./schemas
Supply the swagger file from the cluster:
kubectl get --raw /openapi/v2 | flux-schema extract k8s /dev/stdin -d ./schemas
The same -f, --output-format template used by extract crd works here, so the
generated files remain resolvable by validate with a single --schema-location
for both built-ins and CRDs. Core API kinds (apiVersion: v1) render under the
core/ group directory.
The emitted schemas are the standalone-strict variant:
- Every
$ref is inlined so schemas have no cross-file dependencies.
- Objects with
properties are closed with additionalProperties: false, except
under nodes marked x-kubernetes-preserve-unknown-fields: true.
- Integer-or-string fields are rewritten to
oneOf: [{type: string}, {type: integer}].
- Optional fields are marked nullable (
type: [<t>, "null"]), matching the
Kubernetes API server's behavior of accepting null for unset optional values.
apiVersion and kind are injected into every kind's properties and required list.
Kubernetes Manifests Validation
The validate command reads Kubernetes YAML manifests from one or more files or directories
and validates each document against a JSON Schema resolved from its apiVersion and kind.
Schemas are loaded from --schema-location templates, which are tried in order; the first
match wins.
flux-schema validate ./manifests \
--schema-location './schemas/{{.Kind}}-{{.GroupPrefix}}-{{.Version}}.json'
Output example with validation errors:
manifests/sources.yaml - Bucket/apps/minio is invalid: schema validation failed
- /spec: missing property 'bucketName'
- /spec/interval: got number, want string
- /spec/secretRef/name: got object, want string
- /spec: additional properties 'force' not allowed
manifests/sources.yaml - OCIRepository/apps/podinfo is invalid: YAML parse failed
- line 18: key "app.kubernetes.io/name" already set in map
manifests/sources.yaml - HelmChart/apps/redis is valid
Summary: 3 resources found in 1 file - Valid: 1, Invalid: 2, Skipped: 0
Validation is strict by default:
- YAML documents with duplicate keys are rejected.
- Documents missing both
metadata.name and metadata.generateName are flagged as invalid
matching Kubernetes API behavior.
- Schemas produced by
flux-schema extract crd close objects with additionalProperties: false,
so undocumented fields under spec fail validation.
- String formats
duration, date, datetime/date-time, and time are validated
matching Kubernetes API conventions.
Multiple schema locations are tried in order, so you can combine a remote CRD catalog with
local overrides:
flux-schema validate k8s-*.yaml \
--skip-missing-schemas \
--schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.Kind}}_{{.Version}}.json' \
--schema-location './schemas/{{.Kind}}-{{.GroupPrefix}}-{{.Version}}.json'
Manifests can also be piped via /dev/stdin:
kustomize build . | flux-schema validate /dev/stdin \
--schema-location './schemas/{{.Group}}/{{.Kind}}_{{.Version}}.json'
A non-zero exit code is returned when any document is invalid or errored.