Fix GitOps dry run issue with validating profiles with secrets (#32104)
Fixes #31477 Docs PR: https://github.com/fleetdm/fleet/pull/32116 # 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - GitOps now supports FLEET_SECRET_ placeholders in macOS (.mobileconfig/.xml) profiles. Secrets are expanded only for validation, while remaining unexpanded in uploaded content. - Improved environment variable handling: non-secret vars expand as before; server-side secrets are preserved. - Validation enforces that profile display names cannot contain FLEET_SECRET_ values. - Bug Fixes - Resolves validation issues when FLEET_SECRET_ appears in <data> tags by performing safe client-side expansion for validation. - More accurate error reporting during profile parsing and validation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
This commit is contained in:
co-authored by
Lucas Manuel Rodriguez
parent
53b7a0628a
commit
1d7aab04ab
@@ -5,9 +5,11 @@ import (
|
||||
"crypto/md5" // nolint: gosec
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -258,6 +260,24 @@ func NewMDMAppleConfigProfile(raw []byte, teamID *uint) (*MDMAppleConfigProfile,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// payloadDisplayNameRegex is used to extract PayloadDisplayName values from raw XML content
|
||||
var payloadDisplayNameRegex = regexp.MustCompile(`<key>PayloadDisplayName</key>\s*<string>([^<]*)</string>`)
|
||||
|
||||
// ValidateNoSecretsInProfileName checks if PayloadDisplayName contains FLEET_SECRET_ variables
|
||||
// in the raw XML content of a profile.
|
||||
func ValidateNoSecretsInProfileName(xmlContent []byte) error {
|
||||
matches := payloadDisplayNameRegex.FindAllSubmatch(xmlContent, -1)
|
||||
for _, match := range matches {
|
||||
if len(match) > 1 {
|
||||
displayName := string(match[1])
|
||||
if len(ContainsPrefixVars(displayName, ServerSecretPrefix)) > 0 {
|
||||
return errors.New("PayloadDisplayName cannot contain FLEET_SECRET variables")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cp MDMAppleConfigProfile) ValidateUserProvided() error {
|
||||
// first screen the top-level object for reserved identifiers and names
|
||||
if _, ok := mobileconfig.FleetPayloadIdentifiers()[cp.Identifier]; ok {
|
||||
|
||||
@@ -654,3 +654,100 @@ func TestConfigurationProfileLabelEqual(t *testing.T) {
|
||||
"Does cmp.Equal for ConfigurationProfileLabel needs to be updated for new/updated field(s)?")
|
||||
assert.True(t, cmp.Equal(items[0], items[1]))
|
||||
}
|
||||
|
||||
func TestValidateNoSecretsInProfileName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
xmlContent string
|
||||
expectErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "no secrets",
|
||||
xmlContent: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Test Profile</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.test.profile</string>
|
||||
</dict>
|
||||
</plist>`,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "secret in PayloadDisplayName",
|
||||
xmlContent: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Test $FLEET_SECRET_PASSWORD Profile</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.test.profile</string>
|
||||
</dict>
|
||||
</plist>`,
|
||||
expectErr: true,
|
||||
errMsg: "PayloadDisplayName cannot contain FLEET_SECRET variables",
|
||||
},
|
||||
{
|
||||
name: "multiple PayloadDisplayNames with secret in one",
|
||||
xmlContent: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Main Profile</string>
|
||||
<key>PayloadContent</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Sub Profile $FLEET_SECRET_KEY</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>`,
|
||||
expectErr: true,
|
||||
errMsg: "PayloadDisplayName cannot contain FLEET_SECRET variables",
|
||||
},
|
||||
{
|
||||
name: "secret in other field not PayloadDisplayName",
|
||||
xmlContent: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Test Profile</string>
|
||||
<key>PayloadDescription</key>
|
||||
<string>Description with $FLEET_SECRET_VALUE</string>
|
||||
</dict>
|
||||
</plist>`,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "whitespace in PayloadDisplayName value",
|
||||
xmlContent: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string> Test Profile </string>
|
||||
</dict>
|
||||
</plist>`,
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := ValidateNoSecretsInProfileName([]byte(tc.xmlContent))
|
||||
if tc.expectErr {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.errMsg)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,6 +390,11 @@ func (svc *Service) NewMDMAppleConfigProfile(ctx context.Context, teamID uint, r
|
||||
})
|
||||
}
|
||||
|
||||
// Check for secrets in profile name before expansion
|
||||
if err := fleet.ValidateNoSecretsInProfileName(b); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("profile", err.Error()))
|
||||
}
|
||||
|
||||
// Expand and validate secrets in profile
|
||||
expanded, secretsUpdatedAt, err := svc.ds.ExpandEmbeddedSecretsAndUpdatedAt(ctx, string(b))
|
||||
if err != nil {
|
||||
@@ -2594,6 +2599,11 @@ func (svc *Service) BatchSetMDMAppleProfiles(ctx context.Context, tmID *uint, tm
|
||||
fleet.NewInvalidArgumentError(fmt.Sprintf("profiles[%d]", i), "maximum configuration profile file size is 1 MB"),
|
||||
)
|
||||
}
|
||||
// Check for secrets in profile name before expansion
|
||||
if err := fleet.ValidateNoSecretsInProfileName(prof); err != nil {
|
||||
return ctxerr.Wrap(ctx,
|
||||
fleet.NewInvalidArgumentError(fmt.Sprintf("profiles[%d]", i), err.Error()))
|
||||
}
|
||||
// Expand profile for validation
|
||||
expanded, secretsUpdatedAt, err := svc.ds.ExpandEmbeddedSecretsAndUpdatedAt(ctx, string(prof))
|
||||
if err != nil {
|
||||
|
||||
@@ -778,6 +778,12 @@ func TestNewMDMAppleConfigProfile(t *testing.T) {
|
||||
r = bytes.NewReader(mcBytes)
|
||||
_, err = svc.NewMDMAppleConfigProfile(ctx, 0, r, nil, fleet.LabelsIncludeAll)
|
||||
assert.ErrorContains(t, err, "Fleet variable")
|
||||
|
||||
// Test profile with FLEET_SECRET in PayloadDisplayName
|
||||
mcBytes = mcBytesForTest("Profile $FLEET_SECRET_PASSWORD", "test.identifier", "UUID")
|
||||
r = bytes.NewReader(mcBytes)
|
||||
_, err = svc.NewMDMAppleConfigProfile(ctx, 0, r, nil, fleet.LabelsIncludeAll)
|
||||
assert.ErrorContains(t, err, "PayloadDisplayName cannot contain FLEET_SECRET variables")
|
||||
}
|
||||
|
||||
func mcBytesForTest(name, identifier, uuid string) []byte {
|
||||
@@ -802,6 +808,23 @@ func mcBytesForTest(name, identifier, uuid string) []byte {
|
||||
`, name, identifier, uuid))
|
||||
}
|
||||
|
||||
func TestBatchSetMDMAppleProfilesWithSecrets(t *testing.T) {
|
||||
svc, ctx, _ := setupAppleMDMService(t, &fleet.LicenseInfo{Tier: fleet.TierPremium})
|
||||
ctx = viewer.NewContext(ctx, viewer.Viewer{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
||||
|
||||
// Test profile with FLEET_SECRET in PayloadDisplayName
|
||||
profileWithSecret := mcBytesForTest("Profile $FLEET_SECRET_PASSWORD", "test.identifier", "UUID")
|
||||
err := svc.BatchSetMDMAppleProfiles(ctx, nil, nil, [][]byte{profileWithSecret}, false, false)
|
||||
assert.ErrorContains(t, err, "PayloadDisplayName cannot contain FLEET_SECRET variables")
|
||||
|
||||
// Test multiple profiles where one has a secret in PayloadDisplayName
|
||||
goodProfile := mcBytesForTest("Good Profile", "good.identifier", "UUID1")
|
||||
badProfile := mcBytesForTest("Bad $FLEET_SECRET_KEY Profile", "bad.identifier", "UUID2")
|
||||
err = svc.BatchSetMDMAppleProfiles(ctx, nil, nil, [][]byte{goodProfile, badProfile}, false, false)
|
||||
assert.ErrorContains(t, err, "PayloadDisplayName cannot contain FLEET_SECRET variables")
|
||||
assert.ErrorContains(t, err, "profiles[1]")
|
||||
}
|
||||
|
||||
func TestNewMDMAppleDeclaration(t *testing.T) {
|
||||
svc, ctx, ds := setupAppleMDMService(t, &fleet.LicenseInfo{Tier: fleet.TierPremium})
|
||||
ctx = viewer.NewContext(ctx, viewer.Viewer{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
||||
|
||||
@@ -363,15 +363,46 @@ func getProfilesContents(baseDir string, macProfiles []fleet.MDMProfileSpec, win
|
||||
if platform == "macos" {
|
||||
switch ext {
|
||||
case ".mobileconfig", ".xml": // allowing .xml for backwards compatibility
|
||||
mc, err := fleet.NewMDMAppleConfigProfile(fileContents, nil)
|
||||
if err != nil {
|
||||
errForMsg := errors.Unwrap(err)
|
||||
if errForMsg == nil {
|
||||
errForMsg = err
|
||||
// For validation, we need to expand FLEET_SECRET_ variables in <data> tags so the XML parser
|
||||
// can properly validate the profile structure. However, we must be careful not to expose
|
||||
// secrets in the profile name.
|
||||
containsSecrets := len(fleet.ContainsPrefixVars(string(fileContents), fleet.ServerSecretPrefix)) > 0
|
||||
|
||||
if containsSecrets {
|
||||
// If profile contains secrets, check for secrets in PayloadDisplayName first
|
||||
if err := fleet.ValidateNoSecretsInProfileName(fileContents); err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", prefixErrMsg, err)
|
||||
}
|
||||
return nil, fmt.Errorf("%s: %w", prefixErrMsg, errForMsg)
|
||||
|
||||
// Expand secrets for validation
|
||||
validationContents, expandErr := spec.ExpandEnvBytesIncludingSecrets(fileContents)
|
||||
if expandErr != nil {
|
||||
return nil, fmt.Errorf("%s: expanding secrets for validation: %w", prefixErrMsg, expandErr)
|
||||
}
|
||||
|
||||
// Validate the profile structure with expanded secrets
|
||||
mcExpanded, validationErr := fleet.NewMDMAppleConfigProfile(validationContents, nil)
|
||||
if validationErr != nil {
|
||||
errForMsg := errors.Unwrap(validationErr)
|
||||
if errForMsg == nil {
|
||||
errForMsg = validationErr
|
||||
}
|
||||
return nil, fmt.Errorf("%s: %w", prefixErrMsg, errForMsg)
|
||||
}
|
||||
|
||||
name = strings.TrimSpace(mcExpanded.Name)
|
||||
} else {
|
||||
// No secrets, parse normally
|
||||
mc, err := fleet.NewMDMAppleConfigProfile(fileContents, nil)
|
||||
if err != nil {
|
||||
errForMsg := errors.Unwrap(err)
|
||||
if errForMsg == nil {
|
||||
errForMsg = err
|
||||
}
|
||||
return nil, fmt.Errorf("%s: %w", prefixErrMsg, errForMsg)
|
||||
}
|
||||
name = strings.TrimSpace(mc.Name)
|
||||
}
|
||||
name = strings.TrimSpace(mc.Name)
|
||||
case ".json":
|
||||
if mdm.GetRawProfilePlatform(fileContents) != "darwin" {
|
||||
return nil, fmt.Errorf("%s: %s", prefixErrMsg, "Declaration profiles should include valid JSON.")
|
||||
|
||||
@@ -720,6 +720,165 @@ func TestGetProfilesContents(t *testing.T) {
|
||||
expectError: true,
|
||||
wantErr: "Couldn't edit macos_settings.custom_settings (bar.cfg): macOS configuration profiles must be .mobileconfig or .json files",
|
||||
},
|
||||
{
|
||||
name: "with FLEET_SECRET in data tag",
|
||||
baseDir: tempDir,
|
||||
macSetupFiles: [][2]string{
|
||||
{"cert.mobileconfig", `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadContent</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.security.root</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.cert</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>11111111-2222-3333-4444-555555555555</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Test Certificate</string>
|
||||
<key>PayloadContent</key>
|
||||
<data>$FLEET_SECRET_CERT_DATA</data>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.profile</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Certificate Profile</string>
|
||||
</dict>
|
||||
</plist>`},
|
||||
},
|
||||
environment: map[string]string{
|
||||
"FLEET_SECRET_CERT_DATA": "VGVzdENlcnREYXRhQmFzZTY0", // "TestCertDataBase64" in base64
|
||||
},
|
||||
expandEnv: true,
|
||||
expectError: false,
|
||||
want: []fleet.MDMProfileBatchPayload{
|
||||
{
|
||||
Name: "Certificate Profile",
|
||||
Contents: []byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadContent</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.security.root</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.cert</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>11111111-2222-3333-4444-555555555555</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Test Certificate</string>
|
||||
<key>PayloadContent</key>
|
||||
<data>$FLEET_SECRET_CERT_DATA</data>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.profile</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Certificate Profile</string>
|
||||
</dict>
|
||||
</plist>`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with FLEET_SECRET in PayloadDisplayName - should reject",
|
||||
baseDir: tempDir,
|
||||
macSetupFiles: [][2]string{
|
||||
{"secret_name.mobileconfig", `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.profile</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Profile $FLEET_SECRET_NAME</string>
|
||||
</dict>
|
||||
</plist>`},
|
||||
},
|
||||
environment: map[string]string{
|
||||
"FLEET_SECRET_NAME": "SecretProfileName",
|
||||
},
|
||||
expandEnv: true,
|
||||
expectError: true,
|
||||
wantErr: "PayloadDisplayName cannot contain FLEET_SECRET variables",
|
||||
},
|
||||
{
|
||||
name: "with FLEET_VAR in profile - should not expand",
|
||||
baseDir: tempDir,
|
||||
macSetupFiles: [][2]string{
|
||||
{"fleet_var.mobileconfig", `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.profile</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Profile with FLEET_VAR</string>
|
||||
<key>SomeValue</key>
|
||||
<string>$FLEET_VAR_HOST_END_USER_IDP_USERNAME</string>
|
||||
</dict>
|
||||
</plist>`},
|
||||
},
|
||||
expandEnv: true,
|
||||
expectError: false,
|
||||
want: []fleet.MDMProfileBatchPayload{
|
||||
{
|
||||
Name: "Profile with FLEET_VAR",
|
||||
Contents: []byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.example.profile</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>Profile with FLEET_VAR</string>
|
||||
<key>SomeValue</key>
|
||||
<string>$FLEET_VAR_HOST_END_USER_IDP_USERNAME</string>
|
||||
</dict>
|
||||
</plist>`),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -93,9 +93,9 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
<key>PayloadContent</key>
|
||||
<array/>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>$FLEET_SECRET_INVALID</string>
|
||||
<string>My profile</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>N3</string>
|
||||
<string>$FLEET_SECRET_INVALID</string>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadUUID</key>
|
||||
@@ -110,6 +110,31 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
errMsg := extractServerErrorText(res.Body)
|
||||
require.Contains(t, errMsg, "$FLEET_SECRET_INVALID")
|
||||
|
||||
invalidSecretsProfile = []byte(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadContent</key>
|
||||
<array/>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>$FLEET_SECRET_INVALID</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>N3</string>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>601E0B42-0989-4FAD-A61B-18656BA3670E</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
`)
|
||||
|
||||
res = s.Do("POST", "/api/v1/fleet/mdm/apple/profiles/batch", batchSetMDMAppleProfilesRequest{Profiles: [][]byte{invalidSecretsProfile}}, http.StatusUnprocessableEntity)
|
||||
errMsg = extractServerErrorText(res.Body)
|
||||
require.Contains(t, errMsg, "PayloadDisplayName cannot contain FLEET_SECRET variables")
|
||||
|
||||
// create a new team
|
||||
tm, err := s.ds.NewTeam(ctx, &fleet.Team{Name: "batch_set_mdm_profiles"})
|
||||
require.NoError(t, err)
|
||||
@@ -204,7 +229,6 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
// Use secret variables in a profile
|
||||
secretIdentifier := "secret-identifier-1"
|
||||
secretType := "secret.type.1"
|
||||
secretName := "secretName"
|
||||
secretProfile := string(mobileconfigForTest("NS1", "IS1"))
|
||||
req := createSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
@@ -216,10 +240,6 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
Name: "FLEET_SECRET_TYPE",
|
||||
Value: secretType,
|
||||
},
|
||||
{
|
||||
Name: "FLEET_SECRET_NAME",
|
||||
Value: secretName,
|
||||
},
|
||||
{
|
||||
Name: "FLEET_SECRET_PROFILE",
|
||||
Value: secretProfile,
|
||||
@@ -233,7 +253,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
teamProfiles = [][]byte{
|
||||
mobileconfigForTest("N4", "I4"),
|
||||
mobileconfigForTestWithContent("N5", "I5", "$FLEET_SECRET_IDENTIFIER", "${FLEET_SECRET_TYPE}",
|
||||
"$FLEET_SECRET_NAME"),
|
||||
"InnerName5"),
|
||||
// The whole profile is one big secret.
|
||||
[]byte("$FLEET_SECRET_PROFILE"),
|
||||
}
|
||||
@@ -253,7 +273,6 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
// Manually replace the expected secret variables in the profile
|
||||
wantTeamProfiles[1] = []byte(strings.ReplaceAll(string(wantTeamProfiles[1]), "$FLEET_SECRET_IDENTIFIER", secretIdentifier))
|
||||
wantTeamProfiles[1] = []byte(strings.ReplaceAll(string(wantTeamProfiles[1]), "${FLEET_SECRET_TYPE}", secretType))
|
||||
wantTeamProfiles[1] = []byte(strings.ReplaceAll(string(wantTeamProfiles[1]), "$FLEET_SECRET_NAME", secretName))
|
||||
wantTeamProfiles[2] = []byte(secretProfile)
|
||||
// verify that we should install the team profiles
|
||||
s.signedProfilesMatch(wantTeamProfiles, installs)
|
||||
@@ -272,12 +291,16 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
require.Empty(t, removes)
|
||||
|
||||
// Change the secret variable and upload the profiles again. We should see the profile with updated secret installed.
|
||||
secretName = "newSecretName"
|
||||
secretType = "new.secret.type.1"
|
||||
req = createSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_NAME",
|
||||
Value: secretName, // changed
|
||||
Name: "FLEET_SECRET_IDENTIFIER",
|
||||
Value: secretIdentifier, // did not change
|
||||
},
|
||||
{
|
||||
Name: "FLEET_SECRET_TYPE",
|
||||
Value: secretType, // changed
|
||||
},
|
||||
{
|
||||
Name: "FLEET_SECRET_PROFILE",
|
||||
@@ -297,7 +320,6 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
wantTeamProfilesChanged[0] = []byte(strings.ReplaceAll(string(wantTeamProfilesChanged[0]), "$FLEET_SECRET_IDENTIFIER",
|
||||
secretIdentifier))
|
||||
wantTeamProfilesChanged[0] = []byte(strings.ReplaceAll(string(wantTeamProfilesChanged[0]), "${FLEET_SECRET_TYPE}", secretType))
|
||||
wantTeamProfilesChanged[0] = []byte(strings.ReplaceAll(string(wantTeamProfilesChanged[0]), "$FLEET_SECRET_NAME", secretName))
|
||||
// verify that we should install the team profiles
|
||||
s.signedProfilesMatch(wantTeamProfilesChanged, installs)
|
||||
wantTeamProfiles[1] = wantTeamProfilesChanged[0]
|
||||
@@ -343,12 +365,16 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
require.Empty(t, removes)
|
||||
|
||||
// Change the secret variable and upload the profiles again. We should see the profile with updated secret installed.
|
||||
secretName = "new2SecretName"
|
||||
secretType = "new2.secret.type.1"
|
||||
req = createSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_NAME",
|
||||
Value: secretName, // changed
|
||||
Name: "FLEET_SECRET_IDENTIFIER",
|
||||
Value: secretIdentifier, // did not change
|
||||
},
|
||||
{
|
||||
Name: "FLEET_SECRET_TYPE",
|
||||
Value: secretType, // changed
|
||||
},
|
||||
{
|
||||
Name: "FLEET_SECRET_PROFILE",
|
||||
@@ -368,7 +394,6 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
wantTeamProfilesChanged[0] = []byte(strings.ReplaceAll(string(wantTeamProfilesChanged[0]), "$FLEET_SECRET_IDENTIFIER",
|
||||
secretIdentifier))
|
||||
wantTeamProfilesChanged[0] = []byte(strings.ReplaceAll(string(wantTeamProfilesChanged[0]), "${FLEET_SECRET_TYPE}", secretType))
|
||||
wantTeamProfilesChanged[0] = []byte(strings.ReplaceAll(string(wantTeamProfilesChanged[0]), "$FLEET_SECRET_NAME", secretName))
|
||||
// verify that we should install the team profiles
|
||||
s.signedProfilesMatch(wantTeamProfilesChanged, installs)
|
||||
wantTeamProfiles[1] = wantTeamProfilesChanged[0]
|
||||
|
||||
Reference in New Issue
Block a user