1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00
sap-jenkins-library/cmd/malwareExecuteScan_test.go
Pavel Busko 1f750af16d
feat(cnbBuild): cache buildpacks during multi-image build (#3635)
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
2022-03-30 13:58:16 +02:00

306 lines
9.6 KiB
Go

package cmd
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"testing"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/fake"
piperDocker "github.com/SAP/jenkins-library/pkg/docker"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/malwarescan"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/stretchr/testify/assert"
)
var malwareScanConfig = malwareExecuteScanOptions{
Host: "https://example.org/malwarescanner",
Username: "me",
Password: "********",
ScanFile: "target/myFile",
Timeout: "60",
}
type malwareScanUtilsMockBundle struct {
*mock.FilesMock
returnScanResult *malwarescan.ScanResult
returnSHA256 string
}
func (utils *malwareScanUtilsMockBundle) SHA256(filePath string) (string, error) {
if utils.returnSHA256 == "" {
return utils.returnScanResult.SHA256, nil
}
return utils.returnSHA256, nil
}
func (utils *malwareScanUtilsMockBundle) OpenFile(path string, flag int, perm os.FileMode) (io.ReadCloser, error) {
return utils.FilesMock.OpenFile(path, flag, perm)
}
func (utils *malwareScanUtilsMockBundle) FileWrite(path string, content []byte, perm os.FileMode) error {
return utils.FilesMock.FileWrite(path, content, perm)
}
func (utils *malwareScanUtilsMockBundle) Info() (*malwarescan.Info, error) {
return &malwarescan.Info{EngineVersion: "Mock Malware Scanner", SignatureTimestamp: "n/a"}, nil
}
func (utils *malwareScanUtilsMockBundle) Scan(candidate io.Reader) (*malwarescan.ScanResult, error) {
return utils.returnScanResult, nil
}
func (utils *malwareScanUtilsMockBundle) newDockerClient(options piperDocker.ClientOptions) piperDocker.Download {
return &dockerClientMock{imageName: options.ImageName, registryURL: options.RegistryURL, localPath: options.LocalPath}
}
func TestMalwareScanWithNoBuildtool(t *testing.T) {
files := &mock.FilesMock{}
files.AddFile("target/myFile", []byte(`HELLO`))
utils := malwareScanUtilsMockBundle{
FilesMock: files,
}
t.Run("No malware, no encrypted content in file", func(t *testing.T) {
utils.returnScanResult = &malwarescan.ScanResult{
MalwareDetected: false,
EncryptedContentDetected: false,
ScanSize: 298782,
MimeType: "application/octet-stream",
SHA256: "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.NoError(t, error)
})
t.Run("Malware detected in file", func(t *testing.T) {
utils.returnScanResult = &malwarescan.ScanResult{
MalwareDetected: true,
EncryptedContentDetected: false,
ScanSize: 298782,
MimeType: "application/octet-stream",
SHA256: "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85",
Finding: "Win.Test.EICAR_HDB-1",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.EqualError(t, error, "Malware scan failed for file 'target/myFile'. Malware detected: true, encrypted content detected: false, finding: Win.Test.EICAR_HDB-1")
})
t.Run("Encrypted content detected in file", func(t *testing.T) {
utils.returnScanResult = &malwarescan.ScanResult{
MalwareDetected: false,
EncryptedContentDetected: true,
ScanSize: 298782,
MimeType: "application/octet-stream",
SHA256: "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.EqualError(t, error, "Malware scan failed for file 'target/myFile'. Malware detected: false, encrypted content detected: true, finding: ")
})
t.Run("Malware and encrypted content detected in file", func(t *testing.T) {
utils.returnScanResult = &malwarescan.ScanResult{
MalwareDetected: true,
EncryptedContentDetected: true,
ScanSize: 298782,
MimeType: "application/octet-stream",
SHA256: "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85",
Finding: "Win.Test.EICAR_HDB-1",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.EqualError(t, error, "Malware scan failed for file 'target/myFile'. Malware detected: true, encrypted content detected: true, finding: Win.Test.EICAR_HDB-1")
})
t.Run("No file and no buildtool specified", func(t *testing.T) {
malwareScanConfig := malwareExecuteScanOptions{
Host: "https://example.org/malwarescanner",
Username: "me",
Password: "********",
Timeout: "60",
}
error := runMalwareScan(&malwareScanConfig, nil, nil)
assert.EqualError(t, error, "Please specify a file to be scanned")
})
t.Run("File to be scanned, can't be found", func(t *testing.T) {
utils.returnScanResult = nil
malwareScanConfig := malwareExecuteScanOptions{
Host: "https://example.org/malwarescanner",
Username: "me",
Password: "********",
Timeout: "60",
ScanFile: "target/fileWhichDoesntExist",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.EqualError(t, error, "the file 'target/fileWhichDoesntExist' does not exist: file does not exist")
})
}
func TestMalwareScanWithDockerAsBuildtoolTests(t *testing.T) {
files := &mock.FilesMock{}
files.AddFile("dockerimagename_latest.tar", []byte(``))
utils := malwareScanUtilsMockBundle{
FilesMock: files,
}
t.Run("No malware detected in docker image", func(t *testing.T) {
utils.returnScanResult = &malwarescan.ScanResult{
MalwareDetected: false,
EncryptedContentDetected: false,
ScanSize: 298782,
MimeType: "application/octet-stream",
SHA256: "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85",
}
malwareScanConfig := malwareExecuteScanOptions{
Host: "https://example.org/malwarescanner",
Username: "me",
Password: "********",
Timeout: "60",
BuildTool: "docker",
ScanImage: "dockerimagename:latest",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.NoError(t, error)
})
t.Run("No file and no buildtool specified", func(t *testing.T) {
malwareScanConfig := malwareExecuteScanOptions{
Host: "https://example.org/malwarescanner",
Username: "me",
Password: "********",
Timeout: "60",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.EqualError(t, error, "Please specify a file to be scanned")
})
}
func TestMalwareScanWithOtherBuildtoolTests(t *testing.T) {
files := &mock.FilesMock{}
files.AddFile("dockerimagename_latest.tar", []byte(``))
utils := malwareScanUtilsMockBundle{
FilesMock: files,
}
t.Run("No malware detected in docker image", func(t *testing.T) {
utils.returnScanResult = &malwarescan.ScanResult{
MalwareDetected: false,
EncryptedContentDetected: false,
ScanSize: 298782,
MimeType: "application/octet-stream",
SHA256: "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85",
}
malwareScanConfig := malwareExecuteScanOptions{
Host: "https://example.org/malwarescanner",
Username: "me",
Password: "********",
Timeout: "60",
BuildTool: "golang",
ScanImage: "dockerimagename:latest",
}
error := runMalwareScan(&malwareScanConfig, nil, &utils)
assert.NoError(t, error)
})
}
type httpMock struct {
Method string // is set during test execution
URL string // is set before test execution
ResponseBody string // is set before test execution
Options piperhttp.ClientOptions // is set during test
StatusCode int // is set during test
Body readCloserMock // is set during test
}
func (c *httpMock) SetOptions(options piperhttp.ClientOptions) {
c.Options = options
}
func (c *httpMock) SendRequest(method string, url string, r io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
if strings.HasSuffix(url, "/info") {
return &http.Response{StatusCode: 200, Body: &readCloserMock{Content: "{\"engineVersion\": \"Malware Service Mock\", \"signatureTimestamp\": \"2022-01-12T09:26:28.000Z\"}"}}, nil
}
c.Method = method
c.URL = url
_, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
c.Body = readCloserMock{Content: c.ResponseBody}
res := http.Response{StatusCode: c.StatusCode, Body: &c.Body}
return &res, nil
}
type readCloserMock struct {
Content string
Closed bool
}
func (rc readCloserMock) Read(b []byte) (n int, err error) {
if len(b) < len(rc.Content) {
// in real life we would fill the buffer according to buffer size ...
return 0, fmt.Errorf("Buffer size (%d) not sufficient, need: %d", len(b), len(rc.Content))
}
copy(b, rc.Content)
return len(rc.Content), io.EOF
}
func (rc *readCloserMock) Close() error {
rc.Closed = true
return nil
}
type dockerClientMock struct {
imageName string
registryURL string
localPath string
includeLayers bool
}
//DownloadImage download the image to the specified path
func (c *dockerClientMock) DownloadImage(imageSource, filePath string) (v1.Image, error) {
return &fake.FakeImage{}, nil // fmt.Errorf("%s", filePath)
}
//DownloadImage download the image to the specified path
func (c *dockerClientMock) DownloadImageContent(imageSource, filePath string) (v1.Image, error) {
return &fake.FakeImage{}, nil // fmt.Errorf("%s", filePath)
}
// GetRemoteImageInfo return remote image information
func (c *dockerClientMock) GetRemoteImageInfo(imageSoure string) (v1.Image, error) {
return &fake.FakeImage{}, nil
}