Skip to content

Fix fleetctl get fleets to use source of truth (DB) for software - #46480

Merged
lucasmrod merged 12 commits into
mainfrom
44970-fix-get-fleets
Jun 1, 2026
Merged

Fix fleetctl get fleets to use source of truth (DB) for software#46480
lucasmrod merged 12 commits into
mainfrom
44970-fix-get-fleets

Conversation

@lucasmrod

@lucasmrod lucasmrod commented May 29, 2026

Copy link
Copy Markdown
Member

Resolves #44970 (1/2).


  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • Bug Fixes
    • fleetctl get fleets / get teams now display software and setup experience from authoritative software endpoints.
    • Preserve literal setup_experience fields (avoid erroneous macos_setup renames) when applying and when transmitting JSON for software entries.
  • Tests
    • Added regression tests and test helpers to ensure software/setup_experience are sourced correctly and to prevent nil panics in related tests.

Copilot AI review requested due to automatic review settings May 29, 2026 18:57
@lucasmrod
lucasmrod requested a review from a team as a code owner May 29, 2026 18:57

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Copilot AI 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.

Pull request overview

This PR fixes fleetctl get fleets / fleetctl get teams YAML/JSON export so the software section (notably per-item setup_experience) is derived from the authoritative software + setup experience endpoints, instead of the potentially stale team config. This addresses issue #44970 where exported YAML could contain setup_experience: null for apps that are actually configured for setup experience.

Changes:

  • Update fleetctl get fleets/teams to fetch per-team software (packages, Fleet-maintained apps, VPP apps) and setup experience membership from source-of-truth endpoints when running against a Premium server.
  • Add a regression test ensuring setup_experience: true is emitted for an app that is in setup experience.
  • Update existing tests to stub the newly-used software endpoints where those tests don’t care about software output.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
cmd/fleetctl/fleetctl/get.go Build team software spec from software titles + setup experience endpoints (Premium-only) when printing YAML/JSON.
cmd/fleetctl/fleetctl/get_test.go Add software regression test and add mocks for software endpoints in unrelated tests.
cmd/fleetctl/fleetctl/apply_test.go Stub software endpoints in tests impacted by the new get fleets behavior.
cmd/fleetctl/fleetctl/apply_deprecated_test.go Stub software endpoints in tests impacted by the new get fleets behavior.
changes/44970-get-fleets-setup-experience Add release note for the user-visible behavior change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/fleetctl/fleetctl/get_test.go
Comment thread cmd/fleetctl/fleetctl/get_test.go
Comment thread cmd/fleetctl/fleetctl/get_test.go
Comment thread cmd/fleetctl/fleetctl/get_test.go
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 78a8f975-e0d5-4aeb-8c9c-bdc5a9717f50

📥 Commits

Reviewing files that changed from the base of the PR and between 259dadd and a7c3a14.

📒 Files selected for processing (3)
  • changes/44970-fix-apply
  • server/platform/endpointer/json_key_rewriter.go
  • server/platform/endpointer/json_key_rewriter_test.go
✅ Files skipped from review due to trivial changes (1)
  • changes/44970-fix-apply

Walkthrough

This PR fixes a bug where fleetctl get fleets --yaml returned setup_experience: null by sourcing software sections and setup_experience flags from the software titles and setup-experience endpoints (the source of truth) instead of stale team config. The CLI now computes a per-team SoftwareSpec (attached to TeamSpec for YAML or team.Config for non-YAML), JSON key rewriting is made to skip the software subtree to avoid alias collisions, tests were added/updated (including a regression test), and changelogs were updated.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: fixing fleetctl get fleets to use the database as the authoritative source for software data.
Description check ✅ Passed The description includes the related issue number (#44970), confirms changes file added, tests added/updated, and manual QA performed—meeting all key checklist items.
Linked Issues check ✅ Passed The PR directly addresses #44970 by updating fleetctl get fleets to source software data from the database and fixing the JSON key rewriter to prevent setup_experience from being incorrectly renamed.
Out of Scope Changes check ✅ Passed All code changes align with the objective of fixing fleetctl get fleets to use the database as the source of truth for software and fixing the key rewriter—no out-of-scope changes detected.

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

✨ 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 44970-fix-get-fleets

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.

@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.02878% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.85%. Comparing base (032246d) to head (a7c3a14).
⚠️ Report is 34 commits behind head on main.

Files with missing lines Patch % Lines
cmd/fleetctl/fleetctl/get.go 60.00% 33 Missing and 11 partials ⚠️
server/platform/endpointer/json_key_rewriter.go 79.31% 3 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #46480      +/-   ##
==========================================
+ Coverage   66.81%   66.85%   +0.04%     
==========================================
  Files        2804     2804              
  Lines      223574   223642      +68     
  Branches    11481    11400      -81     
==========================================
+ Hits       149379   149520     +141     
+ Misses      60639    60534     -105     
- Partials    13556    13588      +32     
Flag Coverage Δ
backend 68.58% <64.02%> (+0.05%) ⬆️
backend-activity 86.35% <ø> (ø)

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.

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

Why do we need to check the license when teams are a premium-only feature anyway?

@lucasmrod

Copy link
Copy Markdown
Member Author

Why do we need to check the license when teams are a premium-only feature anyway?

You are right. No need. (It fails earlier in the list teams request.)
Removed.

@lucasmrod
lucasmrod requested a review from sgress454 June 1, 2026 12:28

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
cmd/fleetctl/fleetctl/get.go (2)

323-330: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Potential key mismatch for App Store apps may cause setup_experience to be incorrectly omitted.

On line 328, the setup experience map is keyed by app.FullyQualifiedName() from the setup experience endpoint response. However, on line 397, the lookup uses app.VPPAppID.String() from the software title detail response. If these methods return different string formats, App Store apps will fail to match and InstallDuringSetup will remain unset—which is exactly the bug this PR intends to fix.

Run the following to verify the key formats match:

#!/bin/bash
# Find the definition of FullyQualifiedName and VPPAppID.String() to compare their output formats

echo "=== FullyQualifiedName implementation ==="
ast-grep --pattern $'func ($_ $_) FullyQualifiedName() string {
  $$$
}'

echo ""
echo "=== VPPAppID type and String method ==="
rg -nP --type=go -A10 'type VPPAppID'

echo ""
echo "=== VPPAppID String method ==="
ast-grep --pattern $'func ($_ VPPAppID) String() string {
  $$$
}'

Also applies to: 394-411

🤖 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 `@cmd/fleetctl/fleetctl/get.go` around lines 323 - 330, The setupAppsByName map
is populated using app.FullyQualifiedName() in the setup loop but later looked
up with app.VPPAppID.String(), causing mismatches; update the map population in
the loop that iterates setupSoftware so AppStore apps are keyed using the same
identifier used at lookup (use app.VPPAppID.String() when app.VPPAppID is
present, otherwise fall back to FullyQualifiedName()), so the lookup at the
later check (where app.VPPAppID.String() is used) will correctly find entries;
adjust the logic around setupAppsByName and references to
FullyQualifiedName/VPPAppID.String() accordingly.

306-313: ⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Gracefully handle premium-gated software endpoints in getTeamSoftwareSpec

getTeamSoftwareSpec is called for every team and currently fails the whole fleetctl get fleets run if either software endpoint errors. On non-premium deployments, the server explicitly returns fleet.ErrMissingLicense (402) from:

  • server/service/software_titles.go (ListSoftwareTitles when fleet_id/team_id is provided)
  • server/service/setup_experience.go (ListSetupExperienceSoftware)

Catch ErrMissingLicense around ListSoftwareTitles / GetSetupExperienceSoftware and treat it as “no software section” (nil/empty) instead of returning an error.

🤖 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 `@cmd/fleetctl/fleetctl/get.go` around lines 306 - 313, getTeamSoftwareSpec
currently returns an error when ListSoftwareTitles fails, which breaks `fleetctl
get fleets` on non-premium deployments; update getTeamSoftwareSpec to catch
`fleet.ErrMissingLicense` from `client.ListSoftwareTitles` (and likewise for
calls to `client.GetSetupExperienceSoftware` where used) and treat that case as
“no software” by returning nil (or an empty spec) instead of an error;
specifically, wrap the error check after calling `client.ListSoftwareTitles` to
if errors.Is(err, fleet.ErrMissingLicense) { return nil, nil } and apply the
same pattern around `client.GetSetupExperienceSoftware` calls so premium-gated
endpoints degrade to an empty/no software section.
🤖 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.

Outside diff comments:
In `@cmd/fleetctl/fleetctl/get.go`:
- Around line 323-330: The setupAppsByName map is populated using
app.FullyQualifiedName() in the setup loop but later looked up with
app.VPPAppID.String(), causing mismatches; update the map population in the loop
that iterates setupSoftware so AppStore apps are keyed using the same identifier
used at lookup (use app.VPPAppID.String() when app.VPPAppID is present,
otherwise fall back to FullyQualifiedName()), so the lookup at the later check
(where app.VPPAppID.String() is used) will correctly find entries; adjust the
logic around setupAppsByName and references to
FullyQualifiedName/VPPAppID.String() accordingly.
- Around line 306-313: getTeamSoftwareSpec currently returns an error when
ListSoftwareTitles fails, which breaks `fleetctl get fleets` on non-premium
deployments; update getTeamSoftwareSpec to catch `fleet.ErrMissingLicense` from
`client.ListSoftwareTitles` (and likewise for calls to
`client.GetSetupExperienceSoftware` where used) and treat that case as “no
software” by returning nil (or an empty spec) instead of an error; specifically,
wrap the error check after calling `client.ListSoftwareTitles` to if
errors.Is(err, fleet.ErrMissingLicense) { return nil, nil } and apply the same
pattern around `client.GetSetupExperienceSoftware` calls so premium-gated
endpoints degrade to an empty/no software section.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b830bac0-a558-4c3a-9e05-103ba78dfabe

📥 Commits

Reviewing files that changed from the base of the PR and between 4813539 and 259dadd.

📒 Files selected for processing (1)
  • cmd/fleetctl/fleetctl/get.go

)

Resolves #44970 (2/2).

The issue is that in `fleetctl apply` the `setup_experience` field in
software items was being converted to `macos_setup` (which we don't want
because that rename should only happen in MDM).

I tried to make the change as simple as possible and isolated to
`software` (I checked and it seems there are no renames under `software`
spec). Supporting some context aware renaming (or prevention of
renaming) requires a bigger refactor on the rewriter functionality.

- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [X] Added/updated automated tests
- [X] QA'd all new/changed functionality manually

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

I wonder if there's some way we could be leveraging the generate_gitops code for this (assuming it's doing it right). Anything to do with fleetctl get feels close to throwaway code anyway, and we don't want to have to keep maintaining both (for example if we added a new key to the software package spec).

@lucasmrod
lucasmrod merged commit 9032883 into main Jun 1, 2026
49 of 51 checks passed
@lucasmrod
lucasmrod deleted the 44970-fix-get-fleets branch June 1, 2026 14:41
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 get fleets returns setup_experience: null for apps

3 participants