Skip to content

Commit 4fd7753

Browse files
authored
Fix default branch verification (#778)
* Fix default branch verification In case the Scorecard action is used in a reusable GitHub workflow, the repository of the workflow can be different from the repository of the project being analyzed. Currently, the server checks that the branch for which the Scorecard is computed is the default branch of the repository containing the **reusable** workflow. This PR modifies the verification procedure to use the repository of the **calling** workflow instead. Closes #554 Signed-off-by: Piotr P. Karwasz <[email protected]> * Fix linter error Signed-off-by: Piotr P. Karwasz <[email protected]> --------- Signed-off-by: Piotr P. Karwasz <[email protected]>
1 parent 613af5f commit 4fd7753

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

app/server/post_results.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,18 +177,21 @@ func splitFullPath(path string) (org, repo, subPath string, ok bool) {
177177
return parts[0], parts[1], parts[2], true
178178
}
179179

180+
// splitRepoName extracts the org, repo from a full repository name.
181+
func splitRepoName(path string) (org, repo string, ok bool) {
182+
parts := strings.SplitN(path, "/", 2)
183+
if len(parts) < 2 {
184+
return "", "", false
185+
}
186+
return parts[0], parts[1], true
187+
}
188+
180189
// getAndVerifyWorkflowContent retrieves the workflow content from the repository and verifies it.
181190
// It verifies the branch is a default branch and gets the scorecard workflow from the repository
182191
// from the specific commit and verifies it to ensure that it hasn't been tampered with.
183192
func getAndVerifyWorkflowContent(ctx context.Context,
184193
scorecardResult *models.VerifiedScorecardResult, info certInfo,
185194
) error {
186-
org, repo, path, ok := splitFullPath(info.workflowPath)
187-
if !ok {
188-
return fmt.Errorf("cert workflow path is malformed")
189-
}
190-
workflowRepoFullName := fullName(org, repo)
191-
192195
// Get the corresponding GitHub repository.
193196
httpClient := http.DefaultClient
194197
if scorecardResult.AccessToken != "" {
@@ -197,6 +200,11 @@ func getAndVerifyWorkflowContent(ctx context.Context,
197200
}
198201
}
199202
client := github.NewClient(httpClient)
203+
// Organization and repo of the project being analyzed
204+
org, repo, ok := splitRepoName(info.repoFullName)
205+
if !ok {
206+
return fmt.Errorf("cert repository name is malformed")
207+
}
200208
repoClient, _, err := client.Repositories.Get(ctx, org, repo)
201209
if err != nil {
202210
return fmt.Errorf("error getting repository: %w", err)
@@ -209,14 +217,21 @@ func getAndVerifyWorkflowContent(ctx context.Context,
209217
return verificationError{e: errNotDefaultBranch}
210218
}
211219

220+
// Organization and repo of the (possibly) reusable workflow
221+
workflowOrg, workflowRepo, path, ok := splitFullPath(info.workflowPath)
222+
if !ok {
223+
return fmt.Errorf("cert workflow path is malformed")
224+
}
225+
workflowRepoFullName := fullName(workflowOrg, workflowRepo)
226+
212227
// Use the cert commit SHA if the workflow file is in the repo being analyzed.
213228
// Otherwise fall back to the workflowRef, which may be a commit SHA, or it may be more vague e.g. refs/heads/main
214229
opts := &github.RepositoryContentGetOptions{Ref: info.repoSHA}
215230
if workflowRepoFullName != info.repoFullName {
216231
opts.Ref = info.workflowRef
217232
}
218233

219-
contents, _, _, err := client.Repositories.GetContents(ctx, org, repo, path, opts)
234+
contents, _, _, err := client.Repositories.GetContents(ctx, workflowOrg, workflowRepo, path, opts)
220235
if err != nil {
221236
return fmt.Errorf("error downloading workflow contents from repo: %w", err)
222237
}

app/server/post_results_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,47 @@ func FuzzExtractCertInfo(f *testing.F) {
219219
})
220220
}
221221

222+
func Test_splitRepoName(t *testing.T) {
223+
t.Parallel()
224+
type results struct {
225+
org, repo string
226+
ok bool
227+
}
228+
tests := []struct {
229+
name string
230+
path string
231+
want results
232+
}{
233+
{
234+
name: "valid path",
235+
path: "org/repo",
236+
want: results{
237+
org: "org",
238+
repo: "repo",
239+
ok: true,
240+
},
241+
},
242+
{
243+
name: "malformed path",
244+
path: "malformed",
245+
want: results{
246+
org: "",
247+
repo: "",
248+
ok: false,
249+
},
250+
},
251+
}
252+
for _, tt := range tests {
253+
t.Run(tt.name, func(t *testing.T) {
254+
t.Parallel()
255+
o, r, ok := splitRepoName(tt.path)
256+
assert.Equal(t, tt.want.ok, ok)
257+
assert.Equal(t, tt.want.org, o)
258+
assert.Equal(t, tt.want.repo, r)
259+
})
260+
}
261+
}
262+
222263
func Test_splitFullPath(t *testing.T) {
223264
t.Parallel()
224265
type results struct {

0 commit comments

Comments
 (0)