Files
trivy/pkg/dependency/parser/java/pom/artifact.go
Teppei Fukuda 983ac15f22 ci: add depguard (#6963)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
2024-06-20 02:48:08 +00:00

159 lines
3.6 KiB
Go

package pom
import (
"fmt"
"os"
"regexp"
"slices"
"strings"
"github.com/samber/lo"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
)
var (
varRegexp = regexp.MustCompile(`\${(\S+?)}`)
)
type artifact struct {
GroupID string
ArtifactID string
Version version
Licenses []string
Exclusions map[string]struct{}
Module bool
Relationship ftypes.Relationship
Locations ftypes.Locations
}
func newArtifact(groupID, artifactID, version string, licenses []string, props map[string]string) artifact {
return artifact{
GroupID: evaluateVariable(groupID, props, nil),
ArtifactID: evaluateVariable(artifactID, props, nil),
Version: newVersion(evaluateVariable(version, props, nil)),
Licenses: licenses,
Relationship: ftypes.RelationshipIndirect, // default
}
}
func (a artifact) IsEmpty() bool {
return a.GroupID == "" || a.ArtifactID == "" || a.Version.String() == ""
}
func (a artifact) Equal(o artifact) bool {
return a.GroupID == o.GroupID || a.ArtifactID == o.ArtifactID || a.Version.String() == o.Version.String()
}
func (a artifact) ToPOMLicenses() pomLicenses {
return pomLicenses{
License: lo.Map(a.Licenses, func(lic string, _ int) pomLicense {
return pomLicense{Name: lic}
}),
}
}
func (a artifact) Inherit(parent artifact) artifact {
// inherited from a parent
if a.GroupID == "" {
a.GroupID = parent.GroupID
}
if len(a.Licenses) == 0 {
a.Licenses = parent.Licenses
}
if a.Version.String() == "" {
a.Version = parent.Version
}
return a
}
func (a artifact) Name() string {
return fmt.Sprintf("%s:%s", a.GroupID, a.ArtifactID)
}
func (a artifact) String() string {
return fmt.Sprintf("%s:%s", a.Name(), a.Version)
}
type version struct {
ver string
hard bool
}
// Only soft and hard requirements for the specified version are supported at the moment.
func newVersion(s string) version {
var hard bool
if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") {
s = strings.Trim(s, "[]")
hard = true
}
// TODO: Other requirements are not supported
if strings.ContainsAny(s, ",()[]") {
s = ""
}
return version{
ver: s,
hard: hard,
}
}
func (v1 version) shouldOverride(v2 version) bool {
if !v1.hard && v2.hard {
return true
}
return false
}
func (v1 version) String() string {
return v1.ver
}
func evaluateVariable(s string, props map[string]string, seenProps []string) string {
if props == nil {
props = make(map[string]string)
}
for _, m := range varRegexp.FindAllStringSubmatch(s, -1) {
var newValue string
// env.X: https://maven.apache.org/pom.html#Properties
// e.g. env.PATH
if strings.HasPrefix(m[1], "env.") {
newValue = os.Getenv(strings.TrimPrefix(m[1], "env."))
} else {
// <properties> might include another property.
// e.g. <animal.sniffer.skip>${skipTests}</animal.sniffer.skip>
ss, ok := props[m[1]]
if ok {
// search for looped properties
if slices.Contains(seenProps, ss) {
printLoopedPropertiesStack(m[0], seenProps)
return ""
}
seenProps = append(seenProps, ss) // save evaluated props to check if we get this prop again
newValue = evaluateVariable(ss, props, seenProps)
seenProps = []string{} // clear props if we returned from recursive. Required for correct work with 2 same props like ${foo}-${foo}
}
}
s = strings.ReplaceAll(s, m[0], newValue)
}
return s
}
func printLoopedPropertiesStack(env string, usedProps []string) {
var s string
for _, prop := range usedProps {
s += fmt.Sprintf("%s -> ", prop)
}
log.Warn("Lopped properties were detected", log.String("prop", s+env))
}