-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(dart): use first version of constraint for dependencies using SDK version #6239
Changes from 10 commits
835cc07
6f861aa
e8a892a
c5ce4bc
f585220
1aa02bb
eb67467
0bbe7c5
91c2b1b
35a6f0a
191270c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,10 @@ import ( | |
"golang.org/x/xerrors" | ||
"gopkg.in/yaml.v3" | ||
|
||
goversion "github.com/aquasecurity/go-version/pkg/version" | ||
"github.com/aquasecurity/trivy/pkg/dependency" | ||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" | ||
"github.com/aquasecurity/trivy/pkg/log" | ||
xio "github.com/aquasecurity/trivy/pkg/x/io" | ||
) | ||
|
||
|
@@ -16,37 +18,64 @@ const ( | |
) | ||
|
||
// Parser is a parser for pubspec.lock | ||
type Parser struct{} | ||
type Parser struct { | ||
logger *log.Logger | ||
} | ||
|
||
func NewParser() *Parser { | ||
return &Parser{} | ||
return &Parser{ | ||
logger: log.WithPrefix("pub"), | ||
} | ||
} | ||
|
||
type lock struct { | ||
Packages map[string]Dep `yaml:"packages"` | ||
Packages map[string]Dep `yaml:"packages"` | ||
Sdks map[string]string `yaml:"sdks"` | ||
} | ||
|
||
type Dep struct { | ||
Dependency string `yaml:"dependency"` | ||
Version string `yaml:"version"` | ||
Dependency string `yaml:"dependency"` | ||
Version string `yaml:"version"` | ||
Source string `yaml:"source"` | ||
Description Description `yaml:"description"` | ||
} | ||
|
||
type Description string | ||
|
||
func (p Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { | ||
l := &lock{} | ||
if err := yaml.NewDecoder(r).Decode(&l); err != nil { | ||
return nil, nil, xerrors.Errorf("failed to decode pubspec.lock: %w", err) | ||
} | ||
var pkgs []ftypes.Package | ||
for name, dep := range l.Packages { | ||
// Some dependencies use one of the SDK versions. | ||
// In this case dep.Version == `0.0.0`. | ||
// We can't get versions for these dependencies. | ||
// Therefore, we use the first version of the SDK constraint specified in the Description. | ||
// See https://github.com/aquasecurity/trivy/issues/6017 | ||
version := dep.Version | ||
if version == "0.0.0" && dep.Source == "sdk" { | ||
if constraint, ok := l.Sdks[string(dep.Description)]; ok { | ||
v, err := firstVersionOfConstrain(constraint) | ||
if err != nil { | ||
p.logger.Warn("unable to get sdk version from constraint: %w", log.Err(err)) | ||
} else if v != "" { | ||
p.logger.Info("The first version of the constraint from the sdk source was used.", log.String("dep", name), log.String("constraint", constraint)) | ||
version = v | ||
} | ||
} | ||
} | ||
|
||
// We would like to exclude dev dependencies, but we cannot identify | ||
// which indirect dependencies were introduced by dev dependencies | ||
// as there are 3 dependency types, "direct main", "direct dev" and "transitive". | ||
// It will be confusing if we exclude direct dev dependencies and include transitive dev dependencies. | ||
// We decided to keep all dev dependencies until Pub will add support for "transitive main" and "transitive dev". | ||
pkg := ftypes.Package{ | ||
ID: dependency.ID(ftypes.Pub, name, dep.Version), | ||
ID: dependency.ID(ftypes.Pub, name, version), | ||
Name: name, | ||
Version: dep.Version, | ||
Version: version, | ||
Relationship: p.relationship(dep.Dependency), | ||
} | ||
pkgs = append(pkgs, pkg) | ||
|
@@ -64,3 +93,37 @@ func (p Parser) relationship(dep string) ftypes.Relationship { | |
} | ||
return ftypes.RelationshipUnknown | ||
} | ||
|
||
// firstVersionOfConstrain returns the first acceptable version for constraint | ||
func firstVersionOfConstrain(constraint string) (string, error) { | ||
css, err := goversion.NewConstraints(constraint) | ||
if err != nil { | ||
return "", xerrors.Errorf("unable to parse constraints: %w", err) | ||
} | ||
|
||
// Dart uses only `>=` and `^` operators: | ||
// cf. https://dart.dev/tools/pub/dependencies#traditional-syntax | ||
constraints := css.List() | ||
if len(constraints) == 0 || len(constraints[0]) == 0 { | ||
return "", nil | ||
} | ||
// We only need to get the first version from the range | ||
if constraints[0][0].Operator() != ">=" && constraints[0][0].Operator() != "^" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we check the length of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it won't hurt. |
||
return "", nil | ||
} | ||
|
||
return constraints[0][0].Version(), nil | ||
} | ||
|
||
func (d *Description) UnmarshalYAML(value *yaml.Node) error { | ||
var tmp any | ||
if err := value.Decode(&tmp); err != nil { | ||
return err | ||
} | ||
// Description can be a string or a struct | ||
// We only need a string value for SDK mapping | ||
if desc, ok := tmp.(string); ok { | ||
*d = Description(desc) | ||
} | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,4 +22,4 @@ packages: | |
version: "3.0.6" | ||
sdks: | ||
dart: ">=2.18.0 <3.0.0" | ||
flutter: ">=3.3.0" | ||
flutter: "^3.3.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 191270c