mirror of
https://github.com/anchore/syft.git
synced 2026-07-04 18:18:26 +02:00
fix: composite action version parsing (#4616)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
parent
e7f1a803e7
commit
deee79411a
@ -73,7 +73,6 @@ func parseStepUsageStatement(use, comment string) (string, string) {
|
||||
|
||||
// if version looks like a commit hash and we have a comment, try to extract version from comment
|
||||
if version != "" && regexp.MustCompile(`^[0-9a-f]{7,}$`).MatchString(version) && comment != "" {
|
||||
versionRegex := regexp.MustCompile(`v?\d+\.\d+\.\d+`)
|
||||
matches := versionRegex.FindStringSubmatch(comment)
|
||||
|
||||
if len(matches) >= 1 {
|
||||
|
||||
@ -24,12 +24,19 @@ type compositeActionRunsDef struct {
|
||||
}
|
||||
|
||||
func parseCompositeActionForActionUsage(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var ca compositeActionDef
|
||||
var errs error
|
||||
if errs = yaml.NewDecoder(reader).Decode(&ca); errs != nil {
|
||||
var node yaml.Node
|
||||
if errs = yaml.NewDecoder(reader).Decode(&node); errs != nil {
|
||||
return nil, nil, fmt.Errorf("unable to parse yaml workflow file: %w", errs)
|
||||
}
|
||||
|
||||
var ca compositeActionDef
|
||||
if errs = node.Decode(&ca); errs != nil {
|
||||
return nil, nil, fmt.Errorf("unable to parse yaml composite action file: %w", errs)
|
||||
}
|
||||
|
||||
attachCompositeActionUsageComments(&node, ca.Runs.Steps)
|
||||
|
||||
// we use a collection to help with deduplication before raising to higher level processing
|
||||
pkgs := pkg.NewCollection()
|
||||
|
||||
@ -49,3 +56,62 @@ func parseCompositeActionForActionUsage(_ context.Context, _ file.Resolver, _ *g
|
||||
|
||||
return pkgs.Sorted(), nil, errs
|
||||
}
|
||||
|
||||
func attachCompositeActionUsageComments(node *yaml.Node, steps []stepDef) {
|
||||
root := node
|
||||
if root.Kind == yaml.DocumentNode && len(root.Content) > 0 {
|
||||
root = root.Content[0]
|
||||
}
|
||||
if root.Kind != yaml.MappingNode {
|
||||
return
|
||||
}
|
||||
|
||||
// find the "runs" key
|
||||
for i := 0; i < len(root.Content); i += 2 {
|
||||
key := root.Content[i]
|
||||
value := root.Content[i+1]
|
||||
if key.Value != "runs" || value.Kind != yaml.MappingNode {
|
||||
continue
|
||||
}
|
||||
// find the "steps" key within runs
|
||||
for j := 0; j < len(value.Content); j += 2 {
|
||||
stepsKey := value.Content[j]
|
||||
stepsValue := value.Content[j+1]
|
||||
if stepsKey.Value != "steps" || stepsValue.Kind != yaml.SequenceNode {
|
||||
continue
|
||||
}
|
||||
readSteps(stepsValue, steps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readSteps(stepsValue *yaml.Node, steps []stepDef) {
|
||||
// iterate over each step
|
||||
for stepIdx, stepNode := range stepsValue.Content {
|
||||
if stepNode.Kind != yaml.MappingNode {
|
||||
continue
|
||||
}
|
||||
// find the "uses" key within the step
|
||||
for k := 0; k < len(stepNode.Content); k += 2 {
|
||||
usesKey := stepNode.Content[k]
|
||||
usesValue := stepNode.Content[k+1]
|
||||
if usesKey.Value != "uses" || usesValue.Kind != yaml.ScalarNode {
|
||||
continue
|
||||
}
|
||||
comment := usesValue.LineComment
|
||||
if comment == "" {
|
||||
comment = usesValue.HeadComment
|
||||
}
|
||||
if comment == "" {
|
||||
comment = usesValue.FootComment
|
||||
}
|
||||
if comment == "" {
|
||||
continue
|
||||
}
|
||||
versionMatch := versionRegex.FindString(comment)
|
||||
if versionMatch != "" && stepIdx < len(steps) {
|
||||
steps[stepIdx].UsesComment = versionMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,28 @@ func Test_parseCompositeActionForActionUsage(t *testing.T) {
|
||||
fixtureLocationSet := file.NewLocationSet(file.NewLocation(fixture).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||
|
||||
expected := []pkg.Package{
|
||||
{
|
||||
Name: "actions/checkout",
|
||||
Version: "11",
|
||||
Type: pkg.GithubActionPkg,
|
||||
Locations: fixtureLocationSet,
|
||||
PURL: "pkg:github/actions/checkout@11",
|
||||
Metadata: pkg.GitHubActionsUseStatement{
|
||||
Value: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683",
|
||||
Comment: "11",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "actions/setup-go",
|
||||
Version: "v5.1.0",
|
||||
Type: pkg.GithubActionPkg,
|
||||
Locations: fixtureLocationSet,
|
||||
PURL: "pkg:github/actions/setup-go@v5.1.0",
|
||||
Metadata: pkg.GitHubActionsUseStatement{
|
||||
Value: "actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed",
|
||||
Comment: "v5.1.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "actions/setup-go",
|
||||
Version: "v4",
|
||||
|
||||
@ -19,6 +19,8 @@ var (
|
||||
_ generic.Parser = parseWorkflowForWorkflowUsage
|
||||
)
|
||||
|
||||
var versionRegex = regexp.MustCompile(`v?\d+(\.\d+)*`)
|
||||
|
||||
type workflowDef struct {
|
||||
Jobs map[string]workflowJobDef `yaml:"jobs"`
|
||||
}
|
||||
@ -185,7 +187,6 @@ func processUsesNode(node *yaml.Node, wf *workflowDef, currentJob *string, curre
|
||||
}
|
||||
|
||||
if comment != "" {
|
||||
versionRegex := regexp.MustCompile(`v?\d+(\.\d+)*`)
|
||||
versionMatch := versionRegex.FindString(comment)
|
||||
|
||||
if versionMatch != "" {
|
||||
|
||||
@ -35,6 +35,13 @@ runs:
|
||||
path: ${{ github.workspace }}/.tmp
|
||||
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v 11
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed #v5.1.0
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
|
||||
# note: we need to keep restoring the go mod cache before bootstrapping tools since `go install` is used in
|
||||
# some installations of project tools.
|
||||
- name: Restore go module cache
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user