@@ -18,26 +18,38 @@ package scorecard
1818import (
1919 "context"
2020 "fmt"
21- "io"
22- "net/http"
23- "net/url"
24- "os"
25- "time"
26-
2721 "github.com/guacsec/guac/pkg/logging"
2822 "github.com/ossf/scorecard/v4/checker"
2923 "github.com/ossf/scorecard/v4/checks"
3024 "github.com/ossf/scorecard/v4/log"
3125 sc "github.com/ossf/scorecard/v4/pkg"
26+ "io"
27+ "net/http"
28+ "net/url"
29+ "os"
30+ "strings"
31+ "time"
3232)
3333
34+ const githubPrefix = "github.com/"
35+
3436// scorecardRunner is a struct that implements the Scorecard interface.
3537type scorecardRunner struct {
3638 ctx context.Context
3739}
3840
41+ // normalizeRepoName ensures the repo name has the github.com/ prefix required by the Scorecard API.
42+ // If the prefix is missing, it is added. If the repo name already has the prefix, it is returned as-is.
43+ func normalizeRepoName (repoName string ) string {
44+ if strings .HasPrefix (repoName , githubPrefix ) {
45+ return repoName
46+ }
47+ return githubPrefix + repoName
48+ }
49+
3950func (s scorecardRunner ) GetScore (repoName , commitSHA , tag string ) (* sc.ScorecardResult , error ) {
4051 logger := logging .FromContext (s .ctx )
52+ repoName = normalizeRepoName (repoName )
4153
4254 // First try API approach
4355 logger .Debugf ("Attempting to fetch scorecard from API for repo: %s, commit: %s" , repoName , commitSHA )
@@ -67,30 +79,44 @@ func (s scorecardRunner) GetScore(repoName, commitSHA, tag string) (*sc.Scorecar
6779func (s scorecardRunner ) getScoreFromAPI (repoName , commitSHA , tag string ) (* sc.ScorecardResult , error ) {
6880 logger := logging .FromContext (s .ctx )
6981
70- // The Scorecard API only supports commit SHAs, not tags.
71- // If a tag is provided without a commitSHA, we cannot use the API
72- // and must fall back to local computation to avoid returning incorrect results.
82+ // If tag is provided without a valid commitSHA, skip API and use local computation
83+ // The API cannot resolve tags, but computeScore can look up the commit for a tag
7384 if (commitSHA == "" || commitSHA == "HEAD" ) && tag != "" {
74- logger .Debugf ("Cannot use API for tag %s without commit SHA - will fall back to local computation" , tag )
75- return nil , fmt .Errorf ("scorecard API does not support tags; commit SHA required for tag %s" , tag )
85+ logger .Debugf ("Tag %s provided without commit SHA - skipping API, will use local computation" , tag )
86+ return nil , fmt .Errorf ("tag provided without commit SHA; falling back to local computation for tag %s" , tag )
7687 }
7788
78- url , err := url .JoinPath ("https://api.securityscorecards.dev" , "projects" , repoName )
89+ baseURL , err := url .JoinPath ("https://api.securityscorecards.dev" , "projects" , repoName )
7990 if err != nil {
8091 return nil , err
8192 }
8293
94+ // If commitSHA is provided, try with it first
8395 if commitSHA != "" && commitSHA != "HEAD" {
84- url += "?commit=" + commitSHA
96+ urlWithCommit := baseURL + "?commit=" + commitSHA
97+ result , err := s .fetchFromAPI (urlWithCommit )
98+ if err == nil {
99+ return result , nil
100+ }
101+ logger .Debugf ("API call with commit %s failed, retrying without commit: %v" , commitSHA , err )
85102 }
86103
87- logger .Debugf ("Making API request to: %s" , url )
104+ result , err := s .fetchFromAPI (baseURL )
105+ if err != nil {
106+ return nil , err
107+ }
108+ return result , nil
109+ }
110+
111+ func (s scorecardRunner ) fetchFromAPI (apiURL string ) (* sc.ScorecardResult , error ) {
112+ logger := logging .FromContext (s .ctx )
113+ logger .Debugf ("Making API request to: %s" , apiURL )
88114
89115 httpClient := & http.Client {
90116 Timeout : 30 * time .Second ,
91117 }
92118
93- req , err := http .NewRequestWithContext (s .ctx , http .MethodGet , url , nil )
119+ req , err := http .NewRequestWithContext (s .ctx , http .MethodGet , apiURL , nil )
94120 if err != nil {
95121 return nil , fmt .Errorf ("failed to create request: %w" , err )
96122 }
@@ -111,7 +137,7 @@ func (s scorecardRunner) getScoreFromAPI(repoName, commitSHA, tag string) (*sc.S
111137 logger .Debugf ("API response status code: %d" , resp .StatusCode )
112138
113139 if resp .StatusCode == http .StatusNotFound {
114- return nil , fmt .Errorf ("Scorecard for repo %s not found in scorecard API" , repoName )
140+ return nil , fmt .Errorf ("scorecard not found in API" )
115141 }
116142
117143 if resp .StatusCode >= 400 {
@@ -198,4 +224,4 @@ func NewScorecardRunner(ctx context.Context) (Scorecard, error) {
198224 return scorecardRunner {
199225 ctx ,
200226 }, nil
201- }
227+ }
0 commit comments