Skip to content

fleetctl/generate-gitops: warn on missing MaintainedApp instead of aborting#43837

Open
SAY-5 wants to merge 1 commit intofleetdm:mainfrom
SAY-5:fix/generate-gitops-maintained-app-notfound-43770
Open

fleetctl/generate-gitops: warn on missing MaintainedApp instead of aborting#43837
SAY-5 wants to merge 1 commit intofleetdm:mainfrom
SAY-5:fix/generate-gitops-maintained-app-notfound-43770

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 21, 2026

Summary

Fixes #43770.

When a patch-software policy references a MaintainedApp id that is no longer in the datastore (the policy was authored before the app got cleaned up), generatePolicies returns the Resource Not Found: MaintainedApp was not found in the datastore error straight up to the top-level command. That kills the whole fleetctl generate-gitops export for every team - not just the team with the stale reference - and no files are produced. The error message doesn't name the offending policy either, so operators have no way to identify what to clean up.

Fix

Check for fleet.IsNotFound explicitly in the PatchSoftware branch:

  • Log a per-policy warning that names the policy and the unresolved maintained-app id
  • Omit fleet_maintained_app_slug from the generated spec for that policy
  • Keep processing the remaining policies and teams

Any other error still bubbles up unchanged so genuine datastore failures don't silently mask data loss.

Test plan

  • go build ./cmd/fleetctl/fleetctl/
  • go test ./cmd/fleetctl/fleetctl/ -run "TestGenerateGitops|TestPolicies|TestGitops" -count=1 (all pass)
  • Manually pointed the generator at a fixture with a stale MaintainedAppID and verified the export completes with a warning line on stderr instead of aborting

Added the change file under changes/43770-generate-gitops-missing-maintained-app.

Summary by CodeRabbit

  • Bug Fixes

    • fleetctl generate-gitops now warns and continues when encountering policies referencing missing maintained apps, instead of aborting the export.
  • Documentation

    • Updated documentation to reflect the new runtime behavior.

…orting

When a patch-software policy references a maintained app id that
is no longer in the datastore (the policy was authored before the
app got cleaned up), generatePolicies returned the `Resource Not
Found: MaintainedApp was not found in the datastore` error
straight up to the top-level command, killing the whole
`fleetctl generate-gitops` export for every team - not just the
team with the stale reference. No files are produced and the
error message doesn't identify the offending policy (fleetdm#43770).

Check for fleet.IsNotFound explicitly: log a per-policy warning
that names the policy and the unresolved maintained-app id, omit
the fleet_maintained_app_slug field from the generated spec, and
keep processing. Any other error still bubbles up unchanged so
genuine datastore failures don't silently mask data loss.

Signed-off-by: SAY-5 <[email protected]>

Fixes fleetdm#43770
@SAY-5 SAY-5 requested a review from a team as a code owner April 21, 2026 06:30
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 21, 2026

Walkthrough

The pull request modifies fleetctl generate-gitops to handle missing MaintainedApp references in policies more gracefully. Updated documentation and code changes in generate_gitops.go now allow the command to emit a warning and continue exporting when a patch-software policy references a MaintainedApp that no longer exists in the datastore. The fleet_maintained_app_slug field is omitted for affected policies. Other error types are still returned immediately, halting the export.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: handling missing MaintainedApp references in fleetctl generate-gitops by warning instead of aborting.
Description check ✅ Passed The PR description clearly explains the problem, fix approach, and testing performed. All required checklist items are addressed (changes file added, testing completed).
Linked Issues check ✅ Passed The code changes fully address all objectives from issue #43770: graceful handling of missing MaintainedApp references, continued export processing, warning output with policy identification, and proper error propagation [#43770].
Out of Scope Changes check ✅ Passed All changes are directly related to fixing issue #43770: the changes file documents the behavior change, and the code modification handles the specific not-found case for MaintainedApp references during policy export.
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 unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/fleetctl/generate_gitops.go`:
- Around line 1515-1528: In the switch handling the lookup of the MaintainedApp
(the block that currently sets policySpec["fleet_maintained_app_slug"] when err
== nil and emits a warning on fleet.IsNotFound(err)), always emit the
fleet_maintained_app_slug key even on the not-found branch: set
policySpec["fleet_maintained_app_slug"] to an explicit empty string (or
placeholder) inside the fleet.IsNotFound(err) case, keep the existing warning to
ErrWriter, and retain the default branch to return other errors; this ensures
policySpec contains the key for discovery while preserving current error
handling for fma lookups (referencing policySpec, fleet_maintained_app_slug,
fma, and cachedSWTitle.MaintainedAppID).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3ee8507e-ecc9-47e4-96d2-df947d5f4d9e

📥 Commits

Reviewing files that changed from the base of the PR and between 43a7aea and 3be0359.

📒 Files selected for processing (2)
  • changes/43770-generate-gitops-missing-maintained-app
  • cmd/fleetctl/fleetctl/generate_gitops.go

Comment on lines +1515 to 1528
switch {
case err == nil:
policySpec["fleet_maintained_app_slug"] = fma.Slug
case fleet.IsNotFound(err):
// The policy references a MaintainedApp that no longer exists
// (e.g. deleted after the policy was authored). Warn and keep
// generating the rest of the export instead of aborting the
// whole `fleetctl generate-gitops` run (#43770); the operator
// can clean the stale reference up post-export.
fmt.Fprintf(cmd.CLI.App.ErrWriter,
"Warning: policy %q references maintained app %d which is no longer in the datastore; omitting fleet_maintained_app_slug.\n",
policy.Name, cachedSWTitle.MaintainedAppID)
default:
return nil, err
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.

⚠️ Potential issue | 🟠 Major

Keep emitting fleet_maintained_app_slug in the stale-reference case.

The new not-found branch avoids aborting, but omitting the field hides the required GitOps key from the generated policy. The provided context notes fleet_maintained_app_slug is part of PolicySpec in server/fleet/policies.go:481-485 and required by patch-policy validation, so leaving a TODO/blank field is safer for discoverability and follow-up fixes.

Proposed adjustment
 		switch {
 		case err == nil:
 			policySpec["fleet_maintained_app_slug"] = fma.Slug
 		case fleet.IsNotFound(err):
 			// The policy references a MaintainedApp that no longer exists
 			// (e.g. deleted after the policy was authored). Warn and keep
 			// generating the rest of the export instead of aborting the
 			// whole `fleetctl generate-gitops` run (`#43770`); the operator
 			// can clean the stale reference up post-export.
+			policySpec["fleet_maintained_app_slug"] = cmd.AddComment(filePath,
+				fmt.Sprintf("TODO: Resolve missing Fleet-maintained app %d for policy %q", cachedSWTitle.MaintainedAppID, policy.Name))
 			fmt.Fprintf(cmd.CLI.App.ErrWriter,
-				"Warning: policy %q references maintained app %d which is no longer in the datastore; omitting fleet_maintained_app_slug.\n",
+				"Warning: policy %q references maintained app %d which is no longer in the datastore; leaving fleet_maintained_app_slug as a TODO.\n",
 				policy.Name, cachedSWTitle.MaintainedAppID)
 		default:
 			return nil, err
 		}

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.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
switch {
case err == nil:
policySpec["fleet_maintained_app_slug"] = fma.Slug
case fleet.IsNotFound(err):
// The policy references a MaintainedApp that no longer exists
// (e.g. deleted after the policy was authored). Warn and keep
// generating the rest of the export instead of aborting the
// whole `fleetctl generate-gitops` run (#43770); the operator
// can clean the stale reference up post-export.
fmt.Fprintf(cmd.CLI.App.ErrWriter,
"Warning: policy %q references maintained app %d which is no longer in the datastore; omitting fleet_maintained_app_slug.\n",
policy.Name, cachedSWTitle.MaintainedAppID)
default:
return nil, err
switch {
case err == nil:
policySpec["fleet_maintained_app_slug"] = fma.Slug
case fleet.IsNotFound(err):
// The policy references a MaintainedApp that no longer exists
// (e.g. deleted after the policy was authored). Warn and keep
// generating the rest of the export instead of aborting the
// whole `fleetctl generate-gitops` run (`#43770`); the operator
// can clean the stale reference up post-export.
policySpec["fleet_maintained_app_slug"] = cmd.AddComment(filePath,
fmt.Sprintf("TODO: Resolve missing Fleet-maintained app %d for policy %q", cachedSWTitle.MaintainedAppID, policy.Name))
fmt.Fprintf(cmd.CLI.App.ErrWriter,
"Warning: policy %q references maintained app %d which is no longer in the datastore; leaving fleet_maintained_app_slug as a TODO.\n",
policy.Name, cachedSWTitle.MaintainedAppID)
default:
return nil, err
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/fleetctl/fleetctl/generate_gitops.go` around lines 1515 - 1528, In the
switch handling the lookup of the MaintainedApp (the block that currently sets
policySpec["fleet_maintained_app_slug"] when err == nil and emits a warning on
fleet.IsNotFound(err)), always emit the fleet_maintained_app_slug key even on
the not-found branch: set policySpec["fleet_maintained_app_slug"] to an explicit
empty string (or placeholder) inside the fleet.IsNotFound(err) case, keep the
existing warning to ErrWriter, and retain the default branch to return other
errors; this ensures policySpec contains the key for discovery while preserving
current error handling for fma lookups (referencing policySpec,
fleet_maintained_app_slug, fma, and cachedSWTitle.MaintainedAppID).

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 37.50000% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.91%. Comparing base (43a7aea) to head (3be0359).

Files with missing lines Patch % Lines
cmd/fleetctl/fleetctl/generate_gitops.go 37.50% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #43837      +/-   ##
==========================================
- Coverage   66.91%   66.91%   -0.01%     
==========================================
  Files        2601     2601              
  Lines      208982   208998      +16     
  Branches     9191     9191              
==========================================
+ Hits       139842   139848       +6     
- Misses      56398    56408      +10     
  Partials    12742    12742              
Flag Coverage Δ
backend 68.69% <37.50%> (-0.01%) ⬇️

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

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

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.

fleetctl generate-gitops aborts entire export on unresolvable MaintainedApp lookup

1 participant