Projects STRLCPY scorecard Commits e2715fd7
🤬
  • ■ ■ ■ ■
    Makefile
    skipped 334 lines
    335 335   TOKEN_TYPE="GITHUB_TOKEN" $(GINKGO) --race -p -v -cover -coverprofile=e2e-coverage.out --keep-separate-coverprofiles ./...
    336 336   
    337 337  e2e-gitlab-token: ## Runs e2e tests that require a GITLAB_TOKEN
    338  - TOKEN_TYPE="GITLAB_PAT" $(GINKGO) --race -p -vv --focus '.*GitLab Token' ./...
     338 + TEST_GITLAB_EXTERNAL=1 TOKEN_TYPE="GITLAB_PAT" $(GINKGO) --race -p -vv --focus '.*GitLab Token' ./...
    339 339   
    340 340  e2e-gitlab: ## Runs e2e tests for GitLab only. TOKEN_TYPE is not used (since these are public APIs), but must be set to something
    341 341   TOKEN_TYPE="GITLAB_PAT" $(GINKGO) --race -p -vv --focus '.*GitLab' ./...
    skipped 102 lines
  • ■ ■ ■ ■ ■ ■
    checks/raw/security_policy.go
    skipped 24 lines
    25 25   "github.com/ossf/scorecard/v4/checker"
    26 26   "github.com/ossf/scorecard/v4/checks/fileparser"
    27 27   "github.com/ossf/scorecard/v4/clients"
    28  - "github.com/ossf/scorecard/v4/clients/githubrepo"
    29 28   sce "github.com/ossf/scorecard/v4/errors"
    30 29   "github.com/ossf/scorecard/v4/finding"
    31  - "github.com/ossf/scorecard/v4/log"
    32 30  )
    33 31   
    34 32  type securityPolicyFilesWithURI struct {
    skipped 27 lines
    62 60   
    63 61   // Check if present in parent org.
    64 62   // https#://docs.github.com/en/github/building-a-strong-community/creating-a-default-community-health-file.
    65  - // TODO(1491): Make this non-GitHub specific.
    66  - logger := log.NewLogger(log.InfoLevel)
    67  - // HAD TO HARD CODE TO 30
    68  - dotGitHubClient := githubrepo.CreateGithubRepoClient(c.Ctx, logger)
    69  - err = dotGitHubClient.InitRepo(c.Repo.Org(), clients.HeadSHA, 0)
     63 + client, err := c.RepoClient.GetOrgRepoClient(c.Ctx)
     64 + 
    70 65   switch {
    71 66   case err == nil:
    72  - defer dotGitHubClient.Close()
    73  - data.uri = dotGitHubClient.URI()
    74  - err = fileparser.OnAllFilesDo(dotGitHubClient, isSecurityPolicyFile, &data)
     67 + defer client.Close()
     68 + data.uri = client.URI()
     69 + err = fileparser.OnAllFilesDo(client, isSecurityPolicyFile, &data)
    75 70   if err != nil {
    76  - return checker.SecurityPolicyData{}, err
     71 + return checker.SecurityPolicyData{}, fmt.Errorf("unable to create github client: %w", err)
    77 72   }
    78 73   
    79  - case errors.Is(err, sce.ErrRepoUnreachable):
     74 + case errors.Is(err, sce.ErrRepoUnreachable), errors.Is(err, clients.ErrUnsupportedFeature):
    80 75   break
    81 76   default:
    82 77   return checker.SecurityPolicyData{}, err
    skipped 8 lines
    91 86   if data.files[idx].File.Type == finding.FileTypeURL {
    92 87   filePattern = strings.Replace(filePattern, data.uri+"/", "", 1)
    93 88   }
    94  - err := fileparser.OnMatchingFileContentDo(dotGitHubClient, fileparser.PathMatcher{
     89 + err := fileparser.OnMatchingFileContentDo(client, fileparser.PathMatcher{
    95 90   Pattern: filePattern,
    96 91   CaseSensitive: false,
    97 92   }, checkSecurityPolicyFileContent, &data.files[idx].File, &data.files[idx].Information)
    skipped 163 lines
  • ■ ■ ■ ■ ■ ■
    checks/raw/security_policy_test.go
    skipped 137 lines
    138 138   mockRepo := mockrepo.NewMockRepo(ctrl)
    139 139   
    140 140   mockRepoClient.EXPECT().ListFiles(gomock.Any()).Return(tt.files, nil).AnyTimes()
    141  - mockRepo.EXPECT().Org().Return(nil).AnyTimes()
    142  - //
    143 141   // the revised Security Policy will immediate go for the
    144 142   // file contents once found. This test will return that
    145 143   // mock file, but this specific unit test is not testing
    skipped 40 lines
  • ■ ■ ■ ■ ■ ■
    clients/githubrepo/client.go
    skipped 194 lines
    195 195   return client.repo.CreatedAt.Time, nil
    196 196  }
    197 197   
     198 +func (client *Client) GetOrgRepoClient(ctx context.Context) (clients.RepoClient, error) {
     199 + dotGithubRepo, err := MakeGithubRepo(fmt.Sprintf("%s/.github", client.repourl.owner))
     200 + if err != nil {
     201 + return nil, fmt.Errorf("error during MakeGithubRepo: %w", err)
     202 + }
     203 + 
     204 + logger := log.NewLogger(log.InfoLevel)
     205 + c := CreateGithubRepoClient(ctx, logger)
     206 + if err := c.InitRepo(dotGithubRepo, clients.HeadSHA, 0); err != nil {
     207 + return nil, fmt.Errorf("error during InitRepo: %w", err)
     208 + }
     209 + 
     210 + return c, nil
     211 +}
     212 + 
    198 213  // ListWebhooks implements RepoClient.ListWebhooks.
    199 214  func (client *Client) ListWebhooks() ([]clients.Webhook, error) {
    200 215   return client.webhook.listWebhooks()
    skipped 122 lines
  • ■ ■ ■ ■ ■ ■
    clients/githubrepo/repo.go
    skipped 22 lines
    23 23   sce "github.com/ossf/scorecard/v4/errors"
    24 24  )
    25 25   
    26  -const (
    27  - githubOrgRepo = ".github"
    28  -)
    29  - 
    30 26  type repoURL struct {
    31 27   host, owner, repo, defaultBranch, commitSHA string
    32 28   metadata []string
    skipped 50 lines
    83 79  // String implements Repo.String.
    84 80  func (r *repoURL) String() string {
    85 81   return fmt.Sprintf("%s-%s-%s", r.host, r.owner, r.repo)
    86  -}
    87  - 
    88  -// Org implements Repo.Org.
    89  -func (r *repoURL) Org() clients.Repo {
    90  - return &repoURL{
    91  - host: r.host,
    92  - owner: r.owner,
    93  - repo: githubOrgRepo,
    94  - }
    95 82  }
    96 83   
    97 84  // IsValid implements Repo.IsValid.
    skipped 44 lines
  • ■ ■ ■ ■ ■
    clients/gitlabrepo/client.go
    skipped 50 lines
    51 51   webhook *webhookHandler
    52 52   languages *languagesHandler
    53 53   licenses *licensesHandler
     54 + tarball *tarballHandler
    54 55   ctx context.Context
    55 56   commitDepth int
    56 57  }
    skipped 71 lines
    128 129   // Init languagesHandler
    129 130   client.licenses.init(client.repourl)
    130 131   
     132 + // Init tarballHandler
     133 + client.tarball.init(client.ctx, client.repourl, repo, commitSHA)
     134 + 
    131 135   return nil
    132 136  }
    133 137   
    skipped 6 lines
    140 144  }
    141 145   
    142 146  func (client *Client) ListFiles(predicate func(string) (bool, error)) ([]string, error) {
    143  - return nil, nil
     147 + return client.tarball.listFiles(predicate)
    144 148  }
    145 149   
    146 150  func (client *Client) GetFileContent(filename string) ([]byte, error) {
    147  - return nil, nil
     151 + return client.tarball.getFileContent(filename)
    148 152  }
    149 153   
    150 154  func (client *Client) ListCommits() ([]clients.Commit, error) {
    skipped 30 lines
    181 185   
    182 186  func (client *Client) GetCreatedAt() (time.Time, error) {
    183 187   return client.project.getCreatedAt()
     188 +}
     189 + 
     190 +func (client *Client) GetOrgRepoClient(ctx context.Context) (clients.RepoClient, error) {
     191 + return nil, fmt.Errorf("GetOrgRepoClient (GitLab): %w", clients.ErrUnsupportedFeature)
    184 192  }
    185 193   
    186 194  func (client *Client) ListWebhooks() ([]clients.Webhook, error) {
    skipped 82 lines
    269 277   glClient: client,
    270 278   },
    271 279   licenses: &licensesHandler{},
     280 + tarball: &tarballHandler{},
    272 281   }, nil
    273 282  }
    274 283   
    skipped 16 lines
  • ■ ■ ■ ■ ■ ■
    clients/gitlabrepo/repo.go
    skipped 26 lines
    27 27   sce "github.com/ossf/scorecard/v4/errors"
    28 28  )
    29 29   
    30  -const (
    31  - gitlabOrgProj = ".gitlab"
    32  -)
    33  - 
    34 30  type repoURL struct {
    35 31   scheme string
    36 32   host string
    skipped 56 lines
    93 89  // String implements Repo.String.
    94 90  func (r *repoURL) String() string {
    95 91   return fmt.Sprintf("%s-%s_%s", r.host, r.owner, r.project)
    96  -}
    97  - 
    98  -func (r *repoURL) Org() clients.Repo {
    99  - return &repoURL{
    100  - host: r.host,
    101  - owner: r.owner,
    102  - project: gitlabOrgProj,
    103  - }
    104 92  }
    105 93   
    106 94  // IsValid implements Repo.IsValid.
    skipped 53 lines
  • ■ ■ ■ ■ ■ ■
    clients/gitlabrepo/repo_test.go
    skipped 15 lines
    16 16   
    17 17  import (
    18 18   "fmt"
     19 + "os"
    19 20   "testing"
    20 21   
    21 22   "github.com/google/go-cmp/cmp"
    skipped 3 lines
    25 26  func TestRepoURL_IsValid(t *testing.T) {
    26 27   t.Parallel()
    27 28   tests := []struct {
    28  - name string
    29  - inputURL string
    30  - expected repoURL
    31  - wantErr bool
     29 + name string
     30 + inputURL string
     31 + expected repoURL
     32 + wantErr bool
     33 + flagRequired bool
    32 34   }{
    33 35   {
    34 36   name: "github repository",
    skipped 38 lines
    73 75   inputURL: "https://gitlab.com/ossf-test/scorecard-check-binary-artifacts-e2e/",
    74 76   wantErr: false,
    75 77   },
    76  - 
    77 78   {
    78 79   name: "valid hosted gitlab project",
    79 80   expected: repoURL{
    skipped 2 lines
    82 83   owner: "webmaster-team",
    83 84   project: "webml",
    84 85   },
    85  - inputURL: "https://salsa.debian.org/webmaster-team/webwml",
    86  - wantErr: false,
     86 + inputURL: "https://salsa.debian.org/webmaster-team/webwml",
     87 + wantErr: false,
     88 + flagRequired: true,
    87 89   },
    88 90   }
    89 91   for _, tt := range tests {
    90 92   tt := tt // Re-initializing variable so it is not changed while executing the closure blow
     93 + if tt.flagRequired && os.Getenv("TEST_GITLAB_EXTERNAL") == "" {
     94 + continue
     95 + }
    91 96   t.Run(tt.name, func(t *testing.T) {
    92 97   t.Parallel()
    93 98   r := repoURL{
    skipped 22 lines
    116 121   
    117 122  func TestRepoURL_DetectGitlab(t *testing.T) {
    118 123   tests := []struct {
    119  - repouri string
    120  - expected bool
     124 + repouri string
     125 + expected bool
     126 + flagRequired bool
    121 127   }{
    122 128   {
    123 129   repouri: "github.com/ossf/scorecard",
    skipped 12 lines
    136 142   expected: true,
    137 143   },
    138 144   {
    139  - repouri: "https://salsa.debian.org/webmaster-team/webml",
    140  - expected: true,
     145 + repouri: "https://salsa.debian.org/webmaster-team/webml",
     146 + expected: true,
     147 + flagRequired: true,
    141 148   },
    142 149   {
    143 150   // Invalid repo
    skipped 3 lines
    147 154   }
    148 155   
    149 156   for _, tt := range tests {
     157 + if tt.flagRequired && os.Getenv("TEST_GITLAB_EXTERNAL") == "" {
     158 + continue
     159 + }
    150 160   g := DetectGitLab(tt.repouri)
    151 161   if g != tt.expected {
    152 162   t.Errorf("got %s isgitlab: %t expected %t", tt.repouri, g, tt.expected)
    skipped 4 lines
  • ■ ■ ■ ■ ■ ■
    clients/gitlabrepo/tarball.go
     1 +// Copyright 2021 Security Scorecard Authors
     2 +//
     3 +// Licensed under the Apache License, Version 2.0 (the "License");
     4 +// you may not use this file except in compliance with the License.
     5 +// You may obtain a copy of the License at
     6 +//
     7 +// http://www.apache.org/licenses/LICENSE-2.0
     8 +//
     9 +// Unless required by applicable law or agreed to in writing, software
     10 +// distributed under the License is distributed on an "AS IS" BASIS,
     11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 +// See the License for the specific language governing permissions and
     13 +// limitations under the License.
     14 + 
     15 +package gitlabrepo
     16 + 
     17 +import (
     18 + "archive/tar"
     19 + "compress/gzip"
     20 + "context"
     21 + "errors"
     22 + "fmt"
     23 + "io"
     24 + "log"
     25 + "net/http"
     26 + "os"
     27 + "path/filepath"
     28 + "strings"
     29 + "sync"
     30 + 
     31 + "github.com/xanzy/go-gitlab"
     32 + 
     33 + sce "github.com/ossf/scorecard/v4/errors"
     34 +)
     35 + 
     36 +const (
     37 + repoDir = "project*"
     38 + repoFilename = "gitlabproject*.tar.gz"
     39 +)
     40 + 
     41 +var (
     42 + errTarballNotFound = errors.New("tarball not found")
     43 + errTarballCorrupted = errors.New("corrupted tarball")
     44 + errZipSlip = errors.New("ZipSlip path detected")
     45 +)
     46 + 
     47 +func extractAndValidateArchivePath(path, dest string) (string, error) {
     48 + const splitLength = 2
     49 + // The tarball will have a top-level directory which contains all the repository files.
     50 + // Discard the directory and only keep the actual files.
     51 + names := strings.SplitN(path, "/", splitLength)
     52 + if len(names) < splitLength {
     53 + return dest, nil
     54 + }
     55 + if names[1] == "" {
     56 + return dest, nil
     57 + }
     58 + // Check for ZipSlip: https://snyk.io/research/zip-slip-vulnerability
     59 + cleanpath := filepath.Join(dest, names[1])
     60 + if !strings.HasPrefix(cleanpath, filepath.Clean(dest)+string(os.PathSeparator)) {
     61 + return "", fmt.Errorf("%w: %s", errZipSlip, names[1])
     62 + }
     63 + return cleanpath, nil
     64 +}
     65 + 
     66 +type tarballHandler struct {
     67 + errSetup error
     68 + once *sync.Once
     69 + ctx context.Context
     70 + repo *gitlab.Project
     71 + repourl *repoURL
     72 + commitSHA string
     73 + tempDir string
     74 + tempTarFile string
     75 + files []string
     76 +}
     77 + 
     78 +func (handler *tarballHandler) init(ctx context.Context, repourl *repoURL, repo *gitlab.Project, commitSHA string) {
     79 + handler.errSetup = nil
     80 + handler.once = new(sync.Once)
     81 + handler.ctx = ctx
     82 + handler.repo = repo
     83 + handler.repourl = repourl
     84 + handler.commitSHA = commitSHA
     85 +}
     86 + 
     87 +func (handler *tarballHandler) setup() error {
     88 + handler.once.Do(func() {
     89 + // cleanup any previous state.
     90 + if err := handler.cleanup(); err != nil {
     91 + handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, err.Error())
     92 + return
     93 + }
     94 + 
     95 + // setup tem dir/files and download repo tarball.
     96 + if err := handler.getTarball(); errors.Is(err, errTarballNotFound) {
     97 + log.Printf("unable to get tarball %v. Skipping...", err)
     98 + return
     99 + } else if err != nil {
     100 + handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, err.Error())
     101 + return
     102 + }
     103 + 
     104 + // extract file names and content from tarball.
     105 + if err := handler.extractTarball(); errors.Is(err, errTarballCorrupted) {
     106 + log.Printf("unable to extract tarball %v. Skipping...", err)
     107 + } else if err != nil {
     108 + handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, err.Error())
     109 + }
     110 + })
     111 + return handler.errSetup
     112 +}
     113 + 
     114 +func (handler *tarballHandler) getTarball() error {
     115 + url := fmt.Sprintf("%s/api/v4/projects/%d/repository/archive.tar.gz?sha=%s",
     116 + handler.repourl.Host(), handler.repo.ID, handler.commitSHA)
     117 + req, err := http.NewRequestWithContext(handler.ctx, http.MethodGet, url, nil)
     118 + if err != nil {
     119 + return fmt.Errorf("http.NewRequestWithContext: %w", err)
     120 + }
     121 + req.Header.Set("PRIVATE-TOKEN", os.Getenv("GITLAB_AUTH_TOKEN"))
     122 + resp, err := http.DefaultClient.Do(req)
     123 + if err != nil {
     124 + return fmt.Errorf("http.DefaultClient.Do: %w", err)
     125 + }
     126 + defer resp.Body.Close()
     127 + 
     128 + // Handler 400/404 errors.
     129 + switch resp.StatusCode {
     130 + case http.StatusNotFound, http.StatusBadRequest:
     131 + return fmt.Errorf("%w: %s", errTarballNotFound, url)
     132 + }
     133 + 
     134 + // Create a temp file. This automatically appends a random number to the name.
     135 + tempDir, err := os.MkdirTemp("", repoDir)
     136 + if err != nil {
     137 + return fmt.Errorf("os.MkdirTemp: %w", err)
     138 + }
     139 + repoFile, err := os.CreateTemp(tempDir, repoFilename)
     140 + if err != nil {
     141 + return fmt.Errorf("os.CreateTemp: %w", err)
     142 + }
     143 + defer repoFile.Close()
     144 + if _, err := io.Copy(repoFile, resp.Body); err != nil {
     145 + // If the incomming tarball is corrupted or the server times out.
     146 + return fmt.Errorf("%w io.Copy: %v", errTarballNotFound, err)
     147 + }
     148 + 
     149 + handler.tempDir = tempDir
     150 + handler.tempTarFile = repoFile.Name()
     151 + return nil
     152 +}
     153 + 
     154 +// nolint: gocognit
     155 +func (handler *tarballHandler) extractTarball() error {
     156 + in, err := os.OpenFile(handler.tempTarFile, os.O_RDONLY, 0o644)
     157 + if err != nil {
     158 + return fmt.Errorf("os.OpenFile: %w", err)
     159 + }
     160 + gz, err := gzip.NewReader(in)
     161 + if err != nil {
     162 + return fmt.Errorf("%w: gzip.NewReader %v %v", errTarballCorrupted, handler.tempTarFile, err)
     163 + }
     164 + tr := tar.NewReader(gz)
     165 + for {
     166 + header, err := tr.Next()
     167 + if errors.Is(err, io.EOF) {
     168 + break
     169 + }
     170 + if err != nil {
     171 + return fmt.Errorf("%w tarReader.Next: %v", errTarballCorrupted, err)
     172 + }
     173 + 
     174 + switch header.Typeflag {
     175 + case tar.TypeDir:
     176 + dirpath, err := extractAndValidateArchivePath(header.Name, handler.tempDir)
     177 + if err != nil {
     178 + return err
     179 + }
     180 + if dirpath == filepath.Clean(handler.tempDir) {
     181 + continue
     182 + }
     183 + 
     184 + if err := os.Mkdir(dirpath, 0o755); err != nil {
     185 + return fmt.Errorf("error during os.Mkdir: %w", err)
     186 + }
     187 + case tar.TypeReg:
     188 + if header.Size <= 0 {
     189 + continue
     190 + }
     191 + filenamepath, err := extractAndValidateArchivePath(header.Name, handler.tempDir)
     192 + if err != nil {
     193 + return err
     194 + }
     195 + 
     196 + if _, err := os.Stat(filepath.Dir(filenamepath)); os.IsNotExist(err) {
     197 + if err := os.Mkdir(filepath.Dir(filenamepath), 0o755); err != nil {
     198 + return fmt.Errorf("os.Mkdir: %w", err)
     199 + }
     200 + }
     201 + outFile, err := os.Create(filenamepath)
     202 + if err != nil {
     203 + return fmt.Errorf("os.Create: %w", err)
     204 + }
     205 + 
     206 + //nolint: gosec
     207 + // Potential for DoS vulnerability via decompression bomb.
     208 + // Since such an attack will only impact a single shard, ignoring this for now.
     209 + if _, err := io.Copy(outFile, tr); err != nil {
     210 + return fmt.Errorf("%w io.Copy: %v", errTarballCorrupted, err)
     211 + }
     212 + outFile.Close()
     213 + handler.files = append(handler.files,
     214 + strings.TrimPrefix(filenamepath, filepath.Clean(handler.tempDir)+string(os.PathSeparator)))
     215 + case tar.TypeXGlobalHeader, tar.TypeSymlink:
     216 + continue
     217 + default:
     218 + log.Printf("Unknown file type %s: '%s'", header.Name, string(header.Typeflag))
     219 + continue
     220 + }
     221 + }
     222 + return nil
     223 +}
     224 + 
     225 +func (handler *tarballHandler) listFiles(predicate func(string) (bool, error)) ([]string, error) {
     226 + if err := handler.setup(); err != nil {
     227 + return nil, fmt.Errorf("error during tarballHandler.setup: %w", err)
     228 + }
     229 + ret := make([]string, 0)
     230 + for _, file := range handler.files {
     231 + matches, err := predicate(file)
     232 + if err != nil {
     233 + return nil, err
     234 + }
     235 + if matches {
     236 + ret = append(ret, file)
     237 + }
     238 + }
     239 + return ret, nil
     240 +}
     241 + 
     242 +func (handler *tarballHandler) getFileContent(filename string) ([]byte, error) {
     243 + if err := handler.setup(); err != nil {
     244 + fmt.Printf("err: %v\n", err)
     245 + return nil, fmt.Errorf("error during tarballHandler.setup: %w", err)
     246 + }
     247 + fmt.Printf("handler.tempDir: %v\n", handler.tempDir)
     248 + fmt.Printf("filename: %v\n", filename)
     249 + content, err := os.ReadFile(filepath.Join(handler.tempDir, filename))
     250 + if err != nil {
     251 + return content, fmt.Errorf("os.ReadFile: %w", err)
     252 + }
     253 + return content, nil
     254 +}
     255 + 
     256 +func (handler *tarballHandler) cleanup() error {
     257 + if err := os.RemoveAll(handler.tempDir); err != nil && !os.IsNotExist(err) {
     258 + return fmt.Errorf("os.Remove: %w", err)
     259 + }
     260 + 
     261 + // Remove old file so we don't iterate through them.
     262 + handler.files = nil
     263 + return nil
     264 +}
     265 + 
  • ■ ■ ■ ■ ■ ■
    clients/gitlabrepo/tarball_test.go
     1 +// Copyright 2021 Security Scorecard Authors
     2 +//
     3 +// Licensed under the Apache License, Version 2.0 (the "License");
     4 +// you may not use this file except in compliance with the License.
     5 +// You may obtain a copy of the License at
     6 +//
     7 +// http://www.apache.org/licenses/LICENSE-2.0
     8 +//
     9 +// Unless required by applicable law or agreed to in writing, software
     10 +// distributed under the License is distributed on an "AS IS" BASIS,
     11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 +// See the License for the specific language governing permissions and
     13 +// limitations under the License.
     14 + 
     15 +package gitlabrepo
     16 + 
     17 +import (
     18 + "errors"
     19 + "fmt"
     20 + "io"
     21 + "os"
     22 + "strings"
     23 + "sync"
     24 + "testing"
     25 + 
     26 + "github.com/google/go-cmp/cmp"
     27 + "github.com/google/go-cmp/cmp/cmpopts"
     28 +)
     29 + 
     30 +type listfileTest struct {
     31 + predicate func(string) (bool, error)
     32 + err error
     33 + outcome []string
     34 +}
     35 + 
     36 +type getcontentTest struct {
     37 + err error
     38 + filename string
     39 + output []byte
     40 +}
     41 + 
     42 +func isSortedString(x, y string) bool {
     43 + return x < y
     44 +}
     45 + 
     46 +func setup(inputFile string) (tarballHandler, error) {
     47 + tempDir, err := os.MkdirTemp("", repoDir)
     48 + if err != nil {
     49 + return tarballHandler{}, fmt.Errorf("test failed to create TempDir: %w", err)
     50 + }
     51 + tempFile, err := os.CreateTemp(tempDir, repoFilename)
     52 + if err != nil {
     53 + return tarballHandler{}, fmt.Errorf("test failed to create TempFile: %w", err)
     54 + }
     55 + testFile, err := os.OpenFile(inputFile, os.O_RDONLY, 0o644)
     56 + if err != nil {
     57 + return tarballHandler{}, fmt.Errorf("unable to open testfile: %w", err)
     58 + }
     59 + if _, err := io.Copy(tempFile, testFile); err != nil {
     60 + return tarballHandler{}, fmt.Errorf("unable to do io.Copy: %w", err)
     61 + }
     62 + tarballHandler := tarballHandler{
     63 + tempDir: tempDir,
     64 + tempTarFile: tempFile.Name(),
     65 + once: new(sync.Once),
     66 + }
     67 + tarballHandler.once.Do(func() {
     68 + // We don't want to run the code in tarballHandler.setup(), so if we execute tarballHandler.once.Do() right
     69 + // here, it won't get executed later when setup() is called.
     70 + })
     71 + return tarballHandler, nil
     72 +}
     73 + 
     74 +// nolint: gocognit
     75 +func TestExtractTarball(t *testing.T) {
     76 + t.Parallel()
     77 + testcases := []struct {
     78 + name string
     79 + inputFile string
     80 + listfileTests []listfileTest
     81 + getcontentTests []getcontentTest
     82 + }{
     83 + {
     84 + name: "Basic",
     85 + inputFile: "testdata/basic.tar.gz",
     86 + listfileTests: []listfileTest{
     87 + {
     88 + // Returns all files in the tarball.
     89 + predicate: func(string) (bool, error) { return true, nil },
     90 + outcome: []string{"file0", "dir1/file1", "dir1/dir2/file2"},
     91 + },
     92 + {
     93 + // Skips all files inside `dir1/dir2` directory.
     94 + predicate: func(fn string) (bool, error) { return !strings.HasPrefix(fn, "dir1/dir2"), nil },
     95 + outcome: []string{"file0", "dir1/file1"},
     96 + },
     97 + {
     98 + // Skips all files.
     99 + predicate: func(fn string) (bool, error) { return false, nil },
     100 + outcome: []string{},
     101 + },
     102 + },
     103 + getcontentTests: []getcontentTest{
     104 + {
     105 + filename: "file0",
     106 + output: []byte("content0\n"),
     107 + },
     108 + {
     109 + filename: "dir1/file1",
     110 + output: []byte("content1\n"),
     111 + },
     112 + {
     113 + filename: "dir1/dir2/file2",
     114 + output: []byte("content2\n"),
     115 + },
     116 + {
     117 + filename: "does/not/exist",
     118 + err: os.ErrNotExist,
     119 + },
     120 + },
     121 + },
     122 + }
     123 + 
     124 + for _, testcase := range testcases {
     125 + testcase := testcase
     126 + t.Run(testcase.name, func(t *testing.T) {
     127 + t.Parallel()
     128 + 
     129 + // Setup
     130 + handler, err := setup(testcase.inputFile)
     131 + if err != nil {
     132 + t.Fatalf("test setup failed: %v", err)
     133 + }
     134 + 
     135 + // Extract tarball.
     136 + if err := handler.extractTarball(); err != nil {
     137 + t.Fatalf("test failed: %v", err)
     138 + }
     139 + 
     140 + // Test ListFiles API.
     141 + for _, listfiletest := range testcase.listfileTests {
     142 + matchedFiles, err := handler.listFiles(listfiletest.predicate)
     143 + if !errors.Is(err, listfiletest.err) {
     144 + t.Errorf("test failed: expected - %v, got - %v", listfiletest.err, err)
     145 + continue
     146 + }
     147 + if !cmp.Equal(listfiletest.outcome,
     148 + matchedFiles,
     149 + cmpopts.SortSlices(isSortedString)) {
     150 + t.Errorf("test failed: expected - %q, got - %q", listfiletest.outcome, matchedFiles)
     151 + }
     152 + }
     153 + 
     154 + // Test GetFileContent API.
     155 + for _, getcontenttest := range testcase.getcontentTests {
     156 + content, err := handler.getFileContent(getcontenttest.filename)
     157 + if getcontenttest.err != nil && !errors.Is(err, getcontenttest.err) {
     158 + t.Errorf("test failed: expected - %v, got - %v", getcontenttest.err, err)
     159 + }
     160 + if getcontenttest.err == nil && !cmp.Equal(getcontenttest.output, content) {
     161 + t.Errorf("test failed: expected - %s, got - %s", string(getcontenttest.output), string(content))
     162 + }
     163 + }
     164 + 
     165 + // Test that files get deleted.
     166 + if err := handler.cleanup(); err != nil {
     167 + t.Errorf("test failed: %v", err)
     168 + }
     169 + if _, err := os.Stat(handler.tempDir); !os.IsNotExist(err) {
     170 + t.Errorf("%v", err)
     171 + }
     172 + if len(handler.files) != 0 {
     173 + t.Error("client.files not cleaned up!")
     174 + }
     175 + })
     176 + }
     177 +}
     178 + 
  • clients/gitlabrepo/testdata/basic.tar.gz
    Binary file.
  • ■ ■ ■ ■ ■ ■
    clients/localdir/client.go
    skipped 258 lines
    259 259   return time.Time{}, fmt.Errorf("GetCreatedAt: %w", clients.ErrUnsupportedFeature)
    260 260  }
    261 261   
     262 +func (client *localDirClient) GetOrgRepoClient(ctx context.Context) (clients.RepoClient, error) {
     263 + return nil, fmt.Errorf("GetOrgRepoClient: %w", clients.ErrUnsupportedFeature)
     264 +}
     265 + 
    262 266  // CreateLocalDirClient returns a client which implements RepoClient interface.
    263 267  func CreateLocalDirClient(ctx context.Context, logger *log.Logger) clients.RepoClient {
    264 268   return &localDirClient{
    skipped 5 lines
  • ■ ■ ■ ■ ■
    clients/localdir/repo.go
    skipped 45 lines
    46 46   return r.URI()
    47 47  }
    48 48   
    49  -// Org implements Repo.Org.
    50  -func (r *repoLocal) Org() clients.Repo {
    51  - return nil
    52  -}
    53  - 
    54 49  // IsValid implements Repo.IsValid.
    55 50  func (r *repoLocal) IsValid() error {
    56 51   f, err := os.Stat(r.path)
    skipped 33 lines
  • ■ ■ ■ ■ ■ ■
    clients/mockclients/repo.go
    skipped 22 lines
    23 23   reflect "reflect"
    24 24   
    25 25   gomock "github.com/golang/mock/gomock"
    26  - clients "github.com/ossf/scorecard/v4/clients"
    27 26  )
    28 27   
    29 28  // MockRepo is a mock of Repo interface.
    skipped 61 lines
    91 90  func (mr *MockRepoMockRecorder) Metadata() *gomock.Call {
    92 91   mr.mock.ctrl.T.Helper()
    93 92   return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockRepo)(nil).Metadata))
    94  -}
    95  - 
    96  -// Org mocks base method.
    97  -func (m *MockRepo) Org() clients.Repo {
    98  - m.ctrl.T.Helper()
    99  - ret := m.ctrl.Call(m, "Org")
    100  - ret0, _ := ret[0].(clients.Repo)
    101  - return ret0
    102  -}
    103  - 
    104  -// Org indicates an expected call of Org.
    105  -func (mr *MockRepoMockRecorder) Org() *gomock.Call {
    106  - mr.mock.ctrl.T.Helper()
    107  - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Org", reflect.TypeOf((*MockRepo)(nil).Org))
    108 93  }
    109 94   
    110 95  // String mocks base method.
    skipped 35 lines
  • ■ ■ ■ ■ ■ ■
    clients/mockclients/repo_client.go
    skipped 19 lines
    20 20  package mockrepo
    21 21   
    22 22  import (
     23 + "context"
    23 24   reflect "reflect"
    24 25   time "time"
    25 26   
    skipped 111 lines
    137 138  func (mr *MockRepoClientMockRecorder) GetFileContent(filename interface{}) *gomock.Call {
    138 139   mr.mock.ctrl.T.Helper()
    139 140   return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileContent", reflect.TypeOf((*MockRepoClient)(nil).GetFileContent), filename)
     141 +}
     142 + 
     143 +// GetOrgRepoClient mocks base method.
     144 +func (m *MockRepoClient) GetOrgRepoClient(ctx context.Context) (clients.RepoClient, error) {
     145 + m.ctrl.T.Helper()
     146 + ret := m.ctrl.Call(m, "GetOrgRepoClient")
     147 + ret0, _ := ret[0].(clients.RepoClient)
     148 + ret1, _ := ret[1].(error)
     149 + return ret0, ret1
    140 150  }
    141 151   
    142 152  // InitRepo mocks base method.
    skipped 252 lines
  • ■ ■ ■ ■ ■ ■
    clients/ossfuzz/client.go
    skipped 14 lines
    15 15  package ossfuzz
    16 16   
    17 17  import (
     18 + "context"
    18 19   "encoding/json"
    19 20   "errors"
    20 21   "fmt"
    skipped 165 lines
    186 187  // GetDefaultBranch implements RepoClient.GetDefaultBranch.
    187 188  func (c *client) GetDefaultBranch() (*clients.BranchRef, error) {
    188 189   return nil, fmt.Errorf("GetDefaultBranch: %w", clients.ErrUnsupportedFeature)
     190 +}
     191 + 
     192 +// GetOrgRepoClient implements RepoClient.GetOrgRepoClient.
     193 +func (c *client) GetOrgRepoClient(ctx context.Context) (clients.RepoClient, error) {
     194 + return nil, fmt.Errorf("GetOrgRepoClient: %w", clients.ErrUnsupportedFeature)
    189 195  }
    190 196   
    191 197  // GetDefaultBranchName implements RepoClient.GetDefaultBranchName.
    skipped 69 lines
  • ■ ■ ■ ■ ■
    clients/repo.go
    skipped 18 lines
    19 19   URI() string
    20 20   Host() string
    21 21   String() string
    22  - Org() Repo
    23 22   IsValid() error
    24 23   Metadata() []string
    25 24   AppendMetadata(metadata ...string)
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    clients/repo_client.go
    skipped 15 lines
    16 16  package clients
    17 17   
    18 18  import (
     19 + "context"
    19 20   "errors"
    20 21   "time"
    21 22  )
    skipped 18 lines
    40 41   GetCreatedAt() (time.Time, error)
    41 42   GetDefaultBranchName() (string, error)
    42 43   GetDefaultBranch() (*BranchRef, error)
     44 + GetOrgRepoClient(context.Context) (RepoClient, error)
    43 45   ListCommits() ([]Commit, error)
    44 46   ListIssues() ([]Issue, error)
    45 47   ListLicenses() ([]License, error)
    skipped 12 lines
  • ■ ■ ■ ■ ■ ■
    e2e/e2e_suite_test.go
    skipped 39 lines
    40 40  const (
    41 41   patTokenType tokenType = iota
    42 42   githubWorkflowDefaultTokenType
     43 + gitlabPATTokenType
    43 44  )
    44 45   
    45 46  var tokType tokenType
    skipped 12 lines
    58 59   tokType = patTokenType
    59 60   case "GITHUB_TOKEN":
    60 61   tokType = githubWorkflowDefaultTokenType
     62 + case "GITLAB_PAT":
     63 + tokType = gitlabPATTokenType
    61 64   default:
    62 65   panic(fmt.Sprintf("invald TOKEN_TYPE: %s", tt))
    63 66   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    e2e/security_policy_test.go
    skipped 24 lines
    25 25   "github.com/ossf/scorecard/v4/checks"
    26 26   "github.com/ossf/scorecard/v4/clients"
    27 27   "github.com/ossf/scorecard/v4/clients/githubrepo"
     28 + "github.com/ossf/scorecard/v4/clients/gitlabrepo"
    28 29   "github.com/ossf/scorecard/v4/clients/localdir"
    29 30   scut "github.com/ossf/scorecard/v4/utests"
    30 31  )
    skipped 140 lines
    171 172   // New version.
    172 173   Expect(scut.ValidateTestReturn(nil, "policy found", &expected, &result, &dl)).Should(BeTrue())
    173 174   Expect(x.Close()).Should(BeNil())
     175 + })
     176 + It("Should return valid security policy - GitLab", func() {
     177 + skipIfTokenIsNot(gitlabPATTokenType, "GitLab only")
     178 + 
     179 + dl := scut.TestDetailLogger{}
     180 + // project url is gitlab.com/bramw/baserow.
     181 + repo, err := gitlabrepo.MakeGitlabRepo("gitlab.com/ossf-test/baserow")
     182 + Expect(err).Should(BeNil())
     183 + repoClient, err := gitlabrepo.CreateGitlabClientWithToken(context.Background(), os.Getenv("GITLAB_AUTH_TOKEN"), repo)
     184 + Expect(err).Should(BeNil())
     185 + err = repoClient.InitRepo(repo, clients.HeadSHA, 0)
     186 + Expect(err).Should(BeNil())
     187 + 
     188 + req := checker.CheckRequest{
     189 + Ctx: context.Background(),
     190 + RepoClient: repoClient,
     191 + Repo: repo,
     192 + Dlogger: &dl,
     193 + }
     194 + // TODO: update expected based on what is returned from gitlab project.
     195 + expected := scut.TestReturn{
     196 + Error: nil,
     197 + Score: 9,
     198 + NumberOfWarn: 1,
     199 + NumberOfInfo: 3,
     200 + NumberOfDebug: 0,
     201 + }
     202 + result := checks.SecurityPolicy(&req)
     203 + // New version.
     204 + Expect(scut.ValidateTestReturn(nil, "policy found", &expected, &result, &dl)).Should(BeTrue())
     205 + Expect(repoClient.Close()).Should(BeNil())
     206 + })
     207 + It("Should return valid security policy at commitSHA - GitLab", func() {
     208 + skipIfTokenIsNot(gitlabPATTokenType, "GitLab only")
     209 + 
     210 + dl := scut.TestDetailLogger{}
     211 + // project url is gitlab.com/bramw/baserow.
     212 + repo, err := gitlabrepo.MakeGitlabRepo("gitlab.com/ossf-test/baserow")
     213 + Expect(err).Should(BeNil())
     214 + repoClient, err := gitlabrepo.CreateGitlabClientWithToken(context.Background(), os.Getenv("GITLAB_AUTH_TOKEN"), repo)
     215 + Expect(err).Should(BeNil())
     216 + // url to commit is https://gitlab.com/bramw/baserow/-/commit/28e6224b7d86f7b30bad6adb6b42f26a814c2f58
     217 + err = repoClient.InitRepo(repo, "28e6224b7d86f7b30bad6adb6b42f26a814c2f58", 0)
     218 + Expect(err).Should(BeNil())
     219 + 
     220 + req := checker.CheckRequest{
     221 + Ctx: context.Background(),
     222 + RepoClient: repoClient,
     223 + Repo: repo,
     224 + Dlogger: &dl,
     225 + }
     226 + 
     227 + expected := scut.TestReturn{
     228 + Error: nil,
     229 + Score: 9,
     230 + NumberOfWarn: 1,
     231 + NumberOfInfo: 3,
     232 + NumberOfDebug: 0,
     233 + }
     234 + result := checks.SecurityPolicy(&req)
     235 + // New version.
     236 + Expect(scut.ValidateTestReturn(nil, "policy found", &expected, &result, &dl)).Should(BeTrue())
     237 + Expect(repoClient.Close()).Should(BeNil())
    174 238   })
    175 239   })
    176 240  })
    skipped 1 lines
Please wait...
Page is in error, reload to recover