diff --git a/providers/os/resources/python.go b/providers/os/resources/python.go index 97674e7b2d..d88feb4b30 100644 --- a/providers/os/resources/python.go +++ b/providers/os/resources/python.go @@ -15,8 +15,10 @@ import ( "github.com/spf13/afero" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" + "go.mondoo.com/cnquery/v10/providers-sdk/v1/util/convert" "go.mondoo.com/cnquery/v10/providers/os/connection/shared" "go.mondoo.com/cnquery/v10/providers/os/resources/python" + "go.mondoo.com/cnquery/v10/types" ) type pythonDirectory struct { @@ -68,12 +70,12 @@ func initPython(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[stri return args, nil, nil } -func (k *mqlPython) id() (string, error) { - return "python", nil +func (r *mqlPython) id() (string, error) { + return "python/" + r.Path.Data, nil } -func (k *mqlPython) packages() ([]interface{}, error) { - allPyPkgDetails, err := k.getAllPackages() +func (r *mqlPython) packages() ([]interface{}, error) { + allPyPkgDetails, err := r.getAllPackages() if err != nil { return nil, err } @@ -85,7 +87,7 @@ func (k *mqlPython) packages() ([]interface{}, error) { resp := []interface{}{} for _, pyPkgDetails := range allPyPkgDetails { - res, err := pythonPackageDetailsWithDependenciesToResource(k.MqlRuntime, pyPkgDetails, allPyPkgDetails, pythonPackageResourceMap) + res, err := pythonPackageDetailsWithDependenciesToResource(r.MqlRuntime, pyPkgDetails, allPyPkgDetails, pythonPackageResourceMap) if err != nil { log.Error().Err(err).Msg("error while creating resource(s) for python package") // we will keep trying to make resources even if a single one failed @@ -97,8 +99,8 @@ func (k *mqlPython) packages() ([]interface{}, error) { return resp, nil } -func (k *mqlPython) toplevel() ([]interface{}, error) { - allPyPkgDetails, err := k.getAllPackages() +func (r *mqlPython) toplevel() ([]interface{}, error) { + allPyPkgDetails, err := r.getAllPackages() if err != nil { return nil, err } @@ -114,7 +116,7 @@ func (k *mqlPython) toplevel() ([]interface{}, error) { continue } - res, err := pythonPackageDetailsWithDependenciesToResource(k.MqlRuntime, pyPkgDetails, allPyPkgDetails, pythonPackageResourceMap) + res, err := pythonPackageDetailsWithDependenciesToResource(r.MqlRuntime, pyPkgDetails, allPyPkgDetails, pythonPackageResourceMap) if err != nil { log.Error().Err(err).Msg("error while creating resource(s) for python package") // we will keep trying to make resources even if a single one failed @@ -126,19 +128,19 @@ func (k *mqlPython) toplevel() ([]interface{}, error) { return resp, nil } -func (k *mqlPython) getAllPackages() ([]python.PackageDetails, error) { +func (r *mqlPython) getAllPackages() ([]python.PackageDetails, error) { allResults := []python.PackageDetails{} - conn, ok := k.MqlRuntime.Connection.(shared.Connection) + conn, ok := r.MqlRuntime.Connection.(shared.Connection) if !ok { return nil, fmt.Errorf("provider is not an operating system provider") } afs := &afero.Afero{Fs: conn.FileSystem()} - if k.Path.Error != nil { - return nil, k.Path.Error + if r.Path.Error != nil { + return nil, r.Path.Error } - pyPath := k.Path.Data + pyPath := r.Path.Data if pyPath != "" { // only search the specific path provided (if it was provided) allResults = gatherPackages(afs, pyPath) @@ -428,3 +430,182 @@ func darwinSearch(afs *afero.Afero) ([]python.PackageDetails, error) { } return allResults, nil } + +func newMqlPythonPackage(runtime *plugin.Runtime, ppd python.PackageDetails, dependencies []interface{}) (plugin.Resource, error) { + f, err := CreateResource(runtime, "file", map[string]*llx.RawData{ + "path": llx.StringData(ppd.File), + }) + if err != nil { + log.Error().Err(err).Msg("error while creating file resource for python package resource") + return nil, err + } + + cpes := []interface{}{} + for i := range ppd.Cpes { + cpe, err := runtime.CreateSharedResource("cpe", map[string]*llx.RawData{ + "uri": llx.StringData(ppd.Cpes[i]), + }) + if err != nil { + return nil, err + } + cpes = append(cpes, cpe) + } + + r, err := CreateResource(runtime, "python.package", map[string]*llx.RawData{ + "id": llx.StringData(ppd.File), + "name": llx.StringData(ppd.Name), + "version": llx.StringData(ppd.Version), + "author": llx.StringData(ppd.Author), + "authorEmail": llx.StringData(ppd.AuthorEmail), + "summary": llx.StringData(ppd.Summary), + "license": llx.StringData(ppd.License), + "file": llx.ResourceData(f, f.MqlName()), + "dependencies": llx.ArrayData(dependencies, types.Any), + "purl": llx.StringData(ppd.Purl), + "cpes": llx.ArrayData(cpes, types.Resource("cpe")), + }) + if err != nil { + log.Error().AnErr("err", err).Msg("error while creating MQL resource") + return nil, err + } + return r, nil +} + +func (r *mqlPythonPackage) id() (string, error) { + return r.Id.Data, nil +} + +func initPythonPackage(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) { + if len(args) > 1 { + return args, nil, nil + } + if x, ok := args["path"]; ok { + path, ok := x.Value.(string) + if !ok { + return nil, nil, errors.New("Wrong type for 'path' in python.package initialization, it must be a string") + } + + file, err := CreateResource(runtime, "file", map[string]*llx.RawData{ + "path": llx.StringData(path), + }) + if err != nil { + return nil, nil, err + } + args["id"] = llx.StringData(path) + args["file"] = llx.ResourceData(file, "file") + + delete(args, "path") + } + return args, nil, nil +} + +func (r *mqlPythonPackage) name() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.Name.Data, nil +} + +func (r *mqlPythonPackage) version() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.Version.Data, nil +} + +func (r *mqlPythonPackage) license() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.License.Data, nil +} + +func (r *mqlPythonPackage) author() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.Author.Data, nil +} + +func (r *mqlPythonPackage) authorEmail() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.AuthorEmail.Data, nil +} + +func (r *mqlPythonPackage) summary() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.Summary.Data, nil +} + +func (r *mqlPythonPackage) purl() (string, error) { + err := r.populateData() + if err != nil { + return "", err + } + return r.Purl.Data, nil +} + +func (r *mqlPythonPackage) cpes() ([]interface{}, error) { + err := r.populateData() + if err != nil { + return nil, err + } + return r.Cpes.Data, nil +} + +func (r *mqlPythonPackage) dependencies() ([]interface{}, error) { + err := r.populateData() + if err != nil { + return nil, err + } + return r.Dependencies.Data, nil +} + +func (r *mqlPythonPackage) populateData() error { + file := r.GetFile() + if file.Error != nil { + return file.Error + } + + if file.Data == nil || file.Data.Path.Data == "" { + return fmt.Errorf("file path is empty") + } + + pkg, err := python.ParseMIME(strings.NewReader(file.Data.Content.Data), file.Data.Path.Data) + if err != nil { + return fmt.Errorf("error parsing python package data: %s", err) + } + + r.Name = plugin.TValue[string]{Data: pkg.Name, State: plugin.StateIsSet} + r.Version = plugin.TValue[string]{Data: pkg.Version, State: plugin.StateIsSet} + r.Author = plugin.TValue[string]{Data: pkg.Author, State: plugin.StateIsSet} + r.AuthorEmail = plugin.TValue[string]{Data: pkg.AuthorEmail, State: plugin.StateIsSet} + r.Summary = plugin.TValue[string]{Data: pkg.Summary, State: plugin.StateIsSet} + r.License = plugin.TValue[string]{Data: pkg.License, State: plugin.StateIsSet} + r.Dependencies = plugin.TValue[[]interface{}]{Data: convert.SliceAnyToInterface(pkg.Dependencies), State: plugin.StateIsSet} + + cpes := []interface{}{} + for i := range pkg.Cpes { + cpe, err := r.MqlRuntime.CreateSharedResource("cpe", map[string]*llx.RawData{ + "uri": llx.StringData(pkg.Cpes[i]), + }) + if err != nil { + return err + } + cpes = append(cpes, cpe) + } + + r.Cpes = plugin.TValue[[]interface{}]{Data: cpes, State: plugin.StateIsSet} + r.Purl = plugin.TValue[string]{Data: pkg.Purl, State: plugin.StateIsSet} + return nil +} diff --git a/providers/os/resources/python_package.go b/providers/os/resources/python_package.go deleted file mode 100644 index d54fc022cc..0000000000 --- a/providers/os/resources/python_package.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) Mondoo, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package resources - -import ( - "errors" - "fmt" - "strings" - - "github.com/rs/zerolog/log" - "go.mondoo.com/cnquery/v10/llx" - "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" - "go.mondoo.com/cnquery/v10/providers-sdk/v1/util/convert" - "go.mondoo.com/cnquery/v10/providers/os/resources/python" - "go.mondoo.com/cnquery/v10/types" -) - -func (k *mqlPythonPackage) id() (string, error) { - return k.Id.Data, nil -} - -func initPythonPackage(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) { - if len(args) > 1 { - return args, nil, nil - } - if x, ok := args["path"]; ok { - path, ok := x.Value.(string) - if !ok { - return nil, nil, errors.New("Wrong type for 'path' in python.package initialization, it must be a string") - } - - file, err := CreateResource(runtime, "file", map[string]*llx.RawData{ - "path": llx.StringData(path), - }) - if err != nil { - return nil, nil, err - } - args["id"] = llx.StringData(path) - args["file"] = llx.ResourceData(file, "file") - - delete(args, "path") - } - return args, nil, nil -} - -func (k *mqlPythonPackage) name() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.Name.Data, nil -} - -func (k *mqlPythonPackage) version() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.Version.Data, nil -} - -func (k *mqlPythonPackage) license() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.License.Data, nil -} - -func (k *mqlPythonPackage) author() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.Author.Data, nil -} - -func (k *mqlPythonPackage) authorEmail() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.AuthorEmail.Data, nil -} - -func (k *mqlPythonPackage) summary() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.Summary.Data, nil -} - -func (k *mqlPythonPackage) purl() (string, error) { - err := k.populateData() - if err != nil { - return "", err - } - return k.Purl.Data, nil -} - -func (k *mqlPythonPackage) cpes() ([]interface{}, error) { - err := k.populateData() - if err != nil { - return nil, err - } - return k.Cpes.Data, nil -} - -func (k *mqlPythonPackage) dependencies() ([]interface{}, error) { - err := k.populateData() - if err != nil { - return nil, err - } - return k.Dependencies.Data, nil -} - -func (k *mqlPythonPackage) populateData() error { - file := k.GetFile() - if file.Error != nil { - return file.Error - } - - if file.Data == nil || file.Data.Path.Data == "" { - return fmt.Errorf("file path is empty") - } - - ppd, err := python.ParseMIME(strings.NewReader(file.Data.Content.Data), file.Data.Path.Data) - if err != nil { - return fmt.Errorf("error parsing python package data: %s", err) - } - - k.Name = plugin.TValue[string]{Data: ppd.Name, State: plugin.StateIsSet} - k.Version = plugin.TValue[string]{Data: ppd.Version, State: plugin.StateIsSet} - k.Author = plugin.TValue[string]{Data: ppd.Author, State: plugin.StateIsSet} - k.AuthorEmail = plugin.TValue[string]{Data: ppd.AuthorEmail, State: plugin.StateIsSet} - k.Summary = plugin.TValue[string]{Data: ppd.Summary, State: plugin.StateIsSet} - k.License = plugin.TValue[string]{Data: ppd.License, State: plugin.StateIsSet} - k.Dependencies = plugin.TValue[[]interface{}]{Data: convert.SliceAnyToInterface(ppd.Dependencies), State: plugin.StateIsSet} - - cpes := []interface{}{} - for i := range ppd.Cpes { - cpe, err := k.MqlRuntime.CreateSharedResource("cpe", map[string]*llx.RawData{ - "uri": llx.StringData(ppd.Cpes[i]), - }) - if err != nil { - return err - } - cpes = append(cpes, cpe) - } - - k.Cpes = plugin.TValue[[]interface{}]{Data: cpes, State: plugin.StateIsSet} - k.Purl = plugin.TValue[string]{Data: ppd.Purl, State: plugin.StateIsSet} - return nil -} - -func newMqlPythonPackage(runtime *plugin.Runtime, ppd python.PackageDetails, dependencies []interface{}) (plugin.Resource, error) { - f, err := CreateResource(runtime, "file", map[string]*llx.RawData{ - "path": llx.StringData(ppd.File), - }) - if err != nil { - log.Error().Err(err).Msg("error while creating file resource for python package resource") - return nil, err - } - - cpes := []interface{}{} - for i := range ppd.Cpes { - cpe, err := runtime.CreateSharedResource("cpe", map[string]*llx.RawData{ - "uri": llx.StringData(ppd.Cpes[i]), - }) - if err != nil { - return nil, err - } - cpes = append(cpes, cpe) - } - - r, err := CreateResource(runtime, "python.package", map[string]*llx.RawData{ - "id": llx.StringData(ppd.File), - "name": llx.StringData(ppd.Name), - "version": llx.StringData(ppd.Version), - "author": llx.StringData(ppd.Author), - "authorEmail": llx.StringData(ppd.AuthorEmail), - "summary": llx.StringData(ppd.Summary), - "license": llx.StringData(ppd.License), - "file": llx.ResourceData(f, f.MqlName()), - "dependencies": llx.ArrayData(dependencies, types.Any), - "purl": llx.StringData(ppd.Purl), - "cpes": llx.ArrayData(cpes, types.Resource("cpe")), - }) - if err != nil { - log.Error().AnErr("err", err).Msg("error while creating MQL resource") - return nil, err - } - return r, nil -}