diff --git a/orbit/pkg/profiles/profiles_darwin.go b/orbit/pkg/profiles/profiles_darwin.go
index 0cd3c6ffdc..e140a6f4ea 100644
--- a/orbit/pkg/profiles/profiles_darwin.go
+++ b/orbit/pkg/profiles/profiles_darwin.go
@@ -4,7 +4,6 @@ package profiles
import (
"bytes"
- "encoding/json"
"errors"
"fmt"
"net/url"
@@ -13,39 +12,64 @@ import (
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
+ "github.com/groob/plist"
)
-// GetFleetdConfig reads a system level setting set with Fleet's payload identifier.
-func GetFleetdConfig() (*fleet.MDMAppleFleetdConfig, error) {
- readFleetdConfigAppleScript := fmt.Sprintf(`
- const config = $.NSUserDefaults.alloc.initWithSuiteName("%s");
- const enrollSecret = config.objectForKey("EnrollSecret");
- const fleetURL = config.objectForKey("FleetURL");
- const enableScripts = config.objectForKey("EnableScripts");
- JSON.stringify({
- EnrollSecret: ObjC.deepUnwrap(enrollSecret),
- FleetURL: ObjC.deepUnwrap(fleetURL),
- EnableScripts: ObjC.deepUnwrap(enableScripts),
- });
- `, mobileconfig.FleetdConfigPayloadIdentifier)
+type profileItem struct {
+ PayloadContent fleet.MDMAppleFleetdConfig
+ PayloadType string
+ PayloadIdentifier string
+}
- outBuf, err := execScript(readFleetdConfigAppleScript)
+type profilePayload struct {
+ ProfileItems []profileItem
+}
+
+type profilesOutput struct {
+ ComputerLevel []profilePayload `plist:"_computerlevel"`
+}
+
+// GetFleetdConfig searches and parses a device level configuration profile
+// with Fleet's payload identifier.
+func GetFleetdConfig() (*fleet.MDMAppleFleetdConfig, error) {
+ p, err := getProfile(mobileconfig.FleetdConfigPayloadIdentifier)
+ if err != nil {
+ if err == ErrNotFound {
+ return &fleet.MDMAppleFleetdConfig{}, nil
+ }
+
+ return nil, err
+ }
+
+ return &p.ProfileItems[0].PayloadContent, nil
+}
+
+func getProfile(identifier string) (*profilePayload, error) {
+ outBuf, err := execProfileCmd()
if err != nil {
return nil, fmt.Errorf("get profile: %w", err)
}
- var cfg fleet.MDMAppleFleetdConfig
- if err = json.Unmarshal(outBuf.Bytes(), &cfg); err != nil {
- return nil, fmt.Errorf("unmarshaling configuration: %w", err)
+ var profiles profilesOutput
+ if err := plist.Unmarshal(outBuf.Bytes(), &profiles); err != nil {
+ return nil, fmt.Errorf("get profile: %w", err)
}
- return &cfg, err
+ for _, profile := range profiles.ComputerLevel {
+ for _, item := range profile.ProfileItems {
+ if item.PayloadIdentifier == identifier {
+ return &profile, nil
+ }
+ }
+ }
+
+ return nil, ErrNotFound
}
-// execScript is declared as a variable so it can be overwritten by tests.
-var execScript = func(script string) (*bytes.Buffer, error) {
+// execProfileCmd is declared as a variable so it can be overwritten by tests.
+var execProfileCmd = func() (*bytes.Buffer, error) {
var outBuf bytes.Buffer
- cmd := exec.Command("osascript", "-l", "JavaScript", "-e", script)
+ cmd := exec.Command("/usr/bin/profiles", "list", "-o", "stdout-xml")
cmd.Stdout = &outBuf
cmd.Stderr = &outBuf
if err := cmd.Run(); err != nil {
diff --git a/orbit/pkg/profiles/profiles_darwin_test.go b/orbit/pkg/profiles/profiles_darwin_test.go
index 4e7176816a..8919c42270 100644
--- a/orbit/pkg/profiles/profiles_darwin_test.go
+++ b/orbit/pkg/profiles/profiles_darwin_test.go
@@ -5,6 +5,7 @@ package profiles
import (
"bytes"
"errors"
+ "io"
"testing"
"github.com/fleetdm/fleet/v4/server/fleet"
@@ -18,55 +19,18 @@ func TestGetFleetdConfig(t *testing.T) {
cmdOut *string
cmdErr error
wantOut *fleet.MDMAppleFleetdConfig
- wantErr string
+ wantErr error
}{
- {nil, testErr, nil, testErr.Error()},
- {ptr.String("invalid-json"), nil, nil, "unmarshaling configuration"},
- {ptr.String("{}"), nil, &fleet.MDMAppleFleetdConfig{}, ""},
- {
- ptr.String(`{"EnrollSecret": "ENROLL_SECRET", "FleetURL": "https://test.example.com", "EnableScripts": true}`),
- nil,
- &fleet.MDMAppleFleetdConfig{
- EnrollSecret: "ENROLL_SECRET",
- FleetURL: "https://test.example.com",
- EnableScripts: true,
- },
- "",
- },
- {
- ptr.String(`{"EnrollSecret": "ENROLL_SECRET", "FleetURL": "https://test.example.com", "EnableScripts": false}`),
- nil,
- &fleet.MDMAppleFleetdConfig{
- EnrollSecret: "ENROLL_SECRET",
- FleetURL: "https://test.example.com",
- EnableScripts: false,
- },
- "",
- },
- {
- ptr.String(`{"EnableScripts": true}`),
- nil,
- &fleet.MDMAppleFleetdConfig{EnableScripts: true},
- "",
- },
- {
- ptr.String(`{"EnrollSecret": "ENROLL_SECRET", "FleetURL": ""}`),
- nil,
- &fleet.MDMAppleFleetdConfig{EnrollSecret: "ENROLL_SECRET"},
- "",
- },
- {
- ptr.String(`{"EnrollSecret": "", "FleetURL": "https://test.example.com"}`),
- nil,
- &fleet.MDMAppleFleetdConfig{FleetURL: "https://test.example.com"},
- "",
- },
+ {nil, testErr, nil, testErr},
+ {ptr.String("invalid-xml"), nil, nil, io.EOF},
+ {&emptyOutput, nil, &fleet.MDMAppleFleetdConfig{}, nil},
+ {&withFleetdConfig, nil, &fleet.MDMAppleFleetdConfig{EnrollSecret: "ENROLL_SECRET", FleetURL: "https://test.example.com"}, nil},
}
- origExecScript := execScript
- t.Cleanup(func() { execScript = origExecScript })
+ origExecProfileCmd := execProfileCmd
+ t.Cleanup(func() { execProfileCmd = origExecProfileCmd })
for _, c := range cases {
- execScript = func(script string) (*bytes.Buffer, error) {
+ execProfileCmd = func() (*bytes.Buffer, error) {
if c.cmdOut == nil {
return nil, c.cmdErr
}
@@ -77,15 +41,73 @@ func TestGetFleetdConfig(t *testing.T) {
}
out, err := GetFleetdConfig()
- if c.wantErr != "" {
- require.ErrorContains(t, err, c.wantErr)
- } else {
- require.NoError(t, err)
- }
+ require.ErrorIs(t, err, c.wantErr)
require.Equal(t, c.wantOut, out)
}
+
}
+var (
+ emptyOutput = `
+
+
+
+`
+
+ withFleetdConfig = `
+
+
+
+
+ _computerlevel
+
+
+ ProfileDescription
+ test descripiton
+ ProfileDisplayName
+ test name
+ ProfileIdentifier
+ com.fleetdm.fleetd.config
+ ProfileInstallDate
+ 2023-02-27 18:55:07 +0000
+ ProfileItems
+
+
+ PayloadContent
+
+ EnrollSecret
+ ENROLL_SECRET
+ FleetURL
+ https://test.example.com
+
+ PayloadDescription
+ test description
+ PayloadDisplayName
+ test name
+ PayloadIdentifier
+ com.fleetdm.fleetd.config
+ PayloadType
+ com.fleetdm.fleetd
+ PayloadUUID
+ 0C6AFB45-01B6-4E19-944A-123CD16381C7
+ PayloadVersion
+ 1
+
+
+ ProfileRemovalDisallowed
+ true
+ ProfileType
+ Configuration
+ ProfileUUID
+ 8D0F62E6-E24F-4B2F-AFA8-CAC1F07F4FDC
+ ProfileVersion
+ 1
+
+
+
+`
+)
+
func TestIsEnrolledInMDM(t *testing.T) {
cases := []struct {
cmdOut *string
diff --git a/orbit/pkg/update/notifications.go b/orbit/pkg/update/notifications.go
index 7d02fb7a17..18076ba922 100644
--- a/orbit/pkg/update/notifications.go
+++ b/orbit/pkg/update/notifications.go
@@ -318,7 +318,7 @@ func ApplyRunScriptsConfigFetcherMiddleware(fetcher OrbitConfigFetcher, scriptsE
Fetcher: fetcher,
ScriptsExecutionEnabled: scriptsEnabled,
ScriptsClient: scriptsClient,
- dynamicScriptsEnabledCheckInterval: time.Minute,
+ dynamicScriptsEnabledCheckInterval: 5 * time.Minute,
}
// start the dynamic check for scripts enabled if required
scriptsFetcher.runDynamicScriptsEnabledCheck()