mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Implement FMA software policy automation (#42533)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #36751 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests - [X] QA'd all new/changed functionality manually - [X] Verified that `fleetctl generate-gitops` correctly outputs policies with `install_software.fleet_maintained_app_slug` populated when the policies have FMA automation - [X] Verified that running `fleetctl gitops` using files with `install_software.fleet_maintained_app_slug` creates/updates FMA policy automation correctly - [X] Verified no changes to the above for custom packages or VPP apps - [X] Verified that when software is excepted from GitOps, FMA policy automations still work (correctly validates FMAs exist before applying) ## 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: - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [ ] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) checking on this - [X] 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) - [X] Verified that any relevant UI is disabled when GitOps mode is enabled
This commit is contained in:
parent
ec35465d1f
commit
07a8378a68
12 changed files with 219 additions and 30 deletions
1
changes/36751-add-fmas-to-policy-automation
Normal file
1
changes/36751-add-fmas-to-policy-automation
Normal file
|
|
@ -0,0 +1 @@
|
|||
- Allow specifying a Fleet-Maintained App (FMA) as a policy software automation in GitOps
|
||||
|
|
@ -57,6 +57,7 @@ type Software struct {
|
|||
AppStoreId string
|
||||
Comment string
|
||||
MaintainedAppID uint
|
||||
Slug string
|
||||
}
|
||||
|
||||
type teamToProcess struct {
|
||||
|
|
@ -1542,11 +1543,16 @@ func (cmd *GenerateGitopsCommand) generatePolicies(teamId *uint, filePath string
|
|||
// Handle software automation.
|
||||
if policy.InstallSoftware != nil {
|
||||
if software, ok := cmd.SoftwareList[policy.InstallSoftware.SoftwareTitleID]; ok {
|
||||
if software.Hash != "" {
|
||||
switch {
|
||||
case software.MaintainedAppID != 0 && software.Slug != "":
|
||||
policySpec["install_software"] = map[string]any{
|
||||
"fleet_maintained_app_slug": software.Slug,
|
||||
}
|
||||
case software.Hash != "":
|
||||
policySpec["install_software"] = map[string]any{
|
||||
"hash_sha256": software.Hash + " " + software.Comment,
|
||||
}
|
||||
} else if software.AppStoreId != "" {
|
||||
case software.AppStoreId != "":
|
||||
policySpec["install_software"] = map[string]any{
|
||||
"app_store_id": software.AppStoreId,
|
||||
}
|
||||
|
|
@ -1869,6 +1875,11 @@ func (cmd *GenerateGitopsCommand) generateSoftware(filePath string, teamID uint,
|
|||
}
|
||||
if sw.SoftwarePackage != nil && sw.SoftwarePackage.FleetMaintainedAppID != nil {
|
||||
swEntry.MaintainedAppID = *sw.SoftwarePackage.FleetMaintainedAppID
|
||||
slug, err := slugResolver.resolve(*sw.SoftwarePackage.FleetMaintainedAppID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
swEntry.Slug = slug
|
||||
}
|
||||
|
||||
cmd.SoftwareList[sw.ID] = swEntry
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ func (MockClient) GetPolicies(teamID *uint) ([]*fleet.Policy, error) {
|
|||
},
|
||||
}, nil
|
||||
}
|
||||
return []*fleet.Policy{
|
||||
policies := []*fleet.Policy{
|
||||
{
|
||||
PolicyData: fleet.PolicyData{
|
||||
ID: 1,
|
||||
|
|
@ -414,7 +414,41 @@ func (MockClient) GetPolicies(teamID *uint) ([]*fleet.Policy, error) {
|
|||
SoftwareTitleID: 2,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
// Only add FMA and package install policies for actual teams, not unassigned.
|
||||
if *teamID != 0 {
|
||||
policies = append(policies,
|
||||
&fleet.Policy{
|
||||
PolicyData: fleet.PolicyData{
|
||||
ID: 4,
|
||||
Name: "Team FMA install policy",
|
||||
Query: "SELECT 1 FROM filevault_status WHERE status LIKE '%on%';",
|
||||
Resolution: ptr.String("Install the FMA"),
|
||||
Description: "This is a team policy with FMA install automation",
|
||||
Platform: "darwin",
|
||||
Type: fleet.PolicyTypeDynamic,
|
||||
},
|
||||
InstallSoftware: &fleet.PolicySoftwareTitle{
|
||||
SoftwareTitleID: 8,
|
||||
},
|
||||
},
|
||||
&fleet.Policy{
|
||||
PolicyData: fleet.PolicyData{
|
||||
ID: 5,
|
||||
Name: "Team package install policy",
|
||||
Query: "SELECT 1 FROM mounts WHERE path = '/' AND CAST(blocks_available AS REAL) / blocks > 0.10;",
|
||||
Resolution: ptr.String("Install the package"),
|
||||
Description: "This is a team policy with custom package install automation",
|
||||
Platform: "linux,windows",
|
||||
Type: fleet.PolicyTypeDynamic,
|
||||
},
|
||||
InstallSoftware: &fleet.PolicySoftwareTitle{
|
||||
SoftwareTitleID: 1,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func (MockClient) GetQueries(teamID *uint, name *string) ([]fleet.Query, error) {
|
||||
|
|
@ -423,7 +457,7 @@ func (MockClient) GetQueries(teamID *uint, name *string) ([]fleet.Query, error)
|
|||
{
|
||||
ID: 1,
|
||||
Name: "Global Query",
|
||||
Query: "SELECT * FROM global_query WHERE id = 1",
|
||||
Query: "SELECT * FROM os_version;",
|
||||
Description: "This is a global query",
|
||||
Platform: "darwin",
|
||||
Interval: 3600,
|
||||
|
|
@ -443,7 +477,7 @@ func (MockClient) GetQueries(teamID *uint, name *string) ([]fleet.Query, error)
|
|||
{
|
||||
ID: 1,
|
||||
Name: "Team Query",
|
||||
Query: "SELECT * FROM team_query WHERE id = 1",
|
||||
Query: "SELECT * FROM plist WHERE path LIKE '/Users/%/Library/Preferences/com.apple.CloudSubscriptionFeatures.optIn.plist';",
|
||||
Description: "This is a team query",
|
||||
Platform: "linux,windows",
|
||||
Interval: 1800,
|
||||
|
|
|
|||
|
|
@ -1240,7 +1240,23 @@ func TestGitOpsSoftwareExceptionPolicyValidation(t *testing.T) {
|
|||
Platform: string(fleet.MacOSPlatform),
|
||||
},
|
||||
},
|
||||
}, 2, nil, nil
|
||||
{
|
||||
ID: 40,
|
||||
Name: "Zoom",
|
||||
HashSHA256: ptr.String("fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1fma1"),
|
||||
SoftwarePackage: &fleet.SoftwarePackageOrApp{
|
||||
Name: "zoom.pkg",
|
||||
Platform: "darwin",
|
||||
Version: "6.0",
|
||||
FleetMaintainedAppID: ptr.Uint(100),
|
||||
},
|
||||
},
|
||||
}, 3, nil, nil
|
||||
}
|
||||
ds.ListAvailableFleetMaintainedAppsFunc = func(ctx context.Context, teamID *uint, opt fleet.ListOptions) ([]fleet.MaintainedApp, *fleet.PaginationMetadata, error) {
|
||||
return []fleet.MaintainedApp{
|
||||
{ID: 100, Slug: "zoom/darwin"},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
// Config files that omit software: but have policies referencing server-side software
|
||||
|
|
@ -1270,6 +1286,10 @@ policies:
|
|||
query: SELECT 1
|
||||
install_software:
|
||||
app_store_id: "5128675309"
|
||||
- name: FMA Policy
|
||||
query: SELECT 1
|
||||
install_software:
|
||||
fleet_maintained_app_slug: zoom/darwin
|
||||
agent_options:
|
||||
reports:
|
||||
`), 0o644))
|
||||
|
|
@ -1290,13 +1310,15 @@ policies:
|
|||
require.NoError(t, err, "gitops should succeed when policies reference server-side software and software is excepted")
|
||||
// Check that policies for "Test Fleet" contained the expected software title IDs.
|
||||
testFleetPolicySpecs := policySpecsByTeam["Test Fleet"]
|
||||
require.Len(t, testFleetPolicySpecs, 2, "expected 2 policies for Test Fleet")
|
||||
require.Len(t, testFleetPolicySpecs, 3, "expected 3 policies for Test Fleet")
|
||||
for _, spec := range testFleetPolicySpecs {
|
||||
switch spec.Name {
|
||||
case "Package Policy":
|
||||
assert.Equal(t, uint(10), *spec.SoftwareTitleID, "expected server-side software ID to be injected into Package Policy spec")
|
||||
case "VPP Policy":
|
||||
assert.Equal(t, uint(20), *spec.SoftwareTitleID, "expected server-side software ID to be injected into VPP Policy spec")
|
||||
case "FMA Policy":
|
||||
assert.Equal(t, uint(40), *spec.SoftwareTitleID, "expected server-side software ID to be injected into FMA Policy spec")
|
||||
default:
|
||||
t.Errorf("unexpected policy name: %s", spec.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@
|
|||
name: Global Query
|
||||
observer_can_run: true
|
||||
platform: darwin
|
||||
query: SELECT * FROM global_query WHERE id = 1
|
||||
query: SELECT * FROM os_version;
|
||||
discard_data: false
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
name: Team Query
|
||||
observer_can_run: false
|
||||
platform: linux,windows
|
||||
query: SELECT * FROM team_query WHERE id = 1
|
||||
query: SELECT * FROM plist WHERE path LIKE '/Users/%/Library/Preferences/com.apple.CloudSubscriptionFeatures.optIn.plist';
|
||||
|
|
@ -204,4 +204,4 @@ reports:
|
|||
name: Global Query
|
||||
observer_can_run: true
|
||||
platform: darwin
|
||||
query: SELECT * FROM global_query WHERE id = 1
|
||||
query: SELECT * FROM os_version;
|
||||
|
|
|
|||
|
|
@ -200,4 +200,4 @@ reports:
|
|||
name: Global Query
|
||||
observer_can_run: true
|
||||
platform: darwin
|
||||
query: SELECT * FROM global_query WHERE id = 1
|
||||
query: SELECT * FROM os_version;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,31 @@ policies:
|
|||
resolution: Install the app
|
||||
type: dynamic
|
||||
webhooks_and_tickets_enabled: true
|
||||
- calendar_events_enabled: false
|
||||
conditional_access_enabled: false
|
||||
critical: false
|
||||
description: This is a team policy with FMA install automation
|
||||
install_software:
|
||||
fleet_maintained_app_slug: fma1/darwin
|
||||
name: Team FMA install policy
|
||||
platform: darwin
|
||||
query: SELECT 1 FROM filevault_status WHERE status LIKE '%on%';
|
||||
resolution: Install the FMA
|
||||
type: dynamic
|
||||
webhooks_and_tickets_enabled: false
|
||||
- calendar_events_enabled: false
|
||||
conditional_access_enabled: false
|
||||
critical: false
|
||||
description: This is a team policy with custom package install automation
|
||||
install_software:
|
||||
hash_sha256: software-package-hash # My Software Package (my-software.pkg) version 13.37
|
||||
name: Team package install policy
|
||||
platform: linux,windows
|
||||
query: SELECT 1 FROM mounts WHERE path = '/' AND CAST(blocks_available AS REAL)
|
||||
/ blocks > 0.10;
|
||||
resolution: Install the package
|
||||
type: dynamic
|
||||
webhooks_and_tickets_enabled: false
|
||||
reports:
|
||||
- automations_enabled: true
|
||||
description: This is a team query
|
||||
|
|
@ -92,7 +117,7 @@ reports:
|
|||
name: Team Query
|
||||
observer_can_run: false
|
||||
platform: linux,windows
|
||||
query: SELECT * FROM team_query WHERE id = 1
|
||||
query: SELECT * FROM plist WHERE path LIKE '/Users/%/Library/Preferences/com.apple.CloudSubscriptionFeatures.optIn.plist';
|
||||
settings:
|
||||
features:
|
||||
enable_host_users: true
|
||||
|
|
|
|||
|
|
@ -227,9 +227,10 @@ type PolicyRunScript struct {
|
|||
}
|
||||
|
||||
type PolicyInstallSoftware struct {
|
||||
PackagePath string `json:"package_path"`
|
||||
AppStoreID string `json:"app_store_id"`
|
||||
HashSHA256 string `json:"hash_sha256"`
|
||||
PackagePath string `json:"package_path"`
|
||||
AppStoreID string `json:"app_store_id"`
|
||||
HashSHA256 string `json:"hash_sha256"`
|
||||
FleetMaintainedAppSlug string `json:"fleet_maintained_app_slug"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
|
|
@ -1420,7 +1421,7 @@ func parsePolicies(top map[string]json.RawMessage, result *GitOps, baseDir strin
|
|||
multiError = multierror.Append(multiError, validateRawKeys(policiesRaw, reflect.TypeFor[[]Policy](), filePath, []string{"policies"})...)
|
||||
for _, item := range policies {
|
||||
if item.Path == nil {
|
||||
if errs := parsePolicyInstallSoftware(baseDir, result.TeamName, &item, result.Software.Packages, result.Software.AppStoreApps); errs != nil {
|
||||
if errs := parsePolicyInstallSoftware(baseDir, result.TeamName, &item, result.Software.Packages, result.Software.AppStoreApps, fmasBySlug); errs != nil {
|
||||
multiError = multierror.Append(multiError, errs...)
|
||||
continue
|
||||
}
|
||||
|
|
@ -1456,7 +1457,7 @@ func parsePolicies(top map[string]json.RawMessage, result *GitOps, baseDir strin
|
|||
multiError, fmt.Errorf("nested paths are not supported: %s in %s", *pp.Path, *item.Path),
|
||||
)
|
||||
} else {
|
||||
if errs := parsePolicyInstallSoftware(filepath.Dir(*item.Path), result.TeamName, pp, result.Software.Packages, result.Software.AppStoreApps); errs != nil {
|
||||
if errs := parsePolicyInstallSoftware(filepath.Dir(*item.Path), result.TeamName, pp, result.Software.Packages, result.Software.AppStoreApps, fmasBySlug); errs != nil {
|
||||
multiError = multierror.Append(multiError, errs...)
|
||||
continue
|
||||
}
|
||||
|
|
@ -1555,7 +1556,7 @@ func parsePolicyRunScript(baseDir string, parentFilePath string, teamName *strin
|
|||
return nil
|
||||
}
|
||||
|
||||
func parsePolicyInstallSoftware(baseDir string, teamName *string, policy *Policy, packages []*fleet.SoftwarePackageSpec, appStoreApps []*fleet.TeamSpecAppStoreApp) []error {
|
||||
func parsePolicyInstallSoftware(baseDir string, teamName *string, policy *Policy, packages []*fleet.SoftwarePackageSpec, appStoreApps []*fleet.TeamSpecAppStoreApp, fmasBySlug map[string]struct{}) []error {
|
||||
installSoftwareObj := policy.InstallSoftware.Other
|
||||
if installSoftwareObj == nil {
|
||||
policy.SoftwareTitleID = ptr.Uint(0) // unset the installer
|
||||
|
|
@ -1568,14 +1569,20 @@ func parsePolicyInstallSoftware(baseDir string, teamName *string, policy *Policy
|
|||
wrapErrs := func(err error) []error {
|
||||
return []error{wrapErr(err)}
|
||||
}
|
||||
if (installSoftwareObj.PackagePath != "" || installSoftwareObj.AppStoreID != "") && teamName == nil {
|
||||
if (installSoftwareObj.PackagePath != "" || installSoftwareObj.AppStoreID != "" || installSoftwareObj.HashSHA256 != "" || installSoftwareObj.FleetMaintainedAppSlug != "") && teamName == nil {
|
||||
return wrapErrs(errors.New("install_software can only be set on team policies"))
|
||||
}
|
||||
if installSoftwareObj.PackagePath == "" && installSoftwareObj.AppStoreID == "" && installSoftwareObj.HashSHA256 == "" {
|
||||
return wrapErrs(errors.New("install_software must include either a package_path, an app_store_id or a hash_sha256"))
|
||||
if installSoftwareObj.PackagePath == "" && installSoftwareObj.AppStoreID == "" && installSoftwareObj.HashSHA256 == "" && installSoftwareObj.FleetMaintainedAppSlug == "" {
|
||||
return wrapErrs(errors.New("install_software must include either a package_path, an app_store_id, a hash_sha256 or a fleet_maintained_app_slug"))
|
||||
}
|
||||
if installSoftwareObj.PackagePath != "" && installSoftwareObj.AppStoreID != "" {
|
||||
return wrapErrs(errors.New("install_software must have only one of package_path or app_store_id"))
|
||||
setCount := 0
|
||||
for _, s := range []string{installSoftwareObj.PackagePath, installSoftwareObj.AppStoreID, installSoftwareObj.HashSHA256, installSoftwareObj.FleetMaintainedAppSlug} {
|
||||
if s != "" {
|
||||
setCount++
|
||||
}
|
||||
}
|
||||
if setCount > 1 {
|
||||
return wrapErrs(errors.New("install_software must have only one of package_path, app_store_id, hash_sha256 or fleet_maintained_app_slug"))
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
|
@ -1639,6 +1646,13 @@ func parsePolicyInstallSoftware(baseDir string, teamName *string, policy *Policy
|
|||
}
|
||||
}
|
||||
|
||||
if installSoftwareObj.FleetMaintainedAppSlug != "" {
|
||||
if _, ok := fmasBySlug[installSoftwareObj.FleetMaintainedAppSlug]; !ok {
|
||||
errs = append(errs, wrapErr(fmt.Errorf("install_software.fleet_maintained_app_slug %q not found in software.fleet_maintained_apps for team %s", installSoftwareObj.FleetMaintainedAppSlug, *teamName)))
|
||||
}
|
||||
policy.FleetMaintainedAppSlug = installSoftwareObj.FleetMaintainedAppSlug
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1207,7 +1207,7 @@ policies:
|
|||
package_path:
|
||||
`
|
||||
_, err = gitOpsFromString(t, config)
|
||||
assert.ErrorContains(t, err, "install_software must include either a package_path, an app_store_id or a hash_sha256")
|
||||
assert.ErrorContains(t, err, "install_software must include either a package_path, an app_store_id, a hash_sha256 or a fleet_maintained_app_slug")
|
||||
|
||||
config = getTeamConfig([]string{"policies"})
|
||||
config += `
|
||||
|
|
@ -1219,7 +1219,7 @@ policies:
|
|||
app_store_id: "123456"
|
||||
`
|
||||
_, err = gitOpsFromString(t, config)
|
||||
assert.ErrorContains(t, err, "must have only one of package_path or app_store_id")
|
||||
assert.ErrorContains(t, err, "must have only one of package_path, app_store_id, hash_sha256 or fleet_maintained_app_slug")
|
||||
|
||||
// Software has a URL that's too big
|
||||
tooBigURL := fmt.Sprintf("https://ftp.mozilla.org/%s", strings.Repeat("a", 4000-23))
|
||||
|
|
@ -3373,9 +3373,9 @@ func TestParsePolicyInstallSoftware(t *testing.T) {
|
|||
InstallSoftware: installSoftware, // no package_path, app_store_id, or hash_sha256
|
||||
},
|
||||
}
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, nil, nil)
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, nil, nil, nil)
|
||||
require.Len(t, errs, 1)
|
||||
assert.Equal(t, errs[0].Error(), `failed to parse policy install_software "my policy": install_software must include either a package_path, an app_store_id or a hash_sha256`)
|
||||
assert.Equal(t, errs[0].Error(), `failed to parse policy install_software "my policy": install_software must include either a package_path, an app_store_id, a hash_sha256 or a fleet_maintained_app_slug`)
|
||||
})
|
||||
|
||||
t.Run("unknown key in package_path file", func(t *testing.T) {
|
||||
|
|
@ -3396,12 +3396,84 @@ func TestParsePolicyInstallSoftware(t *testing.T) {
|
|||
},
|
||||
}
|
||||
packages := []*fleet.SoftwarePackageSpec{{SHA256: sha}}
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, packages, nil)
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, packages, nil, nil)
|
||||
require.Len(t, errs, 1)
|
||||
var unknownErr *ParseUnknownKeyError
|
||||
require.ErrorAs(t, errs[0], &unknownErr)
|
||||
assert.Equal(t, "bad_field", unknownErr.Field)
|
||||
})
|
||||
t.Run("fleet_maintained_app_slug valid", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var installSoftware optjson.BoolOr[*PolicyInstallSoftware]
|
||||
installSoftware.Other = &PolicyInstallSoftware{FleetMaintainedAppSlug: "zoom/darwin"}
|
||||
|
||||
policy := &Policy{
|
||||
GitOpsPolicySpec: GitOpsPolicySpec{
|
||||
PolicySpec: fleet.PolicySpec{Name: "fma policy"},
|
||||
InstallSoftware: installSoftware,
|
||||
},
|
||||
}
|
||||
fmasBySlug := map[string]struct{}{"zoom/darwin": {}}
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, nil, nil, fmasBySlug)
|
||||
require.Nil(t, errs)
|
||||
assert.Equal(t, "zoom/darwin", policy.FleetMaintainedAppSlug)
|
||||
})
|
||||
|
||||
t.Run("fleet_maintained_app_slug not in FMAs", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var installSoftware optjson.BoolOr[*PolicyInstallSoftware]
|
||||
installSoftware.Other = &PolicyInstallSoftware{FleetMaintainedAppSlug: "notreal/darwin"}
|
||||
|
||||
policy := &Policy{
|
||||
GitOpsPolicySpec: GitOpsPolicySpec{
|
||||
PolicySpec: fleet.PolicySpec{Name: "bad fma policy"},
|
||||
InstallSoftware: installSoftware,
|
||||
},
|
||||
}
|
||||
fmasBySlug := map[string]struct{}{"zoom/darwin": {}}
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, nil, nil, fmasBySlug)
|
||||
require.Len(t, errs, 1)
|
||||
assert.Contains(t, errs[0].Error(), `fleet_maintained_app_slug "notreal/darwin" not found`)
|
||||
})
|
||||
|
||||
t.Run("fleet_maintained_app_slug with other fields errors", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var installSoftware optjson.BoolOr[*PolicyInstallSoftware]
|
||||
installSoftware.Other = &PolicyInstallSoftware{
|
||||
FleetMaintainedAppSlug: "zoom/darwin",
|
||||
HashSHA256: "abc123",
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
GitOpsPolicySpec: GitOpsPolicySpec{
|
||||
PolicySpec: fleet.PolicySpec{Name: "conflicting policy"},
|
||||
InstallSoftware: installSoftware,
|
||||
},
|
||||
}
|
||||
errs := parsePolicyInstallSoftware(".", &teamName, policy, nil, nil, nil)
|
||||
require.Len(t, errs, 1)
|
||||
assert.Contains(t, errs[0].Error(), "install_software must have only one of")
|
||||
})
|
||||
|
||||
t.Run("fleet_maintained_app_slug on global policy errors", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var installSoftware optjson.BoolOr[*PolicyInstallSoftware]
|
||||
installSoftware.Other = &PolicyInstallSoftware{FleetMaintainedAppSlug: "zoom/darwin"}
|
||||
|
||||
policy := &Policy{
|
||||
GitOpsPolicySpec: GitOpsPolicySpec{
|
||||
PolicySpec: fleet.PolicySpec{Name: "global fma policy"},
|
||||
InstallSoftware: installSoftware,
|
||||
},
|
||||
}
|
||||
errs := parsePolicyInstallSoftware(".", nil, policy, nil, nil, nil)
|
||||
require.Len(t, errs, 1)
|
||||
assert.Contains(t, errs[0].Error(), "install_software can only be set on team policies")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGitOpsPresenceTracking(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -2880,7 +2880,6 @@ func (c *Client) doGitOpsPolicies(config *spec.GitOps, teamSoftwareInstallers []
|
|||
config.Policies[i].SoftwareTitleID = ptr.Uint(0) // 0 unsets the installer
|
||||
|
||||
if !config.Policies[i].InstallSoftware.IsOther && config.Policies[i].InstallSoftware.Bool {
|
||||
fmt.Printf("softwareTitleIDsBySlug: %v\n", softwareTitleIDsBySlug)
|
||||
softwareTitleID, ok := softwareTitleIDsBySlug[config.Policies[i].FleetMaintainedAppSlug]
|
||||
if !ok {
|
||||
// Should not happen because FMAs are uploaded first.
|
||||
|
|
@ -2928,6 +2927,17 @@ func (c *Client) doGitOpsPolicies(config *spec.GitOps, teamSoftwareInstallers []
|
|||
}
|
||||
config.Policies[i].SoftwareTitleID = &softwareTitleID
|
||||
}
|
||||
if config.Policies[i].InstallSoftware.Other.FleetMaintainedAppSlug != "" {
|
||||
softwareTitleID, ok := softwareTitleIDsBySlug[config.Policies[i].InstallSoftware.Other.FleetMaintainedAppSlug]
|
||||
if !ok {
|
||||
// Should not happen because FMAs are uploaded first.
|
||||
if !dryRun {
|
||||
logFn("[!] fleet-maintained app slug without software title ID: %s\n", config.Policies[i].InstallSoftware.Other.FleetMaintainedAppSlug)
|
||||
}
|
||||
continue
|
||||
}
|
||||
config.Policies[i].SoftwareTitleID = &softwareTitleID
|
||||
}
|
||||
}
|
||||
|
||||
// Get scripts for the team.
|
||||
|
|
|
|||
Loading…
Reference in a new issue