Skip to content

Commit

Permalink
fix the failing on the conditional skip scan
Browse files Browse the repository at this point in the history
  • Loading branch information
Kravalg authored and viktigpetterr committed Jan 23, 2023
1 parent 1a839d8 commit 1ed7511
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 30 deletions.
101 changes: 76 additions & 25 deletions pkg/client/testdata/deb_client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,44 @@ package testdata

import (
"bytes"
"github.com/debricked/cli/pkg/client"
"io"
"net/http"
"net/url"
)

type DebClientMock struct {
responseQueue []MockResponse
realDebClient *client.DebClient
responseQueue []MockResponse
responseUriQueue map[string]MockResponse
}

func NewDebClientMock() *DebClientMock {
return &DebClientMock{responseQueue: []MockResponse{}}
debClient := client.NewDebClient(nil)
return &DebClientMock{
realDebClient: debClient,
responseQueue: []MockResponse{},
responseUriQueue: map[string]MockResponse{}}
}

func (mock *DebClientMock) Get(_ string, _ string) (*http.Response, error) {
return mock.popResponse()
func (mock *DebClientMock) Get(uri string, format string) (*http.Response, error) {
response, err := mock.popResponse(mock.RemoveQueryParamsFromUri(uri))

if response != nil {
return response, err
}

return mock.realDebClient.Get(uri, format)
}

func (mock *DebClientMock) Post(_ string, _ string, _ *bytes.Buffer) (*http.Response, error) {
return mock.popResponse()
func (mock *DebClientMock) Post(uri string, format string, body *bytes.Buffer) (*http.Response, error) {
response, err := mock.popResponse(mock.RemoveQueryParamsFromUri(uri))

if response != nil {
return response, err
}

return mock.realDebClient.Post(uri, format, body)
}

type MockResponse struct {
Expand All @@ -32,25 +52,56 @@ func (mock *DebClientMock) AddMockResponse(response MockResponse) {
mock.responseQueue = append(mock.responseQueue, response)
}

func (mock *DebClientMock) popResponse() (*http.Response, error) {
responseMock := mock.responseQueue[0] // The first element is the one to be dequeued.
mock.responseQueue = mock.responseQueue[1:] // Slice off the element once it is dequeued.

res := http.Response{
Status: "",
StatusCode: responseMock.StatusCode,
Proto: "",
ProtoMajor: 0,
ProtoMinor: 0,
Header: nil,
Body: responseMock.ResponseBody,
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
func (mock *DebClientMock) AddMockUriResponse(uri string, response MockResponse) {
mock.responseUriQueue[uri] = response
}

func (mock *DebClientMock) RemoveQueryParamsFromUri(uri string) string {
u, err := url.Parse(uri)
if err != nil {
return uri
}
q := u.Query()
for s := range q {
q.Del(s)
}
u.RawQuery = q.Encode()
return u.String()
}

func (mock *DebClientMock) popResponse(uri string) (*http.Response, error) {
var responseMock MockResponse
_, existsInUriQueue := mock.responseUriQueue[uri]
existsInQueue := len(mock.responseQueue) != 0
if existsInUriQueue {
responseMock = mock.responseUriQueue[uri]
delete(mock.responseUriQueue, uri)
} else if existsInQueue {
responseMock = mock.responseQueue[0] // The first element is the one to be dequeued.
mock.responseQueue = mock.responseQueue[1:] // Slice off the element once it is dequeued.
}

var res http.Response

if existsInUriQueue || existsInQueue {
res = http.Response{
Status: "",
StatusCode: responseMock.StatusCode,
Proto: "",
ProtoMajor: 0,
ProtoMinor: 0,
Header: nil,
Body: responseMock.ResponseBody,
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}
} else {
return nil, nil
}

return &res, responseMock.Error
Expand Down
5 changes: 5 additions & 0 deletions pkg/scan/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ func (dScanner *DebrickedScanner) Scan(o IOptions) error {
return err
}

if result == nil {
fmt.Println("Progress polling terminated due to long scan times. Please try again later")
return nil
}

fmt.Printf("\n%d vulnerabilities found\n", result.VulnerabilitiesFound)
fmt.Println("")
failPipeline := false
Expand Down
92 changes: 91 additions & 1 deletion pkg/scan/scanner_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package scan

import (
"bytes"
"encoding/json"
"github.com/debricked/cli/pkg/ci"
"github.com/debricked/cli/pkg/ci/argo"
"github.com/debricked/cli/pkg/ci/azure"
Expand All @@ -12,8 +14,12 @@ import (
"github.com/debricked/cli/pkg/ci/gitlab"
"github.com/debricked/cli/pkg/ci/travis"
"github.com/debricked/cli/pkg/client"
"github.com/debricked/cli/pkg/client/testdata"
"github.com/debricked/cli/pkg/file"
"github.com/debricked/cli/pkg/git"
"github.com/debricked/cli/pkg/upload"
"io"
"net/http"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -166,6 +172,85 @@ func TestScanBadOpts(t *testing.T) {
}
}

func TestScanEmptyResult(t *testing.T) {
var debClient client.IDebClient
clientMock := testdata.NewDebClientMock()

// Create mocked formats response
formats := []file.Format{{
Regex: "",
LockFileRegexes: []string{"yarn\\.lock"},
}}
formatsBytes, _ := json.Marshal(formats)
formatsMockRes := testdata.MockResponse{
StatusCode: http.StatusOK,
ResponseBody: io.NopCloser(bytes.NewReader(formatsBytes)),
}
clientMock.AddMockUriResponse("/api/1.0/open/files/supported-formats", formatsMockRes)

// Create mocked file upload response
uploadMockRes := testdata.MockResponse{
StatusCode: http.StatusOK,
ResponseBody: io.NopCloser(strings.NewReader("{\"ciUploadId\": 1}")),
}
clientMock.AddMockUriResponse("/api/1.0/open/uploads/dependencies/files", uploadMockRes)

// Create a mocked finish response
finishMockRes := testdata.MockResponse{
StatusCode: http.StatusNoContent,
ResponseBody: io.NopCloser(strings.NewReader("{}")),
}
clientMock.AddMockUriResponse("/api/1.0/open/finishes/dependencies/files/uploads", finishMockRes)

// Create mocked scan result response, 201 is returned when the queue time are too long
scanMockRes := testdata.MockResponse{
StatusCode: http.StatusCreated,
ResponseBody: io.NopCloser(strings.NewReader("{}")),
}
clientMock.AddMockUriResponse("/api/1.0/open/ci/upload/status", scanMockRes)

debClient = clientMock

var ciService ci.IService
ciService = ci.NewService(nil)
scanner, _ := NewDebrickedScanner(&debClient, ciService)
path := "testdata/yarn"
repositoryName := path
commitName := "testdata/yarn-commit"
cwd, _ := os.Getwd()
opts := DebrickedOptions{
Path: path,
Exclusions: nil,
RepositoryName: repositoryName,
CommitName: commitName,
BranchName: "",
CommitAuthor: "",
RepositoryUrl: "",
IntegrationName: "",
}

rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

err := scanner.Scan(opts)

_ = w.Close()
out, _ := io.ReadAll(r)
os.Stdout = rescueStdout

existsMessageInCMDOutput := strings.Contains(
string(out),
"Progress polling terminated due to long scan times. Please try again later")

if err != nil || !existsMessageInCMDOutput {
t.Error("failed to assert that scan ran without errors. Error:", err)
}

// reset working directory that has been manipulated in scanner.Scan
_ = os.Chdir(cwd)
}

func TestMapEnvToOptions(t *testing.T) {
dOptionsTemplate := DebrickedOptions{
Path: "path",
Expand Down Expand Up @@ -328,7 +413,12 @@ func TestSetWorkingDirectory(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
err := SetWorkingDirectory(&c.opts)
defer os.Chdir(cwd)
defer func(dir string) {
err := os.Chdir(dir)
if err != nil {
t.Fatal("Can not read the directory: ", dir)
}
}(cwd)

if len(c.errMessages) > 0 {
containsCorrectErrMsg := false
Expand Down
7 changes: 4 additions & 3 deletions pkg/upload/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import (
)

var (
NoFilesErr = errors.New("failed to find dependency files")
NoFilesErr = errors.New("failed to find dependency files")
PollingTerminatedErr = errors.New("progress polling terminated due to long queue times")
)

type uploadBatch struct {
Expand Down Expand Up @@ -182,9 +183,9 @@ func (uploadBatch *uploadBatch) wait() (*UploadResult, error) {
if res.StatusCode == http.StatusCreated {
err := bar.Finish()
if err != nil {
return nil, err
return resultStatus, err
}
return nil, errors.New("progress polling terminated due to long queue times")
return resultStatus, PollingTerminatedErr
}
status, err := newUploadStatus(res)
if err != nil {
Expand Down
27 changes: 27 additions & 0 deletions pkg/upload/batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/debricked/cli/pkg/client/testdata"
"github.com/debricked/cli/pkg/file"
"github.com/debricked/cli/pkg/git"
"io"
"log"
"net/http"
"os"
Expand Down Expand Up @@ -65,3 +66,29 @@ func captureOutput(f func()) string {
log.SetOutput(os.Stderr)
return buf.String()
}

func TestWaitWithPollingTerminatedError(t *testing.T) {
group := file.NewGroup("package.json", nil, []string{"yarn.lock"})
var groups file.Groups
groups.Add(*group)
metaObj, err := git.NewMetaObject("", "repository-name", "commit-name", "", "", "")
if err != nil {
t.Fatal("failed to create new MetaObject")
}

var c client.IDebClient
clientMock := testdata.NewDebClientMock()
mockRes := testdata.MockResponse{
StatusCode: http.StatusCreated,
ResponseBody: io.NopCloser(strings.NewReader("{}")),
}
clientMock.AddMockResponse(mockRes)
c = clientMock
batch := newUploadBatch(&c, groups, metaObj, "CLI")

uploadResult, err := batch.wait()

if uploadResult != nil && err != PollingTerminatedErr {
t.Fatal("Upload result must be nil and err must be PollingTerminatedErr")
}
}
5 changes: 5 additions & 0 deletions pkg/upload/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ func (uploader *Uploader) Upload(o IOptions) (*UploadResult, error) {
}

result, err := batch.wait()

if err != nil {
// the command should not fail because some file can't be scanned
if err == PollingTerminatedErr {
return result, nil
}
return nil, err
}

Expand Down
Empty file modified scripts/test_cli.sh
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion scripts/test_docker.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ case $type in
docker build -f build/docker/Dockerfile -t debricked/cli-scan:latest --target scan .
;;
*)
echo "${type} type is not supported!"
echo -e "Please use the following type dev, cli, scan. For example ./test_docker.sh dev"
exit 1
;;
esac
Expand Down

0 comments on commit 1ed7511

Please sign in to comment.