diff --git a/changes/issue-26148-remove-config-settings-when-no-team-removed b/changes/issue-26148-remove-config-settings-when-no-team-removed new file mode 100644 index 0000000000..9d4c4710ea --- /dev/null +++ b/changes/issue-26148-remove-config-settings-when-no-team-removed @@ -0,0 +1 @@ +- remove fleet config no team settings when the no-team.yml file is removed via gitops diff --git a/cmd/fleetctl/gitops.go b/cmd/fleetctl/gitops.go index f60a5d64b8..2af554fde1 100644 --- a/cmd/fleetctl/gitops.go +++ b/cmd/fleetctl/gitops.go @@ -9,6 +9,7 @@ import ( "github.com/fleetdm/fleet/v4/pkg/spec" "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/service" "github.com/urfave/cli/v2" "golang.org/x/text/unicode/norm" @@ -340,6 +341,19 @@ func gitopsCommand() *cli.Command { } } + // we only want to reset the no-team config if the global config was loaded. + // NOTE: noTeamPresent is refering to the "No Team" team. It does not + // mean that other teams are not present. + if globalConfigLoaded && !noTeamPresent { + defaultNoTeamConfig := new(spec.GitOps) + defaultNoTeamConfig.TeamName = ptr.String(fleet.TeamNameNoTeam) + _, err = fleetClient.DoGitOps(c.Context, defaultNoTeamConfig, "no-team.yml", logf, flDryRun, nil, appConfig, + map[string][]fleet.SoftwarePackageResponse{}, map[string][]fleet.VPPAppResponse{}, map[string][]fleet.ScriptResponse{}) + if err != nil { + return err + } + } + if flDryRun { _, _ = fmt.Fprintf(c.App.Writer, "[!] gitops dry run succeeded\n") } else { diff --git a/cmd/fleetctl/gitops_enterprise_integration_test.go b/cmd/fleetctl/gitops_enterprise_integration_test.go index 72faca1aa5..2b4f785b60 100644 --- a/cmd/fleetctl/gitops_enterprise_integration_test.go +++ b/cmd/fleetctl/gitops_enterprise_integration_test.go @@ -405,7 +405,6 @@ team_settings: assert.Equal(t, 0, result) return nil }) - } // TestCAIntegrations enables DigiCert and Custom SCEP CAs via GitOps. @@ -542,7 +541,6 @@ queries: require.NoError(t, err) assert.Empty(t, appConfig.Integrations.DigiCert.Value) assert.Empty(t, appConfig.Integrations.CustomSCEPProxy.Value) - } // TestUnsetConfigurationProfileLabels tests the removal of labels associated with a @@ -814,3 +812,83 @@ team_settings: require.Len(t, meta.LabelsExcludeAny, 0) require.Len(t, meta.LabelsIncludeAny, 0) } + +func (s *enterpriseIntegrationGitopsTestSuite) TestDeletingNoTeamYAML() { + t := s.T() + ctx := context.Background() + + user := s.createGitOpsUser(t) + fleetctlConfig := s.createFleetctlConfig(t, user) + + // Set the required environment variables + t.Setenv("FLEET_URL", s.server.URL) + + // global file setup + const ( + globalTemplate = ` +agent_options: +controls: +org_settings: + server_settings: + server_url: $FLEET_URL + org_info: + org_name: Fleet + secrets: +policies: +queries: +` + ) + + globalFile, err := os.CreateTemp(t.TempDir(), "*.yml") + require.NoError(t, err) + _, err = globalFile.WriteString(globalTemplate) + require.NoError(t, err) + err = globalFile.Close() + require.NoError(t, err) + + // setup script + const testScriptTemplate = `echo "Hello, world!"` + + scriptFile, err := os.CreateTemp(t.TempDir(), "*.sh") + require.NoError(t, err) + _, err = scriptFile.WriteString(testScriptTemplate) + require.NoError(t, err) + err = scriptFile.Close() + require.NoError(t, err) + + // no team file setup + const ( + noTeamTemplate = `name: No team +policies: +controls: + macos_setup: + script: %s +software: +` + ) + + noTeamFile, err := os.CreateTemp(t.TempDir(), "*.yml") + require.NoError(t, err) + _, err = noTeamFile.WriteString(fmt.Sprintf(noTeamTemplate, scriptFile.Name())) + require.NoError(t, err) + err = noTeamFile.Close() + require.NoError(t, err) + noTeamFilePath := filepath.Join(filepath.Dir(noTeamFile.Name()), "no-team.yml") + err = os.Rename(noTeamFile.Name(), noTeamFilePath) + require.NoError(t, err) + + _ = runAppForTest(t, []string{"gitops", "--config", fleetctlConfig.Name(), "-f", globalFile.Name(), "-f", noTeamFilePath, "--dry-run"}) + _ = runAppForTest(t, []string{"gitops", "--config", fleetctlConfig.Name(), "-f", globalFile.Name(), "-f", noTeamFilePath}) + + // Check script existance + _, err = s.ds.GetSetupExperienceScript(ctx, nil) + require.NoError(t, err) + + _ = runAppForTest(t, []string{"gitops", "--config", fleetctlConfig.Name(), "-f", globalFile.Name(), "--dry-run"}) + _ = runAppForTest(t, []string{"gitops", "--config", fleetctlConfig.Name(), "-f", globalFile.Name()}) + + // Check script does not exist + _, err = s.ds.GetSetupExperienceScript(ctx, nil) + var nfe fleet.NotFoundError + require.ErrorAs(t, err, &nfe) +} diff --git a/cmd/fleetctl/gitops_test.go b/cmd/fleetctl/gitops_test.go index b570def680..f9a61f861d 100644 --- a/cmd/fleetctl/gitops_test.go +++ b/cmd/fleetctl/gitops_test.go @@ -115,6 +115,11 @@ func TestGitOpsBasicGlobalFree(t *testing.T) { ds.ListQueriesFunc = func(ctx context.Context, opts fleet.ListQueryOptions) ([]*fleet.Query, int, *fleet.PaginationMetadata, error) { return nil, 0, nil, nil } + ds.ListTeamPoliciesFunc = func( + ctx context.Context, teamID uint, opts fleet.ListOptions, iopts fleet.ListOptions, + ) (teamPolicies []*fleet.Policy, inheritedPolicies []*fleet.Policy, err error) { + return nil, nil, nil + } // Mock appConfig savedAppConfig := &fleet.AppConfig{} @@ -352,6 +357,18 @@ func TestGitOpsBasicGlobalPremium(t *testing.T) { } } + ds.DeleteSetupExperienceScriptFunc = func(ctx context.Context, teamID *uint) error { + return nil + } + ds.ListTeamPoliciesFunc = func( + ctx context.Context, teamID uint, opts fleet.ListOptions, iopts fleet.ListOptions, + ) (teamPolicies []*fleet.Policy, inheritedPolicies []*fleet.Policy, err error) { + return nil, nil, nil + } + ds.SetTeamVPPAppsFunc = func(ctx context.Context, teamID *uint, adamIDs []fleet.VPPAppTeam) error { + return nil + } + tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml") require.NoError(t, err) @@ -720,6 +737,11 @@ func TestGitOpsFullGlobal(t *testing.T) { policy.ID = 1 policy.Name = "Policy to delete" policyDeleted := false + ds.ListTeamPoliciesFunc = func( + ctx context.Context, teamID uint, opts fleet.ListOptions, iopts fleet.ListOptions, + ) (teamPolicies []*fleet.Policy, inheritedPolicies []*fleet.Policy, err error) { + return nil, nil, nil + } ds.ListGlobalPoliciesFunc = func(ctx context.Context, opts fleet.ListOptions) ([]*fleet.Policy, error) { return []*fleet.Policy{&policy}, nil } @@ -1082,7 +1104,10 @@ func TestGitOpsFullTeam(t *testing.T) { ds.ListTeamPoliciesFunc = func( ctx context.Context, teamID uint, opts fleet.ListOptions, iopts fleet.ListOptions, ) (teamPolicies []*fleet.Policy, inheritedPolicies []*fleet.Policy, err error) { - return []*fleet.Policy{&policy}, nil, nil + if teamID != 0 { + return []*fleet.Policy{&policy}, nil, nil + } + return nil, nil, nil } ds.PoliciesByIDFunc = func(ctx context.Context, ids []uint) (map[uint]*fleet.Policy, error) { if slices.Contains(ids, 1) { @@ -1140,7 +1165,9 @@ func TestGitOpsFullTeam(t *testing.T) { var appliedSoftwareInstallers []*fleet.UploadSoftwareInstallerPayload ds.BatchSetSoftwareInstallersFunc = func(ctx context.Context, teamID *uint, installers []*fleet.UploadSoftwareInstallerPayload) error { - appliedSoftwareInstallers = installers + if teamID != nil && *teamID != 0 { + appliedSoftwareInstallers = installers + } return nil } ds.GetSoftwareInstallersFunc = func(ctx context.Context, tmID uint) ([]fleet.SoftwarePackageResponse, error) { @@ -2420,7 +2447,7 @@ func TestGitOpsTeamSoftwareInstallersQueryEnv(t *testing.T) { t.Setenv("QUERY_VAR", "IT_WORKS") ds.BatchSetSoftwareInstallersFunc = func(ctx context.Context, tmID *uint, installers []*fleet.UploadSoftwareInstallerPayload) error { - if installers[0].PreInstallQuery != "select IT_WORKS" { + if len(installers) != 0 && installers[0].PreInstallQuery != "select IT_WORKS" { return fmt.Errorf("Missing env var, got %s", installers[0].PreInstallQuery) } return nil