Skip to content

Commit

Permalink
fix: resolve lambda timeout for pinToImmutable settings
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham-stepsecurity committed Feb 12, 2025
1 parent cea4ccb commit 957e16f
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 4 deletions.
39 changes: 39 additions & 0 deletions remediation/workflow/pin/action_image_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"regexp"
"strings"
"sync"

"net/http"

Expand All @@ -22,6 +23,44 @@ type ociManifest struct {
ArtifactType string `json:"artifactType"`
}

// immutableResult holds the result for an image reference.
type immutableResult struct {
action string
isImmutable bool
}

// Run isImmutableAction concurrently for all the actions simultaneously
// Individual runs takes up to 600 ms with concurrency it can be achieved under 1000 ms for all actions present
func IsImmutableActionConcurrently(actions []string) map[string]bool {
var wg sync.WaitGroup
// Buffered channel to hold one result per image.
resultChan := make(chan immutableResult, len(actions))

for _, action := range actions {
wg.Add(1)
go func(a string) {
defer wg.Done()
isImmutable := IsImmutableAction(a)
resultChan <- immutableResult{
action: a,
isImmutable: isImmutable,
}
}(action)
}

// Wait for all goroutines to finish.
wg.Wait()
close(resultChan)

// Collect the results.
results := make(map[string]bool)
for res := range resultChan {
results[res.action] = res.isImmutable
}

return results
}

// isImmutableAction checks if the action is an immutable action or not
// It queries the OCI manifest for the action and checks if the artifact type is "application/vnd.github.actions.package.v1+json"
//
Expand Down
69 changes: 65 additions & 4 deletions remediation/workflow/pin/pinactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ func PinActions(inputYaml string, exemptedActions []string, pinToImmutable bool)

out := inputYaml

// get immutable map for the semantic versions of the actions present in the workflow
immutableMap := getSemanticActionsImmutableMap(workflow, pinToImmutable)

for _, job := range workflow.Jobs {

for _, step := range job.Steps {
if len(step.Uses) > 0 {
localUpdated := false
out, localUpdated = PinAction(step.Uses, out, exemptedActions, pinToImmutable)
out, localUpdated = PinAction(step.Uses, out, exemptedActions, immutableMap)
updated = updated || localUpdated
}
}
Expand All @@ -38,14 +41,15 @@ func PinActions(inputYaml string, exemptedActions []string, pinToImmutable bool)
return out, updated, nil
}

func PinAction(action, inputYaml string, exemptedActions []string, pinToImmutable bool) (string, bool) {
func PinAction(action, inputYaml string, exemptedActions []string, immutableMap map[string]bool) (string, bool) {

updated := false
if !strings.Contains(action, "@") || strings.HasPrefix(action, "docker://") {
return inputYaml, updated // Cannot pin local actions and docker actions
}

if isAbsolute(action) || (pinToImmutable && IsImmutableAction(action)) {
// if already semantic than the action must be present in immutableMap
if isAbsolute(action) || immutableMap[action] {
return inputYaml, updated
}
leftOfAt := strings.Split(action, "@")
Expand Down Expand Up @@ -84,7 +88,8 @@ func PinAction(action, inputYaml string, exemptedActions []string, pinToImmutabl

// if the action with version is immutable, then pin the action with version instead of sha
pinnedActionWithVersion := fmt.Sprintf("%s@%s", leftOfAt[0], tagOrBranch)
if pinToImmutable && semanticTagRegex.MatchString(tagOrBranch) && IsImmutableAction(pinnedActionWithVersion) {
// if found update pinned action with immutable pinned version
if semanticTagRegex.MatchString(tagOrBranch) && immutableMap[pinnedActionWithVersion] {
pinnedAction = pinnedActionWithVersion
}

Expand Down Expand Up @@ -211,3 +216,59 @@ func ActionExists(actionName string, patterns []string) bool {
}
return false
}

func getSemanticActionsImmutableMap(workflow metadata.Workflow, pinToImmutable bool) map[string]bool {
var allActions []string
var allSemanticActions []string
immutableMap := make(map[string]bool)

// return if pinToImmutable is set to false
if !pinToImmutable {
return immutableMap
}

// get all jobs present in the workflow
for _, job := range workflow.Jobs {
for _, step := range job.Steps {
if strings.Contains(step.Uses, "@") && !strings.HasPrefix(step.Uses, "docker://") && !isAbsolute(step.Uses) {
allActions = append(allActions, step.Uses)
}
}
}

PAT := os.Getenv("PAT")

ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: PAT},
)
tc := oauth2.NewClient(ctx, ts)

client := github.NewClient(tc)

// get corresponding semantic actions for the actions present in the workflow
for _, action := range allActions {
leftOfAt := strings.Split(action, "@")
tagOrBranch := leftOfAt[1]

splitOnSlash := strings.Split(leftOfAt[0], "/")
owner := splitOnSlash[0]
repo := splitOnSlash[1]

commitSHA, _, err := client.Repositories.GetCommitSHA1(ctx, owner, repo, tagOrBranch, "")
if err != nil {
return immutableMap
}

tagOrBranch, err = getSemanticVersion(client, owner, repo, tagOrBranch, commitSHA)
if err != nil {
return immutableMap
}

pinnedActionWithSemanticVersion := fmt.Sprintf("%s@%s", leftOfAt[0], tagOrBranch)

allSemanticActions = append(allSemanticActions, pinnedActionWithSemanticVersion)
}

return IsImmutableActionConcurrently(allSemanticActions)
}

0 comments on commit 957e16f

Please sign in to comment.