github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/githubactions/parse_workflow.go (about)

     1  package githubactions
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"gopkg.in/yaml.v3"
     8  
     9  	"github.com/anchore/syft/syft/artifact"
    10  	"github.com/anchore/syft/syft/file"
    11  	"github.com/anchore/syft/syft/pkg"
    12  	"github.com/anchore/syft/syft/pkg/cataloger/generic"
    13  )
    14  
    15  var (
    16  	_ generic.Parser = parseWorkflowForActionUsage
    17  	_ generic.Parser = parseWorkflowForWorkflowUsage
    18  )
    19  
    20  type workflowDef struct {
    21  	Jobs map[string]workflowJobDef `yaml:"jobs"`
    22  }
    23  
    24  type workflowJobDef struct {
    25  	Uses  string    `yaml:"uses"`
    26  	Steps []stepDef `yaml:"steps"`
    27  }
    28  
    29  type stepDef struct {
    30  	Name string `yaml:"name"`
    31  	Uses string `yaml:"uses"`
    32  	With struct {
    33  		Path string `yaml:"path"`
    34  		Key  string `yaml:"key"`
    35  	} `yaml:"with"`
    36  }
    37  
    38  func parseWorkflowForWorkflowUsage(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    39  	contents, err := io.ReadAll(reader)
    40  	if err != nil {
    41  		return nil, nil, fmt.Errorf("unable to read yaml workflow file: %w", err)
    42  	}
    43  
    44  	var wf workflowDef
    45  	if err = yaml.Unmarshal(contents, &wf); err != nil {
    46  		return nil, nil, fmt.Errorf("unable to parse yaml workflow file: %w", err)
    47  	}
    48  
    49  	// we use a collection to help with deduplication before raising to higher level processing
    50  	pkgs := pkg.NewCollection()
    51  
    52  	for _, job := range wf.Jobs {
    53  		if job.Uses != "" {
    54  			p := newPackageFromUsageStatement(job.Uses, reader.Location)
    55  			if p != nil {
    56  				pkgs.Add(*p)
    57  			}
    58  		}
    59  	}
    60  
    61  	return pkgs.Sorted(), nil, nil
    62  }
    63  
    64  func parseWorkflowForActionUsage(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    65  	contents, err := io.ReadAll(reader)
    66  	if err != nil {
    67  		return nil, nil, fmt.Errorf("unable to read yaml workflow file: %w", err)
    68  	}
    69  
    70  	var wf workflowDef
    71  	if err = yaml.Unmarshal(contents, &wf); err != nil {
    72  		return nil, nil, fmt.Errorf("unable to parse yaml workflow file: %w", err)
    73  	}
    74  
    75  	// we use a collection to help with deduplication before raising to higher level processing
    76  	pkgs := pkg.NewCollection()
    77  
    78  	for _, job := range wf.Jobs {
    79  		for _, step := range job.Steps {
    80  			if step.Uses == "" {
    81  				continue
    82  			}
    83  			p := newPackageFromUsageStatement(step.Uses, reader.Location)
    84  			if p != nil {
    85  				pkgs.Add(*p)
    86  			}
    87  		}
    88  	}
    89  
    90  	return pkgs.Sorted(), nil, nil
    91  }