Skip to content
Merged
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
5 changes: 5 additions & 0 deletions syft/pkg/cataloger/python/parse_requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ func parseRequirementsTxt(_ source.FileResolver, _ *generic.Environment, reader
version = strings.TrimFunc(version, func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})

if name == "" || version == "" {
log.WithFields("path", reader.RealPath).Debugf("found empty package in requirements.txt line: %q", line)
continue
}
packages = append(packages, newPackageForIndex(name, version, reader.Location))
}

Expand Down
11 changes: 10 additions & 1 deletion syft/pkg/cataloger/python/parse_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,13 @@ func parseSetup(_ source.FileResolver, _ *generic.Environment, reader source.Loc
version := strings.TrimSpace(parts[len(parts)-1])
version = strings.Trim(version, "'\"")

if hasTemplateDirective(name) || hasTemplateDirective(version) {
// this can happen in more dynamic setup.py where there is templating
continue
}

if name == "" || version == "" {
log.WithFields("path", reader.RealPath).Warnf("unable to parse package in setup.py line: %q", line)
log.WithFields("path", reader.RealPath).Debugf("unable to parse package in setup.py line: %q", line)
continue
}

Expand All @@ -54,3 +59,7 @@ func parseSetup(_ source.FileResolver, _ *generic.Environment, reader source.Loc

return packages, nil, nil
}

func hasTemplateDirective(s string) bool {
return strings.Contains(s, `%s`) || strings.Contains(s, `{`) || strings.Contains(s, `}`)
}
125 changes: 88 additions & 37 deletions syft/pkg/cataloger/python/parse_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,110 @@ package python
import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
"github.com/anchore/syft/syft/source"
)

func TestParseSetup(t *testing.T) {
fixture := "test-fixtures/setup/setup.py"
locations := source.NewLocationSet(source.NewLocation(fixture))
expectedPkgs := []pkg.Package{
tests := []struct {
fixture string
expected []pkg.Package
}{
{
fixture: "test-fixtures/setup/setup.py",
expected: []pkg.Package{
{
Name: "pathlib3",
Version: "2.2.0",
PURL: "pkg:pypi/pathlib3@2.2.0",
Language: pkg.Python,
Type: pkg.PythonPkg,
},
{
Name: "mypy",
Version: "v0.770",
PURL: "pkg:pypi/mypy@v0.770",
Language: pkg.Python,
Type: pkg.PythonPkg,
},
{
Name: "mypy1",
Version: "v0.770",
PURL: "pkg:pypi/mypy1@v0.770",
Language: pkg.Python,
Type: pkg.PythonPkg,
},
{
Name: "mypy2",
Version: "v0.770",
PURL: "pkg:pypi/mypy2@v0.770",
Language: pkg.Python,
Type: pkg.PythonPkg,
},
{
Name: "mypy3",
Version: "v0.770",
PURL: "pkg:pypi/mypy3@v0.770",
Language: pkg.Python,
Type: pkg.PythonPkg,
},
},
},
{
// regression... ensure we clean packages names and don't find "%s" as the name
fixture: "test-fixtures/setup/dynamic-setup.py",
expected: nil,
},
}

for _, tt := range tests {
t.Run(tt.fixture, func(t *testing.T) {
locations := source.NewLocationSet(source.NewLocation(tt.fixture))
for i := range tt.expected {
tt.expected[i].Locations = locations
}
var expectedRelationships []artifact.Relationship

pkgtest.TestFileParser(t, tt.fixture, parseSetup, tt.expected, expectedRelationships)
})
}

}

func Test_hasTemplateDirective(t *testing.T) {

tests := []struct {
input string
want bool
}{
{
Name: "pathlib3",
Version: "2.2.0",
PURL: "pkg:pypi/pathlib3@2.2.0",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
input: "foo",
want: false,
},
{
Name: "mypy",
Version: "v0.770",
PURL: "pkg:pypi/mypy@v0.770",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
input: "foo %s",
want: true,
},
{
Name: "mypy1",
Version: "v0.770",
PURL: "pkg:pypi/mypy1@v0.770",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
input: "%s",
want: true,
},
{
Name: "mypy2",
Version: "v0.770",
PURL: "pkg:pypi/mypy2@v0.770",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
input: "{f_string}",
want: true,
},
{
Name: "mypy3",
Version: "v0.770",
PURL: "pkg:pypi/mypy3@v0.770",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
input: "{}", // .format() directive
want: true,
},
}

var expectedRelationships []artifact.Relationship

pkgtest.TestFileParser(t, fixture, parseSetup, expectedPkgs, expectedRelationships)
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
assert.Equal(t, tt.want, hasTemplateDirective(tt.input))
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ argh==0.26.2 \
--hash=sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3 \
--hash=sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65
argh==0.26.3 --hash=sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3 --hash=sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65
# CommentedOut == 1.2.3
# maybe invalid, but found out in the wild
==2.3.4
Loading