Skip to content

Commit e144fee

Browse files
authored
feat: support to retrieve reports in async-mode (#16)
1 parent 0269dc8 commit e144fee

File tree

22 files changed

+559
-195
lines changed

22 files changed

+559
-195
lines changed

.github/workflows/ci.yaml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
name: CI
22

33
on:
4-
push:
5-
branches:
6-
- master
74
pull_request:
5+
branches:
6+
- master
7+
push:
88
branches:
99
- master
1010

@@ -22,18 +22,20 @@ jobs:
2222
- name: Check out code
2323
uses: actions/checkout@v2
2424

25-
- name: Cache modules
26-
uses: actions/cache@v1
25+
- name: Cache Go modules
26+
uses: actions/cache@v3
2727
with:
28-
path: ~/go/pkg/mod
28+
path: |
29+
~/.cache/go-build
30+
~/go/pkg/mod
2931
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
3032
restore-keys: |
3133
${{ runner.os }}-go-
3234
3335
- name: Get dependencies
3436
run: |
3537
go get -v -t -d ./...
36-
go get github.com/onsi/ginkgo/ginkgo
38+
go install github.com/onsi/ginkgo/ginkgo@v1.16.5
3739
3840
- name: Build
3941
run: go build ./...

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414

1515
# Dependency directories (remove the comment below to include it)
1616
# vendor/
17+
18+
.idea

cmd/harbor-scanner-sysdig-secure/main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"errors"
56
"fmt"
67
"os"
@@ -27,12 +28,19 @@ func main() {
2728
os.Exit(1)
2829
}
2930

31+
ctx, cancel := context.WithCancel(context.Background())
32+
defer cancel()
33+
3034
log.SetOutput(os.Stdout)
3135
log.SetLevel(log.TraceLevel)
3236
log.Info("Starting harbor-scanner-sysdig-secure")
3337

34-
apiHandler := v1.NewAPIHandler(getAdapter(), log.StandardLogger())
38+
adapter := getAdapter()
39+
if viper.GetBool("async_mode") {
40+
adapter = scanner.NewAsyncAdapter(ctx, adapter, log.StandardLogger(), scanner.DefaultAsyncAdapterRefreshRate)
41+
}
3542

43+
apiHandler := v1.NewAPIHandler(adapter, log.StandardLogger())
3644
apiServer := api.NewServer(apiHandler)
3745

3846
log.Fatal(apiServer.ListenAndServe())
@@ -45,6 +53,7 @@ func configure() error {
4553
pflag.String("secure_url", "https://secure.sysdig.com", "Sysdig Secure URL Endpoint")
4654
pflag.Bool("verify_ssl", true, "Verify SSL when connecting to Sysdig Secure URL Endpoint")
4755
pflag.Bool("inline_scanning", false, "Use Inline Scanning Adapter")
56+
pflag.Bool("async_mode", false, "Use Async-Mode to perform reports retrieval")
4857
pflag.String("namespace_name", "", "Namespace where inline scanning jobs are spawned")
4958
pflag.String("secret_name", "", "Secret which keeps the inline scanning secrets ")
5059
pflag.String("inline_scanning_extra_params", "", "Extra parameters to provide to inline-scanner")

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/golang/mock v1.4.3
77
github.com/gorilla/handlers v1.4.2
88
github.com/gorilla/mux v1.7.4
9-
github.com/onsi/ginkgo v1.16.4
9+
github.com/onsi/ginkgo v1.16.5
1010
github.com/onsi/gomega v1.10.1
1111
github.com/sirupsen/logrus v1.5.0
1212
github.com/spf13/pflag v1.0.5

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,8 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
224224
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
225225
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
226226
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
227-
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
228-
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
227+
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
228+
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
229229
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
230230
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
231231
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=

pkg/harbor/model.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const (
1111
ScanAdapterErrorMimeType = "application/vnd.scanner.adapter.error+json; version=1.0"
1212
)
1313

14+
type ScanRequestID string
15+
1416
type Scanner struct {
1517
Name string `json:"name,omitempty"`
1618
Vendor string `json:"vendor,omitempty"`
@@ -53,7 +55,7 @@ type ErrorResponse struct {
5355
}
5456

5557
type ScanResponse struct {
56-
ID string `json:"id"`
58+
ID ScanRequestID `json:"id"`
5759
}
5860

5961
type VulnerabilityReport struct {

pkg/http/api/v1/handler.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import (
1414
"github.com/sysdiglabs/harbor-scanner-sysdig-secure/pkg/scanner"
1515
)
1616

17+
const (
18+
DefaultRefreshTimeInSeconds = 60
19+
)
20+
1721
type requestHandler struct {
1822
adapter scanner.Adapter
1923
logger Logger
@@ -91,27 +95,27 @@ func (h *requestHandler) scan(res http.ResponseWriter, req *http.Request) {
9195
func (h *requestHandler) getReport(res http.ResponseWriter, req *http.Request) {
9296
vars := mux.Vars(req)
9397

94-
vulnerabilityReport, err := h.adapter.GetVulnerabilityReport(vars["scan_request_id"])
98+
vulnerabilityReport, err := h.adapter.GetVulnerabilityReport(harbor.ScanRequestID(vars["scan_request_id"]))
9599
if err != nil {
96100
h.logRequestError(req, err)
97101
switch err {
98102
case scanner.ErrScanRequestIDNotFound:
99103
res.WriteHeader(http.StatusNotFound)
100-
json.NewEncoder(res).Encode(errorResponseFromError(err))
101-
case scanner.ErrVulnerabiltyReportNotReady:
102-
res.Header().Set("Refresh-After", "120")
104+
_ = json.NewEncoder(res).Encode(errorResponseFromError(err))
105+
case scanner.ErrVulnerabilityReportNotReady:
106+
res.Header().Set("Refresh-After", fmt.Sprintf("%d", DefaultRefreshTimeInSeconds))
103107
res.Header().Set("Location", req.URL.String())
104108
res.WriteHeader(http.StatusFound)
105109
default:
106110
res.Header().Set("Content-Type", harbor.ScanAdapterErrorMimeType)
107111
res.WriteHeader(http.StatusInternalServerError)
108-
json.NewEncoder(res).Encode(errorResponseFromError(err))
112+
_ = json.NewEncoder(res).Encode(errorResponseFromError(err))
109113
}
110114
return
111115
}
112116

113117
res.Header().Set("Content-Type", harbor.ScanReportMimeType)
114-
json.NewEncoder(res).Encode(vulnerabilityReport)
118+
_ = json.NewEncoder(res).Encode(vulnerabilityReport)
115119
}
116120

117121
func (h *requestHandler) logRequestError(req *http.Request, err error) {

pkg/http/api/v1/handler_test.go

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package v1_test
33
import (
44
"encoding/json"
55
"errors"
6-
log "github.com/sirupsen/logrus"
6+
"fmt"
77
"net/http"
88
"net/http/httptest"
99
"strings"
1010

11+
log "github.com/sirupsen/logrus"
12+
1113
"github.com/golang/mock/gomock"
1214
. "github.com/onsi/ginkgo"
1315
. "github.com/onsi/gomega"
@@ -192,25 +194,28 @@ var _ = Describe("Harbor Scanner Sysdig Secure API Adapter", func() {
192194
})
193195

194196
Context("GET /api/v1/scan/{scan_request_id}/report", func() {
197+
reqID := harbor.ScanRequestID("scan-request-id")
198+
reqPath := fmt.Sprintf("/api/v1/scan/%s/report", reqID)
199+
195200
It("returns OK", func() {
196-
adapter.EXPECT().GetVulnerabilityReport("scan-request-id").Return(vulnerabilityReport(), nil)
201+
adapter.EXPECT().GetVulnerabilityReport(reqID).Return(vulnerabilityReport(), nil)
197202

198-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
203+
response := doGetRequest(handler, reqPath)
199204

200205
Expect(response.StatusCode).To(Equal(http.StatusOK))
201206
})
202207

203208
It("returns scanner.adapter.vuln.report.harbor Mime Type", func() {
204-
adapter.EXPECT().GetVulnerabilityReport("scan-request-id").Return(vulnerabilityReport(), nil)
209+
adapter.EXPECT().GetVulnerabilityReport(reqID).Return(vulnerabilityReport(), nil)
205210

206-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
211+
response := doGetRequest(handler, reqPath)
207212

208213
Expect(response.Header.Get("Content-Type")).To(Equal("application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0"))
209214
})
210215

211216
It("returns a valid scanner.vuln.report.harbor as JSON", func() {
212-
adapter.EXPECT().GetVulnerabilityReport("scan-request-id").Return(vulnerabilityReport(), nil)
213-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
217+
adapter.EXPECT().GetVulnerabilityReport(reqID).Return(vulnerabilityReport(), nil)
218+
response := doGetRequest(handler, reqPath)
214219

215220
var result harbor.VulnerabilityReport
216221
json.NewDecoder(response.Body).Decode(&result)
@@ -220,59 +225,59 @@ var _ = Describe("Harbor Scanner Sysdig Secure API Adapter", func() {
220225

221226
Context("when scan_request_id doesn't exist", func() {
222227
BeforeEach(func() {
223-
adapter.EXPECT().GetVulnerabilityReport("scan-request-id").Return(vulnerabilityReport(), scanner.ErrScanRequestIDNotFound)
228+
adapter.EXPECT().GetVulnerabilityReport(reqID).Return(vulnerabilityReport(), scanner.ErrScanRequestIDNotFound)
224229
})
225230

226231
It("returns NOT_FOUND", func() {
227-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
232+
response := doGetRequest(handler, reqPath)
228233

229234
Expect(response.StatusCode).To(Equal(http.StatusNotFound))
230235
})
231236
})
232237

233238
Context("when image is still being scanned", func() {
234239
BeforeEach(func() {
235-
adapter.EXPECT().GetVulnerabilityReport("scan-request-id").Return(vulnerabilityReport(), scanner.ErrVulnerabiltyReportNotReady)
240+
adapter.EXPECT().GetVulnerabilityReport(reqID).Return(vulnerabilityReport(), scanner.ErrVulnerabilityReportNotReady)
236241
})
237242

238243
It("returns FOUND", func() {
239-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
244+
response := doGetRequest(handler, reqPath)
240245

241246
Expect(response.StatusCode).To(Equal(http.StatusFound))
242247
})
243248

244249
It("returns the interval after request should be retried", func() {
245-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
250+
response := doGetRequest(handler, reqPath)
246251

247-
Expect(response.Header.Get("Refresh-After")).To(Equal("120"))
252+
Expect(response.Header.Get("Refresh-After")).To(Equal(fmt.Sprintf("%d", v1.DefaultRefreshTimeInSeconds)))
248253
})
249254

250255
It("returns the Location header with the URL to check", func() {
251-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
256+
response := doGetRequest(handler, reqPath)
252257

253-
Expect(response.Header.Get("Location")).To(Equal("/api/v1/scan/scan-request-id/report"))
258+
Expect(response.Header.Get("Location")).To(Equal(reqPath))
254259
})
255260
})
256261

257262
Context("when other unexpected errors happen", func() {
258263
BeforeEach(func() {
259-
adapter.EXPECT().GetVulnerabilityReport("scan-request-id").Return(vulnerabilityReport(), ErrUnexpected)
264+
adapter.EXPECT().GetVulnerabilityReport(reqID).Return(vulnerabilityReport(), ErrUnexpected)
260265
})
261266

262267
It("returns INTERNAL_SERVER_ERROR", func() {
263-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
268+
response := doGetRequest(handler, reqPath)
264269

265270
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
266271
})
267272

268273
It("returns scanner.adapter.error mime type", func() {
269-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
274+
response := doGetRequest(handler, reqPath)
270275

271276
Expect(response.Header.Get("Content-Type")).To(Equal("application/vnd.scanner.adapter.error+json; version=1.0"))
272277
})
273278

274279
It("returns a the error encoded as JSON", func() {
275-
response := doGetRequest(handler, "/api/v1/scan/scan-request-id/report")
280+
response := doGetRequest(handler, reqPath)
276281

277282
var result harbor.ErrorResponse
278283
json.NewDecoder(response.Body).Decode(&result)

pkg/scanner/adapter.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import (
77
)
88

99
var (
10-
ErrScanRequestIDNotFound = errors.New("scanRequestID cannot be found")
11-
ErrVulnerabiltyReportNotReady = errors.New("image is being scanned and report is still not ready")
10+
ErrScanRequestIDNotFound = errors.New("scanRequestID cannot be found")
11+
ErrVulnerabilityReportNotReady = errors.New("image is being scanned and report is still not ready")
1212
)
1313

1414
//go:generate mockgen -source=$GOFILE -destination=./mocks/${GOFILE} -package=mocks
1515
type Adapter interface {
1616
GetMetadata() (harbor.ScannerAdapterMetadata, error)
1717
Scan(req harbor.ScanRequest) (harbor.ScanResponse, error)
18-
GetVulnerabilityReport(scanResponseID string) (harbor.VulnerabilityReport, error)
18+
GetVulnerabilityReport(scanResponseID harbor.ScanRequestID) (harbor.VulnerabilityReport, error)
1919
}

0 commit comments

Comments
 (0)