@@ -75,6 +75,7 @@ func main() {
75
75
fmt .Fprintf (flag .CommandLine .Output (), "usage: vulnreport [cmd] [filename.yaml]\n " )
76
76
fmt .Fprintf (flag .CommandLine .Output (), " create [githubIssueNumber]: creates a new vulnerability YAML report\n " )
77
77
fmt .Fprintf (flag .CommandLine .Output (), " create-excluded: creates and commits all open github issues marked as excluded\n " )
78
+ fmt .Fprintf (flag .CommandLine .Output (), " symbols filename.yaml: finds and populates possible vulnerable symbols for a given report\n " )
78
79
fmt .Fprintf (flag .CommandLine .Output (), " lint filename.yaml ...: lints vulnerability YAML reports\n " )
79
80
fmt .Fprintf (flag .CommandLine .Output (), " cve filename.yaml ...: creates and saves CVE 5.0 record from the provided YAML reports\n " )
80
81
fmt .Fprintf (flag .CommandLine .Output (), " fix filename.yaml ...: fixes and reformats YAML reports\n " )
@@ -161,6 +162,8 @@ func main() {
161
162
cmdFunc = func (ctx context.Context , name string ) error { return cveCmd (ctx , name ) }
162
163
case "fix" :
163
164
cmdFunc = func (ctx context.Context , name string ) error { return fix (ctx , name , ghsaClient , pc , * force ) }
165
+ case "symbols" :
166
+ cmdFunc = func (ctx context.Context , name string ) error { return findSymbols (ctx , name ) }
164
167
case "osv" :
165
168
cmdFunc = func (ctx context.Context , name string ) error { return osvCmd (ctx , name , pc ) }
166
169
case "set-dates" :
@@ -741,6 +744,77 @@ func addReferenceTODOs(r *report.Report) {
741
744
}
742
745
}
743
746
747
+ func findSymbols (_ context.Context , filename string ) (err error ) {
748
+ defer derrors .Wrap (& err , "findSymbols(%q)" , filename )
749
+ infolog .Printf ("findSymbols %s\n " , filename )
750
+ r , err := report .Read (filename )
751
+ if err != nil {
752
+ return err
753
+ }
754
+ var defaultFixes []string
755
+
756
+ for _ , ref := range r .References {
757
+ if ref .Type == osv .ReferenceTypeFix {
758
+ if filepath .Base (filepath .Dir (ref .URL )) == "commit" {
759
+ defaultFixes = append (defaultFixes , ref .URL )
760
+ }
761
+ }
762
+ }
763
+ if len (defaultFixes ) == 0 {
764
+ return fmt .Errorf ("no commit fix links found" )
765
+ }
766
+
767
+ for _ , mod := range r .Modules {
768
+ hasFixLink := mod .FixLink != ""
769
+ if hasFixLink {
770
+ defaultFixes = append (defaultFixes , mod .FixLink )
771
+ }
772
+ numFixedSymbols := make ([]int , len (defaultFixes ))
773
+ for i , fixLink := range defaultFixes {
774
+ fixHash := filepath .Base (fixLink )
775
+ fixRepo := strings .TrimSuffix (fixLink , "/commit/" + fixHash )
776
+ pkgsToSymbols , err := symbols .Patched (mod .Module , fixRepo , fixHash , errlog )
777
+ if err != nil {
778
+ errlog .Print (err )
779
+ continue
780
+ }
781
+ packages := mod .AllPackages ()
782
+ for pkg , symbols := range pkgsToSymbols {
783
+ if _ , exists := packages [pkg ]; exists {
784
+ packages [pkg ].Symbols = append (packages [pkg ].Symbols , symbols ... )
785
+ } else {
786
+ mod .Packages = append (mod .Packages , & report.Package {
787
+ Package : pkg ,
788
+ Symbols : symbols ,
789
+ })
790
+ }
791
+ numFixedSymbols [i ] += len (symbols )
792
+ }
793
+ }
794
+ // if the module's link field wasn't already populated, populate it with
795
+ // the link that results in the most symbols
796
+ if hasFixLink {
797
+ defaultFixes = defaultFixes [:len (defaultFixes )- 1 ]
798
+ } else {
799
+ mod .FixLink = defaultFixes [indexMax (numFixedSymbols )]
800
+ }
801
+ }
802
+ return r .Write (filename )
803
+ }
804
+
805
+ // indexMax takes a slice of nonempty ints and returns the index of the maximum value
806
+ func indexMax (s []int ) (index int ) {
807
+ maxVal := s [0 ]
808
+ index = 0
809
+ for i , val := range s {
810
+ if val > maxVal {
811
+ maxVal = val
812
+ index = i
813
+ }
814
+ }
815
+ return index
816
+ }
817
+
744
818
func lint (_ context.Context , filename string , pc * proxy.Client ) (err error ) {
745
819
defer derrors .Wrap (& err , "lint(%q)" , filename )
746
820
infolog .Printf ("lint %s\n " , filename )
0 commit comments