{"id":49149547,"url":"https://github.com/fluxcd/flux-schema","last_synced_at":"2026-04-24T10:05:10.502Z","repository":{"id":352645622,"uuid":"1215710376","full_name":"fluxcd/flux-schema","owner":"fluxcd","description":"Flux CLI plugin for Kubernetes schema extraction and manifests validation","archived":false,"fork":false,"pushed_at":"2026-04-20T15:36:38.000Z","size":46,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T15:40:46.308Z","etag":null,"topics":["fluxcd","gitops","openapi-validation","plugin"],"latest_commit_sha":null,"homepage":"https://fluxcd.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluxcd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-20T07:19:37.000Z","updated_at":"2026-04-20T15:40:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fluxcd/flux-schema","commit_stats":null,"previous_names":["fluxcd/flux-schema"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/fluxcd/flux-schema","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluxcd","download_url":"https://codeload.github.com/fluxcd/flux-schema/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-schema/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32122783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T00:31:26.853Z","status":"online","status_checked_at":"2026-04-22T02:00:05.693Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fluxcd","gitops","openapi-validation","plugin"],"created_at":"2026-04-22T05:35:03.225Z","updated_at":"2026-04-24T10:05:10.494Z","avatar_url":"https://github.com/fluxcd.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flux-schema\n\n[![release](https://img.shields.io/github/release/fluxcd/flux-schema/all.svg)](https://github.com/fluxcd/flux-schema/releases)\n[![test](https://github.com/fluxcd/flux-schema/actions/workflows/test.yaml/badge.svg)](https://github.com/fluxcd/flux-schema/actions/workflows/test.yaml)\n[![cve-scan](https://github.com/fluxcd/flux-schema/workflows/cve-scan/badge.svg)](https://github.com/fluxcd/flux-schema/actions/workflows/cve-scan.yml)\n[![license](https://img.shields.io/github/license/fluxcd/flux-schema.svg)](https://github.com/fluxcd/flux-schema/blob/main/LICENSE)\n[![slsa](https://slsa.dev/images/gh-badge-level2.svg)](https://github.com/fluxcd/flux-schema/attestations)\n\nFlux CLI plugin for Kubernetes schema extraction and manifests validation.\n\n\u003e [!NOTE]\n\u003e This repository is in early development and the plugin system is not yet available in a stable release of Flux.\n\u003e The instructions for installing and using the plugin will be added here when [RFC-0013](https://github.com/fluxcd/flux2/blob/main/rfcs/0013-cli-plugin-system/README.md)\n\u003e has been implemented and released in Flux 2.9 or later.\n\n## Available Commands\n\n- `flux-schema validate [paths...]`: Validate Kubernetes manifests against JSON Schemas\n    - `--schema-location`: URL or file path for schemas (repeatable, tried in order); `default` points at the built-in catalog\n    - `--skip-missing-schemas`: Skip documents for which no schema can be found\n    - `--skip-kind`: Skip documents matching `Kind` or `apiVersion/Kind` (repeatable)\n    - `--fail-fast`: Exit after the first invalid document\n    - `--concurrent`: Number of concurrent workers (default 8)\n    - `--insecure-skip-tls-verify`: Disable TLS certificate verification when fetching schemas over HTTPS\n    - `-v, --verbose`: Print a line for every document, including valid and skipped ones\n    - `--config`: Path to a YAML file supplying default values for validate flags (env: `FLUX_SCHEMA_CONFIG`)\n- `flux-schema extract crd [files...]`: Extract JSON Schema from Kubernetes CRD YAMLs\n  - `-d, --output-dir`: Directory to write JSON Schema files to (mutually exclusive with `--output-archive`)\n  - `-a, --output-archive`: Path to write a gzipped tar archive of JSON Schema files to\n  - `-f, --output-format`: Go template for output file paths (default: `{{ .Group }}/{{ .Kind }}_{{ .Version }}.json`)\n  - `--strip-description`: Drop `description` fields from the generated schemas to reduce their size\n- `flux-schema extract k8s [swagger-file]`: Extract JSON Schema from a Kubernetes OpenAPI v2 swagger document\n  - `--version X.Y.Z`: Fetch the swagger from `kubernetes/kubernetes` for the given release tag (mutually exclusive with a swagger file)\n  - `-d, --output-dir`, `-f, --output-format`, `--strip-description`: same as `extract crd`\n\n### Kubernetes Manifests Validation\n\nThe validate command reads Kubernetes YAML manifests from one or more files or directories\nand validates each document against a JSON Schema resolved from its `apiVersion` and `kind`.\n\nWhen no `--schema-location` is given, validate uses the [flux-schema catalog](catalog/README.md),\nwhich covers the latest Kubernetes APIs, the stable channel of Gateway API,\nand the Flux ecosystem CRDs:\n\n```shell\nflux-schema validate ./manifests\n```\n\nTo validate against your own schemas generated by `flux-schema extract`, pass the\ndirectory as `--schema-location`. Bare paths and URLs are auto-expanded to the\ncatalog layout `{{.Group}}/{{.Kind}}_{{.Version}}.json`:\n\n```shell\nflux-schema validate ./manifests --schema-location ./my-schemas\n```\n\nFor a different layout, pass a full Go template ending in `.json`:\n\n```shell\nflux-schema validate ./manifests \\\n  --skip-missing-schemas \\\n  --schema-location './schemas/{{.Kind}}-{{.GroupPrefix}}-{{.Version}}.json'\n```\n\nTemplate variables are `.Group`, `.GroupPrefix`, `.Kind`, and `.Version`.\n\nThe `--schema-location` flag is repeatable and locations are tried in order (the first match wins).\nPass the literal value `default` to include the flux-schema catalog alongside your own schemas:\n\n```shell\nflux-schema validate ./manifests \\\n  --schema-location default \\\n  --schema-location https://raw.githubusercontent.com/datreeio/CRDs-catalog/main \\\n  --schema-location './schemas/{{.Kind}}-{{.GroupPrefix}}-{{.Version}}.json'\n```\n\nManifests can also be piped in and certain documents skipped with `--skip-kind`:\n\n```shell\nkustomize build . | flux-schema validate \\\n  --skip-kind 'v1/Secret' \\\n  --skip-kind 'source.toolkit.fluxcd.io/v1/ExternalArtifact'\n```\n\nOutput example with validation errors:\n\n```\nmanifests/sources.yaml - Bucket/apps/s3-data is invalid: schema validation failed\n  - /spec: missing property 'bucketName'\n  - /spec/interval: got number, want string\n  - /spec/secretRef/name: got object, want string\n  - /spec: additional properties 'force' not allowed\nmanifests/sources.yaml - OCIRepository/apps/podinfo is invalid: YAML parse failed\n  - line 18: key \"app.kubernetes.io/name\" already set in map\nmanifests/sources.yaml - HelmChart/apps/redis is valid\nmanifests/sources.yaml - Secret/apps/auth-sops is skipped: kind skipped\nSummary: 4 resources found in 1 file - Valid: 1, Invalid: 2, Skipped: 1\n```\n\nA non-zero exit code is returned when any document is invalid or errored.\n\n#### Validation rules\n\n- YAML documents with duplicate keys are rejected matching Flux behavior.\n- Documents missing both `metadata.name` and `metadata.generateName` are flagged as invalid\n  matching Kubernetes API behavior.\n- Schemas produced by `flux-schema extract crd` close objects with `additionalProperties: false`,\n  so undocumented fields under `spec` fail validation.\n- String formats `duration`, `date`, `datetime`/`date-time`, and `time` are validated\n  matching Kubernetes API conventions.\n\n#### Config file\n\nFlag values can be pre-set in a YAML config file and referenced with `--config`\nor with the `FLUX_SCHEMA_CONFIG` environment variable.\nThis keeps long invocations out of CI scripts and makes validation reproducible\nacross developers:\n\n```shell\nflux-schema validate ./manifests --config .flux-schema.yaml\n```\n\nThe file has a `version` (required, must be `\"1\"`) and a `validate` section\nwhose keys mirror the CLI flag names:\n\n```yaml\nversion: \"1\"\nvalidate:\n  schema-location:\n    - default\n    - https://raw.githubusercontent.com/datreeio/CRDs-catalog/main\n  skip-kind:\n    - v1/Secret\n    - source.toolkit.fluxcd.io/v1/ExternalArtifact\n  skip-missing-schemas: false\n  verbose: true\n  fail-fast: false\n  concurrent: 8\n  insecure-skip-tls-verify: false\n```\n\nRules:\n\n- CLI flags override config values. Setting `--verbose=false` wins over `verbose: true` in the file.\n- Setting `--config` overrides `FLUX_SCHEMA_CONFIG`. When both are set, the flag wins and the env var is ignored.\n- Manifest paths stay positional. The config file configures how to validate; paths are given on the command line.\n\n### Kubernetes CRD Extraction\n\nThe `extract crd` command reads Kubernetes CustomResourceDefinition YAML\nand writes one JSON Schema file per CRD version.\nThe input can be a bare CRD, a `List` of CRDs, or a multi-document YAML stream.\n\nGenerate schemas for every CRD installed in a cluster, using the\nper-group-directory layout:\n\n```shell\nkubectl get crds -o yaml | flux-schema extract crd -d ./schemas\n```\n\nYou can supply `-f, --output-format` with a Go template to change the layout, e.g. the\n`kubeconform`/`kubeval` flat layout:\n\n```shell\nflux-schema extract crd crds.yaml -f '{{ .Kind }}-{{ .GroupPrefix }}-{{ .Version }}.json'\n```\n\n\u003e The output is compatible with `kubeconform` and `kubeval`, making this command a drop-in replacement for kubeconform's\n\u003e [openapi2jsonschema.py](https://github.com/yannh/kubeconform/blob/master/scripts/openapi2jsonschema.py) script.\n\nTo bundle the schemas into a gzipped tar archive instead of writing to a directory,\nuse `-a, --output-archive`:\n\n```shell\nkustomize build config/crd | flux-schema extract crd -a dist/crd-schemas.tar.gz\n```\n\nThe archive path must end in `.tar.gz` or `.tgz`, and its parent directory is created if missing.\n`-f, --output-format` still controls the entry paths inside the archive, so a nested template produces\nsubdirectories within the tarball.\n\nSupported template variables (all lowercased at render time):\n\n| Variable       | Example                    |\n|----------------|----------------------------|\n| `.Group`       | `source.toolkit.fluxcd.io` |\n| `.GroupPrefix` | `source`                   |\n| `.Kind`        | `gitrepository`            |\n| `.Version`     | `v1`                       |\n\nAn empty `.Group` (Kubernetes core API, e.g. `apiVersion: v1`) is normalized to `core`, and `.GroupPrefix`\nis derived from `.Group` when unset. So a core `Pod` renders as `core/pod_v1.json` with the default template\nand resolves to the same path when `validate` looks up its schema.\n\nNote that the generated schemas apply the following OpenAPI → JSON Schema transformations:\n\n- Objects with `properties` are closed with `additionalProperties: false`, except under nodes\n  marked with `x-kubernetes-preserve-unknown-fields: true`, which stay open so free-form maps validate correctly.\n- Integer-or-string fields are rewritten to `oneOf: [{type: string}, {type: integer}]`. Both the\n  legacy `format: int-or-string` and the structural `x-kubernetes-int-or-string: true` forms are recognized.\n\n### Kubernetes OpenAPI Extraction\n\nThe `extract k8s` command reads a Kubernetes OpenAPI v2 swagger document and writes\none JSON Schema file per kind listed under `x-kubernetes-group-version-kind`. Helper\ntypes (e.g. `PodSpec`, `ObjectMeta`) are not emitted as standalone files — they are\ninlined into the kinds that reference them.\n\nFetch the upstream swagger for a Kubernetes release and generate schemas:\n\n```shell\nflux-schema extract k8s --version 1.35.0 -d ./schemas\n```\n\nSupply the swagger file from the cluster:\n\n```shell\nkubectl get --raw /openapi/v2 | flux-schema extract k8s -d ./schemas\n```\n\nThe same `-f, --output-format` template used by `extract crd` works here, so the\ngenerated files remain resolvable by `validate` with a single `--schema-location`\nfor both built-ins and CRDs. Core API kinds (`apiVersion: v1`) render under the\n`core/` group directory.\n\nThe emitted schemas are the standalone-strict variant:\n\n- Every `$ref` is inlined so schemas have no cross-file dependencies.\n- Objects with `properties` are closed with `additionalProperties: false`, except\n  under nodes marked `x-kubernetes-preserve-unknown-fields: true`.\n- Integer-or-string fields are rewritten to `oneOf: [{type: string}, {type: integer}]`.\n- Optional fields are marked nullable (`type: [\u003ct\u003e, \"null\"]`), matching the\n  Kubernetes API server's behavior of accepting `null` for unset optional values.\n- `apiVersion` and `kind` are injected into every kind's properties and required list.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxcd%2Fflux-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluxcd%2Fflux-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxcd%2Fflux-schema/lists"}