Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/test-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,12 @@ jobs:
uses: vladopajic/go-test-coverage@v2
with:
config: ./.testcoverage.yml
test-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: run tests
run: go test ./...
15 changes: 13 additions & 2 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import (
osq "github.com/macadmins/osquery-extension/pkg/utils"
)

const launchServicesPlistPath = "Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist"

type Client struct {
Runner osq.CmdRunner
CurrentUser string
PlistLocation string
}

type Option func(*Client)
type currentUserLookup func() (*user.User, error)

func WithCurrentUser(currentUser string) Option {
return func(c *Client) {
Expand All @@ -27,23 +30,31 @@ func WithPlistLocation(plistLocation string) Option {
}

func NewClient(opts ...Option) (Client, error) {
return newClient(user.Current, opts...)
}

func newClient(lookupCurrentUser currentUserLookup, opts ...Option) (Client, error) {
c := Client{}
c.Runner = osq.NewRunner().Runner
for _, opt := range opts {
opt(&c)
}

if c.CurrentUser == "" {
currentUser, err := user.Current()
currentUser, err := lookupCurrentUser()
if err != nil {
return c, err
}
c.CurrentUser = currentUser.Username
}

if c.PlistLocation == "" {
c.PlistLocation = "/Users/" + c.CurrentUser + "/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist"
c.PlistLocation = defaultLaunchServicesPlistLocation(c.CurrentUser)
}

return c, nil
}

func defaultLaunchServicesPlistLocation(currentUser string) string {
return "/Users/" + currentUser + "/" + launchServicesPlistPath
}
39 changes: 34 additions & 5 deletions pkg/client/client_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"errors"
"os/user"
"testing"

Expand All @@ -20,15 +21,16 @@ func TestNewClientWithCurrentUser(t *testing.T) {
client, err := NewClient(WithCurrentUser(expectedUser))
assert.NoError(t, err, "NewClient should not return an error")
assert.Equal(t, expectedUser, client.CurrentUser, "CurrentUser should be set to the provided value")
assert.Equal(t, "/Users/testuser/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist", client.PlistLocation, "PlistLocation should use the provided current user")
}

func TestNewClientDefaultCurrentUser(t *testing.T) {
currentUser, err := user.Current()
assert.NoError(t, err, "user.Current should not return an error")

client, err := NewClient()
client, err := newClient(func() (*user.User, error) {
return &user.User{Username: "systemuser"}, nil
})
assert.NoError(t, err, "NewClient should not return an error")
assert.Equal(t, currentUser.Username, client.CurrentUser, "CurrentUser should be set to the system's current user")
assert.Equal(t, "systemuser", client.CurrentUser, "CurrentUser should be set to the system's current user")
assert.Equal(t, "/Users/systemuser/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist", client.PlistLocation, "PlistLocation should use the system's current user")
}

func TestNewClientWithPlistLocation(t *testing.T) {
Expand All @@ -37,3 +39,30 @@ func TestNewClientWithPlistLocation(t *testing.T) {
assert.NoError(t, err, "NewClient should not return an error")
assert.Equal(t, expectedPlistLocation, client.PlistLocation, "PlistLocation should be set to the provided value")
}

func TestNewClientWithCurrentUserSkipsCurrentUserLookup(t *testing.T) {
client, err := newClient(func() (*user.User, error) {
return nil, errors.New("current user lookup should not be called")
}, WithCurrentUser("testuser"))

assert.NoError(t, err, "NewClient should not return an error")
assert.Equal(t, "testuser", client.CurrentUser, "CurrentUser should be set to the provided value")
assert.Equal(t, "/Users/testuser/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist", client.PlistLocation, "PlistLocation should use the provided current user")
}

func TestNewClientReturnsCurrentUserLookupError(t *testing.T) {
expectedErr := errors.New("current user lookup failed")

client, err := newClient(func() (*user.User, error) {
return nil, expectedErr
})

assert.ErrorIs(t, err, expectedErr, "NewClient should return the current user lookup error")
assert.Empty(t, client.CurrentUser, "CurrentUser should not be set when lookup fails")
}

func TestDefaultLaunchServicesPlistLocation(t *testing.T) {
location := defaultLaunchServicesPlistLocation("testuser")

assert.Equal(t, "/Users/testuser/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist", location, "default LaunchServices plist location should match the legacy path")
}
Loading