@@ -32,6 +32,10 @@ type SarifTransformer struct {
3232 ruleToEcosystem map [string ]string
3333 richDescription bool
3434 dataSource * ocsffindinginfo.DataSource
35+
36+ // the root path to which all file paths should be relative to, will be ultimately removed from findings,
37+ // this is used to handle CI/CD cases where findings have absolute path to the filesystem as opposed to project root.
38+ workspacePath string
3539}
3640
3741var typeName = map [int64 ]string {
@@ -76,6 +80,7 @@ func NewTransformer(
7680 guidProvider StableUUIDProvider ,
7781 richDescription bool ,
7882 dataSource * ocsffindinginfo.DataSource ,
83+ workspacePath string ,
7984) (* SarifTransformer , error ) {
8085 if scanResult == nil {
8186 return nil , errors .Errorf ("method 'NewTransformer called with nil scanResult" )
@@ -97,6 +102,11 @@ func NewTransformer(
97102 return nil , errors .Errorf ("invalid data source provider: %w" , err )
98103 }
99104
105+ cleanedWorkspacePath := filepath .Clean (workspacePath )
106+ if ! filepath .IsAbs (cleanedWorkspacePath ) {
107+ return nil , errors .Errorf ("workspace path must be an absolute path" )
108+ }
109+
100110 return & SarifTransformer {
101111 clock : clock ,
102112 sarifResult : * scanResult ,
@@ -106,6 +116,7 @@ func NewTransformer(
106116 taxasByCWEID : make (map [string ]sarif.ReportingDescriptor ),
107117 richDescription : richDescription ,
108118 dataSource : dataSource ,
119+ workspacePath : cleanedWorkspacePath ,
109120 }, nil
110121}
111122
@@ -161,7 +172,10 @@ func (s *SarifTransformer) transformToOCSF(
161172 res * sarif.Result ,
162173) (* ocsf.VulnerabilityFinding , error ) {
163174 slog .Debug ("parsing run from" , slog .String ("toolname" , toolName ))
164- affectedCode , affectedPackages := s .mapAffected (res )
175+ affectedCode , affectedPackages , err := s .mapAffected (res )
176+ if err != nil {
177+ return nil , errors .Errorf ("could not map affected code/packages: %w" , err )
178+ }
165179
166180 var (
167181 ruleID * string
@@ -346,6 +360,32 @@ func (s *SarifTransformer) isSnykURI(uri string) bool {
346360 return strings .HasPrefix (uri , "https_//" )
347361}
348362
363+ // constructPath will take a given path and construct a file url pointing to the file relative to the workspacePath
364+ func (s * SarifTransformer ) constructPath (path string ) (string , error ) {
365+ // if path is a file url (file://) we need to get the path after file before adding it back
366+ if strings .HasPrefix (path , "file://" ) {
367+ pathURL , err := url .Parse (path )
368+ if err != nil {
369+ return "" , errors .Errorf ("could not parse file url %s: %w" , path , err )
370+ }
371+ if pathURL .Host != "" {
372+ path = pathURL .Host + pathURL .Path
373+ } else {
374+ path = pathURL .Path
375+ }
376+ }
377+ cleanedPath := filepath .Clean (path )
378+ if s .workspacePath != "" && strings .HasPrefix (cleanedPath , s .workspacePath ) {
379+ pth , err := filepath .Rel (s .workspacePath , cleanedPath )
380+ if err != nil {
381+ return "" , errors .Errorf ("could not get relative path from path %s using prefix %q" , cleanedPath , s .workspacePath )
382+ }
383+ cleanedPath = pth
384+ }
385+ finalPath := fmt .Sprintf ("file://%s" , cleanedPath )
386+ return finalPath , nil
387+ }
388+
349389func (s * SarifTransformer ) mapAffectedPackage (fixes []sarif.Fix , purl packageurl.PackageURL ) * ocsf.AffectedPackage {
350390 affectedPackage := & ocsf.AffectedPackage {
351391 Purl : utils .Ptr (purl .String ()),
@@ -440,11 +480,11 @@ func (s *SarifTransformer) rulesToEcosystem() map[string]string {
440480 return result
441481}
442482
443- func (s * SarifTransformer ) mapAffected (res * sarif.Result ) ([]* ocsf.AffectedCode , []* ocsf.AffectedPackage ) {
483+ func (s * SarifTransformer ) mapAffected (res * sarif.Result ) ([]* ocsf.AffectedCode , []* ocsf.AffectedPackage , error ) {
444484 var affectedCode []* ocsf.AffectedCode
445485 var affectedPackages []* ocsf.AffectedPackage
446486 if s .dataSource .TargetType == ocsffindinginfo .DataSource_TARGET_TYPE_WEBSITE { // websites do not carry code or package info
447- return nil , nil
487+ return nil , nil , nil
448488 }
449489
450490 for _ , location := range res .Locations {
@@ -469,14 +509,21 @@ func (s *SarifTransformer) mapAffected(res *sarif.Result) ([]*ocsf.AffectedCode,
469509 }
470510
471511 if physicalLocation .ArtifactLocation != nil && physicalLocation .ArtifactLocation .Uri != nil {
512+ uri := * location .PhysicalLocation .ArtifactLocation .Uri
472513 if p := s .detectPackageFromPhysicalLocation (* physicalLocation , pkgType ); p != nil {
473514 affectedPackages = append (affectedPackages , s .mapAffectedPackage (res .Fixes , * p ))
474- } else if ! s .isSnykURI (* location .PhysicalLocation .ArtifactLocation .Uri ) {
475515 // Snyk special case, they use the repo url with some weird replacement as the artifact location
516+ } else if ! s .isSnykURI (uri ) {
517+ finalPath , err := s .constructPath (uri )
518+ if err != nil {
519+ return nil , nil , errors .Errorf ("could not construct path for affected code: %w" , err )
520+ }
521+
476522 ac := & ocsf.AffectedCode {
477523 File : & ocsf.File {
478- Name : * location .PhysicalLocation .ArtifactLocation .Uri ,
479- Path : utils .Ptr (fmt .Sprintf ("file://%s" , * location .PhysicalLocation .ArtifactLocation .Uri )),
524+ // we will also need to change this line as well, if we can
525+ Name : strings .ReplaceAll (finalPath , "file://" , "" ),
526+ Path : utils .Ptr (finalPath ),
480527 },
481528 }
482529
@@ -500,7 +547,7 @@ func (s *SarifTransformer) mapAffected(res *sarif.Result) ([]*ocsf.AffectedCode,
500547 }
501548 }
502549
503- return affectedCode , affectedPackages
550+ return affectedCode , affectedPackages , nil
504551}
505552
506553func (s * SarifTransformer ) mapSeverity (sarifResLevel sarif.ResultLevel ) ocsf.VulnerabilityFinding_SeverityId {
@@ -657,9 +704,16 @@ func (s *SarifTransformer) mergeDataSources(
657704 if s .isSnykURI (* location .PhysicalLocation .ArtifactLocation .Uri ) {
658705 dataSource .Uri = nil
659706 } else {
707+ uri := * location .PhysicalLocation .ArtifactLocation .Uri
708+
709+ finalPath , err := s .constructPath (uri )
710+ if err != nil {
711+ return nil , errors .Errorf ("could not construct path for repository data source: %w" , err )
712+ }
713+
660714 dataSource .Uri = & ocsffindinginfo.DataSource_URI {
661715 UriSchema : ocsffindinginfo .DataSource_URI_SCHEMA_FILE ,
662- Path : "file://" + filepath . Clean ( * location . PhysicalLocation . ArtifactLocation . Uri ) ,
716+ Path : finalPath ,
663717 }
664718 }
665719
0 commit comments