Skip to content

GitOps schema generator and IDE integration - #49717

Merged
jkatz01 merged 16 commits into
mainfrom
jk-experiment-gitops-autocomplete
Jul 28, 2026
Merged

GitOps schema generator and IDE integration #49717
jkatz01 merged 16 commits into
mainfrom
jk-experiment-gitops-autocomplete

Conversation

@jkatz01

@jkatz01 jkatz01 commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary:

Generates a json schema for valid GitOps yaml files, to be used with 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.
  • 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.
gitops-autocompletion-demo.mp4

Testing

  • 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.

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.

jkatz01 added 16 commits July 13, 2026 23:46
tools/gitops-auto-complete reflects Fleet's GitOps structs into a JSON
schema so editors (yaml-language-server) get completion and validation
for GitOps YAML. It runs as its own Go module (replace directive back to
the repo) so invopop/jsonschema stays out of the root go.mod.

Post-processing matches real GitOps files: rename aliases, path/paths
file references on section and list-item types, null-tolerant empty keys,
type-on-hover descriptions, and agent_options.config.options typed from
the generated osqueryOptions struct.

Also includes the hand-written scratch schema and test yaml files.
Keep the JSON type on booleans (and objects/arrays) so wrong types are
caught, while strings and integers stay untyped to avoid false positives
on unquoted YAML values and Fleet ints that marshal as string enums.

Restore anyOf errorMessage on the hand-written schema for friendlier
required-field messages (a yaml-language-server / VS Code extension).
- Pull Fleet Go doc comments into field descriptions (shown on hover) via
  invopop AddGoComments, with the field type appended.
- Mark legacy renameto spellings deprecated so editors steer to the current
  names; keep both spellings valid.
- Type controls.{macos,windows,android}_settings with their real Fleet
  structs so they offer completion instead of being opaque.
- Merge spec.GitOpsMDM's gitops-only keys (end_user_license_agreement) into
  the MDM def, and alias/deprecate any-typed renamed fields.

All standard my-gitops files now validate; remaining flags are genuine
(outdated keys, placeholders, and Fleet's own $-escaping which pure YAML
can't parse).
Each software item must set at least one source: packages need url,
hash_sha256, or path; app_store_apps need app_store_id or path;
fleet_maintained_apps need slug or path. Expressed as an anyOf of required
branches with a shared errorMessage (Fleet enforces this in code, not tags).

Also type the identifier keys (url, hash_sha256, app_store_id, slug) as
strict strings so a mistyped value like url: 12345 is caught, applied after
the null-relaxation pass so it survives.
Restructure the README to a brief description, a How to use section (build
the schema, set up with yaml-language-server, Neovim + lazy.nvim example),
and a high-level How it works; link yaml-language-server.

Remove the temp-test-yaml-schema/ scratch files (the early hand-written
schema and sample yamls) — the generated schema is the deliverable.
Move GitOpsSpec, Controls, and the Go-type -> JSON-schema mapping
(typeMapper, schemaForType, goTypeToJSON) into types.go; main.go keeps the
orchestration and schema post-processing. Rename GitOpsSpec.Settings to
TeamSettings to match spec.GitOps (json tag unchanged, schema output identical).
Adds a map of the gitops keys whose omitted/null/empty apply behavior deviates from the default (an omitted key is reset), plus a schema walker that appends a hover note to each so yaml-language-server surfaces it. The behavior was verified against a live server.
Validates comprehensive valid and invalid gitops fixtures against the generated schema (santhosh-tekuri/jsonschema, draft 2020-12), asserts the post-processing invariants survive (declarative notes, rename aliases, required-source rules, typed source keys, config.options, path refs), and checks the committed schema is up to date. Adds a YAMLLS_TEST=1-gated check that runs the fixtures through a real yaml-language-server. The validator and ghodss/yaml are added to the tool module only; the root module is untouched.
Restructure main.go (main first, iterative tree walk, flatter passes with
blank-line separation), move the schema-building functions out of the data
file (declarative.go -> extra_data.go, now data only), clean up types.go,
and rename generated.schema.json -> generated-schema.json.

Resolve Fleet source paths from this file's own location via runtime.Caller
so the generator produces the same schema regardless of the working
directory, instead of assuming it runs from the module root.
relaxNulls now keeps string leaves typed as [string, null] instead of dropping
the type, so an unquoted numeric value like version: 13.0 (which fleetctl also
rejects) is flagged in the editor while empty placeholders stay valid. Integer
and number leaves still drop their type to avoid rejecting int-backed string
enums like label_membership_type. Adds regression fixtures for both cases.

Also renames the software source passes to installer-reference terminology,
follows the Controls -> ControlsWithTypes struct rename through the schema,
passes spec.GitOpsMDM into mergeMissingMDMKeys, adds a -h/--help flag, and
clarifies the collectNodes and resolveReference internals.
The schema wrongly accepted `- path:` under app_store_apps and
fleet_maintained_apps, which fleetctl rejects (only packages support an
item-level path). Remove path from those defs so it's an unknown key, and
require app_store_id / slug.

Generalize the required-key mechanism to cover labels, policies, and reports:
each requires a name, reports require name and query, with path/paths as
file-reference alternatives.

Model `paths` as a single glob string instead of an array, and add it only to
the defs that support it (policies, labels) rather than the whole-section
defs. Reshape org_settings.yara_rules items from {name, contents} to {path}
to match what gitops parses.

Regenerate the schema and add regression fixtures for each case.
name_template is a valid controls key (spec.GitOpsControls, which gitops
validates must be a string), but the tool's hand-written ControlsWithTypes
had drifted and lacked it, so the closed schema rejected it. Add it as a
string field and regenerate against the merged main (which also adds the
same key to the MDM/TeamMDM defs).
From an AI review of the branch:

Numeric osquery options lost their type. relaxNulls strips the type off every
bare-string scalar leaf, which included the typed config.options.* integers, so
a value like distributed_interval: "abc" validated clean. osqueryOptionsSchema
now emits [type, null] unions; relaxNulls leaves union-typed nodes alone, so the
options stay typed while an empty value still validates. The reflected
string-enum ints (label_type, label_membership_type) stay bare-string and are
still stripped, which is why relaxNulls can't just union all integers.

The yamlls faithfulness test could finalize on a premature empty diagnostic set
and let an invalid fixture pass. diagnose now takes the caller's wantErrors
expectation and, when errors are expected, waits for a set that actually has
errors instead of finalizing on the first (often empty) publish.
custom_host_vitals is a valid top-level gitops key (spec.GitOps / topKeys)
that the hand-written GitOpsSpec was missing, so the closed root schema
rejected a config fleetctl applies cleanly. Add it, using the gitops input
type spec.GitOpsCustomHostVital.

Add TestControlsKeysCoverSpec, which fails when spec.GitOpsControls gains a
controls key that ControlsWithTypes hasn't mirrored, the drift that hid
name_template. Root-key drift still needs manual vigilance, since topKeys is
unexported.

Rewrite the README to follow Fleet's writing style, add a known-limitations
section, and bring the code comments in line with the writing prefs.
command_line_flags reflected to a bare object, so individual flags got no
completion or unknown-key validation. Type it from the generated osquery CLI
flag struct, closed like config.options, matching fleetctl's strict validation.

The same parse also fixes config.options, which was closed but skipped the
embedded per-OS structs and so falsely rejected the ~74 valid options they add.
One helper now builds both schemas from their generated structs, pulling the
embedded keys up into one flat set.
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.86%. Comparing base (a5cfb70) to head (48a82d6).
⚠️ Report is 53 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #49717      +/-   ##
==========================================
+ Coverage   67.81%   67.86%   +0.04%     
==========================================
  Files        3890     3891       +1     
  Lines      247631   248347     +716     
  Branches    13018    13018              
==========================================
+ Hits       167942   168551     +609     
- Misses      64525    64581      +56     
- Partials    15164    15215      +51     
Flag Coverage Δ
backend 69.28% <ø> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jkatz01
jkatz01 marked this pull request as ready for review July 21, 2026 21:47
@jkatz01
jkatz01 requested a review from a team as a code owner July 21, 2026 21:47
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a Go CLI that generates Fleet GitOps JSON Schema from typed models, Go comments, AST-parsed osquery settings, and GitOps-specific rules. It commits the generated schema, adds valid and invalid YAML fixtures, validates schema invariants and regeneration consistency, and provides an optional YAML language-server integration test using LSP diagnostics.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is informative, but it doesn't follow the required template or include the checklist sections and related issue line. Rewrite the PR description using the repository template, including the Related issue line and the required checklist and testing sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main addition: a GitOps schema generator with IDE integration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jk-experiment-gitops-autocomplete

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tools/gitops-auto-complete/yamlls_test.go (1)

126-146: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

request() silently discards notifications while awaiting a response.

Any message read from c.msgs that isn't the matching response is dropped rather than requeued. This is currently safe only because request() is called once (for initialize) before any didOpen/diagnose call can produce publishDiagnostics notifications. If this client is ever extended to call request() again mid-test (e.g. a hover or completion request while a document is open), any in-flight diagnostics notification would be silently lost, causing the corresponding diagnose() call to hang until its hard timeout.

Routing responses and notifications into separate channels in readLoop (based on the hasMethod/hasID check already performed there) removes the ambiguity entirely:

if _, hasMethod := m["method"]; hasMethod {
    if _, hasID := m["id"]; hasID {
        c.respond(m)
    } else {
        c.notifs <- m
    }
    continue
}
c.resps <- m

request() would then read only from c.resps, and diagnose() only from c.notifs, eliminating the shared-channel discard hazard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/gitops-auto-complete/yamlls_test.go` around lines 126 - 146, Separate
JSON-RPC responses from notifications in the yamllsClient read loop, routing
messages with a method and ID to the response path and method-only messages to
the notification path. Update request() to consume only responses and diagnose()
to consume only notifications, preserving matching by request ID while
preventing unrelated in-flight notifications from being discarded.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tools/gitops-auto-complete/yamlls_test.go`:
- Around line 126-146: Separate JSON-RPC responses from notifications in the
yamllsClient read loop, routing messages with a method and ID to the response
path and method-only messages to the notification path. Update request() to
consume only responses and diagnose() to consume only notifications, preserving
matching by request ID while preventing unrelated in-flight notifications from
being discarded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 33f2ddad-6c0b-45e5-a423-713e65d52b7c

📥 Commits

Reviewing files that changed from the base of the PR and between d942640 and 48a82d6.

⛔ Files ignored due to path filters (2)
  • tools/gitops-auto-complete/README.md is excluded by !**/*.md
  • tools/gitops-auto-complete/go.sum is excluded by !**/*.sum
📒 Files selected for processing (23)
  • tools/gitops-auto-complete/extra_data.go
  • tools/gitops-auto-complete/generated-schema.json
  • tools/gitops-auto-complete/go.mod
  • tools/gitops-auto-complete/main.go
  • tools/gitops-auto-complete/schema_test.go
  • tools/gitops-auto-complete/testdata/invalid/app_store_id_wrong_type.yml
  • tools/gitops-auto-complete/testdata/invalid/appstore_path.yml
  • tools/gitops-auto-complete/testdata/invalid/fma_path.yml
  • tools/gitops-auto-complete/testdata/invalid/label_no_name.yml
  • tools/gitops-auto-complete/testdata/invalid/package_no_source.yml
  • tools/gitops-auto-complete/testdata/invalid/paths_wrong_type.yml
  • tools/gitops-auto-complete/testdata/invalid/policy_no_name.yml
  • tools/gitops-auto-complete/testdata/invalid/report_no_name.yml
  • tools/gitops-auto-complete/testdata/invalid/report_no_query.yml
  • tools/gitops-auto-complete/testdata/invalid/unknown_key.yml
  • tools/gitops-auto-complete/testdata/invalid/url_wrong_type.yml
  • tools/gitops-auto-complete/testdata/invalid/version_wrong_type.yml
  • tools/gitops-auto-complete/testdata/invalid/yara_rules_wrong_shape.yml
  • tools/gitops-auto-complete/testdata/valid/global.yml
  • tools/gitops-auto-complete/testdata/valid/references.yml
  • tools/gitops-auto-complete/testdata/valid/team.yml
  • tools/gitops-auto-complete/types.go
  • tools/gitops-auto-complete/yamlls_test.go

@jkatz01

jkatz01 commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

Related to #32322

@jkatz01
jkatz01 merged commit b99e556 into main Jul 28, 2026
46 of 47 checks passed
@jkatz01
jkatz01 deleted the jk-experiment-gitops-autocomplete branch July 28, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants