Skip to content
Closed
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
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ go_library(
"//tables/authdb",
"//tables/chromeuserprofiles",
"//tables/crowdstrike_falcon",
"//tables/dockutil",
"//tables/energyimpact",
"//tables/fileline",
"//tables/filevaultusers",
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/macadmins/osquery-extension/tables/alt_system_info"
"github.com/macadmins/osquery-extension/tables/chromeuserprofiles"
"github.com/macadmins/osquery-extension/tables/crowdstrike_falcon"
"github.com/macadmins/osquery-extension/tables/dockutil"
"github.com/macadmins/osquery-extension/tables/energyimpact"
"github.com/macadmins/osquery-extension/tables/fileline"
"github.com/macadmins/osquery-extension/tables/filevaultusers"
Expand Down Expand Up @@ -93,6 +94,7 @@ func main() {

if runtime.GOOS == "darwin" {
darwinPlugins := []osquery.OsqueryPlugin{
table.NewPlugin("dockutil", dockutil.DockutilColumns(), dockutil.DockutilGenerate),
table.NewPlugin("energy_impact", energyimpact.EnergyImpactColumns(), energyimpact.EnergyImpactGenerate),
table.NewPlugin("filevault_users", filevaultusers.FileVaultUsersColumns(), filevaultusers.FileVaultUsersGenerate),
table.NewPlugin("local_network_permissions", localnetworkpermissions.LocalNetworkPermissionsColumns(), localnetworkpermissions.LocalNetworkPermissionsGenerate),
Expand Down
26 changes: 26 additions & 0 deletions tables/dockutil/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "dockutil",
srcs = ["dockutil.go"],
importpath = "github.com/macadmins/osquery-extension/tables/dockutil",
visibility = ["//visibility:public"],
deps = [
"//pkg/utils",
"@com_github_osquery_osquery_go//plugin/table",
"@com_github_pkg_errors//:errors",
],
)

go_test(
name = "dockutil_test",
srcs = ["dockutil_test.go"],
embed = [":dockutil"],
deps = [
"//pkg/utils",
"@com_github_osquery_osquery_go//plugin/table",
"@com_github_pkg_errors//:errors",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file imports github.com/pkg/errors (line 7 of dockutil_test.go) but this dependency is not declared in the test's deps list. Add @com_github_pkg_errors//:errors to the deps array to fix the missing dependency.

Suggested change
"@com_github_stretchr_testify//require",
"@com_github_stretchr_testify//require",
"@com_github_pkg_errors//:errors",

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 77878f0

],
)
65 changes: 65 additions & 0 deletions tables/dockutil/dockutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package dockutil

import (
"context"
"os"
"strings"

"github.com/macadmins/osquery-extension/pkg/utils"
"github.com/osquery/osquery-go/plugin/table"
"github.com/pkg/errors"
)

const dockutilPath = "/usr/local/bin/dockutil"

func DockutilColumns() []table.ColumnDefinition {
return []table.ColumnDefinition{
table.TextColumn("version"),
table.TextColumn("path"),
}
}

func DockutilGenerate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
var results []map[string]string
r := utils.NewRunner()
fs := utils.OSFileSystem{}

version, path, err := runDockutil(r, fs)
if err != nil {
return results, err
}

// Only add a row if dockutil is installed
if version != "" {
results = append(results, map[string]string{
"version": version,
"path": path,
})
}

return results, nil
}

func runDockutil(r utils.Runner, fs utils.FileSystem) (string, string, error) {
// Check if dockutil exists
_, err := fs.Stat(dockutilPath)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
// Not an error, just not installed
return "", "", nil
}
return "", "", err
}

// Run dockutil --version
out, err := r.Runner.RunCmd(dockutilPath, "--version")
if err != nil {
return "", "", errors.Wrap(err, "dockutil --version")
}

// Parse the output - typically "x.x.x" or "dockutil-x.x.x"
version := strings.TrimSpace(string(out))
version = strings.TrimPrefix(version, "dockutil-")

return version, dockutilPath, nil
}
87 changes: 87 additions & 0 deletions tables/dockutil/dockutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package dockutil

import (
"testing"

"github.com/macadmins/osquery-extension/pkg/utils"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestDockutilColumns(t *testing.T) {
columns := DockutilColumns()
require.Len(t, columns, 2)
assert.Equal(t, "version", columns[0].Name)
assert.Equal(t, "path", columns[1].Name)
}

func TestRunDockutil(t *testing.T) {
tests := []struct {
name string
mockOutput string
mockErr error
fileExists bool
expectedVer string
expectedPath string
shouldError bool
}{
{
name: "dockutil installed - simple version",
mockOutput: "3.0.2\n",
mockErr: nil,
fileExists: true,
expectedVer: "3.0.2",
expectedPath: dockutilPath,
shouldError: false,
},
{
name: "dockutil installed - version with prefix",
mockOutput: "dockutil-3.0.2\n",
mockErr: nil,
fileExists: true,
expectedVer: "3.0.2",
expectedPath: dockutilPath,
shouldError: false,
},
{
name: "dockutil not installed",
mockOutput: "",
mockErr: nil,
fileExists: false,
expectedVer: "",
expectedPath: "",
shouldError: false,
},
{
name: "dockutil command fails",
mockOutput: "",
mockErr: errors.New("command failed"),
fileExists: true,
expectedVer: "",
expectedPath: "",
shouldError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockCmd := utils.MockCmdRunner{
Output: tt.mockOutput,
Err: tt.mockErr,
}
runner := utils.Runner{Runner: mockCmd}
fs := utils.MockFileSystem{FileExists: tt.fileExists}

version, path, err := runDockutil(runner, fs)

if tt.shouldError {
require.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, tt.expectedVer, version)
assert.Equal(t, tt.expectedPath, path)
}
})
}
}
Loading