Demo: https://www.youtube.com/watch?v=cWxZlu9WuwA Guide updates: https://github.com/fleetdm/fleet/pull/49603/changes IT admins can configure the fleet that hosts enrolling through user-driven Windows MDM enrollment (Windows Autopilot, Entra join) are automatically assigned to, via the Windows MDM settings page, the mdm.windows_enrollment.default_fleet config setting, or GitOps. - New windows_enrollment_config row stores the default team; the config API surfaces it by fleet name and hydrates reads from the row so team renames and deletions never serve a stale name. Deleting the fleet clears the setting. - New edited_windows_enrollment_default_fleet activity, emitted only when the value changes. - The OMA-DM session persists the device-reported SMBIOS serial on still-unlinked enrollments, and orbit enrollment reverse-links by that serial and assigns the default fleet before orbit's one-shot setup-experience init, so the default fleet's software, scripts, and profiles apply during the Autopilot ESP. The DevDetail and osquery link paths keep the same assignment as fallbacks, and the EUA-token link path now shares the same post-link bookkeeping. - Hosts are only assigned when new to Fleet in this enrollment cycle: existing hosts, including ones parked in Unassigned, keep their fleet on re-enrollment, matching macOS ABM behavior. - GitOps defers applying the setting until teams declared in the same run are created, and fleetctl generate-gitops exports it. - Windows MDM settings page redesign per Figma: programmatic enrollment toggle, User driven enrollment section with the Entra-gated Default fleet dropdown, and a Migration section. <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #41787 # 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. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually ## Database migrations - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). ## New Fleet configuration settings - [x] Verified that the setting is exported via `fleetctl generate-gitops` - [x] 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) - [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 is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for assigning a default Fleet Premium fleet to new Windows MDM enrollments, including Autopilot and Entra join. * Default-fleet settings can be configured, cleared, and managed through Windows MDM settings and GitOps. * Assigned fleet software, scripts, and profiles can apply during out-of-box setup. * Added activity-feed visibility for default-fleet changes. * Improved Windows enrollment matching using hardware serial numbers. * **Documentation** * Documented default-fleet assignment for Windows enrollment. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1215,6 +1215,7 @@ func (cmd *GenerateGitopsCommand) generateMDM(mdm *fleet.MDM) (map[string]interf
|
||||
}
|
||||
if cmd.AppConfig.License.IsPremium() {
|
||||
result[jsonFieldName(t, "AppleBusinessManager")] = mdm.AppleBusinessManager
|
||||
result[jsonFieldName(t, "WindowsEnrollment")] = mdm.WindowsEnrollment
|
||||
vppTokens, err := cmd.Client.GetVPPTokens()
|
||||
if err != nil {
|
||||
fmt.Fprintf(cmd.CLI.App.ErrWriter, "Error fetching VPP tokens: %s\n", err)
|
||||
|
||||
@@ -1235,6 +1235,20 @@ func TestGenerateOrgSettings(t *testing.T) {
|
||||
|
||||
// Compare.
|
||||
require.Equal(t, expectedAppConfig, orgSettings)
|
||||
|
||||
// An unset mdm.windows_enrollment must serialize as null rather than an object with an empty default_fleet.
|
||||
// Applying null is a no-op; an empty default_fleet would clear whatever default the target server has set.
|
||||
appConfig.MDM.WindowsEnrollment = optjson.Any[fleet.WindowsEnrollment]{}
|
||||
orgSettingsRaw, err = cmd.generateOrgSettings()
|
||||
require.NoError(t, err)
|
||||
b, err = yamlMarshalRenamed(orgSettingsRaw)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, yaml.Unmarshal(b, &orgSettings))
|
||||
mdmSettings, ok := orgSettings["mdm"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
we, present := mdmSettings["windows_enrollment"]
|
||||
require.True(t, present, "windows_enrollment key should still be emitted")
|
||||
require.Nil(t, we, "unset windows_enrollment must serialize as null so applying it is a no-op")
|
||||
}
|
||||
|
||||
func TestGenerateOrgSettingsMaskedGoogleCalendarApiKey(t *testing.T) {
|
||||
|
||||
@@ -146,6 +146,8 @@ func gitopsCommand() *cli.Command {
|
||||
var teamDryRunAssumptions *fleet.TeamSpecsDryRunAssumptions
|
||||
var abmTeams, vppTeams, missingVPPTeams []string
|
||||
var hasMissingABMTeam, usesLegacyABMConfig bool
|
||||
var windowsEnrollmentDefaultFleet string
|
||||
var windowsEnrollmentFleetMissing bool
|
||||
type missingVPPTeamWithApps struct {
|
||||
config *spec.GitOps
|
||||
vppApps []*fleet.TeamSpecAppStoreApp
|
||||
@@ -558,6 +560,24 @@ func gitopsCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// Runs outside the multi-file gate above: the resolved default fleet name is also needed by the --delete-other-fleets guard
|
||||
// below, even on single-file runs.
|
||||
if isGlobalConfig && appConfig.License.IsPremium() {
|
||||
windowsEnrollmentDefaultFleet, windowsEnrollmentFleetMissing, err = checkWindowsEnrollmentAssignment(config, fleetClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if windowsEnrollmentFleetMissing {
|
||||
if mdm, ok := config.OrgSettings["mdm"]; ok {
|
||||
if mdmMap, ok := mdm.(map[string]any); ok {
|
||||
// The referenced fleet may be created later in this run. Deleting the key makes the first apply a no-op for this
|
||||
// setting (an omitted key keeps the stored value); it is applied separately after teams are processed.
|
||||
delete(mdmMap, "windows_enrollment")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Teams need a VPP token before VPP apps can be applied. When some VPP
|
||||
// teams don't exist yet, the VPP config is temporarily removed from the
|
||||
// global config, which clears all VPP token assignments. To avoid
|
||||
@@ -648,6 +668,11 @@ func gitopsCommand() *cli.Command {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if windowsEnrollmentDefaultFleet != "" && windowsEnrollmentFleetMissing {
|
||||
if err = applyWindowsEnrollmentAssignmentIfNeeded(c, teamNames, windowsEnrollmentDefaultFleet, flDryRun, fleetClient); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Now that VPP tokens have been assigned, we can apply VPP apps to the new team.
|
||||
// For simplicity, we simply re-apply the entire config. This only happens once when the team is created.
|
||||
for _, teamWithApps := range missingVPPTeamsWithApps {
|
||||
@@ -687,6 +712,9 @@ func gitopsCommand() *cli.Command {
|
||||
if slices.Contains(vppTeams, team.Name) {
|
||||
return fmt.Errorf("volume_purchasing_program team %s cannot be deleted", team.Name)
|
||||
}
|
||||
if windowsEnrollmentDefaultFleet != "" && norm.NFC.String(team.Name) == windowsEnrollmentDefaultFleet {
|
||||
return fmt.Errorf("windows_enrollment default_fleet %s cannot be deleted", team.Name)
|
||||
}
|
||||
if flDryRun {
|
||||
_, _ = fmt.Fprintf(c.App.Writer, "[!] would've deleted team %s\n", team.Name)
|
||||
} else {
|
||||
@@ -1277,6 +1305,77 @@ func applyABMTokenAssignmentIfNeeded(
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkWindowsEnrollmentAssignment reads org_settings.mdm.windows_enrollment.default_fleet and reports whether the referenced
|
||||
// fleet doesn't exist in Fleet yet (it may be created later in the same gitops run). Returns an empty name when the section or
|
||||
// the value is absent.
|
||||
func checkWindowsEnrollmentAssignment(config *spec.GitOps, fleetClient *service.Client) (defaultFleet string, missingTeam bool, err error) {
|
||||
mdm, ok := config.OrgSettings["mdm"]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
mdmMap, ok := mdm.(map[string]any)
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
we, ok := mdmMap["windows_enrollment"]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
// A wrong shape is passed through untouched so the server-side validation reports it.
|
||||
weMap, ok := we.(map[string]any)
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
name, _ := weMap["default_fleet"].(string)
|
||||
if name == "" {
|
||||
return "", false, nil
|
||||
}
|
||||
// normalize for Unicode support
|
||||
name = norm.NFC.String(name)
|
||||
teams, err := fleetClient.ListTeams("")
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
for _, tm := range teams {
|
||||
if norm.NFC.String(tm.Name) == name {
|
||||
return name, false, nil
|
||||
}
|
||||
}
|
||||
return name, true, nil
|
||||
}
|
||||
|
||||
// applyWindowsEnrollmentAssignmentIfNeeded applies the deferred org_settings.mdm.windows_enrollment.default_fleet once teams have
|
||||
// been processed, failing if the referenced fleet still doesn't exist.
|
||||
func applyWindowsEnrollmentAssignmentIfNeeded(
|
||||
ctx *cli.Context,
|
||||
teamNames []string,
|
||||
defaultFleet string,
|
||||
flDryRun bool,
|
||||
fleetClient *service.Client,
|
||||
) error {
|
||||
knownTeams, err := knownTeamNamesForTokenAssignment(teamNames, fleetClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := knownTeams[norm.NFC.String(defaultFleet)]; !ok {
|
||||
return fmt.Errorf("windows_enrollment default_fleet %q not found in team configs", defaultFleet)
|
||||
}
|
||||
if flDryRun {
|
||||
_, _ = fmt.Fprint(ctx.App.Writer, "[!] would apply Windows enrollment default fleet\n")
|
||||
return nil
|
||||
}
|
||||
_, _ = fmt.Fprintf(ctx.App.Writer, "[+] applying Windows enrollment default fleet\n")
|
||||
appConfigUpdate := map[string]map[string]any{
|
||||
"mdm": {
|
||||
"windows_enrollment": map[string]any{"default_fleet": defaultFleet},
|
||||
},
|
||||
}
|
||||
if err := fleetClient.ApplyAppConfig(appConfigUpdate, fleet.ApplySpecOptions{}); err != nil {
|
||||
return fmt.Errorf("applying fleet config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkVPPTeamAssignments(config *spec.GitOps, fleetClient *service.Client) (
|
||||
vppTeams []string, missingTeams []string, err error,
|
||||
) {
|
||||
|
||||
@@ -4674,6 +4674,225 @@ software:
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitOpsWindowsEnrollment(t *testing.T) {
|
||||
global := func(mdm string) string {
|
||||
return fmt.Sprintf(`
|
||||
controls:
|
||||
queries:
|
||||
policies:
|
||||
agent_options:
|
||||
software:
|
||||
org_settings:
|
||||
server_settings:
|
||||
server_url: "https://foo.example.com"
|
||||
org_info:
|
||||
org_name: GitOps Test
|
||||
secrets:
|
||||
- secret: "global"
|
||||
mdm:
|
||||
%s
|
||||
`, mdm)
|
||||
}
|
||||
|
||||
team := func(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
name: %s
|
||||
team_settings:
|
||||
secrets:
|
||||
- secret: "%s-secret"
|
||||
agent_options:
|
||||
controls:
|
||||
policies:
|
||||
queries:
|
||||
software:
|
||||
`, name, name)
|
||||
}
|
||||
|
||||
workstations := team("💻 Workstations")
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
cfgs []string
|
||||
extraArgs []string
|
||||
seedTeamName string
|
||||
dryRunAssertion func(t *testing.T, out string, defaultTeamID *uint, err error)
|
||||
realRunAssertion func(t *testing.T, out string, defaultTeamID *uint, err error)
|
||||
}{
|
||||
{
|
||||
name: "delete-other-fleets cannot delete the default fleet",
|
||||
cfgs: []string{
|
||||
global(`windows_enrollment:
|
||||
default_fleet: "💻 Workstations"`),
|
||||
team("Other team"),
|
||||
},
|
||||
extraArgs: []string{"--delete-other-fleets"},
|
||||
seedTeamName: "💻 Workstations",
|
||||
dryRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.ErrorContains(t, err, "windows_enrollment default_fleet 💻 Workstations cannot be deleted")
|
||||
},
|
||||
realRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.ErrorContains(t, err, "windows_enrollment default_fleet 💻 Workstations cannot be deleted")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fleet declared in the same run",
|
||||
cfgs: []string{
|
||||
global(`windows_enrollment:
|
||||
default_fleet: "💻 Workstations"`),
|
||||
workstations,
|
||||
},
|
||||
dryRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, defaultTeamID, "dry run must not persist the default fleet")
|
||||
assert.Contains(t, out, "[!] would apply Windows enrollment default fleet")
|
||||
assert.Contains(t, out, "[!] gitops dry run succeeded")
|
||||
},
|
||||
realRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, defaultTeamID)
|
||||
assert.Contains(t, out, "[!] gitops succeeded")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknown fleet errors",
|
||||
cfgs: []string{
|
||||
global(`windows_enrollment:
|
||||
default_fleet: "Ghosts"`),
|
||||
workstations,
|
||||
},
|
||||
dryRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.ErrorContains(t, err, `windows_enrollment default_fleet "Ghosts" not found in team configs`)
|
||||
assert.Nil(t, defaultTeamID)
|
||||
},
|
||||
realRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.ErrorContains(t, err, `windows_enrollment default_fleet "Ghosts" not found in team configs`)
|
||||
assert.Nil(t, defaultTeamID)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty value is accepted and clears",
|
||||
cfgs: []string{
|
||||
global(`windows_enrollment:
|
||||
default_fleet: ""`),
|
||||
workstations,
|
||||
},
|
||||
dryRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, out, "[!] gitops dry run succeeded")
|
||||
},
|
||||
realRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, defaultTeamID)
|
||||
assert.Contains(t, out, "[!] gitops succeeded")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "omitted key is a no-op",
|
||||
cfgs: []string{
|
||||
global(""),
|
||||
workstations,
|
||||
},
|
||||
dryRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, out, "[!] gitops dry run succeeded")
|
||||
},
|
||||
realRunAssertion: func(t *testing.T, out string, defaultTeamID *uint, err error) {
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, defaultTeamID)
|
||||
assert.NotContains(t, out, "applying Windows enrollment default fleet")
|
||||
assert.Contains(t, out, "[!] gitops succeeded")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ds, _, savedTeams := testing_utils.SetupFullGitOpsPremiumServer(t)
|
||||
ds.GetLabelSpecsFunc = func(ctx context.Context, filter fleet.TeamFilter) ([]*fleet.LabelSpec, error) {
|
||||
return nil, nil
|
||||
}
|
||||
ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
|
||||
return []*fleet.ABMToken{}, nil
|
||||
}
|
||||
ds.GetABMTokenCountFunc = func(ctx context.Context) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
|
||||
return nil
|
||||
}
|
||||
ds.TeamsSummaryFunc = func(ctx context.Context) ([]*fleet.TeamSummary, error) {
|
||||
var res []*fleet.TeamSummary
|
||||
for _, tm := range savedTeams {
|
||||
res = append(res, &fleet.TeamSummary{Name: (*tm).Name, ID: (*tm).ID})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
ds.DeleteIconsAssociatedWithTitlesWithoutInstallersFunc = func(ctx context.Context, teamID uint) error {
|
||||
return nil
|
||||
}
|
||||
ds.GetCertificateTemplatesByTeamIDFunc = func(ctx context.Context, teamID uint, options fleet.ListOptions) ([]*fleet.CertificateTemplateResponseSummary, *fleet.PaginationMetadata, error) {
|
||||
return []*fleet.CertificateTemplateResponseSummary{}, &fleet.PaginationMetadata{}, nil
|
||||
}
|
||||
ds.ListCertificateAuthoritiesFunc = func(ctx context.Context) ([]*fleet.CertificateAuthoritySummary, error) {
|
||||
return nil, nil
|
||||
}
|
||||
ds.VerifyAppleConfigProfileScopesDoNotConflictFunc = func(ctx context.Context, cps []*fleet.MDMAppleConfigProfile) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if tt.seedTeamName != "" {
|
||||
seeded := &fleet.Team{ID: 99, Name: tt.seedTeamName}
|
||||
savedTeams[tt.seedTeamName] = &seeded
|
||||
}
|
||||
|
||||
// Track the persisted default fleet, overriding the helper's stateful default so the test can assert on it directly.
|
||||
var defaultTeamID *uint
|
||||
ds.GetWindowsEnrollmentDefaultFleetFunc = func(ctx context.Context) (*uint, string, error) {
|
||||
if defaultTeamID == nil {
|
||||
return nil, "", nil
|
||||
}
|
||||
for _, tm := range savedTeams {
|
||||
if (*tm).ID == *defaultTeamID {
|
||||
return defaultTeamID, (*tm).Name, nil
|
||||
}
|
||||
}
|
||||
return nil, "", nil
|
||||
}
|
||||
ds.SetWindowsEnrollmentDefaultFleetFunc = func(ctx context.Context, teamID *uint) error {
|
||||
defaultTeamID = teamID
|
||||
return nil
|
||||
}
|
||||
|
||||
args := []string{"gitops"}
|
||||
for _, cfg := range tt.cfgs {
|
||||
if cfg != "" {
|
||||
tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml")
|
||||
require.NoError(t, err)
|
||||
_, err = tmpFile.WriteString(cfg)
|
||||
require.NoError(t, err)
|
||||
args = append(args, "-f", tmpFile.Name())
|
||||
}
|
||||
}
|
||||
args = append(args, tt.extraArgs...)
|
||||
|
||||
// Dry run
|
||||
out, err := runAppNoChecks(append(args, "--dry-run"))
|
||||
tt.dryRunAssertion(t, out.String(), defaultTeamID, err)
|
||||
if t.Failed() {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Real run
|
||||
out, err = runAppNoChecks(args)
|
||||
tt.realRunAssertion(t, out.String(), defaultTeamID, err)
|
||||
|
||||
// Second real run, now that all the teams are saved
|
||||
out, err = runAppNoChecks(args)
|
||||
tt.realRunAssertion(t, out.String(), defaultTeamID, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitOpsWindowsMigration(t *testing.T) {
|
||||
cases := []struct {
|
||||
file string
|
||||
|
||||
@@ -196,6 +196,7 @@
|
||||
"require_all_software_windows": false,
|
||||
"software": null
|
||||
},
|
||||
"windows_enrollment": null,
|
||||
"windows_settings": {
|
||||
"custom_settings": null,
|
||||
"configuration_profiles": null,
|
||||
|
||||
+1
@@ -168,6 +168,7 @@
|
||||
"require_all_software_windows": false,
|
||||
"software": null
|
||||
},
|
||||
"windows_enrollment": null,
|
||||
"windows_settings": {
|
||||
"custom_settings": null,
|
||||
"configuration_profiles": null,
|
||||
|
||||
+1
@@ -103,6 +103,7 @@ spec:
|
||||
require_all_software_windows: false
|
||||
macos_script:
|
||||
software:
|
||||
windows_enrollment: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
configuration_profiles: null
|
||||
|
||||
@@ -103,6 +103,7 @@ spec:
|
||||
require_all_software_windows: false
|
||||
macos_script:
|
||||
software:
|
||||
windows_enrollment: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
configuration_profiles: null
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
"require_all_software_windows": false,
|
||||
"software": null
|
||||
},
|
||||
"windows_enrollment": null,
|
||||
"windows_settings": {
|
||||
"custom_settings": null,
|
||||
"configuration_profiles": null,
|
||||
|
||||
@@ -103,6 +103,7 @@ spec:
|
||||
require_all_software_windows: false
|
||||
macos_script:
|
||||
software:
|
||||
windows_enrollment: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
configuration_profiles: null
|
||||
|
||||
@@ -291,6 +291,9 @@
|
||||
"custom_settings": []
|
||||
},
|
||||
"volume_purchasing_program": null,
|
||||
"windows_enrollment": {
|
||||
"default_fleet": "💻 Workstations"
|
||||
},
|
||||
"android_enabled_and_configured": true,
|
||||
"android_settings": {
|
||||
"custom_settings": []
|
||||
|
||||
+2
@@ -103,6 +103,8 @@ mdm:
|
||||
- "\U0001F4BB\U0001F423 Workstations (canary)"
|
||||
- "\U0001F4F1\U0001F3E2 Company-owned mobile devices"
|
||||
- "\U0001F4F1\U0001F510 Personal mobile devices"
|
||||
windows_enrollment:
|
||||
default_fleet: "\U0001F4BB Workstations"
|
||||
org_info:
|
||||
contact_url: https://fleetdm.com/company/contact
|
||||
org_logo_url_dark_mode: http://some-org-logo-url.com
|
||||
|
||||
@@ -101,6 +101,8 @@ mdm:
|
||||
- "\U0001F4BB\U0001F423 Workstations (canary)"
|
||||
- "\U0001F4F1\U0001F3E2 Company-owned mobile devices"
|
||||
- "\U0001F4F1\U0001F510 Personal mobile devices"
|
||||
windows_enrollment:
|
||||
default_fleet: "\U0001F4BB Workstations"
|
||||
org_info:
|
||||
contact_url: https://fleetdm.com/company/contact
|
||||
org_logo_url_dark_mode: http://some-org-logo-url.com
|
||||
|
||||
@@ -143,6 +143,8 @@ org_settings:
|
||||
- "📱🏢 Company-owned mobile devices"
|
||||
- "📱🔐 Personal mobile devices"
|
||||
location: Fleet Device Management Inc.
|
||||
windows_enrollment:
|
||||
default_fleet: "💻 Workstations"
|
||||
org_info:
|
||||
contact_url: https://fleetdm.com/company/contact
|
||||
org_logo_url_dark_mode: http://some-org-logo-url.com
|
||||
|
||||
@@ -62,6 +62,7 @@ spec:
|
||||
custom_settings: null
|
||||
apple_settings:
|
||||
configuration_profiles: null
|
||||
windows_enrollment: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
configuration_profiles: null
|
||||
|
||||
@@ -62,6 +62,7 @@ spec:
|
||||
custom_settings: null
|
||||
apple_settings:
|
||||
configuration_profiles: null
|
||||
windows_enrollment: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
configuration_profiles: null
|
||||
|
||||
@@ -100,6 +100,9 @@ func RunServerWithMockedDS(t *testing.T, opts ...*service.TestServerOpts) (*http
|
||||
ds.ConditionalAccessMicrosoftGetFunc = func(ctx context.Context) (*fleet.ConditionalAccessMicrosoftIntegration, error) {
|
||||
return &fleet.ConditionalAccessMicrosoftIntegration{}, nil
|
||||
}
|
||||
ds.GetWindowsEnrollmentDefaultFleetFunc = func(ctx context.Context) (*uint, string, error) {
|
||||
return nil, "", nil
|
||||
}
|
||||
ds.NewGlobalPolicyFunc = func(ctx context.Context, authorID *uint, args fleet.PolicyPayload) (*fleet.Policy, error) {
|
||||
return &fleet.Policy{
|
||||
PolicyData: fleet.PolicyData{
|
||||
@@ -515,6 +518,23 @@ func SetupFullGitOpsPremiumServer(t *testing.T) (*mock.Store, **fleet.AppConfig,
|
||||
}
|
||||
return nil, ¬FoundError{}
|
||||
}
|
||||
// Stateful default for the Windows enrollment default fleet config row. Tests can override.
|
||||
var windowsEnrollmentDefaultTeamID *uint
|
||||
ds.GetWindowsEnrollmentDefaultFleetFunc = func(ctx context.Context) (*uint, string, error) {
|
||||
if windowsEnrollmentDefaultTeamID == nil {
|
||||
return nil, "", nil
|
||||
}
|
||||
for _, tm := range savedTeams {
|
||||
if (*tm).ID == *windowsEnrollmentDefaultTeamID {
|
||||
return windowsEnrollmentDefaultTeamID, (*tm).Name, nil
|
||||
}
|
||||
}
|
||||
return nil, "", nil
|
||||
}
|
||||
ds.SetWindowsEnrollmentDefaultFleetFunc = func(ctx context.Context, teamID *uint) error {
|
||||
windowsEnrollmentDefaultTeamID = teamID
|
||||
return nil
|
||||
}
|
||||
ds.TeamByFilenameFunc = func(ctx context.Context, filename string) (*fleet.Team, error) {
|
||||
for _, tm := range savedTeams {
|
||||
if (*tm).Filename != nil && *(*tm).Filename == filename {
|
||||
|
||||
Reference in New Issue
Block a user