diff --git a/tables/localnetworkpermissions/local_network_permissions_test.go b/tables/localnetworkpermissions/local_network_permissions_test.go index dda7124..630732d 100644 --- a/tables/localnetworkpermissions/local_network_permissions_test.go +++ b/tables/localnetworkpermissions/local_network_permissions_test.go @@ -1,10 +1,13 @@ package localnetworkpermissions import ( + "context" _ "embed" "os" + "path/filepath" "testing" + "github.com/micromdm/plist" "github.com/osquery/osquery-go/plugin/table" "github.com/stretchr/testify/assert" ) @@ -12,6 +15,15 @@ import ( //go:embed test_networkextension.plist var testPlistData []byte +func withNetworkExtensionPlistPath(t *testing.T, path string) { + t.Helper() + original := networkExtensionPlistPath + networkExtensionPlistPath = path + t.Cleanup(func() { + networkExtensionPlistPath = original + }) +} + func TestLocalNetworkPermissionsColumns(t *testing.T) { t.Parallel() columns := LocalNetworkPermissionsColumns() @@ -62,8 +74,6 @@ func TestLocalNetworkPermissionsGenerate(t *testing.T) { } func TestLocalNetworkPermissionsGenerateFileNotFound(t *testing.T) { - t.Parallel() - // Test readLocalNetworkPermissions with a non-existent file path permissions, err := readLocalNetworkPermissions("/nonexistent/path/to/plist") assert.Error(t, err) // Should return an error for file not found @@ -71,6 +81,66 @@ func TestLocalNetworkPermissionsGenerateFileNotFound(t *testing.T) { assert.Nil(t, permissions) } +func TestLocalNetworkPermissionsGenerateRows(t *testing.T) { + tmpFile := filepath.Join(t.TempDir(), "networkextension.plist") + err := os.WriteFile(tmpFile, testPlistData, 0600) + assert.NoError(t, err) + withNetworkExtensionPlistPath(t, tmpFile) + + results, err := LocalNetworkPermissionsGenerate(context.Background(), table.QueryContext{}) + assert.NoError(t, err) + assert.Equal(t, []map[string]string{ + { + "bundle_id": "com.example.testapp", + "executable_path": "/Applications/TestApp.app/Contents/MacOS/TestApp", + "display_name": "Test App", + "type": "applications", + "state": "1", + "provider_added": "true", + }, + { + "bundle_id": "com.example.anotherapp", + "executable_path": "/Applications/AnotherApp.app/Contents/MacOS/AnotherApp", + "display_name": "Another App", + "type": "applications", + "state": "0", + "provider_added": "false", + }, + }, results) +} + +func TestLocalNetworkPermissionsGenerateMissingFile(t *testing.T) { + withNetworkExtensionPlistPath(t, filepath.Join(t.TempDir(), "missing.plist")) + + results, err := LocalNetworkPermissionsGenerate(context.Background(), table.QueryContext{}) + assert.NoError(t, err) + assert.Empty(t, results) +} + +func TestLocalNetworkPermissionsGenerateInvalidPlist(t *testing.T) { + tmpFile := filepath.Join(t.TempDir(), "networkextension.plist") + err := os.WriteFile(tmpFile, []byte("not plist"), 0600) + assert.NoError(t, err) + withNetworkExtensionPlistPath(t, tmpFile) + + results, err := LocalNetworkPermissionsGenerate(context.Background(), table.QueryContext{}) + assert.Error(t, err) + assert.Nil(t, results) + assert.ErrorContains(t, err, "read local network permissions") +} + +func TestReadLocalNetworkPermissionsWithoutObjects(t *testing.T) { + tmpFile := filepath.Join(t.TempDir(), "networkextension.plist") + err := os.WriteFile(tmpFile, []byte(` + +not_objects`), 0600) + assert.NoError(t, err) + + permissions, err := readLocalNetworkPermissions(tmpFile) + assert.NoError(t, err) + assert.Nil(t, permissions) +} + func TestExtractPermissionsFromObjects(t *testing.T) { t.Parallel() @@ -83,6 +153,42 @@ func TestExtractPermissionsFromObjects(t *testing.T) { assert.Empty(t, permissions) } +func TestExtractPermissionFromDictPartialAndMismatchedObjects(t *testing.T) { + objects := []interface{}{ + "bundleid", + "path", + "com.example.testapp", + map[string]interface{}{ + "NS.keys": []interface{}{uint64(0), uint64(1), "displayname"}, + "NS.objects": []interface{}{uint64(2), "file:///Applications/Test.app"}, + }, + } + + permissions := extractPermissionsFromObjects(objects) + assert.Equal(t, []LocalNetworkPermission{ + { + BundleID: "com.example.testapp", + ExecutablePath: "/Applications/Test.app", + }, + }, permissions) +} + +func TestIsAppPermissionDictRejectsNonPermissionDictionaries(t *testing.T) { + assert.False(t, isAppPermissionDict(map[string]interface{}{}, nil)) + assert.False(t, isAppPermissionDict(map[string]interface{}{ + "NS.keys": []interface{}{"unrelated"}, + "NS.objects": []interface{}{"value"}, + }, nil)) +} + +func TestResolveUID(t *testing.T) { + objects := []interface{}{"zero", "one"} + assert.Equal(t, "one", resolveUID(uint64(1), objects)) + assert.Equal(t, "one", resolveUID(plist.UID(1), objects)) + assert.Equal(t, uint64(3), resolveUID(uint64(3), objects)) + assert.Equal(t, "literal", resolveUID("literal", objects)) +} + func TestToInt(t *testing.T) { t.Parallel()