Skip to content

Make most GitOps top-level optional - #41138

Merged
sgress454 merged 14 commits into
mainfrom
sgress454/41012-make-gitops-top-level-optional
Mar 9, 2026
Merged

Make most GitOps top-level optional#41138
sgress454 merged 14 commits into
mainfrom
sgress454/41012-make-gitops-top-level-optional

Conversation

@sgress454

@sgress454 sgress454 commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Related issue: Resolves #41012

Details

This PR makes it allowable to leave out almost all top-level keys from GitOps files. The only required keys are either name: (for a fleet settings file) or org_settings: (for a global settings file). Omitting a key is identical to supplying it with no value.

Checklist for submitter

If some of the following don't apply, delete the relevant line.

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    See Changes files for more information.

Testing

  • Added/updated automated tests
    Updated the "missing all global keys test", and added some new tests to verify that omitting the key was the same as supplying it with an empty value.
  • QA'd all new/changed functionality manually
  1. Ran fleetctl generate-gitops to get a clean set of GitOps yml files
  2. Removed all removable keys from default.yml and ran fleetctl gitops
  3. Ran fleetctl generate-gitops again into a different dir
  4. Ran fleetctl gitops with the original files to get back to original state
  5. Cleared out all now-removable keys and replaced them with empty value (e.g. reports: with nothing under it)
  6. Ran fleetctl generate-gitops again into a third dir
  7. Compared the files from the second and third generate-gitops runs to verify that omitting the key had the same result as supplying it with an empty value
  8. Did the above steps with a fleet (i.e. non-global) .yml file.

Summary by CodeRabbit

Release Notes

  • New Features

    • GitOps files now support omitting top-level configuration keys instead of requiring them to be explicitly set to empty values.
    • org_settings is now required when team name is not specified.
  • Tests

    • Added integration tests validating behavior when omitting top-level keys in global and team-level GitOps configurations.

@sgress454
sgress454 requested a review from a team as a code owner March 6, 2026 16:55
@sgress454
sgress454 marked this pull request as draft March 6, 2026 17:14
@codecov

codecov Bot commented Mar 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.83333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 66.34%. Comparing base (b0d77e4) to head (f90debe).
⚠️ Report is 115 commits behind head on main.

Files with missing lines Patch % Lines
pkg/spec/gitops.go 95.83% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #41138      +/-   ##
==========================================
+ Coverage   66.31%   66.34%   +0.03%     
==========================================
  Files        2469     2471       +2     
  Lines      197782   198135     +353     
  Branches     8781     8781              
==========================================
+ Hits       131154   131450     +296     
- Misses      54761    54785      +24     
- Partials    11867    11900      +33     

☔ View full report in Codecov by Sentry.
📢 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.

@sgress454
sgress454 marked this pull request as ready for review March 6, 2026 17:57
@sgress454

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR introduces a feature allowing most top-level keys in GitOps YAML files to be omitted instead of requiring empty values. The changes modify the GitOps parsing logic to assign null to missing top-level keys, effectively clearing them when absent. The org_settings field remains required for global configurations, while settings is no longer required for team configurations. Tests are updated to validate this behavior, including new integration tests verifying that omitted keys result in cleared state for policies, agent options, controls, and reports.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Make most GitOps top-level optional' accurately summarizes the main change: making most top-level keys in GitOps files optional rather than required.
Description check ✅ Passed The description covers the main change, references the related issue #41012, includes a changes file, documents testing (automated and manual QA), but lacks some template sections like database migrations and data validation details.
Linked Issues check ✅ Passed The PR successfully implements the core requirement from #41012: making top-level GitOps fields optional except for 'name' (fleet YAML) and 'org_settings' (global YAML), with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are focused on the stated objective of making top-level GitOps keys optional. Test updates, implementation changes, and new integration tests all align with the PR's scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sgress454/41012-make-gitops-top-level-optional

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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 and usage tips.

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
changes/41012-allow-omitting-top-level-gitops-keys (1)

1-1: Clarify that this is parser behavior, not generator output.

This reads like fleetctl generate-gitops may also start omitting empty keys. I’d make it explicit that the parser now accepts omitted top-level keys, while the generator still emits empty fields for discoverability.

Based on learnings: The generate-gitops command in fleetctl should always emit all fields, even when they are empty, so that users can see what configuration options are available for discovery purposes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@changes/41012-allow-omitting-top-level-gitops-keys` at line 1, Update the
release note sentence to explicitly state this is parser behavior: clarify that
the input parser (not the generator) now accepts omitted top-level GitOps keys
and that the fleetctl generate-gitops command continues to emit all top-level
keys (even when empty) for discoverability; reference the parser behavior and
the generate-gitops command by name to avoid confusion.
pkg/spec/gitops_test.go (1)

908-935: Assert the normalized state, not just parse success.

These cases only prove omission is accepted. They won't fail if an omitted key stops clearing state but still parses. Please assert the post-parse shape for at least one global and one team case (AgentOptions, Policies, Queries, TeamSettings, etc.), and consider adding software to the matrix since GitOpsFromFile normalizes it too.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/spec/gitops_test.go` around lines 908 - 935, The tests currently only
check that parsing succeeds for omitted keys; update the cases to assert the
normalized post-parse state for one global case (e.g., the "missing_all_global"
or "missing_reports" entry) and one team case (e.g., "missing_settings" or
"missing_name") by calling GitOpsFromFile and then asserting that the returned
struct has normalized empty/default values for AgentOptions, Policies, Queries
and TeamSettings (and include Software since GitOpsFromFile normalizes it)
rather than merely checking parse success; locate the parsing call to
GitOpsFromFile and add assertions that specific fields (AgentOptions, Policies,
Queries, TeamSettings, Software) are empty/nil/default as appropriate for the
chosen global and team test entries.
cmd/fleetctl/fleetctl/gitops_test.go (2)

231-233: Assert the omitted-controls result before resetting savedAppConfig.

Right now this branch only proves the command returns nil; Line 233 then discards the captured state. If omitting controls started applying a different config than controls:, this test would still pass.

Example assertion to keep this branch meaningful
  _, err = RunAppNoChecks([]string{"gitops", "-f", tmpFile2.Name()})
  require.NoError(t, err)
+ assert.Equal(t, "Foobar", savedAppConfig.OrgInfo.OrgName)
+ assert.Equal(t, "https://example.com", savedAppConfig.ServerSettings.ServerURL)
+ assert.Empty(t, enrolledSecrets)
  savedAppConfig = &fleet.AppConfig{}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/fleetctl/fleetctl/gitops_test.go` around lines 231 - 233, Test currently
only checks RunAppNoChecks returns nil and then immediately resets
savedAppConfig; preserve and assert the captured config before clearing it.
After calling RunAppNoChecks([]string{"gitops", "-f", tmpFile2.Name()}) and
before assigning savedAppConfig = &fleet.AppConfig{}, add an assertion that
savedAppConfig (the value populated by the test harness) matches the expected
structure when controls is omitted—e.g., assert required fields and that
Controls is nil or empty as appropriate—so the branch verifies the actual config
change rather than just a nil error from RunAppNoChecks.

2265-2285: Add observable assertions to this new optional-controls subtest.

Both runs only check that gitops doesn't fail. That makes the test too weak for the PR goal that omitted top-level keys behave the same as explicit empty values.

Mirror the neighboring success assertions here
 		// Dry run, controls is now optional so this should succeed.
 		_ = RunAppForTest(t, []string{
 			"gitops", "-f", globalFileWithoutControlsAndSoftwareKeys.Name(), "-f", teamFileBasic.Name(), "-f",
 			noTeamFileWithoutControls.Name(), "--dry-run",
 		})
+		assert.Equal(t, fleet.AppConfig{}, *savedAppConfig, "AppConfig should be empty")

 		// Real run
 		_ = RunAppForTest(t, []string{
 			"gitops", "-f", globalFileWithoutControlsAndSoftwareKeys.Name(), "-f", teamFileBasic.Name(), "-f",
 			noTeamFileWithoutControls.Name(),
 		})
+		assert.Equal(t, orgName, savedAppConfig.OrgInfo.OrgName)
+		assert.Equal(t, fleetServerURL, savedAppConfig.ServerSettings.ServerURL)
+		assert.Len(t, enrolledSecrets, 1)
+		require.NotNil(t, savedTeam)
+		assert.Equal(t, teamName, savedTeam.Name)
+		require.Len(t, enrolledTeamSecrets, 1)
+		assert.Equal(t, secret, enrolledTeamSecrets[0].Secret)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/fleetctl/fleetctl/gitops_test.go` around lines 2265 - 2285, The subtest
currently only verifies gitops commands don't error by discarding RunAppForTest
results; capture the outputs from both the dry-run and real RunAppForTest calls
(instead of assigning to _), and add the same observable assertions used in the
neighboring successful subtest: assert the output contains the expected success
markers/messages and/or exit status that indicate the operation succeeded (use
the same require.Contains/require.NoError checks as the adjacent test). Target
the RunAppForTest calls that pass
globalFileWithoutControlsAndSoftwareKeys.Name(), teamFileBasic.Name(), and
noTeamFileWithoutControls.Name() and mirror the exact assertions from the
neighboring success test so optional `controls` behavior is validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go`:
- Around line 3865-3886: The test's fullTeamConfig (constructed in
fullTeamConfig using teamName) leaves top-level keys like "software:" empty
while assertions only check settings.features, so the test can miss regressions
that preserve enroll secrets or installers when those keys are omitted; either
populate/seed the omitted sections (e.g., add a non-empty software: block and
any installer/enroller keys you expect) in the Step 1 config and assert their
presence after Step 2, or narrow the test comments and assertions to only
validate settings.features (remove claims about software/enrollers/secrets).
Apply the same fix to the similar block around lines referenced 3917-3952.

---

Nitpick comments:
In `@changes/41012-allow-omitting-top-level-gitops-keys`:
- Line 1: Update the release note sentence to explicitly state this is parser
behavior: clarify that the input parser (not the generator) now accepts omitted
top-level GitOps keys and that the fleetctl generate-gitops command continues to
emit all top-level keys (even when empty) for discoverability; reference the
parser behavior and the generate-gitops command by name to avoid confusion.

In `@cmd/fleetctl/fleetctl/gitops_test.go`:
- Around line 231-233: Test currently only checks RunAppNoChecks returns nil and
then immediately resets savedAppConfig; preserve and assert the captured config
before clearing it. After calling RunAppNoChecks([]string{"gitops", "-f",
tmpFile2.Name()}) and before assigning savedAppConfig = &fleet.AppConfig{}, add
an assertion that savedAppConfig (the value populated by the test harness)
matches the expected structure when controls is omitted—e.g., assert required
fields and that Controls is nil or empty as appropriate—so the branch verifies
the actual config change rather than just a nil error from RunAppNoChecks.
- Around line 2265-2285: The subtest currently only verifies gitops commands
don't error by discarding RunAppForTest results; capture the outputs from both
the dry-run and real RunAppForTest calls (instead of assigning to _), and add
the same observable assertions used in the neighboring successful subtest:
assert the output contains the expected success markers/messages and/or exit
status that indicate the operation succeeded (use the same
require.Contains/require.NoError checks as the adjacent test). Target the
RunAppForTest calls that pass globalFileWithoutControlsAndSoftwareKeys.Name(),
teamFileBasic.Name(), and noTeamFileWithoutControls.Name() and mirror the exact
assertions from the neighboring success test so optional `controls` behavior is
validated.

In `@pkg/spec/gitops_test.go`:
- Around line 908-935: The tests currently only check that parsing succeeds for
omitted keys; update the cases to assert the normalized post-parse state for one
global case (e.g., the "missing_all_global" or "missing_reports" entry) and one
team case (e.g., "missing_settings" or "missing_name") by calling GitOpsFromFile
and then asserting that the returned struct has normalized empty/default values
for AgentOptions, Policies, Queries and TeamSettings (and include Software since
GitOpsFromFile normalizes it) rather than merely checking parse success; locate
the parsing call to GitOpsFromFile and add assertions that specific fields
(AgentOptions, Policies, Queries, TeamSettings, Software) are empty/nil/default
as appropriate for the chosen global and team test entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e0c95626-839a-456a-82e6-0301036c3477

📥 Commits

Reviewing files that changed from the base of the PR and between 891e261 and bc0c4d6.

📒 Files selected for processing (5)
  • changes/41012-allow-omitting-top-level-gitops-keys
  • cmd/fleetctl/fleetctl/gitops_test.go
  • cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go
  • pkg/spec/gitops.go
  • pkg/spec/gitops_test.go

Comment thread cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go Outdated
Comment thread pkg/spec/gitops.go
Comment thread cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go Outdated
Comment thread cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go Outdated
iansltx
iansltx previously approved these changes Mar 6, 2026
@sgress454
sgress454 merged commit 9c4d5ce into main Mar 9, 2026
43 checks passed
@sgress454
sgress454 deleted the sgress454/41012-make-gitops-top-level-optional branch March 9, 2026 13:56
@coderabbitai coderabbitai Bot mentioned this pull request Mar 24, 2026
37 tasks
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.

Treat top-level fields (besides name and org_settings in fleet YAML) as optional

2 participants