Files
Jonathan Katz b99e5564e9 GitOps schema generator and IDE integration (#49717)
### Summary:
Generates a json schema for valid GitOps yaml files, to be used with
[yaml-language-server](https://github.com/redhat-developer/yaml-language-server)
for IDE integration.

This PR includes the actual generated file, so it can be used without
running the tool. All files are in `/tools/gitops-autto-complete`, so
nothing else gets affected.

#### What it adds:
- Complete json schema that defines valid GitOps yaml files and can be
integrated with
[yaml-language-server](https://github.com/redhat-developer/yaml-language-server).
- Auto-completion, error checking, type checking, descriptions.
- Defines all keys for osquery options/flags (based on
`server/fleet/agent_options_generated.go`).
- Additional validation: required keys, strings that must be enclosed in
quotation marks, path support.
- Additional data: descriptions from code comments, notices for fields
that don't reset if null or empty.

#### Limitations:
- Some structs and data are duplicated into the tool and will inevitebly
mismatch over time, because the structs used for gitops are not
sufficient for the schema generation:
- Some fields use an interface/any type that so can't be used for the
schema generation.
- Some important details are not encoded in the type or struct tags for
gitops fields at all.
- Some details (like required fields) are encoded in the Validate()
interface, but the IDE integration cannot run Go code.
- Doesn't work with all yaml file types used for gitops (like a yaml
file that specifies multiple software packages), only the default/fleet
level files. This will require having a subsection of the schema for
each type of file, and some way to detect what it actually is (maybe
specifying the schema in the file itself).
- Requires manual setup to integrate with IDE, it's not an easy to use
extension currently.

#### Dependencies:
- `invopop/jsonschema` reflects Fleet's GitOps structs into the schema.
- `santhosh-tekuri/jsonschema/v6` validates the test fixtures against
that schema.
- `ghodss/yaml` decodes the fixture YAML the way fleetctl does.
 


https://github.com/user-attachments/assets/b6ffacd0-e602-41a2-b46a-7d10300c6ea5



## Testing

- [x] QA'd all new/changed functionality manually
- I have been using and working on this for the past week so it's in a
pretty good state, but some descriptions or keys are probably still
missing.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added GitOps YAML auto-completion powered by a comprehensive JSON
Schema.
* Added validation for GitOps configuration structure, supported fields,
data types, required combinations, and unknown keys.
* Added support for external file references using `path` and `paths` in
supported sections.
* Added clearer guidance for deprecated fields and special field
behaviors.
* **Bug Fixes**
* Improved detection of incorrectly typed values and invalid
configuration shapes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-28 11:50:50 -04:00

2.9 KiB

gitops-auto-complete

Generates a JSON schema from Fleet's GitOps Go structs so yaml-language-server can offer completion, hover docs, and validation while you write GitOps YAML.

How to use

Build the schema

The tool is a separate Go module, so run it from its own directory:

cd tools/gitops-auto-complete
go run . generated-schema.json

The argument is the output file, or omit it to print to stdout. Re-run it whenever the relevant Fleet structs change.

Set up with yaml-language-server

Point yaml-language-server at the generated file. It's used by Neovim, the VS Code YAML extension, and others. There are two ways to do this:

  • Map it to your GitOps files with the yaml.schemas setting, which maps a schema path to file globs.

  • Or add a modeline to the top of a single file:

    # yaml-language-server: $schema=/absolute/path/to/generated-schema.json
    

Neovim and lazy.nvim example

{
  "neovim/nvim-lspconfig",
  dependencies = {
    { "mason-org/mason.nvim", opts = {} },
    "mason-org/mason-lspconfig.nvim",
  },
  config = function()
    vim.lsp.config("yamlls", {
      settings = {
        yaml = {
          schemas = {
            -- schema file -> which YAML files it applies to
            ["/absolute/path/to/generated-schema.json"] = {
              "**/default.yml",
              "**/teams/*.yml",
              "**/fleets/*.yml",
            },
          },
        },
      },
    })
    vim.lsp.enable("yamlls")
  end,
}

Install the server once (:MasonInstall yaml-language-server), reload, and open a GitOps file. Hover a key with K to see its type and docs.

How it works

Reflects a GitOpsSpec struct that mirrors the real top-level GitOps keys, such as org_settings, controls, software, and policies, reusing Fleet's own types for each section, via invopop/jsonschema. It then post-processes the result so the schema matches how GitOps files are written: file-path references, legacy key aliases, required fields for an item, and field docs pulled from Go comments.

It's a separate Go module with a replace back to the repo, so it builds from inside the repo without adding dependencies to the root go.mod.

Known limitations

  • The schema is filename-agnostic, but Fleet applies some keys differently by file. For example, agent_options and reports are rejected in no-team.yml and the unassigned file. The schema still accepts them there, so that mistake shows up at fleetctl apply time, not in the editor.
  • GitOpsSpec and ControlsWithTypes are hand-written mirrors of spec.GitOps and spec.GitOpsControls, because those spec structs are untyped or untagged and reflect poorly. TestControlsKeysCoverSpec catches a controls-key drift, but a new top-level key has to be added to GitOpsSpec by hand, as custom_host_vitals was.