Skip to content

Conversation

@nulmete
Copy link
Member

@nulmete nulmete commented Jan 5, 2026

Related issue: Resolves #35457

Checklist for submitter

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

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements)

  • If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes

Testing

fleetctl generate-gitops

UI

Screenshot 2026-01-07 at 1 14 45 PM

Generated YAML

Screenshot 2026-01-07 at 1 15 23 PM

fleetctl gitops

Source YAML

I set the start_time to 18:30 and end_time to 19:30 for the first app

Screenshot 2026-01-07 at 1 18 33 PM

After the command ran, verified both on the UI and DB that the new values were set

Screenshot 2026-01-07 at 1 18 56 PM Screenshot 2026-01-07 at 1 19 15 PM

New Fleet configuration settings

  • Setting(s) is/are explicitly excluded from GitOps

If you didn't check the box above, follow this checklist for GitOps-enabled settings:

  • Verified that the setting is exported via fleetctl generate-gitops
  • Verified the setting is documented in a separate PR to the GitOps documentation:
    auto_update_enabled: true
    auto_update_window_start: "00:00"
    auto_update_window_end: "04:00"
  • Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional)
  • Verified that any relevant UI is disabled when GitOps mode is enabled

fleetd/orbit/Fleet Desktop

  • Verified compatibility with the latest released version of Fleet (see Must rule)
  • If the change applies to only one platform, confirmed that runtime.GOOS is used as needed to isolate changes
  • Verified that fleetd runs on macOS, Linux and Windows
  • Verified auto-update works from the released version of component to the new version (see tools/tuf/test)

@nulmete nulmete changed the title Export GitOps config for scheduled auto updates settings WIP: GitOps support for scheduled auto updates settings Jan 5, 2026
@codecov
Copy link

codecov bot commented Jan 5, 2026

Codecov Report

❌ Patch coverage is 93.29268% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.98%. Comparing base (799a9fd) to head (d97f5fe).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
ee/server/service/vpp.go 90.83% 6 Missing and 5 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #37851      +/-   ##
==========================================
+ Coverage   65.87%   65.98%   +0.10%     
==========================================
  Files        2392     2372      -20     
  Lines      190799   189476    -1323     
  Branches     8364     7940     -424     
==========================================
- Hits       125697   125021     -676     
+ Misses      53685    53056     -629     
+ Partials    11417    11399      -18     
Flag Coverage Δ
backend 67.72% <93.29%> (+<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.

@lucasmrod lucasmrod self-assigned this Jan 6, 2026
AutoUpdateStartTime: app.AutoUpdateStartTime,
AutoUpdateEndTime: app.AutoUpdateEndTime,
}
if err := svc.ds.UpdateSoftwareTitleAutoUpdateConfig(ctx, titleID, tmID, cfg); err != nil {
Copy link
Member Author

@nulmete nulmete Jan 7, 2026

Choose a reason for hiding this comment

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

This is doing a query for each app, which I don't think is the end of the world if the number of apps is not that big.
Perhaps we could have UpdateSoftwareTitleAutoUpdateConfigs (plural) and we can pass a list of apps to have their auto update properties updated.

Also, I don't see a tx being used in this BatchAssociateVPPApps function and there are several mutative calls to the DB. Should we introduce a tx here?

Copy link
Member

Choose a reason for hiding this comment

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

Perhaps we could have UpdateSoftwareTitleAutoUpdateConfigs (plural) and we can pass a list of apps to have their auto update properties updated.

IMO something to optimize later if really need be.

Also, I don't see a tx being used in this BatchAssociateVPPApps function and there are several mutative calls to the DB. Should we introduce a tx here?

txs would generally go within fleet.Datastore methods not here.
Something to iterate for sure (not as part of this PR :)

@nulmete nulmete changed the title WIP: GitOps support for scheduled auto updates settings GitOps support for scheduled auto updates settings Jan 7, 2026
Comment on lines 334 to 336
if app.AutoUpdateEnabled == nil && app.AutoUpdateStartTime == nil && app.AutoUpdateEndTime == nil {
continue
}
Copy link
Member

Choose a reason for hiding this comment

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

GitOps works by applying what's set, and removing what's not set.

We should support the following scenario:

  1. Set these settings on a VPP app.
  2. Apply GitOps.
  3. Check on the UI that the update schedule config is set.
  4. Remove the three settings from the VPP app.
  5. Apply GitOps.
  6. Check on the UI that the update schedule config all unset.

Let me know if it makes sense.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense, I'll update

Copy link
Member

@lucasmrod lucasmrod left a comment

Choose a reason for hiding this comment

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

Double checking the following

I set (see typo in auto_update_enable, should be auto_update_enabled):

  - app_store_id: "302584613"
    platform: ipados
    auto_update_enable: true
    auto_update_start_time: '00:00'
    auto_update_end_time: '00:30'

I got:

Error: applying app store apps for team: "📱🏢 Company-owned mobile devices": POST /api/latest/fleet/software/app_store_apps/batch received status 422 Validation Failed: Error 1048 (23000): Column 'enabled' cannot be null

Should probably set auto_update_enabled: false on the database, right?
Not the best UX, because the user won't notice the typo but it aligns to what we expect from GitOps.

}
titleID, ok := appStoreIDToTitleID[app.VPPAppID.String()]
if !ok {
continue
Copy link
Member

Choose a reason for hiding this comment

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

Let's log an error if this is the case (because it should not happen AFAICS).

Suggested change
continue
level.Error(svc.logger).Log("msg", "software title missing for vpp app", "adam_id", app.VPPAppID.String())
continue

Copy link
Member

@lucasmrod lucasmrod left a comment

Choose a reason for hiding this comment

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

LGTM. Left some comments/questions.

@nulmete
Copy link
Member Author

nulmete commented Jan 7, 2026

@lucasmrod I addressed the two cases you mentioned:

  1. This scenario:
Set these settings on a VPP app.
Apply GitOps.
Check on the UI that the update schedule config is set.
Remove the three settings from the VPP app.
Apply GitOps.
Check on the UI that the update schedule config all unset.
  1. Set auto_update_enabled: false if there's a typo in the YAML, e.g. auto_update_enable instead of auto_update_enabled.
Screen.Recording.2026-01-07.at.3.56.37.PM.mov

Copy link
Member

@lucasmrod lucasmrod left a comment

Choose a reason for hiding this comment

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

Left two comments.

default:
t.Fatalf("unexpected source: %s", foundTitle.Source)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Test looks great.

At the end of it, could you apply with:

    - app_store_id: "2"
      platform: ipados
      self_service: false

(Without the new fields)

And check that the fields are not set for that title anymore?

Copy link
Member

Choose a reason for hiding this comment

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

Probably enough to check that enabled is false in the DB.

Copy link
Member Author

Choose a reason for hiding this comment

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

In this case, should we delete the entry from software_update_schedules?

Let's say we do the following:

  1. Apply GitOps with
- app_store_id: "1016366447"
    auto_update_enabled: true
    auto_update_end_time: "19:30"
    auto_update_start_time: "18:30"
    platform: ios

an entry is created in software_update_schedules the values above

  1. Reapply GitOps with
- app_store_id: "1016366447"
    platform: ios

Currently, the end state is that the entry in software_update_schedules is still there but with auto_update_enabled = false, and the times are not modified. Is this OK or should we be stricter and delete the entry?

Copy link
Member

Choose a reason for hiding this comment

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

Am ok if this iteration just sets the false in the DB for enabled.


// Validate auto-update window
schedule := fleet.SoftwareAutoUpdateSchedule{SoftwareAutoUpdateConfig: cfg}
if err := schedule.WindowIsValid(); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

It seems we can apply invalid settings (when auto_update_enabled: false):

  - app_store_id: "302584613"
    platform: ipados
    auto_update_enabled: false
    auto_update_start_time: '00:00'
    auto_update_end_time: '00:30'

Seems because scheduled.WindowIsValid() is a no-op when app.AutoUpdateEnabled != nil || !*app.AutoUpdateEnabled.

Could we instead move the initial if in schedule.WindowIsValid() to outside the method where it's currently called in main? (That way WindowIsValid does indeed check the window validity.)

I'm all ears.

Copy link
Member Author

@nulmete nulmete Jan 8, 2026

Choose a reason for hiding this comment

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

@lucasmrod are you suggesting to get rid of:

if s.AutoUpdateEnabled == nil || !*s.AutoUpdateEnabled {
	return nil
}

at the top of WindowIsValid()?

If that's the case, I think we'd still hit the "Start and end time must both be set" error when auto_update_enabled: false and no times are provided.

... Or only call WindowIsValid() in the callers only if auto_update_enabled = true?
Note that we have 3 places where we perform this call

Copy link
Member

Choose a reason for hiding this comment

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

Yes, and add such if in the current use of WindowIsValid in main.

cc @sgress454

lucasmrod
lucasmrod previously approved these changes Jan 9, 2026
@nulmete nulmete merged commit 227bcdf into main Jan 9, 2026
69 of 71 checks passed
@nulmete nulmete deleted the nulmete/schedule-auto-updates-gitops branch January 9, 2026 15:17
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.

iOS/iPad VPP auto-updates: GitOps

3 participants