diff --git a/pkg/osquery/table/platform_tables_darwin.go b/pkg/osquery/table/platform_tables_darwin.go
index b3292bd105..45342ad464 100644
--- a/pkg/osquery/table/platform_tables_darwin.go
+++ b/pkg/osquery/table/platform_tables_darwin.go
@@ -12,6 +12,7 @@ import (
"github.com/kolide/launcher/pkg/osquery/tables/apple_silicon_security_policy"
"github.com/kolide/launcher/pkg/osquery/tables/dataflattentable"
"github.com/kolide/launcher/pkg/osquery/tables/execparsers/remotectl"
+ "github.com/kolide/launcher/pkg/osquery/tables/execparsers/softwareupdate"
"github.com/kolide/launcher/pkg/osquery/tables/filevault"
"github.com/kolide/launcher/pkg/osquery/tables/firmwarepasswd"
"github.com/kolide/launcher/pkg/osquery/tables/ioreg"
@@ -116,5 +117,6 @@ func platformTables(client *osquery.ExtensionManagerClient, logger log.Logger, c
munki.ManagedInstalls(client, logger),
munki.MunkiReport(client, logger),
dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, []string{`/usr/libexec/remotectl`, `dumpstate`}),
+ dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, []string{`/usr/sbin/softwareupdate`, `--list`, `--no-scan`}),
}
}
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/parse.go b/pkg/osquery/tables/execparsers/softwareupdate/parse.go
new file mode 100644
index 0000000000..44050f3626
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/parse.go
@@ -0,0 +1,62 @@
+//go:build darwin
+// +build darwin
+
+package softwareupdate
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "strings"
+)
+
+func (p *parser) parseSoftwareupdate(reader io.Reader) (any, error) {
+ results := make([]map[string]string, 0)
+
+ p.scanner = bufio.NewScanner(reader)
+ for p.scanner.Scan() {
+ currentLine := strings.TrimSpace(p.scanner.Text())
+
+ // There are some header lines (e.g. `Software Update Tool`) that we can safely discard.
+ // We only care about pairs of lines, where the first line begins in the following way.
+ if !strings.HasPrefix(currentLine, "* Label:") {
+ continue
+ }
+
+ // Software updates are listed in the following format:
+ // * Label:
+ // Title: , Version: , Size: , Recommended: YES|?, Action: ,
+ label := strings.TrimSpace(strings.TrimPrefix(currentLine, "* Label:"))
+ labelAttributes, err := p.parseUpdate(label)
+ if err != nil {
+ return results, fmt.Errorf("could not parse software update data for label %s: %w", label, err)
+ }
+
+ results = append(results, labelAttributes)
+ }
+
+ return results, nil
+}
+
+func (p *parser) parseUpdate(label string) (map[string]string, error) {
+ result := make(map[string]string)
+ result["Label"] = label
+
+ // Get the next line
+ if !p.scanner.Scan() {
+ return result, fmt.Errorf("software update data missing for label %s", label)
+ }
+ updateDataStr := strings.TrimSuffix(strings.TrimSpace(p.scanner.Text()), ",")
+
+ // Add each update attribute to the result
+ updateData := strings.Split(updateDataStr, ",")
+ for _, attr := range updateData {
+ keyValPair := strings.SplitN(attr, ":", 2)
+ if len(keyValPair) < 2 {
+ return result, fmt.Errorf("software update data has malformed attribute %s", attr)
+ }
+ result[strings.TrimSpace(keyValPair[0])] = strings.TrimSpace(keyValPair[1])
+ }
+
+ return result, nil
+}
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/parse_test.go b/pkg/osquery/tables/execparsers/softwareupdate/parse_test.go
new file mode 100644
index 0000000000..0e64df46c9
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/parse_test.go
@@ -0,0 +1,149 @@
+package softwareupdate
+
+import (
+ "bytes"
+ _ "embed"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+//go:embed test-data/beta-update-available-noscan.txt
+var beta_update_available_noscan []byte
+
+//go:embed test-data/beta-update-available-scan.txt
+var beta_update_available_scan []byte
+
+//go:embed test-data/error-scan.txt
+var error_scan []byte
+
+//go:embed test-data/multiple-updates-available-noscan.txt
+var multiple_updates_available_noscan []byte
+
+//go:embed test-data/no-update-available-noscan.txt
+var no_update_available_noscan []byte
+
+//go:embed test-data/no-update-available-scan.txt
+var no_update_available_scan []byte
+
+//go:embed test-data/update-available-noscan.txt
+var update_available_noscan []byte
+
+//go:embed test-data/update-available-scan.txt
+var update_available_scan []byte
+
+func TestParse(t *testing.T) {
+ t.Parallel()
+
+ var tests = []struct {
+ name string
+ input []byte
+ expected []map[string]string
+ }{
+ {
+ name: "beta update available, --no-scan",
+ input: beta_update_available_noscan,
+ expected: []map[string]string{
+ {
+ "Label": "macOS Ventura 13.3 Beta 3-22E5236f",
+ "Title": "macOS Ventura 13.3 Beta 3",
+ "Version": "13.3",
+ "Size": "3310848K",
+ "Recommended": "YES",
+ "Action": "restart",
+ },
+ },
+ },
+ {
+ name: "beta update available",
+ input: beta_update_available_scan,
+ expected: []map[string]string{
+ {
+ "Label": "macOS Ventura 13.3 Beta 3-22E5236f",
+ "Title": "macOS Ventura 13.3 Beta 3",
+ "Version": "13.3",
+ "Size": "3310848K",
+ "Recommended": "YES",
+ "Action": "restart",
+ },
+ },
+ },
+ {
+ name: "error when scanning",
+ input: error_scan,
+ expected: make([]map[string]string, 0),
+ },
+ {
+ name: "multiple updates available, --no-scan",
+ input: multiple_updates_available_noscan,
+ expected: []map[string]string{
+ {
+ "Label": "Command Line Tools for Xcode-14.3",
+ "Title": "Command Line Tools for Xcode",
+ "Version": "14.3",
+ "Size": "711888KiB",
+ "Recommended": "YES",
+ },
+ {
+ "Label": "macOS Ventura 13.4 Beta-22F5027f",
+ "Title": "macOS Ventura 13.4 Beta",
+ "Version": "13.4",
+ "Size": "11487824K",
+ "Recommended": "YES",
+ "Action": "restart",
+ },
+ },
+ },
+ {
+ name: "no update available, --no-scan",
+ input: no_update_available_noscan,
+ expected: make([]map[string]string, 0),
+ },
+ {
+ name: "no update available",
+ input: no_update_available_scan,
+ expected: make([]map[string]string, 0),
+ },
+ {
+ name: "update available, --no-scan",
+ input: update_available_noscan,
+ expected: []map[string]string{
+ {
+ "Label": "macOS Ventura 13.3.1-22E261",
+ "Title": "macOS Ventura 13.3.1",
+ "Version": "13.3.1",
+ "Size": "868648KiB",
+ "Recommended": "YES",
+ "Action": "restart",
+ },
+ },
+ },
+ {
+ name: "update available",
+ input: update_available_scan,
+ expected: []map[string]string{
+ {
+ "Label": "macOS Ventura 13.3.1-22E261",
+ "Title": "macOS Ventura 13.3.1",
+ "Version": "13.3.1",
+ "Size": "868648KiB",
+ "Recommended": "YES",
+ "Action": "restart",
+ },
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+ })
+
+ p := New()
+ result, err := p.Parse(bytes.NewReader(tt.input))
+ require.NoError(t, err, "unexpected error parsing input")
+
+ require.ElementsMatch(t, tt.expected, result)
+ }
+}
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/softwareupdate.go b/pkg/osquery/tables/execparsers/softwareupdate/softwareupdate.go
new file mode 100644
index 0000000000..0e62460682
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/softwareupdate.go
@@ -0,0 +1,23 @@
+//go:build darwin
+// +build darwin
+
+package softwareupdate
+
+import (
+ "bufio"
+ "io"
+)
+
+type parser struct {
+ scanner *bufio.Scanner
+}
+
+var Parser = New()
+
+func New() *parser {
+ return &parser{}
+}
+
+func (p *parser) Parse(reader io.Reader) (any, error) {
+ return p.parseSoftwareupdate(reader)
+}
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/beta-update-available-noscan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/beta-update-available-noscan.txt
new file mode 100644
index 0000000000..c089d1a1d6
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/beta-update-available-noscan.txt
@@ -0,0 +1,5 @@
+Software Update Tool
+
+Software Update found the following new or updated software:
+* Label: macOS Ventura 13.3 Beta 3-22E5236f
+ Title: macOS Ventura 13.3 Beta 3, Version: 13.3, Size: 3310848K, Recommended: YES, Action: restart,
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/beta-update-available-scan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/beta-update-available-scan.txt
new file mode 100644
index 0000000000..3482753194
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/beta-update-available-scan.txt
@@ -0,0 +1,7 @@
+
+Software Update Tool
+
+Finding available software
+Software Update found the following new or updated software:
+* Label: macOS Ventura 13.3 Beta 3-22E5236f
+ Title: macOS Ventura 13.3 Beta 3, Version: 13.3, Size: 3310848K, Recommended: YES, Action: restart,
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/error-scan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/error-scan.txt
new file mode 100644
index 0000000000..20713e2dba
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/error-scan.txt
@@ -0,0 +1,3 @@
+Software Update Tool
+
+Scan finished with error: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorDomainKey=1, NSLocalizedRecoverySuggestion=Make sure you're connected to the Internet, and then try again., NSLocalizedDescription=The network connection was lost., SUErrorRelatedCode=SUErrorCodeScanCatalogNotFound, NSErrorFailingURLStringKey=https://swscan.apple.com/content/catalogs/others/index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz, NSErrorFailingURLKey=https://swscan.apple.com/content/catalogs/others/index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz, _kCFStreamErrorCodeKey=57}
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/multiple-updates-available-noscan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/multiple-updates-available-noscan.txt
new file mode 100644
index 0000000000..4da9bfd889
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/multiple-updates-available-noscan.txt
@@ -0,0 +1,7 @@
+Software Update Tool
+
+Software Update found the following new or updated software:
+* Label: Command Line Tools for Xcode-14.3
+ Title: Command Line Tools for Xcode, Version: 14.3, Size: 711888KiB, Recommended: YES,
+* Label: macOS Ventura 13.4 Beta-22F5027f
+ Title: macOS Ventura 13.4 Beta, Version: 13.4, Size: 11487824K, Recommended: YES, Action: restart,
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/no-update-available-noscan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/no-update-available-noscan.txt
new file mode 100644
index 0000000000..608abdc1a5
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/no-update-available-noscan.txt
@@ -0,0 +1,3 @@
+Software Update Tool
+
+No new software available.
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/no-update-available-scan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/no-update-available-scan.txt
new file mode 100644
index 0000000000..4cb14cac70
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/no-update-available-scan.txt
@@ -0,0 +1,4 @@
+Software Update Tool
+
+Finding available software
+No new software available.
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/update-available-noscan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/update-available-noscan.txt
new file mode 100644
index 0000000000..1c8a77821a
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/update-available-noscan.txt
@@ -0,0 +1,5 @@
+Software Update Tool
+
+Software Update found the following new or updated software:
+* Label: macOS Ventura 13.3.1-22E261
+ Title: macOS Ventura 13.3.1, Version: 13.3.1, Size: 868648KiB, Recommended: YES, Action: restart,
diff --git a/pkg/osquery/tables/execparsers/softwareupdate/test-data/update-available-scan.txt b/pkg/osquery/tables/execparsers/softwareupdate/test-data/update-available-scan.txt
new file mode 100644
index 0000000000..d34d526a55
--- /dev/null
+++ b/pkg/osquery/tables/execparsers/softwareupdate/test-data/update-available-scan.txt
@@ -0,0 +1,6 @@
+Software Update Tool
+
+Finding available software
+Software Update found the following new or updated software:
+* Label: macOS Ventura 13.3.1-22E261
+ Title: macOS Ventura 13.3.1, Version: 13.3.1, Size: 868648KiB, Recommended: YES, Action: restart,