Projects STRLCPY scorecard Commits 70d045b9
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    checks/branch_protection_test.go
    skipped 32 lines
    33 33   return *branch.Name
    34 34  }
    35 35   
    36  -func getBranch(branches []*clients.BranchRef, name string) *clients.BranchRef {
     36 +func getBranch(branches []*clients.BranchRef, name string, isNonAdmin bool) *clients.BranchRef {
    37 37   for _, branch := range branches {
    38 38   branchName := getBranchName(branch)
    39 39   if branchName == name {
    40  - return branch
     40 + if !isNonAdmin {
     41 + return branch
     42 + }
     43 + return scrubBranch(branch)
    41 44   }
    42 45   }
    43 46   return nil
    skipped 2 lines
    46 49  func scrubBranch(branch *clients.BranchRef) *clients.BranchRef {
    47 50   ret := branch
    48 51   ret.BranchProtectionRule = clients.BranchProtectionRule{}
    49  - return ret
    50  -}
    51  - 
    52  -func scrubBranches(branches []*clients.BranchRef) []*clients.BranchRef {
    53  - ret := make([]*clients.BranchRef, len(branches))
    54  - for i, branch := range branches {
    55  - ret[i] = scrubBranch(branch)
    56  - }
    57 52   return ret
    58 53  }
    59 54   
    skipped 339 lines
    399 394   mockRepoClient := mockrepo.NewMockRepoClient(ctrl)
    400 395   mockRepoClient.EXPECT().GetDefaultBranch().
    401 396   DoAndReturn(func() (*clients.BranchRef, error) {
    402  - defaultBranch := getBranch(tt.branches, tt.defaultBranch)
    403  - if defaultBranch != nil && tt.nonadmin {
    404  - return scrubBranch(defaultBranch), nil
    405  - }
     397 + defaultBranch := getBranch(tt.branches, tt.defaultBranch, tt.nonadmin)
    406 398   return defaultBranch, nil
    407 399   }).AnyTimes()
    408 400   mockRepoClient.EXPECT().ListReleases().
    skipped 6 lines
    415 407   }
    416 408   return ret, nil
    417 409   }).AnyTimes()
    418  - mockRepoClient.EXPECT().ListBranches().
    419  - DoAndReturn(func() ([]*clients.BranchRef, error) {
    420  - if tt.nonadmin {
    421  - return scrubBranches(tt.branches), nil
    422  - }
    423  - return tt.branches, nil
     410 + mockRepoClient.EXPECT().GetBranch(gomock.Any()).
     411 + DoAndReturn(func(b string) (*clients.BranchRef, error) {
     412 + return getBranch(tt.branches, b, tt.nonadmin), nil
    424 413   }).AnyTimes()
    425 414   dl := scut.TestDetailLogger{}
    426 415   req := checker.CheckRequest{
    skipped 12 lines
  • ■ ■ ■ ■ ■
    checks/evaluation/security_policy.go
    skipped 39 lines
    40 40   }
    41 41   if msg.Type == checker.FileTypeURL {
    42 42   msg.Text = "security policy detected in org repo"
    43  - 
    44 43   } else {
    45 44   msg.Text = "security policy detected in current repo"
    46 45   }
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    checks/raw/branch_protection.go
    skipped 14 lines
    15 15  package raw
    16 16   
    17 17  import (
    18  - "errors"
    19 18   "fmt"
    20 19   "regexp"
    21 20   
    22 21   "github.com/ossf/scorecard/v4/checker"
    23 22   "github.com/ossf/scorecard/v4/clients"
    24  - sce "github.com/ossf/scorecard/v4/errors"
    25 23  )
    26 24   
    27 25  const master = "master"
    28 26   
    29  -type branchMap map[string]*clients.BranchRef
     27 +var commit = regexp.MustCompile("^[a-f0-9]{40}$")
     28 + 
     29 +type branchSet struct {
     30 + exists map[string]bool
     31 + set []clients.BranchRef
     32 +}
     33 + 
     34 +func (set *branchSet) add(branch *clients.BranchRef) bool {
     35 + if branch != nil &&
     36 + branch.Name != nil &&
     37 + *branch.Name != "" &&
     38 + !set.exists[*branch.Name] {
     39 + set.set = append(set.set, *branch)
     40 + set.exists[*branch.Name] = true
     41 + return true
     42 + }
     43 + return false
     44 +}
     45 + 
     46 +func (set branchSet) contains(branch string) bool {
     47 + _, contains := set.exists[branch]
     48 + return contains
     49 +}
    30 50   
    31 51  // BranchProtection retrieves the raw data for the Branch-Protection check.
    32 52  func BranchProtection(c clients.RepoClient) (checker.BranchProtectionsData, error) {
    33  - // Checks branch protection on both release and development branch.
    34  - // Get all branches. This will include information on whether they are protected.
    35  - branches, err := c.ListBranches()
     53 + branches := branchSet{
     54 + exists: make(map[string]bool),
     55 + }
     56 + // Add default branch.
     57 + defaultBranch, err := c.GetDefaultBranch()
    36 58   if err != nil {
    37 59   return checker.BranchProtectionsData{}, fmt.Errorf("%w", err)
    38 60   }
    39  - branchesMap := getBranchMapFrom(branches)
     61 + branches.add(defaultBranch)
    40 62   
    41 63   // Get release branches.
    42 64   releases, err := c.ListReleases()
    43 65   if err != nil {
    44 66   return checker.BranchProtectionsData{}, fmt.Errorf("%w", err)
    45 67   }
    46  - 
    47  - commit := regexp.MustCompile("^[a-f0-9]{40}$")
    48  - checkBranches := make(map[string]bool)
    49 68   for _, release := range releases {
    50 69   if release.TargetCommitish == "" {
    51 70   // Log with a named error if target_commitish is nil.
    skipped 5 lines
    57 76   continue
    58 77   }
    59 78   
    60  - // Try to resolve the branch name.
    61  - b, err := branchesMap.getBranchByName(release.TargetCommitish)
    62  - if err != nil {
    63  - // If the commitish branch is still not found, fail.
    64  - return checker.BranchProtectionsData{}, err
     79 + if branches.contains(release.TargetCommitish) ||
     80 + branches.contains(branchRedirect(release.TargetCommitish)) {
     81 + continue
    65 82   }
    66 83   
    67  - // Branch is valid, add to list of branches to check.
    68  - checkBranches[*b.Name] = true
    69  - }
    70  - 
    71  - // Add default branch.
    72  - defaultBranch, err := c.GetDefaultBranch()
    73  - if err != nil {
    74  - return checker.BranchProtectionsData{}, fmt.Errorf("%w", err)
    75  - }
    76  - defaultBranchName := getBranchName(defaultBranch)
    77  - if defaultBranchName != "" {
    78  - checkBranches[defaultBranchName] = true
    79  - }
    80  - 
    81  - rawData := checker.BranchProtectionsData{}
    82  - // Check protections on all the branches.
    83  - for b := range checkBranches {
    84  - branch, err := branchesMap.getBranchByName(b)
     84 + // Get the associated release branch.
     85 + branchRef, err := c.GetBranch(release.TargetCommitish)
    85 86   if err != nil {
    86  - if errors.Is(err, errInternalBranchNotFound) {
    87  - continue
    88  - }
    89  - return checker.BranchProtectionsData{}, err
     87 + return checker.BranchProtectionsData{},
     88 + fmt.Errorf("error during GetBranch(%s): %w", release.TargetCommitish, err)
     89 + }
     90 + if branches.add(branchRef) {
     91 + continue
    90 92   }
    91 93   
    92  - rawData.Branches = append(rawData.Branches, *branch)
     94 + // Couldn't find the branch check for redirects.
     95 + redirectBranch := branchRedirect(release.TargetCommitish)
     96 + if redirectBranch == "" {
     97 + continue
     98 + }
     99 + branchRef, err = c.GetBranch(redirectBranch)
     100 + if err != nil {
     101 + return checker.BranchProtectionsData{},
     102 + fmt.Errorf("error during GetBranch(%s) %w", redirectBranch, err)
     103 + }
     104 + branches.add(branchRef)
     105 + // Branch doesn't exist or was deleted. Continue.
    93 106   }
    94 107   
    95 108   // No error, return the data.
    96  - return rawData, nil
     109 + return checker.BranchProtectionsData{
     110 + Branches: branches.set,
     111 + }, nil
    97 112  }
    98 113   
    99  -func (b branchMap) getBranchByName(name string) (*clients.BranchRef, error) {
    100  - val, exists := b[name]
    101  - if exists {
    102  - return val, nil
    103  - }
    104  - 
     114 +func branchRedirect(name string) string {
    105 115   // Ideally, we should check using repositories.GetBranch if there was a branch redirect.
    106 116   // See https://github.com/google/go-github/issues/1895
    107 117   // For now, handle the common master -> main redirect.
    108 118   if name == master {
    109  - val, exists := b["main"]
    110  - if exists {
    111  - return val, nil
    112  - }
     119 + return "main"
    113 120   }
    114  - return nil, sce.WithMessage(sce.ErrScorecardInternal,
    115  - fmt.Sprintf("could not find branch name %s: %v", name, errInternalBranchNotFound))
    116  -}
    117  - 
    118  -func getBranchMapFrom(branches []*clients.BranchRef) branchMap {
    119  - ret := make(branchMap)
    120  - for _, branch := range branches {
    121  - branchName := getBranchName(branch)
    122  - if branchName != "" {
    123  - ret[branchName] = branch
    124  - }
    125  - }
    126  - return ret
    127  -}
    128  - 
    129  -func getBranchName(branch *clients.BranchRef) string {
    130  - if branch == nil || branch.Name == nil {
    131  - return ""
    132  - }
    133  - return *branch.Name
     121 + return ""
    134 122  }
    135 123   
  • ■ ■ ■ ■ ■ ■
    checks/raw/branch_protection_test.go
    skipped 14 lines
    15 15  package raw
    16 16   
    17 17  import (
     18 + "errors"
    18 19   "testing"
    19 20   
     21 + "github.com/golang/mock/gomock"
    20 22   "github.com/google/go-cmp/cmp"
    21 23   
     24 + "github.com/ossf/scorecard/v4/checker"
    22 25   "github.com/ossf/scorecard/v4/clients"
     26 + mockrepo "github.com/ossf/scorecard/v4/clients/mockclients"
    23 27  )
    24 28   
    25  -var branch = "master"
     29 +var (
     30 + errBPTest = errors.New("test error")
     31 + defaultBranchName = "default"
     32 + releaseBranchName = "release-branch"
     33 + mainBranchName = "main"
     34 +)
    26 35   
    27  -func Test_getBranchName(t *testing.T) {
    28  - t.Parallel()
    29  - type args struct {
    30  - branch *clients.BranchRef
     36 +// nolint: govet
     37 +type branchArg struct {
     38 + err error
     39 + name string
     40 + branchRef *clients.BranchRef
     41 + defaultBranch bool
     42 +}
     43 + 
     44 +type branchesArg []branchArg
     45 + 
     46 +func (ba branchesArg) getDefaultBranch() (*clients.BranchRef, error) {
     47 + for _, branch := range ba {
     48 + if branch.defaultBranch {
     49 + return branch.branchRef, branch.err
     50 + }
    31 51   }
     52 + return nil, nil
     53 +}
     54 + 
     55 +func (ba branchesArg) getBranch(b string) (*clients.BranchRef, error) {
     56 + for _, branch := range ba {
     57 + if branch.name == b {
     58 + return branch.branchRef, branch.err
     59 + }
     60 + }
     61 + return nil, nil
     62 +}
     63 + 
     64 +func TestBranchProtection(t *testing.T) {
     65 + t.Parallel()
     66 + // nolint: govet
    32 67   tests := []struct {
    33  - name string
    34  - args args
    35  - want string
     68 + name string
     69 + branches branchesArg
     70 + releases []clients.Release
     71 + releasesErr error
     72 + want checker.BranchProtectionsData
     73 + wantErr error
    36 74   }{
    37 75   {
    38  - name: "simple",
    39  - args: args{
    40  - branch: &clients.BranchRef{
    41  - Name: &branch,
     76 + name: "default-branch-err",
     77 + branches: branchesArg{
     78 + {
     79 + name: defaultBranchName,
     80 + err: errBPTest,
    42 81   },
    43 82   },
    44  - want: master,
    45 83   },
    46 84   {
    47  - name: "empty name",
    48  - args: args{
    49  - branch: &clients.BranchRef{},
     85 + name: "null-default-branch-only",
     86 + branches: branchesArg{
     87 + {
     88 + name: defaultBranchName,
     89 + defaultBranch: true,
     90 + branchRef: nil,
     91 + },
    50 92   },
    51  - want: "",
    52 93   },
    53  - }
    54  - for _, tt := range tests {
    55  - tt := tt
    56  - t.Run(tt.name, func(t *testing.T) {
    57  - t.Parallel()
    58  - if got := getBranchName(tt.args.branch); got != tt.want {
    59  - t.Errorf("getBranchName() = %v, want %v", got, tt.want)
    60  - }
    61  - })
    62  - }
    63  -}
    64  - 
    65  -func Test_getBranchMapFrom(t *testing.T) {
    66  - t.Parallel()
    67  - type args struct {
    68  - branches []*clients.BranchRef
    69  - }
    70  - //nolint
    71  - tests := []struct {
    72  - name string
    73  - args args
    74  - want branchMap
    75  - }{
    76 94   {
    77  - name: "simple",
    78  - args: args{
    79  - branches: []*clients.BranchRef{
     95 + name: "default-branch-only",
     96 + branches: branchesArg{
     97 + {
     98 + name: defaultBranchName,
     99 + defaultBranch: true,
     100 + branchRef: &clients.BranchRef{
     101 + Name: &defaultBranchName,
     102 + },
     103 + },
     104 + },
     105 + want: checker.BranchProtectionsData{
     106 + Branches: []clients.BranchRef{
    80 107   {
    81  - Name: &branch,
     108 + Name: &defaultBranchName,
    82 109   },
    83 110   },
    84 111   },
    85  - want: branchMap{
    86  - master: &clients.BranchRef{
    87  - Name: &branch,
     112 + },
     113 + {
     114 + name: "list-releases-error",
     115 + releasesErr: errBPTest,
     116 + wantErr: errBPTest,
     117 + },
     118 + {
     119 + name: "no-releases",
     120 + },
     121 + {
     122 + name: "empty-targetcommitish",
     123 + releases: []clients.Release{
     124 + {
     125 + TargetCommitish: "",
    88 126   },
    89 127   },
     128 + wantErr: errInternalCommitishNil,
    90 129   },
    91  - }
    92  - for _, tt := range tests {
    93  - tt := tt
    94  - t.Run(tt.name, func(t *testing.T) {
    95  - t.Parallel()
    96  - if got := getBranchMapFrom(tt.args.branches); !cmp.Equal(got, tt.want) {
    97  - t.Errorf("getBranchMapFrom() = %v, want %v", got, tt.want)
    98  - }
    99  - })
    100  - }
    101  -}
    102  - 
    103  -func Test_branchMap_getBranchByName(t *testing.T) {
    104  - main := "main"
    105  - t.Parallel()
    106  - type args struct {
    107  - name string
    108  - }
    109  - //nolint
    110  - tests := []struct {
    111  - name string
    112  - b branchMap
    113  - args args
    114  - want *clients.BranchRef
    115  - wantErr bool
    116  - }{
    117 130   {
    118  - name: "simple",
    119  - b: branchMap{
    120  - master: &clients.BranchRef{
    121  - Name: &branch,
     131 + name: "release-branch-err",
     132 + releases: []clients.Release{
     133 + {
     134 + TargetCommitish: releaseBranchName,
    122 135   },
    123 136   },
    124  - args: args{
    125  - name: master,
     137 + branches: branchesArg{
     138 + {
     139 + name: releaseBranchName,
     140 + err: errBPTest,
     141 + },
    126 142   },
    127  - want: &clients.BranchRef{
    128  - Name: &branch,
     143 + wantErr: errBPTest,
     144 + },
     145 + {
     146 + name: "nil-release-branch",
     147 + releases: []clients.Release{
     148 + {
     149 + TargetCommitish: releaseBranchName,
     150 + },
     151 + },
     152 + branches: branchesArg{
     153 + {
     154 + name: releaseBranchName,
     155 + branchRef: nil,
     156 + },
    129 157   },
    130 158   },
    131 159   {
    132  - name: "main",
    133  - b: branchMap{
    134  - master: &clients.BranchRef{
    135  - Name: &main,
     160 + name: "add-release-branch",
     161 + releases: []clients.Release{
     162 + {
     163 + TargetCommitish: releaseBranchName,
    136 164   },
    137  - main: &clients.BranchRef{
    138  - Name: &main,
     165 + },
     166 + branches: branchesArg{
     167 + {
     168 + name: releaseBranchName,
     169 + branchRef: &clients.BranchRef{
     170 + Name: &releaseBranchName,
     171 + },
    139 172   },
    140 173   },
    141  - args: args{
    142  - name: "main",
     174 + want: checker.BranchProtectionsData{
     175 + Branches: []clients.BranchRef{
     176 + {
     177 + Name: &releaseBranchName,
     178 + },
     179 + },
     180 + },
     181 + },
     182 + {
     183 + name: "master-to-main-redirect",
     184 + releases: []clients.Release{
     185 + {
     186 + TargetCommitish: "master",
     187 + },
     188 + },
     189 + branches: branchesArg{
     190 + {
     191 + name: mainBranchName,
     192 + branchRef: &clients.BranchRef{
     193 + Name: &mainBranchName,
     194 + },
     195 + },
    143 196   },
    144  - want: &clients.BranchRef{
    145  - Name: &main,
     197 + want: checker.BranchProtectionsData{
     198 + Branches: []clients.BranchRef{
     199 + {
     200 + Name: &mainBranchName,
     201 + },
     202 + },
    146 203   },
    147 204   },
    148 205   {
    149  - name: "not found",
    150  - b: branchMap{
    151  - master: &clients.BranchRef{
    152  - Name: &branch,
     206 + name: "default-and-release-branches",
     207 + releases: []clients.Release{
     208 + {
     209 + TargetCommitish: releaseBranchName,
    153 210   },
    154 211   },
    155  - args: args{
    156  - name: "not-found",
     212 + branches: branchesArg{
     213 + {
     214 + name: defaultBranchName,
     215 + defaultBranch: true,
     216 + branchRef: &clients.BranchRef{
     217 + Name: &defaultBranchName,
     218 + },
     219 + },
     220 + {
     221 + name: releaseBranchName,
     222 + branchRef: &clients.BranchRef{
     223 + Name: &releaseBranchName,
     224 + },
     225 + },
     226 + },
     227 + want: checker.BranchProtectionsData{
     228 + Branches: []clients.BranchRef{
     229 + {
     230 + Name: &defaultBranchName,
     231 + },
     232 + {
     233 + Name: &releaseBranchName,
     234 + },
     235 + },
    157 236   },
    158  - wantErr: true,
    159 237   },
     238 + // TODO: Add tests for commitSHA regex matching.
    160 239   }
    161 240   for _, tt := range tests {
    162 241   tt := tt
    163 242   t.Run(tt.name, func(t *testing.T) {
    164 243   t.Parallel()
    165  - got, err := tt.b.getBranchByName(tt.args.name)
    166  - if (err != nil) != tt.wantErr {
    167  - t.Errorf("branchMap.getBranchByName() error = %v, wantErr %v", err, tt.wantErr)
    168  - return
     244 + ctrl := gomock.NewController(t)
     245 + mockRepoClient := mockrepo.NewMockRepoClient(ctrl)
     246 + mockRepoClient.EXPECT().GetDefaultBranch().
     247 + AnyTimes().DoAndReturn(func() (*clients.BranchRef, error) {
     248 + return tt.branches.getDefaultBranch()
     249 + })
     250 + mockRepoClient.EXPECT().GetBranch(gomock.Any()).AnyTimes().
     251 + DoAndReturn(func(branch string) (*clients.BranchRef, error) {
     252 + return tt.branches.getBranch(branch)
     253 + })
     254 + mockRepoClient.EXPECT().ListReleases().AnyTimes().
     255 + DoAndReturn(func() ([]clients.Release, error) {
     256 + return tt.releases, tt.releasesErr
     257 + })
     258 + 
     259 + rawData, err := BranchProtection(mockRepoClient)
     260 + if !errors.Is(err, tt.wantErr) {
     261 + t.Errorf("failed. expected: %v, got: %v", tt.wantErr, err)
     262 + t.Fail()
    169 263   }
    170  - if !cmp.Equal(got, tt.want) {
    171  - t.Errorf("branchMap.getBranchByName() = %v, want %v", got, tt.want)
     264 + if !cmp.Equal(rawData, tt.want) {
     265 + t.Errorf("failed. expected: %v, got: %v", tt.want, rawData)
     266 + t.Fail()
    172 267   }
    173 268   })
    174 269   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    checks/raw/errors.go
    skipped 18 lines
    19 19  )
    20 20   
    21 21  var (
    22  - errInternalCommitishNil = errors.New("commitish is nil")
    23  - errInternalBranchNotFound = errors.New("branch not found")
    24  - errInvalidArgType = errors.New("invalid arg type")
    25  - errInvalidArgLength = errors.New("invalid arg length")
    26  - errInvalidGitHubWorkflow = errors.New("invalid GitHub workflow")
     22 + errInternalCommitishNil = errors.New("commitish is nil")
     23 + errInvalidArgType = errors.New("invalid arg type")
     24 + errInvalidArgLength = errors.New("invalid arg length")
     25 + errInvalidGitHubWorkflow = errors.New("invalid GitHub workflow")
    27 26  )
    28 27   
  • ■ ■ ■ ■ ■ ■
    clients/githubrepo/branches.go
    skipped 27 lines
    28 28  )
    29 29   
    30 30  const (
    31  - refsToAnalyze = 30
    32  - refPrefix = "refs/heads/"
     31 + refPrefix = "refs/heads/"
    33 32  )
    34 33   
    35 34  // See https://github.community/t/graphql-api-protected-branch/14380
    skipped 61 lines
    97 96   RefUpdateRule *refUpdateRule
    98 97   BranchProtectionRule *branchProtectionRule
    99 98  }
    100  - 
    101  -// nolint:govet // internal structure, ignore.
    102  -type branchesData struct {
     99 +type defaultBranchData struct {
    103 100   Repository struct {
    104  - DefaultBranchRef branch
    105  - Refs struct {
    106  - Nodes []branch
    107  - } `graphql:"refs(first: $refsToAnalyze, refPrefix: $refPrefix)"`
     101 + DefaultBranchRef *branch
    108 102   } `graphql:"repository(owner: $owner, name: $name)"`
    109 103   RateLimit struct {
    110 104   Cost *int
    111 105   }
    112 106  }
    113 107   
     108 +type branchData struct {
     109 + Repository struct {
     110 + Ref *branch `graphql:"ref(qualifiedName: $branchRefName)"`
     111 + } `graphql:"repository(owner: $owner, name: $name)"`
     112 +}
     113 + 
    114 114  type branchesHandler struct {
    115 115   ghClient *github.Client
    116 116   graphClient *githubv4.Client
    117  - data *branchesData
     117 + data *defaultBranchData
    118 118   once *sync.Once
    119 119   ctx context.Context
    120 120   errSetup error
    121 121   repourl *repoURL
    122 122   defaultBranchRef *clients.BranchRef
    123  - branches []*clients.BranchRef
    124 123  }
    125 124   
    126 125  func (handler *branchesHandler) init(ctx context.Context, repourl *repoURL) {
    skipped 10 lines
    137 136   return
    138 137   }
    139 138   vars := map[string]interface{}{
    140  - "owner": githubv4.String(handler.repourl.owner),
    141  - "name": githubv4.String(handler.repourl.repo),
    142  - "refsToAnalyze": githubv4.Int(refsToAnalyze),
    143  - "refPrefix": githubv4.String(refPrefix),
     139 + "owner": githubv4.String(handler.repourl.owner),
     140 + "name": githubv4.String(handler.repourl.repo),
    144 141   }
    145  - handler.data = new(branchesData)
     142 + handler.data = new(defaultBranchData)
    146 143   if err := handler.graphClient.Query(handler.ctx, handler.data, vars); err != nil {
    147 144   handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("githubv4.Query: %v", err))
    148 145   return
    149 146   }
    150 147   handler.defaultBranchRef = getBranchRefFrom(handler.data.Repository.DefaultBranchRef)
    151  - handler.branches = getBranchRefsFrom(handler.data.Repository.Refs.Nodes, handler.defaultBranchRef)
    152 148   })
    153 149   return handler.errSetup
    154 150  }
    155 151   
     152 +func (handler *branchesHandler) query(branchName string) (*clients.BranchRef, error) {
     153 + if !strings.EqualFold(handler.repourl.commitSHA, clients.HeadSHA) {
     154 + return nil, fmt.Errorf("%w: branches only supported for HEAD queries", clients.ErrUnsupportedFeature)
     155 + }
     156 + vars := map[string]interface{}{
     157 + "owner": githubv4.String(handler.repourl.owner),
     158 + "name": githubv4.String(handler.repourl.repo),
     159 + "branchRefName": githubv4.String(refPrefix + branchName),
     160 + }
     161 + queryData := new(branchData)
     162 + if err := handler.graphClient.Query(handler.ctx, queryData, vars); err != nil {
     163 + return nil, sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("githubv4.Query: %v", err))
     164 + }
     165 + return getBranchRefFrom(queryData.Repository.Ref), nil
     166 +}
     167 + 
    156 168  func (handler *branchesHandler) getDefaultBranch() (*clients.BranchRef, error) {
    157 169   if err := handler.setup(); err != nil {
    158 170   return nil, fmt.Errorf("error during branchesHandler.setup: %w", err)
    skipped 1 lines
    160 172   return handler.defaultBranchRef, nil
    161 173  }
    162 174   
    163  -func (handler *branchesHandler) listBranches() ([]*clients.BranchRef, error) {
    164  - if err := handler.setup(); err != nil {
    165  - return nil, fmt.Errorf("error during branchesHandler.setup: %w", err)
     175 +func (handler *branchesHandler) getBranch(branch string) (*clients.BranchRef, error) {
     176 + branchRef, err := handler.query(branch)
     177 + if err != nil {
     178 + return nil, fmt.Errorf("error during branchesHandler.query: %w", err)
    166 179   }
    167  - return handler.branches, nil
     180 + return branchRef, nil
    168 181  }
    169 182   
    170 183  func copyAdminSettings(src *branchProtectionRule, dst *clients.BranchProtectionRule) {
    skipped 26 lines
    197 210   }
    198 211  }
    199 212   
    200  -func getBranchRefFrom(data branch) *clients.BranchRef {
     213 +func getBranchRefFrom(data *branch) *clients.BranchRef {
     214 + if data == nil {
     215 + return nil
     216 + }
    201 217   branchRef := new(clients.BranchRef)
    202 218   if data.Name != nil {
    203 219   branchRef.Name = data.Name
    skipped 35 lines
    239 255   return branchRef
    240 256  }
    241 257   
    242  -func getBranchRefsFrom(data []branch, defaultBranch *clients.BranchRef) []*clients.BranchRef {
    243  - var branchRefs []*clients.BranchRef
    244  - var defaultFound bool
    245  - for i, b := range data {
    246  - branchRefs = append(branchRefs, getBranchRefFrom(b))
    247  - if defaultBranch != nil && branchRefs[i].Name == defaultBranch.Name {
    248  - defaultFound = true
    249  - }
    250  - }
    251  - if !defaultFound {
    252  - branchRefs = append(branchRefs, defaultBranch)
    253  - }
    254  - return branchRefs
    255  -}
    256  - 
  • ■ ■ ■ ■ ■ ■
    clients/githubrepo/client.go
    skipped 29 lines
    30 30   "github.com/ossf/scorecard/v4/log"
    31 31  )
    32 32   
    33  -var errInputRepoType = errors.New("input repo should be of type repoURL")
     33 +var (
     34 + _ clients.RepoClient = &Client{}
     35 + errInputRepoType = errors.New("input repo should be of type repoURL")
     36 +)
    34 37   
    35 38  // Client is GitHub-specific implementation of RepoClient.
    36 39  type Client struct {
    skipped 112 lines
    149 152   return client.branches.getDefaultBranch()
    150 153  }
    151 154   
    152  -// ListBranches implements RepoClient.ListBranches.
    153  -func (client *Client) ListBranches() ([]*clients.BranchRef, error) {
    154  - return client.branches.listBranches()
     155 +// GetBranch implements RepoClient.GetBranch.
     156 +func (client *Client) GetBranch(branch string) (*clients.BranchRef, error) {
     157 + return client.branches.getBranch(branch)
    155 158  }
    156 159   
    157 160  // ListWebhooks implements RepoClient.ListWebhooks.
    skipped 93 lines
  • ■ ■ ■ ■ ■ ■
    clients/localdir/client.go
    skipped 30 lines
    31 31   "github.com/ossf/scorecard/v4/log"
    32 32  )
    33 33   
    34  -var errInputRepoType = errors.New("input repo should be of type repoLocal")
     34 +var (
     35 + _ clients.RepoClient = &localDirClient{}
     36 + errInputRepoType = errors.New("input repo should be of type repoLocal")
     37 +)
    35 38   
    36 39  //nolint:govet
    37 40  type localDirClient struct {
    skipped 118 lines
    156 159   return getFileContent(client.path, filename)
    157 160  }
    158 161   
    159  -// ListBranches implements RepoClient.ListBranches.
    160  -func (client *localDirClient) ListBranches() ([]*clients.BranchRef, error) {
     162 +// GetBranch implements RepoClient.GetBranch.
     163 +func (client *localDirClient) GetBranch(branch string) (*clients.BranchRef, error) {
    161 164   return nil, fmt.Errorf("ListBranches: %w", clients.ErrUnsupportedFeature)
    162 165  }
    163 166   
    skipped 62 lines
  • ■ ■ ■ ■ ■ ■
    clients/mockclients/repo_client.go
    skipped 62 lines
    63 63   return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockRepoClient)(nil).Close))
    64 64  }
    65 65   
     66 +// GetBranch mocks base method.
     67 +func (m *MockRepoClient) GetBranch(branch string) (*clients.BranchRef, error) {
     68 + m.ctrl.T.Helper()
     69 + ret := m.ctrl.Call(m, "GetBranch", branch)
     70 + ret0, _ := ret[0].(*clients.BranchRef)
     71 + ret1, _ := ret[1].(error)
     72 + return ret0, ret1
     73 +}
     74 + 
     75 +// GetBranch indicates an expected call of GetBranch.
     76 +func (mr *MockRepoClientMockRecorder) GetBranch(branch interface{}) *gomock.Call {
     77 + mr.mock.ctrl.T.Helper()
     78 + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBranch", reflect.TypeOf((*MockRepoClient)(nil).GetBranch), branch)
     79 +}
     80 + 
    66 81  // GetDefaultBranch mocks base method.
    67 82  func (m *MockRepoClient) GetDefaultBranch() (*clients.BranchRef, error) {
    68 83   m.ctrl.T.Helper()
    skipped 51 lines
    120 135  func (mr *MockRepoClientMockRecorder) IsArchived() *gomock.Call {
    121 136   mr.mock.ctrl.T.Helper()
    122 137   return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsArchived", reflect.TypeOf((*MockRepoClient)(nil).IsArchived))
    123  -}
    124  - 
    125  -// ListBranches mocks base method.
    126  -func (m *MockRepoClient) ListBranches() ([]*clients.BranchRef, error) {
    127  - m.ctrl.T.Helper()
    128  - ret := m.ctrl.Call(m, "ListBranches")
    129  - ret0, _ := ret[0].([]*clients.BranchRef)
    130  - ret1, _ := ret[1].(error)
    131  - return ret0, ret1
    132  -}
    133  - 
    134  -// ListBranches indicates an expected call of ListBranches.
    135  -func (mr *MockRepoClientMockRecorder) ListBranches() *gomock.Call {
    136  - mr.mock.ctrl.T.Helper()
    137  - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBranches", reflect.TypeOf((*MockRepoClient)(nil).ListBranches))
    138 138  }
    139 139   
    140 140  // ListCheckRunsForRef mocks base method.
    skipped 163 lines
  • ■ ■ ■ ■
    clients/repo_client.go
    skipped 31 lines
    32 32   IsArchived() (bool, error)
    33 33   ListFiles(predicate func(string) (bool, error)) ([]string, error)
    34 34   GetFileContent(filename string) ([]byte, error)
    35  - ListBranches() ([]*BranchRef, error)
     35 + GetBranch(branch string) (*BranchRef, error)
    36 36   GetDefaultBranch() (*BranchRef, error)
    37 37   ListCommits() ([]Commit, error)
    38 38   ListIssues() ([]Issue, error)
    skipped 10 lines
Please wait...
Page is in error, reload to recover