Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into feat/go-build
Browse files Browse the repository at this point in the history
  • Loading branch information
kzantow committed Jun 17, 2024
2 parents b266b31 + 22d5731 commit 96146f4
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 59 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ require (
require google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect

require (
github.com/BurntSushi/toml v1.4.0
github.com/adrg/xdg v0.4.0
github.com/magiconair/properties v1.8.7
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CycloneDX/cyclonedx-go v0.9.0 h1:inaif7qD8bivyxp7XLgxUYtOXWtDez7+j72qKTMQTb8=
github.com/CycloneDX/cyclonedx-go v0.9.0/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw=
Expand Down
106 changes: 47 additions & 59 deletions syft/pkg/cataloger/python/parse_poetry_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"context"
"fmt"
"sort"
"strings"

"github.com/pelletier/go-toml"
"github.com/BurntSushi/toml"

"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
Expand All @@ -19,22 +19,25 @@ import (
var _ generic.Parser = parsePoetryLock

type poetryPackageSource struct {
URL string `toml:"url"`
URL string `toml:"url"`
Type string `toml:"type"`
Reference string `toml:"reference"`
}

type poetryPackages struct {
Packages []poetryPackage `toml:"package"`
}

type poetryPackage struct {
Name string `toml:"name"`
Version string `toml:"version"`
Category string `toml:"category"`
Description string `toml:"description"`
Optional bool `toml:"optional"`
Source poetryPackageSource `toml:"source"`
Dependencies map[string]poetryPackageDependency `toml:"dependencies"`
Extras map[string][]string `toml:"extras"`
Name string `toml:"name"`
Version string `toml:"version"`
Category string `toml:"category"`
Description string `toml:"description"`
Optional bool `toml:"optional"`
Source poetryPackageSource `toml:"source"`
DependenciesUnmarshal map[string]toml.Primitive `toml:"dependencies"`
Extras map[string][]string `toml:"extras"`
Dependencies map[string][]poetryPackageDependency
}

type poetryPackageDependency struct {
Expand All @@ -44,41 +47,6 @@ type poetryPackageDependency struct {
Extras []string `toml:"extras"`
}

func (d *poetryPackageDependency) UnmarshalText(data []byte) error {
// attempt to parse as a map first
var dep map[string]interface{}
if err := toml.Unmarshal(data, &dep); err == nil {
if extras, ok := dep["extras"]; ok {
if extrasList, ok := extras.([]string); ok {
d.Extras = extrasList
}
}

if markers, ok := dep["markers"]; ok {
if markersString, ok := markers.(string); ok {
d.Markers = markersString
}
}

if version, ok := dep["version"]; ok {
if versionString, ok := version.(string); ok {
d.Version = versionString
}
}
return nil
}

if strings.ContainsAny(string(data), "[]{}") {
// odds are this is really a malformed toml array or object
return fmt.Errorf("unable to parse poetry dependency: version is malformed array/object: %q", string(data))
}

// assume this is a simple version string
d.Version = string(data)

return nil
}

// parsePoetryLock is a parser function for poetry.lock contents, returning all python packages discovered.
func parsePoetryLock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
pkgs, err := poetryLockPackages(reader)
Expand All @@ -93,15 +61,33 @@ func parsePoetryLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
}

func poetryLockPackages(reader file.LocationReadCloser) ([]pkg.Package, error) {
tree, err := toml.LoadReader(reader)
metadata := poetryPackages{}
md, err := toml.NewDecoder(reader).Decode(&metadata)
if err != nil {
return nil, fmt.Errorf("unable to load poetry.lock for parsing: %w", err)
return nil, fmt.Errorf("failed to read poetry lock package: %w", err)
}

metadata := poetryPackages{}
err = tree.Unmarshal(&metadata)
if err != nil {
return nil, fmt.Errorf("unable to parse poetry.lock: %w", err)
for i, p := range metadata.Packages {
dependencies := make(map[string][]poetryPackageDependency)
for pkgName, du := range p.DependenciesUnmarshal {
var (
single string
singleObj poetryPackageDependency
multiObj []poetryPackageDependency
)

switch {
case md.PrimitiveDecode(du, &single) == nil:
dependencies[pkgName] = append(dependencies[pkgName], poetryPackageDependency{Version: single})
case md.PrimitiveDecode(du, &singleObj) == nil:
dependencies[pkgName] = append(dependencies[pkgName], singleObj)
case md.PrimitiveDecode(du, &multiObj) == nil:
dependencies[pkgName] = append(dependencies[pkgName], multiObj...)
default:
log.Trace("failed to decode poetry lock package dependencies for %s; skipping", pkgName)
}
}
metadata.Packages[i].Dependencies = dependencies
}

var pkgs []pkg.Package
Expand Down Expand Up @@ -137,13 +123,15 @@ func extractIndex(p poetryPackage) string {

func extractPoetryDependencies(p poetryPackage) []pkg.PythonPoetryLockDependencyEntry {
var deps []pkg.PythonPoetryLockDependencyEntry
for name, dep := range p.Dependencies {
deps = append(deps, pkg.PythonPoetryLockDependencyEntry{
Name: name,
Version: dep.Version,
Extras: dep.Extras,
Markers: dep.Markers,
})
for name, dependencies := range p.Dependencies {
for _, d := range dependencies {
deps = append(deps, pkg.PythonPoetryLockDependencyEntry{
Name: name,
Version: d.Version,
Extras: d.Extras,
Markers: d.Markers,
})
}
}
sort.Slice(deps, func(i, j int) bool {
return deps[i].Name < deps[j].Name
Expand Down
4 changes: 4 additions & 0 deletions syft/pkg/cataloger/python/parse_poetry_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ func TestParsePoetryLock(t *testing.T) {
Index: "https://test.pypi.org/simple",
Dependencies: []pkg.PythonPoetryLockDependencyEntry{
{Name: "docutils", Version: "*"},
{Name: "msal", Version: ">=0.4.1,<2.0.0"},
{Name: "natsort", Version: "*"},
{Name: "packaging", Version: "*"},
{Name: "portalocker", Version: ">=1.0,<3", Markers: `platform_system != "Windows"`},
{Name: "portalocker", Version: ">=1.6,<3", Markers: `platform_system == "Windows"`},
{Name: "six", Version: "*"},
{Name: "sphinx", Version: "*"},
},
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 96146f4

Please sign in to comment.