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 (
2025-10-14 11:13:48 +06:00
"context"
2025-02-27 03:03:33 +00:00
rustaudit "github.com/rust-secure-code/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"
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 { }
2024-05-07 16:25:52 +04:00
func NewParser ( ) * Parser {
2024-02-19 15:16:35 +04:00
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
2025-10-14 11:13:48 +06:00
func ( p * Parser ) Parse ( _ context . Context , r xio . ReadSeekerAt ) ( [ ] ftypes . Package , [ ] ftypes . Dependency , error ) {
2024-02-19 15:16:35 +04:00
info , err := rustaudit . GetDependencyInfo ( r )
if err != nil {
return nil , nil , convertError ( err )
}
2024-05-07 16:25:52 +04:00
var pkgs [ ] ftypes . Package
var deps [ ] ftypes . Dependency
2024-02-19 15:16:35 +04:00
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-05-07 16:25:52 +04:00
pkgs = append ( pkgs , ftypes . Package {
2024-04-27 13:15:12 +04:00
ID : pkgID ,
Name : pkg . Name ,
Version : pkg . Version ,
2024-05-07 16:25:52 +04:00
Relationship : lo . Ternary ( pkg . Root , ftypes . RelationshipRoot , ftypes . 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 {
2024-05-07 16:25:52 +04:00
deps = append ( deps , ftypes . Dependency {
2024-02-19 15:16:35 +04:00
ID : pkgID ,
DependsOn : childDeps ,
} )
}
}
2024-05-07 16:25:52 +04:00
return pkgs , deps , nil
2024-02-19 15:16:35 +04:00
}
2024-03-12 10:56:10 +04:00
func packageID ( name , version string ) string {
return dependency . ID ( ftypes . RustBinary , name , version )
}