2024-02-19 15:16:35 +04:00
// Detects dependencies from Rust binaries built with https://github.com/rust-secure-code/cargo-auditable
package binary
import (
rustaudit "github.com/microsoft/go-rustaudit"
2024-04-27 13:15:12 +04:00
"github.com/samber/lo"
2024-02-19 15:16:35 +04:00
"golang.org/x/xerrors"
2024-03-12 10:56:10 +04:00
"github.com/aquasecurity/trivy/pkg/dependency"
"github.com/aquasecurity/trivy/pkg/dependency/types"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
2024-02-26 09:55:15 +04:00
xio "github.com/aquasecurity/trivy/pkg/x/io"
2024-02-19 15:16:35 +04:00
)
var (
ErrUnrecognizedExe = xerrors . New ( "unrecognized executable format" )
ErrNonRustBinary = xerrors . New ( "non Rust auditable binary" )
)
// convertError detects rustaudit.ErrUnknownFileFormat and convert to
// ErrUnrecognizedExe and convert rustaudit.ErrNoRustDepInfo to ErrNonRustBinary
func convertError ( err error ) error {
if err == rustaudit . ErrUnknownFileFormat {
return ErrUnrecognizedExe
}
if err == rustaudit . ErrNoRustDepInfo {
return ErrNonRustBinary
}
return err
}
type Parser struct { }
func NewParser ( ) types . Parser {
return & Parser { }
}
// Parse scans files to try to report Rust crates and version injected into Rust binaries
// via https://github.com/rust-secure-code/cargo-auditable
2024-02-26 09:55:15 +04:00
func ( p * Parser ) Parse ( r xio . ReadSeekerAt ) ( [ ] types . Library , [ ] types . Dependency , error ) {
2024-02-19 15:16:35 +04:00
info , err := rustaudit . GetDependencyInfo ( r )
if err != nil {
return nil , nil , convertError ( err )
}
var libs [ ] types . Library
var deps [ ] types . Dependency
for _ , pkg := range info . Packages {
if pkg . Kind != rustaudit . Runtime {
continue
}
2024-03-12 10:56:10 +04:00
pkgID := packageID ( pkg . Name , pkg . Version )
2024-02-19 15:16:35 +04:00
libs = append ( libs , types . Library {
2024-04-27 13:15:12 +04:00
ID : pkgID ,
Name : pkg . Name ,
Version : pkg . Version ,
Relationship : lo . Ternary ( pkg . Root , types . RelationshipRoot , types . RelationshipUnknown ) , // TODO: Determine the direct dependencies by checking the dependencies of the root crate
2024-02-19 15:16:35 +04:00
} )
var childDeps [ ] string
for _ , dep_idx := range pkg . Dependencies {
dep := info . Packages [ dep_idx ]
if dep . Kind == rustaudit . Runtime {
2024-03-12 10:56:10 +04:00
childDeps = append ( childDeps , packageID ( dep . Name , dep . Version ) )
2024-02-19 15:16:35 +04:00
}
}
if len ( childDeps ) > 0 {
deps = append ( deps , types . Dependency {
ID : pkgID ,
DependsOn : childDeps ,
} )
}
}
return libs , deps , nil
}
2024-03-12 10:56:10 +04:00
func packageID ( name , version string ) string {
return dependency . ID ( ftypes . RustBinary , name , version )
}