github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/githubactions/parse_workflow.go (about)

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