1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/malwarescan/malwarescan_test.go
Christian Volk b0e4599d4d
feat(malwareExecuteScan): refactoring and docker support (#3421)
* feat(malwareExecuteScan): add support for scanning docker images

* refactoring

* print out finding if available

* generate toolrecord for malware scan

* persist scan report

* docs

* fix

* fix

* rollback cmd/init_unix.go

* auhenticated pull

* fix

* fix: report shall be consistent with the api model

* gcs upload

* fix linter
2022-01-24 09:48:01 +01:00

180 lines
6.1 KiB
Go

package malwarescan
import (
"fmt"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"net/http"
"testing"
)
func TestMalwareServiceScan(t *testing.T) {
t.Run("Scan without finding", func(t *testing.T) {
httpClient := &httpMock{StatusCode: 200, ResponseBody: "{\"malwareDetected\":false,\"encryptedContentDetected\":false,\"scanSize\":298782,\"mimeType\":\"application/octet-stream\",\"SHA256\":\"96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85\"}"}
malwareService := ClientImpl{
HTTPClient: httpClient,
Host: "https://example.org/malwarescanner",
}
candidate := readCloserMock{Content: "HELLO"}
scanResult, err := malwareService.Scan(candidate)
if assert.NoError(t, err) {
assert.True(t, httpClient.Body.Closed)
assert.Equal(t, "https://example.org/malwarescanner/scan", httpClient.URL)
assert.Equal(t, "POST", httpClient.Method)
if assert.NotNil(t, httpClient.Header) {
assert.Equal(t, "application/octet-stream", httpClient.Header.Get("Content-Type"))
}
assert.Equal(t, "application/octet-stream", scanResult.MimeType)
assert.Equal(t, 298782, scanResult.ScanSize)
assert.Equal(t, "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85", scanResult.SHA256)
assert.Equal(t, "", scanResult.Finding)
assert.False(t, scanResult.MalwareDetected)
assert.False(t, scanResult.EncryptedContentDetected)
}
})
t.Run("Scan without finding", func(t *testing.T) {
httpClient := &httpMock{StatusCode: 200, ResponseBody: "{\"malwareDetected\":true,\"encryptedContentDetected\":true,\"scanSize\":298782,\"mimeType\":\"application/octet-stream\",\"SHA256\":\"96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85\", \"finding\": \"Description of the finding\"}"}
malwareService := ClientImpl{
HTTPClient: httpClient,
Host: "https://example.org/malwarescanner",
}
candidate := readCloserMock{Content: "HELLO"}
scanResult, err := malwareService.Scan(candidate)
if assert.NoError(t, err) {
assert.True(t, httpClient.Body.Closed)
assert.Equal(t, "https://example.org/malwarescanner/scan", httpClient.URL)
assert.Equal(t, "POST", httpClient.Method)
if assert.NotNil(t, httpClient.Header) {
assert.Equal(t, "application/octet-stream", httpClient.Header.Get("Content-Type"))
}
assert.Equal(t, "application/octet-stream", scanResult.MimeType)
assert.Equal(t, 298782, scanResult.ScanSize)
assert.Equal(t, "96ca802fbd54d31903f1115a1d95590c685160637d9262bd340ab30d0f817e85", scanResult.SHA256)
assert.Equal(t, "Description of the finding", scanResult.Finding)
assert.True(t, scanResult.MalwareDetected)
assert.True(t, scanResult.EncryptedContentDetected)
}
})
t.Run("Scan results in error - file to large", func(t *testing.T) {
httpClient := &httpMock{StatusCode: 413, ResponseBody: "{\"message\":\"Payload too large - The file is too large and cannot be scanned or the archive structure is too complex.\"}"}
malwareService := ClientImpl{
HTTPClient: httpClient,
Host: "https://example.org/malwarescanner",
}
candidate := readCloserMock{Content: "HELLO"}
scanResult, err := malwareService.Scan(candidate)
assert.Nil(t, scanResult)
assert.EqualError(t, err, "MalwareService returned with status code 413: Payload too large - The file is too large and cannot be scanned or the archive structure is too complex.")
})
t.Run("Scan results in error - unexpected error", func(t *testing.T) {
httpClient := &httpMock{StatusCode: 500, ResponseBody: ""}
malwareService := ClientImpl{
HTTPClient: httpClient,
Host: "https://example.org/malwarescanner",
}
candidate := readCloserMock{Content: "HELLO"}
scanResult, err := malwareService.Scan(candidate)
assert.Nil(t, scanResult)
assert.EqualError(t, err, "MalwareService returned with status code 500, no further information available")
})
}
func TestMalwareServiceInfo(t *testing.T) {
t.Run("Receives engine info", func(t *testing.T) {
httpClient := &httpMock{StatusCode: 200, ResponseBody: "{\"engineVersion\": \"Malware Service Mock\", \"signatureTimestamp\": \"2022-01-12T09:26:28.000Z\", \"maxScanSize\": 666}"}
malwareService := ClientImpl{
HTTPClient: httpClient,
Host: "https://example.org/malwarescanner",
}
info, err := malwareService.Info()
if assert.NoError(t, err) {
assert.True(t, httpClient.Body.Closed)
assert.Equal(t, "https://example.org/malwarescanner/info", httpClient.URL)
assert.Equal(t, "GET", httpClient.Method)
assert.Equal(t, "Malware Service Mock", info.EngineVersion)
assert.Equal(t, "2022-01-12T09:26:28.000Z", info.SignatureTimestamp)
assert.Equal(t, 666, info.MaxScanSize)
}
})
}
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
Header http.Header // 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) {
c.Method = method
c.URL = url
c.Header = header
if r != nil {
_, 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
}