Don't ignore GitOps secrets on free tier (#44148)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #44118

# Details

On free tier, ignore exceptions and always apply enroll secrets when
present.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] 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.
n/a, unreleased

## 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
@AndreyKizimenko QA'd manually

For unreleased bug fixes in a release candidate, one of:

- [X] Confirmed that the fix is not expected to adversely impact load
test results


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed GitOps to correctly apply enrollment secrets and labels on free
tier licenses, even when exception flags are configured.

* **Tests**
* Added tests validating that GitOps properly applies secrets and labels
for free tier customers.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Scott Gress
2026-04-27 16:31:58 -05:00
committed by GitHub
parent 899dc5aa57
commit 9ae4373f89
2 changed files with 117 additions and 2 deletions
+115
View File
@@ -716,6 +716,121 @@ software:
}
}
// TestGitOpsSecretsAppliedOnFreeTierDespiteException verifies that on free tier, secrets
// in a GitOps file are applied even when the server has GitOpsExceptions.Secrets=true
// (the default for new installs). Free-tier users can't toggle the exception off, so
// the exception flag must not cause secrets to be silently dropped.
func TestGitOpsSecretsAppliedOnFreeTierDespiteException(t *testing.T) {
// Cannot run t.Parallel() because it sets environment variables
license := &fleet.LicenseInfo{Tier: fleet.TierFree}
_, ds := testing_utils.RunServerWithMockedDS(
t, &service.TestServerOpts{
License: license,
KeyValueStore: testing_utils.NewMemKeyValueStore(),
},
)
setupEmptyGitOpsMocks(ds)
// Server returns Exceptions.Secrets=true (the default for new installs).
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{
GitOpsConfig: fleet.GitOpsConfig{
Exceptions: fleet.GitOpsExceptions{Secrets: true},
},
}, nil
}
ds.SaveAppConfigFunc = func(ctx context.Context, config *fleet.AppConfig) error { return nil }
var appliedSecrets []*fleet.EnrollSecret
ds.ApplyEnrollSecretsFunc = func(ctx context.Context, teamID *uint, secrets []*fleet.EnrollSecret) error {
appliedSecrets = secrets
return nil
}
ds.IsEnrollSecretAvailableFunc = func(ctx context.Context, secret string, isNew bool, teamID *uint) (bool, error) {
return true, nil
}
globalFile, err := os.CreateTemp(t.TempDir(), "*.yml")
require.NoError(t, err)
_, err = globalFile.WriteString(`
org_settings:
server_settings:
server_url: https://fleet.example.com
org_info:
org_name: Test
secrets:
- secret: free-tier-secret-value
controls:
policies:
agent_options:
`)
require.NoError(t, err)
_, err = RunAppNoChecks([]string{"gitops", "-f", globalFile.Name()})
require.NoError(t, err)
require.Len(t, appliedSecrets, 1, "secrets in YAML should be applied on free tier even when Exceptions.Secrets=true")
assert.Equal(t, "free-tier-secret-value", appliedSecrets[0].Secret)
}
// TestGitOpsLabelsAppliedOnFreeTierDespiteException verifies that on free tier, labels
// in a GitOps file are applied even when the server has GitOpsExceptions.Labels=true
// (the value set by the exceptions migration for existing instances). Free-tier users
// can't toggle the exception off, so applying labels via GitOps must still work.
func TestGitOpsLabelsAppliedOnFreeTierDespiteException(t *testing.T) {
// Cannot run t.Parallel() because it sets environment variables
license := &fleet.LicenseInfo{Tier: fleet.TierFree}
_, ds := testing_utils.RunServerWithMockedDS(
t, &service.TestServerOpts{
License: license,
KeyValueStore: testing_utils.NewMemKeyValueStore(),
},
)
setupEmptyGitOpsMocks(ds)
// Server returns Exceptions.Labels=true (the value set by the migration for existing instances).
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{
GitOpsConfig: fleet.GitOpsConfig{
Exceptions: fleet.GitOpsExceptions{Labels: true},
},
}, nil
}
ds.SaveAppConfigFunc = func(ctx context.Context, config *fleet.AppConfig) error { return nil }
var appliedLabelSpecs []*fleet.LabelSpec
ds.ApplyLabelSpecsWithAuthorFunc = func(ctx context.Context, specs []*fleet.LabelSpec, authorID *uint) error {
appliedLabelSpecs = specs
return nil
}
ds.GetLabelSpecsFunc = func(ctx context.Context, filter fleet.TeamFilter) ([]*fleet.LabelSpec, error) {
return nil, nil
}
globalFile, err := os.CreateTemp(t.TempDir(), "*.yml")
require.NoError(t, err)
_, err = globalFile.WriteString(`
org_settings:
server_settings:
server_url: https://fleet.example.com
org_info:
org_name: Test
labels:
- name: free-tier-label
query: SELECT 1
controls:
policies:
agent_options:
`)
require.NoError(t, err)
_, err = RunAppNoChecks([]string{"gitops", "-f", globalFile.Name()})
require.NoError(t, err)
require.Len(t, appliedLabelSpecs, 1, "labels in YAML should be applied on free tier even when Exceptions.Labels=true")
assert.Equal(t, "free-tier-label", appliedLabelSpecs[0].Name)
}
// TestGitOpsExceptionsPreserveOmittedKeys verifies that when exceptions are ON,
// omitting the excepted keys from YAML preserves existing data.
func TestGitOpsExceptionsPreserveOmittedKeys(t *testing.T) {