Skip to content

Commit

Permalink
process review feedback. pull out registry items to package conversio…
Browse files Browse the repository at this point in the history
…n and add tests.

Signed-off-by: Preslav <preslav@mondoo.com>
  • Loading branch information
preslavgerchev committed Jun 6, 2024
1 parent 66d6887 commit 3d67cc2
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 43 deletions.
87 changes: 44 additions & 43 deletions providers/os/resources/packages/windows_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"io"
"runtime"
"time"

"github.com/cockroachdb/errors"
Expand Down Expand Up @@ -229,8 +230,14 @@ func (w *WinPkgManager) getLocalInstalledApps() ([]Package, error) {
continue
}
for _, c := range children {
// for each package the information is contained as children of that registry's key
p := w.getPackageFromRegistryKey(c)
// for each package the information is contained as items of that registry's key,
// so we request the items under the fully qualified path
items, err := registry.GetNativeRegistryKeyItems(c.Path + "\\" + c.Name)
if err != nil {
log.Debug().Err(err).Str("path", c.Path).Msg("could not read registry key children")
continue
}
p := getPackageFromRegistryKeyItems(items)
if p == nil {
continue
}
Expand All @@ -241,39 +248,32 @@ func (w *WinPkgManager) getLocalInstalledApps() ([]Package, error) {
}

func (w *WinPkgManager) getInstalledApps() ([]Package, error) {
if w.conn.Type() == shared.Type_Local {
if w.conn.Type() == shared.Type_Local && runtime.GOOS == "windows" {
return w.getLocalInstalledApps()
}

cmd, err := w.conn.RunCommand(powershell.Wrap(installedAppsScript))
cmd, err := w.conn.RunCommand(powershell.Encode(installedAppsScript))
if err != nil {
return nil, fmt.Errorf("could not read app package list")
}
return ParseWindowsAppPackages(cmd.Stdout)
}

func (w *WinPkgManager) getPackageFromRegistryKey(key registry.RegistryKeyChild) *Package {
items, err := registry.GetNativeRegistryKeyItems(key.Path + "\\" + key.Name)
if err != nil {
log.Debug().Err(err).Str("path", key.Path).Str("name", key.Name).Msg("could not read registry key items")
return nil
}
func getPackageFromRegistryKeyItems(children []registry.RegistryKeyItem) *Package {
var uninstallString string
var displayName string
var displayVersion string
var publisher string

for _, i := range items {
if i.Key == "UninstallString" {
for _, i := range children {
switch i.Key {
case "UninstallString":
uninstallString = i.Value.String
}
if i.Key == "DisplayName" {
case "DisplayName":
displayName = i.Value.String
}
if i.Key == "DisplayVersion" {
case "DisplayVersion":
displayVersion = i.Value.String
}
if i.Key == "Publisher" {
case "Publisher":
publisher = i.Value.String
}
}
Expand All @@ -282,21 +282,23 @@ func (w *WinPkgManager) getPackageFromRegistryKey(key registry.RegistryKeyChild)
return nil
}

cpeWfn := ""
pkg := &Package{
Name: displayName,
Version: displayVersion,
Format: "windows/app",
}

if displayName != "" && displayVersion != "" {
cpeWfn, err = cpe.NewPackage2Cpe(publisher, displayName, displayVersion, "", "")
cpeWfn, err := cpe.NewPackage2Cpe(publisher, displayName, displayVersion, "", "")
if err != nil {
log.Debug().Err(err).Str("name", displayName).Str("version", displayVersion).Msg("could not create cpe for windows app package")
} else {
pkg.CPE = cpeWfn
}
} else {
log.Debug().Msg("ignored package since information is missing")
}
return &Package{
Name: displayName,
Version: displayVersion,
Format: "windows/app",
CPE: cpeWfn,
}
return pkg
}

// returns installed appx packages as well as hot fixes
Expand All @@ -315,8 +317,11 @@ func (w *WinPkgManager) List() ([]Package, error) {

canRunCmd := w.conn.Capabilities().Has(shared.Capability_RunCommand)
if !canRunCmd {
log.Debug().Msg("cannot run command on windows, skipping appx package list")
} else if b.Build > 10240 {
log.Debug().Msg("cannot run command on windows, skipping appx package and hotfixes list")
return pkgs, nil
}

if b.Build > 10240 {
// only win 10+ are compatible with app x packages
cmd, err := w.conn.RunCommand(powershell.Wrap(WINDOWS_QUERY_APPX_PACKAGES))
if err != nil {
Expand All @@ -329,22 +334,18 @@ func (w *WinPkgManager) List() ([]Package, error) {
pkgs = append(pkgs, appxPkgs...)
}

if !canRunCmd {
log.Debug().Msg("cannot run command on windows, skipping hotfix list")
} else {
// hotfixes
cmd, err := w.conn.RunCommand(powershell.Wrap(WINDOWS_QUERY_HOTFIXES))
if err != nil {
return nil, errors.Wrap(err, "could not fetch hotfixes")
}
hotfixes, err := ParseWindowsHotfixes(cmd.Stdout)
if err != nil {
return nil, errors.Wrapf(err, "could not parse hotfix results")
}
hotfixAsPkgs := HotFixesToPackages(hotfixes)

pkgs = append(pkgs, hotfixAsPkgs...)
// hotfixes
cmd, err := w.conn.RunCommand(powershell.Wrap(WINDOWS_QUERY_HOTFIXES))
if err != nil {
return nil, errors.Wrap(err, "could not fetch hotfixes")
}
hotfixes, err := ParseWindowsHotfixes(cmd.Stdout)
if err != nil {
return nil, errors.Wrapf(err, "could not parse hotfix results")
}
hotfixAsPkgs := HotFixesToPackages(hotfixes)

pkgs = append(pkgs, hotfixAsPkgs...)
return pkgs, nil
}

Expand Down
75 changes: 75 additions & 0 deletions providers/os/resources/packages/windows_packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/stretchr/testify/require"
"go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/v11/providers/os/connection/mock"
"go.mondoo.com/cnquery/v11/providers/os/registry"
"go.mondoo.com/cnquery/v11/providers/os/resources/cpe"
"go.mondoo.com/cnquery/v11/providers/os/resources/powershell"
)

Expand Down Expand Up @@ -109,3 +111,76 @@ func TestWindowsHotFixParser(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 0, len(hotfixes), "detected the right amount of packages")
}

func TestGetPackageFromRegistryKeyItems(t *testing.T) {
t.Run("get package from registry key items that are empty", func(t *testing.T) {
items := []registry.RegistryKeyItem{}
p := getPackageFromRegistryKeyItems(items)
assert.Nil(t, p)
})
t.Run("get package from registry key items with missing required values", func(t *testing.T) {
items := []registry.RegistryKeyItem{
{
Key: "DisplayName",
Value: registry.RegistryKeyValue{
Kind: registry.SZ,
String: "Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.28.29913",
},
},
}
p := getPackageFromRegistryKeyItems(items)
assert.Nil(t, p)
})

t.Run("get package from registry key items", func(t *testing.T) {
items := []registry.RegistryKeyItem{
{
Key: "DisplayName",
Value: registry.RegistryKeyValue{
Kind: registry.SZ,
String: "Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.28.29913",
},
},
{
Key: "UninstallString",
Value: registry.RegistryKeyValue{
Kind: registry.SZ,
String: "UninstallString",
},
},
{
Key: "DisplayVersion",
Value: registry.RegistryKeyValue{
Kind: registry.SZ,
String: "14.28.29913.0",
},
},
{
Key: "Publisher",
Value: registry.RegistryKeyValue{
Kind: registry.SZ,
String: "Microsoft Corporation",
},
},
}
p := getPackageFromRegistryKeyItems(items)
CPE, err := cpe.NewPackage2Cpe(
"Microsoft Corporation",
"Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.28.29913",
"14.28.29913.0",
"",
"")

assert.Nil(t, err)

expected := &Package{
Name: "Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.28.29913",
Version: "14.28.29913.0",
Arch: "",
Format: "windows/app",
CPE: CPE,
}
assert.NotNil(t, p)
assert.Equal(t, expected, p)
})
}

0 comments on commit 3d67cc2

Please sign in to comment.