Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions cmd/fleetctl/fleetctl/generate_gitops.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -561,15 +575,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]any)["controls"] = controls

// Generate software.
if team != nil {
Expand Down Expand Up @@ -659,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 {
Expand All @@ -681,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).
Expand Down Expand Up @@ -1489,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ agent_options:
orbit: edge
osqueryd: edge
controls:
android_enabled_and_configured: true
android_settings:
certificates:
- certificate_authority_name: DIGIDOO
Expand Down Expand Up @@ -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
Expand Down
Loading