From 53824d8173fa19dfc8f16bd837ff7e49c07bcb26 Mon Sep 17 00:00:00 2001 From: Kitarp29 Date: Sun, 9 Aug 2026 00:51:54 +0530 Subject: [PATCH 1/2] Adding the logic to make controls even when it's empty Signed-off-by: Kitarp29 --- cmd/fleetctl/fleetctl/generate_gitops.go | 13 +++++-------- .../generateGitops/test_dir_premium/default.yml | 5 +++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd/fleetctl/fleetctl/generate_gitops.go b/cmd/fleetctl/fleetctl/generate_gitops.go index e448bc86e0c..4d6e0e29cbf 100644 --- a/cmd/fleetctl/fleetctl/generate_gitops.go +++ b/cmd/fleetctl/fleetctl/generate_gitops.go @@ -561,15 +561,12 @@ func (cmd *GenerateGitopsCommand) Run() error { } // Generate controls. - // Only do this on the global team if we're on the free tier. - if teamToProcess.ID != nil || !cmd.AppConfig.License.IsPremium() { - controls, err := cmd.generateControls(teamToProcess.ID, teamFileName, &mdmConfig) - if err != nil { - fmt.Fprintf(cmd.CLI.App.ErrWriter, "Error generating controls for %s: %s\n", teamFileName, err) - return ErrGeneric - } - cmd.FilesToWrite[fileName].(map[string]interface{})["controls"] = controls + controls, err := cmd.generateControls(teamToProcess.ID, teamFileName, &mdmConfig) + if err != nil { + fmt.Fprintf(cmd.CLI.App.ErrWriter, "Error generating controls for %s: %s\n", teamFileName, err) + return ErrGeneric } + cmd.FilesToWrite[fileName].(map[string]interface{})["controls"] = controls // Generate software. if team != nil { diff --git a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml index 86a55378ca3..13ce3d86ff3 100644 --- a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml +++ b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml @@ -253,3 +253,8 @@ reports: observer_can_run: false platform: darwin query: SELECT * FROM users; +controls: + windows_enabled_and_configured: true + android_enabled_and_configured: false + windows_migration_enabled: false + enable_turn_on_windows_mdm_manually: false From 94b69fba7064fadad2c662495082a8f8a2433aad Mon Sep 17 00:00:00 2001 From: Kitarp29 Date: Sun, 9 Aug 2026 02:40:40 +0530 Subject: [PATCH 2/2] Fix GitOps controls generation Signed-off-by: Kitarp29 --- cmd/fleetctl/fleetctl/generate_gitops.go | 32 +++++++--- .../test_dir_premium/default.yml | 59 +++++++++++++++++-- .../fleets/team-a-thumbsup.yml | 2 - 3 files changed, 77 insertions(+), 16 deletions(-) diff --git a/cmd/fleetctl/fleetctl/generate_gitops.go b/cmd/fleetctl/fleetctl/generate_gitops.go index 4d6e0e29cbf..d08a7049525 100644 --- a/cmd/fleetctl/fleetctl/generate_gitops.go +++ b/cmd/fleetctl/fleetctl/generate_gitops.go @@ -278,6 +278,20 @@ type GenerateGitopsCommand struct { ScriptList map[uint]string } +var ( + emptyVal = regexp.MustCompile(`(?m):\s*(null|""|\[\]|\{\})\s*$`) + emptyControls = regexp.MustCompile(`(?m)^controls:\s*\{\}\s*$`) +) + +func replaceEmptyGitOpsValues(b []byte) []byte { + // Preserve an empty controls map: GitOps requires controls to be an object, + // whereas the generic empty-value rewrite would turn it into YAML null. + b = emptyControls.ReplaceAll(b, []byte("controls: ___GITOPS_EMPTY_CONTROLS___")) + // Replace any other empty values with a blank. + b = emptyVal.ReplaceAll(b, []byte(":")) + return bytes.ReplaceAll(b, []byte("controls: ___GITOPS_EMPTY_CONTROLS___"), []byte("controls: {}")) +} + func generateGitopsCommand() *cli.Command { return &cli.Command{ Name: "generate-gitops", @@ -566,7 +580,7 @@ func (cmd *GenerateGitopsCommand) Run() error { fmt.Fprintf(cmd.CLI.App.ErrWriter, "Error generating controls for %s: %s\n", teamFileName, err) return ErrGeneric } - cmd.FilesToWrite[fileName].(map[string]interface{})["controls"] = controls + cmd.FilesToWrite[fileName].(map[string]any)["controls"] = controls // Generate software. if team != nil { @@ -656,7 +670,6 @@ func (cmd *GenerateGitopsCommand) Run() error { return nil } - emptyVal := regexp.MustCompile(`(?m):\s*(null|""|\[\]|\{\})\s*$`) softwareVersion := regexp.MustCompile(`(?m)^([ \t]+version: )([^"\n].*)$`) // Add comments to the result. for path, fileToWrite := range cmd.FilesToWrite { @@ -678,8 +691,7 @@ func (cmd *GenerateGitopsCommand) Run() error { ) } } - // Replace any empty values with a blank. - b = emptyVal.ReplaceAll(b, []byte(":")) + b = replaceEmptyGitOpsValues(b) // Unescape any unicode chars added by the YAML marshaler. b = unescapeUnicodeU8(b) // Keep software versions quoted so YAML treats them as strings (e.g. "10.0" must not become a float). @@ -1486,12 +1498,14 @@ func (cmd *GenerateGitopsCommand) generateControls(teamId *uint, teamName string }) } } - if cmd.AppConfig.MDM.WindowsEnabledAndConfigured { - result["windows_enabled_and_configured"] = cmd.AppConfig.MDM.WindowsEnabledAndConfigured - } + if teamId == nil || *teamId == 0 { + if cmd.AppConfig.MDM.WindowsEnabledAndConfigured { + result["windows_enabled_and_configured"] = cmd.AppConfig.MDM.WindowsEnabledAndConfigured + } - if cmd.AppConfig.MDM.AndroidEnabledAndConfigured { - result["android_enabled_and_configured"] = cmd.AppConfig.MDM.AndroidEnabledAndConfigured + if cmd.AppConfig.MDM.AndroidEnabledAndConfigured { + result["android_enabled_and_configured"] = cmd.AppConfig.MDM.AndroidEnabledAndConfigured + } } if teamId != nil && cmd.AppConfig.MDM.EnabledAndConfigured { diff --git a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml index 13ce3d86ff3..b4852890138 100644 --- a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml +++ b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/default.yml @@ -12,6 +12,60 @@ agent_options: logger_tls_endpoint: /api/osquery/log logger_tls_period: 10 pack_delimiter: / +controls: + android_enabled_and_configured: true + android_settings: + configuration_profiles: + - path: ./lib/profiles/global-android-profile.json + apple_require_hardware_attestation: false + apple_settings: + configuration_profiles: + - labels_include_all: + - Label A + - Label B + path: ./lib/profiles/global-macos-mobileconfig-profile.mobileconfig + - labels_exclude_any: + - Label C + path: ./lib/profiles/global-macos-json-profile.json + enable_disk_encryption: true + enable_recovery_lock_password: false + enable_turn_on_windows_mdm_manually: false + ios_updates: + deadline: "2025-12-31" + deadline_days: + minimum_version: "18.1" + update_new_hosts: + ipados_updates: + deadline: "2026-12-31" + deadline_days: + minimum_version: "18.2" + update_new_hosts: + macos_migration: + enable: true + mode: voluntary + webhook_url: https://some-macos-migration-webhook-url.com + macos_updates: + deadline: "2024-12-31" + deadline_days: + minimum_version: "15.1" + update_new_hosts: true + name_template: No team Mac $FLEET_VAR_HOST_UUID + windows_enabled_and_configured: true + windows_entra_client_ids: + - 7c1de9aa-9b2c-4d3e-8f10-2233445566aa + windows_entra_tenant_ids: + - 5b84b6dd-d257-415e-b8b4-0240666ba4d4 + - 9d30f55f-d117-4574-acf0-ff593e3e06e3 + windows_migration_enabled: true + windows_require_bitlocker_pin: false + windows_settings: + configuration_profiles: + - labels_include_any: + - Label D + path: ./lib/profiles/global-windows-profile.xml + windows_updates: + deadline_days: 5 + grace_period_days: 2 custom_host_vitals: - name: Asset tag - name: Department @@ -253,8 +307,3 @@ reports: observer_can_run: false platform: darwin query: SELECT * FROM users; -controls: - windows_enabled_and_configured: true - android_enabled_and_configured: false - windows_migration_enabled: false - enable_turn_on_windows_mdm_manually: false diff --git a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/fleets/team-a-thumbsup.yml b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/fleets/team-a-thumbsup.yml index 13f40022dce..d3d11075e24 100644 --- a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/fleets/team-a-thumbsup.yml +++ b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/fleets/team-a-thumbsup.yml @@ -17,7 +17,6 @@ agent_options: orbit: edge osqueryd: edge controls: - android_enabled_and_configured: true android_settings: certificates: - certificate_authority_name: DIGIDOO @@ -47,7 +46,6 @@ controls: name_template: iPad $FLEET_VAR_HOST_HARDWARE_SERIAL scripts: - path: "../lib/team-a-👍/scripts/Script B.ps1" - windows_enabled_and_configured: true windows_require_bitlocker_pin: false windows_updates: deadline_days: 95