Skip to content

Commit

Permalink
Merge branch 'main' into semantic-release
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerschrock authored May 9, 2023
2 parents 3dc5050 + 793da0c commit e11d5c7
Show file tree
Hide file tree
Showing 26 changed files with 742 additions and 89 deletions.
4 changes: 2 additions & 2 deletions checks/evaluation/packaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func Packaging(name string, dl checker.DetailLogger, r *checker.PackagingData) c
}

dl.Warn(&checker.LogMessage{
Text: "no GitHub publishing workflow detected",
Text: "no GitHub/GitLab publishing workflow detected",
})

return checker.CreateInconclusiveResult(name,
Expand Down Expand Up @@ -83,7 +83,7 @@ func createLogMessage(p checker.Package) (checker.LogMessage, error) {
return msg, sce.WithMessage(sce.ErrScorecardInternal, "no run data")
}

msg.Text = fmt.Sprintf("GitHub publishing workflow used in run %s", p.Runs[0].URL)
msg.Text = fmt.Sprintf("GitHub/GitLab publishing workflow used in run %s", p.Runs[0].URL)

return msg, nil
}
2 changes: 1 addition & 1 deletion checks/evaluation/packaging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func Test_createLogMessage(t *testing.T) {
},
},
want: checker.LogMessage{
Text: "GitHub publishing workflow used in run ",
Text: "GitHub/GitLab publishing workflow used in run ",
Path: "path",
},
},
Expand Down
21 changes: 21 additions & 0 deletions checks/fileparser/gitlab_workflow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2021 OpenSSF Scorecard Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fileparser

// IsGitlabWorkflowFile determines if a file is a workflow
// as a callback to use for repo client's ListFiles() API.
func IsGitlabWorkflowFile(pathfn string) (bool, error) {
return pathfn == "gitlabscorecard_flattened_ci.yaml", nil
}
18 changes: 16 additions & 2 deletions checks/packaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ package checks
import (
"github.com/ossf/scorecard/v4/checker"
"github.com/ossf/scorecard/v4/checks/evaluation"
"github.com/ossf/scorecard/v4/checks/raw"
"github.com/ossf/scorecard/v4/checks/raw/github"
"github.com/ossf/scorecard/v4/checks/raw/gitlab"
"github.com/ossf/scorecard/v4/clients/githubrepo"
"github.com/ossf/scorecard/v4/clients/gitlabrepo"
sce "github.com/ossf/scorecard/v4/errors"
)

Expand All @@ -34,7 +37,18 @@ func init() {

// Packaging runs Packaging check.
func Packaging(c *checker.CheckRequest) checker.CheckResult {
rawData, err := raw.Packaging(c)
var rawData checker.PackagingData
var err error

switch v := c.RepoClient.(type) {
case *githubrepo.Client:
rawData, err = github.Packaging(c)
case *gitlabrepo.Client:
rawData, err = gitlab.Packaging(c)
default:
_ = v
}

if err != nil {
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
return checker.CreateRuntimeErrorResult(CheckPackaging, e)
Expand Down
6 changes: 3 additions & 3 deletions checks/raw/packaging.go → checks/raw/github/packaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package raw
package github

import (
"fmt"
Expand Down Expand Up @@ -100,7 +100,7 @@ func Packaging(c *checker.CheckRequest) (checker.PackagingData, error) {
data.Packages = append(data.Packages,
checker.Package{
// Debug message.
Msg: stringPointer(fmt.Sprintf("GitHub publishing workflow not used in runs: %v", fp)),
Msg: StringPointer(fmt.Sprintf("GitHub publishing workflow not used in runs: %v", fp)),
File: &checker.File{
Path: fp,
Type: finding.FileTypeSource,
Expand All @@ -115,6 +115,6 @@ func Packaging(c *checker.CheckRequest) (checker.PackagingData, error) {
return data, nil
}

func stringPointer(s string) *string {
func StringPointer(s string) *string {
return &s
}
86 changes: 86 additions & 0 deletions checks/raw/gitlab/packaging.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2020 OpenSSF Scorecard Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gitlab

import (
"fmt"
"strings"

"github.com/ossf/scorecard/v4/checker"
"github.com/ossf/scorecard/v4/checks/fileparser"
"github.com/ossf/scorecard/v4/finding"
)

// Packaging checks for packages.
func Packaging(c *checker.CheckRequest) (checker.PackagingData, error) {
var data checker.PackagingData
matchedFiles, err := c.RepoClient.ListFiles(fileparser.IsGitlabWorkflowFile)
if err != nil {
return data, fmt.Errorf("RepoClient.ListFiles: %w", err)
}

for _, fp := range matchedFiles {
fc, err := c.RepoClient.GetFileContent(fp)
if err != nil {
return data, fmt.Errorf("RepoClient.GetFileContent: %w", err)
}

file, found := isGitlabPackagingWorkflow(fc, fp)

if found {
data.Packages = append(data.Packages, checker.Package{
Name: new(string),
Job: &checker.WorkflowJob{},
File: &file,
Msg: nil,
Runs: []checker.Run{{URL: c.Repo.URI()}},
})
return data, nil
}
}

return data, nil
}

func StringPointer(s string) *string {
return &s
}

func isGitlabPackagingWorkflow(fc []byte, fp string) (checker.File, bool) {
lineNumber := checker.OffsetDefault

packagingStrings := []string{
"docker push",
"nuget push",
"poetry publish",
"twine upload",
}

ParseLines:
for idx, val := range strings.Split(string(fc[:]), "\n") {
for _, element := range packagingStrings {
if strings.Contains(val, element) {
lineNumber = uint(idx + 1)
break ParseLines
}
}
}

return checker.File{
Path: fp,
Offset: lineNumber,
Type: finding.FileTypeSource,
}, lineNumber != checker.OffsetDefault
}
187 changes: 187 additions & 0 deletions checks/raw/gitlab/packaging_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright 2020 OpenSSF Scorecard Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gitlab

import (
"os"
"testing"

"github.com/golang/mock/gomock"

"github.com/ossf/scorecard/v4/checker"
mockrepo "github.com/ossf/scorecard/v4/clients/mockclients"
)

func TestGitlabPackagingYamlCheck(t *testing.T) {
t.Parallel()

//nolint
tests := []struct {
name string
lineNumber uint
filename string
exists bool
}{
{
name: "No Publishing Detected",
filename: "./testdata/no-publishing.yaml",
lineNumber: 1,
exists: false,
},
{
name: "Docker",
filename: "./testdata/docker.yaml",
lineNumber: 31,
exists: true,
},
{
name: "Nuget",
filename: "./testdata/nuget.yaml",
lineNumber: 21,
exists: true,
},
{
name: "Poetry",
filename: "./testdata/poetry.yaml",
lineNumber: 30,
exists: true,
},
{
name: "Twine",
filename: "./testdata/twine.yaml",
lineNumber: 26,
exists: true,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var content []byte
var err error

content, err = os.ReadFile(tt.filename)
if err != nil {
t.Errorf("cannot read file: %v", err)
}

file, found := isGitlabPackagingWorkflow(content, tt.filename)

if tt.exists && !found {
t.Errorf("Packaging %q should exist", tt.name)
} else if !tt.exists && found {
t.Errorf("No packaging information should have been found in %q", tt.name)
}

if file.Offset != tt.lineNumber {
t.Errorf("Expected line number: %d != %d", tt.lineNumber, file.Offset)
}

if err != nil {
return
}
})
}
}

func TestGitlabPackagingPackager(t *testing.T) {
t.Parallel()

//nolint
tests := []struct {
name string
lineNumber uint
filename string
exists bool
}{
{
name: "No Publishing Detected",
filename: "./testdata/no-publishing.yaml",
lineNumber: 1,
exists: false,
},
{
name: "Docker",
filename: "./testdata/docker.yaml",
lineNumber: 31,
exists: true,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

ctrl := gomock.NewController(t)
defer ctrl.Finish()
moqRepoClient := mockrepo.NewMockRepoClient(ctrl)
moqRepo := mockrepo.NewMockRepo(ctrl)

moqRepoClient.EXPECT().ListFiles(gomock.Any()).
Return([]string{tt.filename}, nil).AnyTimes()

moqRepoClient.EXPECT().GetFileContent(tt.filename).
DoAndReturn(func(b string) ([]byte, error) {
//nolint: errcheck
content, _ := os.ReadFile(b)
return content, nil
}).AnyTimes()

if tt.exists {
moqRepo.EXPECT().URI().Return("myurl.com/owner/project")
}

req := checker.CheckRequest{
RepoClient: moqRepoClient,
Repo: moqRepo,
}

//nolint: errcheck
packagingData, _ := Packaging(&req)

if !tt.exists {
if len(packagingData.Packages) != 0 {
t.Errorf("Repo should not contain any packages")
}
return
}

if len(packagingData.Packages) == 0 {
t.Fatalf("Repo should contain related packages")
}

pkg := packagingData.Packages[0].File

if pkg.Offset != tt.lineNumber {
t.Errorf("Expected line number: %d != %d", tt.lineNumber, pkg.Offset)
}
if pkg.Path != tt.filename {
t.Errorf("Expected filename: %v != %v", tt.filename, pkg.Path)
}

runs := packagingData.Packages[0].Runs

if len(runs) != 1 {
t.Errorf("Expected only a single run count, but received %d", len(runs))
}

if runs[0].URL != "myurl.com/owner/project" {
t.Errorf("URL did not match expected value %q", runs[0].URL)
}
})
}
}
Loading

0 comments on commit e11d5c7

Please sign in to comment.