Skip to content

Commit

Permalink
fix: lint errors
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <knqyf263@gmail.com>
  • Loading branch information
knqyf263 committed Feb 12, 2024
1 parent 4aa0e97 commit a0a0b49
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 116 deletions.
99 changes: 57 additions & 42 deletions pkg/dependency/parser/java/jar/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package jar
import (
"archive/zip"
"bufio"
"crypto/sha1"
"crypto/sha1" // nolint:gosec
"encoding/hex"
"errors"
"fmt"
dio "github.com/aquasecurity/trivy/pkg/dependency/parser/io"
"github.com/aquasecurity/trivy/pkg/dependency/parser/log"
Expand Down Expand Up @@ -81,46 +82,14 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency,
func (p *Parser) parseArtifact(filePath string, size int64, r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) {
log.Logger.Debugw("Parsing Java artifacts...", zap.String("file", filePath))

zr, err := zip.NewReader(r, size)
if err != nil {
return nil, nil, xerrors.Errorf("zip error: %w", err)
}

// Try to extract artifactId and version from the file name
// e.g. spring-core-5.3.4-SNAPSHOT.jar => sprint-core, 5.3.4-SNAPSHOT
fileName := filepath.Base(filePath)
fileProps := parseFileName(filePath)

var libs []types.Library
var m manifest
var foundPomProps bool

for _, fileInJar := range zr.File {
switch {
case filepath.Base(fileInJar.Name) == "pom.properties":
props, err := parsePomProperties(fileInJar, filePath)
if err != nil {
return nil, nil, xerrors.Errorf("failed to parse %s: %w", fileInJar.Name, err)
}
libs = append(libs, props.Library())

// Check if the pom.properties is for the original JAR/WAR/EAR
if fileProps.ArtifactID == props.ArtifactID && fileProps.Version == props.Version {
foundPomProps = true
}
case filepath.Base(fileInJar.Name) == "MANIFEST.MF":
m, err = parseManifest(fileInJar)
if err != nil {
return nil, nil, xerrors.Errorf("failed to parse MANIFEST.MF: %w", err)
}
case isArtifact(fileInJar.Name):
innerLibs, _, err := p.parseInnerJar(fileInJar, filePath) //TODO process inner deps
if err != nil {
log.Logger.Debugf("Failed to parse %s: %s", fileInJar.Name, err)
continue
}
libs = append(libs, innerLibs...)
}
libs, m, foundPomProps, err := p.traverseZip(filePath, size, r, fileProps)
if err != nil {
return nil, nil, xerrors.Errorf("zip error: %w", err)
}

// If pom.properties is found, it should be preferred than MANIFEST.MF.
Expand Down Expand Up @@ -151,7 +120,7 @@ func (p *Parser) parseArtifact(filePath string, size int64, r dio.ReadSeekerAt)
props, err := p.searchBySHA1(r, filePath)
if err == nil {
return append(libs, props.Library()), nil, nil
} else if !xerrors.Is(err, ArtifactNotFoundErr) {
} else if !errors.Is(err, ArtifactNotFoundErr) {
return nil, nil, xerrors.Errorf("failed to search by SHA1: %w", err)
}

Expand All @@ -169,13 +138,54 @@ func (p *Parser) parseArtifact(filePath string, size int64, r dio.ReadSeekerAt)
log.Logger.Debugw("POM was determined in a heuristic way", zap.String("file", fileName),
zap.String("artifact", fileProps.String()))
libs = append(libs, fileProps.Library())
} else if !xerrors.Is(err, ArtifactNotFoundErr) {
} else if !errors.Is(err, ArtifactNotFoundErr) {
return nil, nil, xerrors.Errorf("failed to search by artifact id: %w", err)
}

return libs, nil, nil
}

func (p *Parser) traverseZip(filePath string, size int64, r dio.ReadSeekerAt, fileProps Properties) (
[]types.Library, manifest, bool, error) {
var libs []types.Library
var m manifest
var foundPomProps bool

zr, err := zip.NewReader(r, size)
if err != nil {
return nil, manifest{}, false, xerrors.Errorf("zip error: %w", err)
}

for _, fileInJar := range zr.File {
switch {
case filepath.Base(fileInJar.Name) == "pom.properties":
props, err := parsePomProperties(fileInJar, filePath)
if err != nil {
return nil, manifest{}, false, xerrors.Errorf("failed to parse %s: %w", fileInJar.Name, err)
}
libs = append(libs, props.Library())

// Check if the pom.properties is for the original JAR/WAR/EAR
if fileProps.ArtifactID == props.ArtifactID && fileProps.Version == props.Version {
foundPomProps = true
}
case filepath.Base(fileInJar.Name) == "MANIFEST.MF":
m, err = parseManifest(fileInJar)
if err != nil {
return nil, manifest{}, false, xerrors.Errorf("failed to parse MANIFEST.MF: %w", err)
}
case isArtifact(fileInJar.Name):
innerLibs, _, err := p.parseInnerJar(fileInJar, filePath) //TODO process inner deps

Check failure on line 178 in pkg/dependency/parser/java/jar/parse.go

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

commentFormatting: put a space between `//` and comment text (gocritic)
if err != nil {
log.Logger.Debugf("Failed to parse %s: %s", fileInJar.Name, err)
continue
}
libs = append(libs, innerLibs...)
}
}
return libs, m, foundPomProps, nil
}

func (p *Parser) parseInnerJar(zf *zip.File, rootPath string) ([]types.Library, []types.Dependency, error) {
fr, err := zf.Open()
if err != nil {
Expand All @@ -187,17 +197,22 @@ func (p *Parser) parseInnerJar(zf *zip.File, rootPath string) ([]types.Library,
return nil, nil, xerrors.Errorf("unable to create a temp file: %w", err)
}
defer func() {
f.Close()
os.Remove(f.Name())
_ = f.Close()
_ = os.Remove(f.Name())
}()

// Copy the file content to the temp file
if _, err = io.Copy(f, fr); err != nil {
if n, err := io.CopyN(f, fr, int64(zf.UncompressedSize64)); err != nil {
return nil, nil, xerrors.Errorf("file copy error: %w", err)
} else if n != int64(zf.UncompressedSize64) {
return nil, nil, xerrors.Errorf("file copy size error: %w", err)
}

// build full path to inner jar
fullPath := path.Join(rootPath, zf.Name)
if !strings.HasPrefix(fullPath, filepath.Clean(fullPath)) {
return nil, nil, nil // zip slip
}

// Parse jar/war/ear recursively
innerLibs, innerDeps, err := p.parseArtifact(fullPath, int64(zf.UncompressedSize64), f)
Expand All @@ -213,7 +228,7 @@ func (p *Parser) searchBySHA1(r io.ReadSeeker, filePath string) (Properties, err
return Properties{}, xerrors.Errorf("file seek error: %w", err)
}

h := sha1.New()
h := sha1.New() // nolint:gosec
if _, err := io.Copy(h, r); err != nil {
return Properties{}, xerrors.Errorf("unable to calculate SHA-1: %w", err)
}
Expand Down
51 changes: 31 additions & 20 deletions pkg/dependency/parser/java/pom/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pom
import (
"encoding/xml"
"fmt"
"go.uber.org/zap"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -589,8 +590,7 @@ func (p *parser) tryRepository(groupID, artifactID, version string) (*pom, error
// e.g. com.fasterxml.jackson.core, jackson-annotations, 2.10.0
// => com/fasterxml/jackson/core/jackson-annotations/2.10.0/jackson-annotations-2.10.0.pom
paths := strings.Split(groupID, ".")
paths = append(paths, artifactID, version)
paths = append(paths, fmt.Sprintf("%s-%s.pom", artifactID, version))
paths = append(paths, artifactID, version, fmt.Sprintf("%s-%s.pom", artifactID, version))

// Search local remoteRepositories
loaded, err := p.loadPOMFromLocalRepository(paths)
Expand All @@ -599,7 +599,7 @@ func (p *parser) tryRepository(groupID, artifactID, version string) (*pom, error
}

// Search remote remoteRepositories
loaded, err = p.fetchPOMFromRemoteRepository(paths)
loaded, err = p.fetchPOMFromRemoteRepositories(paths)
if err == nil {
return loaded, nil
}
Expand All @@ -614,7 +614,7 @@ func (p *parser) loadPOMFromLocalRepository(paths []string) (*pom, error) {
return p.openPom(localPath)
}

func (p *parser) fetchPOMFromRemoteRepository(paths []string) (*pom, error) {
func (p *parser) fetchPOMFromRemoteRepositories(paths []string) (*pom, error) {
// Do not try fetching pom.xml from remote repositories in offline mode
if p.offline {
log.Logger.Debug("Fetching the remote pom.xml is skipped")
Expand All @@ -623,30 +623,41 @@ func (p *parser) fetchPOMFromRemoteRepository(paths []string) (*pom, error) {

// try all remoteRepositories
for _, repo := range p.remoteRepositories {
repoURL, err := url.Parse(repo)
fetched, err := fetchPOMFromRemoteRepository(repo, paths)
if err != nil {
return nil, xerrors.Errorf("fetch repository error: %w", err)
} else if fetched == nil {
continue
}
return fetched, nil
}
return nil, xerrors.Errorf("the POM was not found in remote remoteRepositories")
}

paths = append([]string{repoURL.Path}, paths...)
repoURL.Path = path.Join(paths...)
func fetchPOMFromRemoteRepository(repo string, paths []string) (*pom, error) {
repoURL, err := url.Parse(repo)
if err != nil {
log.Logger.Errorw("URL parse error", zap.String("repo", repo))
return nil, nil
}

resp, err := http.Get(repoURL.String())
if err != nil || resp.StatusCode != http.StatusOK {
continue
}
paths = append([]string{repoURL.Path}, paths...)
repoURL.Path = path.Join(paths...)

content, err := parsePom(resp.Body)
if err != nil {
return nil, xerrors.Errorf("failed to parse the remote POM: %w", err)
}
resp, err := http.Get(repoURL.String())
if err != nil || resp.StatusCode != http.StatusOK {
return nil, nil
}

return &pom{
filePath: "", // from remote repositories
content: content,
}, nil
content, err := parsePom(resp.Body)
if err != nil {
return nil, xerrors.Errorf("failed to parse the remote POM: %w", err)
}
return nil, xerrors.Errorf("the POM was not found in remote remoteRepositories")

return &pom{
filePath: "", // from remote repositories
content: content,
}, nil
}

func parsePom(r io.Reader) (*pomXML, error) {
Expand Down
26 changes: 13 additions & 13 deletions pkg/dependency/parser/java/pom/pom.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,22 +323,22 @@ func (deps *pomDependencies) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) er
return xerrors.Errorf("XML decode error: %w", err)
}

switch t := token.(type) {
case xml.StartElement:
if t.Name.Local == "dependency" {
var dep pomDependency
dep.StartLine, _ = d.InputPos() // <dependency> tag starts

// Decode the <dependency> element
err = d.DecodeElement(&dep, &t)
if err != nil {
return xerrors.Errorf("Error decoding dependency: %w")
}
t, ok := token.(xml.StartElement)
if !ok {
continue
}

dep.EndLine, _ = d.InputPos() // <dependency> tag ends
if t.Name.Local == "dependency" {
var dep pomDependency
dep.StartLine, _ = d.InputPos() // <dependency> tag starts

deps.Dependency = append(deps.Dependency, dep)
// Decode the <dependency> element
err = d.DecodeElement(&dep, &t)
if err != nil {
return xerrors.Errorf("Error decoding dependency: %w")
}

dep.EndLine, _ = d.InputPos() // <dependency> tag ends
}
}
return nil
Expand Down
9 changes: 5 additions & 4 deletions pkg/dependency/parser/julia/manifest/naive_pkg_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,20 @@ func (parser *naivePkgParser) parse() map[string]pkgPosition {
lineNum := 1
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(strings.TrimSpace(line), "[") {
switch {
case strings.HasPrefix(strings.TrimSpace(line), "["):
if currentPkg.uuid != "" {
currentPkg.setEndPositionIfEmpty(lineNum - 1)
idx[currentPkg.uuid] = currentPkg.position
}
currentPkg = minPkg{}
currentPkg.position.start = lineNum

} else if strings.HasPrefix(strings.TrimSpace(line), "uuid =") {
case strings.HasPrefix(strings.TrimSpace(line), "uuid ="):
currentPkg.uuid = propertyValue(line)
} else if strings.HasPrefix(strings.TrimSpace(line), "version =") {
case strings.HasPrefix(strings.TrimSpace(line), "version ="):
currentPkg.version = propertyValue(line)
} else if strings.TrimSpace(line) == "" {
case strings.TrimSpace(line) == "":
currentPkg.setEndPositionIfEmpty(lineNum - 1)
}

Expand Down
15 changes: 10 additions & 5 deletions pkg/dependency/parser/julia/manifest/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,20 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency,
var deps []types.Dependency
for name, manifestDeps := range man.Dependencies {
for _, manifestDep := range manifestDeps {
version := depVersion(&manifestDep, man.JuliaVersion)
version := depVersion(manifestDep.Version, man.JuliaVersion)
pkgID := manifestDep.UUID
lib := types.Library{
ID: pkgID,
Name: name,
Version: version,
}
if pos, ok := lineNumIdx[manifestDep.UUID]; ok {
lib.Locations = []types.Location{{StartLine: pos.start, EndLine: pos.end}}
lib.Locations = []types.Location{
{
StartLine: pos.start,
EndLine: pos.end,
},
}
}

libs = append(libs, lib)
Expand All @@ -100,11 +105,11 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency,

// Returns the effective version of the `dep`.
// stdlib packages do not have a version in the manifest because they are packaged with julia itself
func depVersion(dep *primitiveDependency, juliaVersion string) string {
if len(dep.Version) == 0 {
func depVersion(depVersion, juliaVersion string) string {
if depVersion == "" {
return juliaVersion
}
return dep.Version
return depVersion
}

// Decodes a primitive manifest using the metadata from parse time.
Expand Down
16 changes: 8 additions & 8 deletions pkg/dependency/parser/nodejs/npm/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ func findDependsOn(pkgPath, depName string, packages map[string]Package) (string
if paths[i] != nodeModulesDir {
continue
}
path := joinPaths(paths[:i+1]...)
path = joinPaths(path, depName)
modulePath := joinPaths(paths[:i+1]...)
modulePath = joinPaths(modulePath, depName)

if dep, ok := packages[path]; ok {
if dep, ok := packages[modulePath]; ok {
return utils.PackageID(depName, dep.Version), nil
}
}
Expand Down Expand Up @@ -340,18 +340,18 @@ func isIndirectLib(pkgPath string, directDeps map[string]struct{}) bool {
return true
}

func pkgNameFromPath(path string) string {
func pkgNameFromPath(pkgPath string) string {
// lock file contains path to dependency in `node_modules`. e.g.:
// node_modules/string-width
// node_modules/string-width/node_modules/strip-ansi
// we renamed to `node_modules` directory prefixes `workspace` when resolving Links
// node_modules/function1
// node_modules/nested_func/node_modules/debug
if index := strings.LastIndex(path, nodeModulesDir); index != -1 {
return path[index+len(nodeModulesDir)+1:]
if index := strings.LastIndex(pkgPath, nodeModulesDir); index != -1 {
return pkgPath[index+len(nodeModulesDir)+1:]
}
log.Logger.Warnf("npm %q package path doesn't have `node_modules` prefix", path)
return path
log.Logger.Warnf("npm %q package path doesn't have `node_modules` prefix", pkgPath)
return pkgPath
}

func joinPaths(paths ...string) string {
Expand Down
Loading

0 comments on commit a0a0b49

Please sign in to comment.