@@ -22,11 +22,17 @@ import (
2222 _ "embed"
2323 "encoding/json"
2424 "fmt"
25+ "io"
26+ "net/http"
27+ "strings"
28+ "time"
29+
2530 "github.com/google/uuid"
2631 openapi_types "github.com/oapi-codegen/runtime/types"
2732 "github.com/pkg/errors"
2833 "github.com/rs/zerolog"
2934 "github.com/snyk/code-client-go/config"
35+
3036 codeClientHTTP "github.com/snyk/code-client-go/http"
3137 orchestrationClient "github.com/snyk/code-client-go/internal/orchestration/2024-02-16"
3238 scans "github.com/snyk/code-client-go/internal/orchestration/2024-02-16/scans"
@@ -35,9 +41,6 @@ import (
3541 workspaces "github.com/snyk/code-client-go/internal/workspace/2024-03-12/workspaces"
3642 "github.com/snyk/code-client-go/observability"
3743 "github.com/snyk/code-client-go/sarif"
38-
39- "strings"
40- "time"
4144)
4245
4346//go:generate mockgen -destination=mocks/analysis.go -source=analysis.go -package mocks
@@ -170,9 +173,6 @@ func (a *analysisOrchestrator) CreateWorkspace(ctx context.Context, orgId string
170173 return workspaceResponse .ApplicationvndApiJSON201 .Data .Id .String (), nil
171174}
172175
173- //go:embed fake.json
174- var fakeResponse []byte
175-
176176func (a * analysisOrchestrator ) RunAnalysis (ctx context.Context , orgId string , workspaceId string ) (* sarif.SarifResponse , error ) {
177177 method := "analysis.RunAnalysis"
178178 logger := a .logger .With ().Str ("method" , method ).Logger ()
@@ -229,15 +229,41 @@ func (a *analysisOrchestrator) RunAnalysis(ctx context.Context, orgId string, wo
229229 return nil , fmt .Errorf ("failed to trigger scan: %w" , err )
230230 }
231231
232- if createScanResponse .ApplicationvndApiJSON201 == nil {
233- msg := a .getStatusCode (createScanResponse )
232+ var scanJobId openapi_types.UUID
233+ var msg string
234+ switch createScanResponse .StatusCode () {
235+ case 201 :
236+ scanJobId = createScanResponse .ApplicationvndApiJSON201 .Data .Id
237+ a .logger .Debug ().Str ("host" , host ).Str ("workspaceId" , workspaceId ).Msg ("starting scan" )
238+ case 400 :
239+ msg = createScanResponse .ApplicationvndApiJSON400 .Errors [0 ].Detail
240+ case 401 :
241+ msg = createScanResponse .ApplicationvndApiJSON401 .Errors [0 ].Detail
242+ case 403 :
243+ msg = createScanResponse .ApplicationvndApiJSON403 .Errors [0 ].Detail
244+ case 404 :
245+ msg = createScanResponse .ApplicationvndApiJSON404 .Errors [0 ].Detail
246+ case 429 :
247+ msg = createScanResponse .ApplicationvndApiJSON429 .Errors [0 ].Detail
248+ case 500 :
249+ msg = createScanResponse .ApplicationvndApiJSON500 .Errors [0 ].Detail
250+ }
251+ if msg != "" {
234252 return nil , errors .New (msg )
235253 }
236254
237- scanJobId := createScanResponse .ApplicationvndApiJSON201 .Data .Id
238- a .logger .Debug ().Str ("host" , host ).Str ("workspaceId" , workspaceId ).Msg ("starting scan" )
255+ response , err := a .pollScanForFindings (ctx , client , org , scanJobId )
256+ if err != nil {
257+ return nil , err
258+ }
259+
260+ return response , nil
261+ }
262+
263+ func (a * analysisOrchestrator ) pollScanForFindings (ctx context.Context , client * orchestrationClient.ClientWithResponses , org uuid.UUID , scanJobId openapi_types.UUID ) (* sarif.SarifResponse , error ) {
264+ method := "analysis.pollScanForFindings"
265+ logger := a .logger .With ().Str ("method" , method ).Logger ()
239266
240- // Actual polling loop.
241267 pollingTicker := time .NewTicker (1 * time .Second )
242268 defer pollingTicker .Stop ()
243269 timeoutTimer := time .NewTimer (a .timeoutInSeconds )
@@ -249,43 +275,54 @@ func (a *analysisOrchestrator) RunAnalysis(ctx context.Context, orgId string, wo
249275 logger .Error ().Str ("scanJobId" , scanJobId .String ()).Msg (msg )
250276 return nil , errors .New (msg )
251277 case <- pollingTicker .C :
252- _ , complete , err := a .poller (ctx , logger , client , org , scanJobId , method ) // todo add processing of the response with the findings
278+ findingsUrl , complete , err := a .retrieveFindingsURL (ctx , client , org , scanJobId )
253279 if err != nil {
254280 return nil , err
255281 }
256282 if ! complete {
257283 continue
258284 }
259285
260- var response sarif.SarifResponse
261- _ = json .Unmarshal (fakeResponse , & response )
286+ findings , err := a .retrieveFindings (findingsUrl )
287+ if err != nil {
288+ return nil , err
289+ }
262290
263- return & response , nil
291+ return findings , nil
264292 }
265293 }
266294}
267295
268- func (a * analysisOrchestrator ) poller (ctx context.Context , logger zerolog.Logger , client * orchestrationClient.ClientWithResponses , org uuid.UUID , scanJobId openapi_types.UUID , method string ) (response * orchestrationClient.GetScanWorkspaceJobForUserResponse , complete bool , err error ) {
269- logger .Debug ().Msg ("polling for ScanJobResult" )
296+ func (a * analysisOrchestrator ) retrieveFindingsURL (ctx context.Context , client * orchestrationClient.ClientWithResponses , org uuid.UUID , scanJobId openapi_types.UUID ) (string , bool , error ) {
297+ method := "analysis.retrieveFindingsURL"
298+ logger := a .logger .With ().Str ("method" , method ).Logger ()
299+ logger .Debug ().Msg ("retrieving findings URL" )
300+
270301 httpResponse , err := client .GetScanWorkspaceJobForUserWithResponse (
271302 ctx ,
272303 org ,
273304 scanJobId ,
274305 & orchestrationClient.GetScanWorkspaceJobForUserParams {Version : "2024-02-16~experimental" },
275306 )
276307 if err != nil {
277- logger .Err (err ).Str ("method" , method ). Str ( " scanJobId" , scanJobId .String ()).Msg ("error requesting the ScanJobResult" )
278- return httpResponse , true , err
308+ logger .Err (err ).Str ("scanJobId" , scanJobId .String ()).Msg ("error requesting the ScanJobResult" )
309+ return "" , true , err
279310 }
280311
281312 var msg string
282313 switch httpResponse .StatusCode () {
283314 case 200 :
284315 scanJobStatus := httpResponse .ApplicationvndApiJSON200 .Data .Attributes .Status
285316 if scanJobStatus == scans .ScanJobResultsAttributesStatusInProgress {
286- return httpResponse , false , nil
317+ return "" , false , nil
287318 } else {
288- return httpResponse , true , nil
319+ findingsUrl := ""
320+ fmt .Println (httpResponse .ApplicationvndApiJSON200 )
321+
322+ if len (httpResponse .ApplicationvndApiJSON200 .Data .Attributes .Components ) > 0 && httpResponse .ApplicationvndApiJSON200 .Data .Attributes .Components [0 ].FindingsUrl != nil {
323+ findingsUrl = * httpResponse .ApplicationvndApiJSON200 .Data .Attributes .Components [0 ].FindingsUrl
324+ }
325+ return findingsUrl , true , nil
289326 }
290327 case 400 :
291328 msg = httpResponse .ApplicationvndApiJSON400 .Errors [0 ].Detail
@@ -300,26 +337,42 @@ func (a *analysisOrchestrator) poller(ctx context.Context, logger zerolog.Logger
300337 case 500 :
301338 msg = httpResponse .ApplicationvndApiJSON500 .Errors [0 ].Detail
302339 }
303- return nil , true , errors .New (msg )
340+ return "" , true , errors .New (msg )
304341}
305342
306- func (a * analysisOrchestrator ) getStatusCode ( createScanResponse * orchestrationClient. CreateScanWorkspaceJobForUserResponse ) string {
307- var msg string
308- switch createScanResponse . StatusCode () {
309- case 400 :
310- msg = createScanResponse . ApplicationvndApiJSON400 . Errors [ 0 ]. Detail
311- case 401 :
312- msg = createScanResponse . ApplicationvndApiJSON401 . Errors [ 0 ]. Detail
313- case 403 :
314- msg = createScanResponse . ApplicationvndApiJSON403 . Errors [ 0 ]. Detail
315- case 404 :
316- msg = createScanResponse . ApplicationvndApiJSON404 . Errors [ 0 ]. Detail
317- case 429 :
318- msg = createScanResponse . ApplicationvndApiJSON429 . Errors [ 0 ]. Detail
319- case 500 :
320- msg = createScanResponse . ApplicationvndApiJSON500 . Errors [ 0 ]. Detail
343+ func (a * analysisOrchestrator ) retrieveFindings ( findingsUrl string ) ( * sarif. SarifResponse , error ) {
344+ method := "analysis.retrieveFindings"
345+ logger := a . logger . With (). Str ( "method" , method ). Logger ()
346+ logger . Debug (). Str ( "findings_url" , findingsUrl ). Msg ( "retrieving findings from URL" )
347+
348+ if findingsUrl == "" {
349+ return nil , errors . New ( "do not have a findings URL" )
350+ }
351+ req , err := http . NewRequest ( http . MethodGet , findingsUrl , nil )
352+ if err != nil {
353+ return nil , err
354+ }
355+ rsp , err := a . httpClient . Do ( req )
356+ if err != nil {
357+ return nil , err
321358 }
322- return msg
359+ defer func () { _ = rsp .Body .Close () }()
360+ bodyBytes , err := io .ReadAll (rsp .Body )
361+ if err != nil {
362+ return nil , err
363+ }
364+
365+ if rsp .StatusCode != http .StatusOK {
366+ return nil , errors .New ("failed to retrieve findings from findings URL" )
367+ }
368+
369+ var sarifResponse sarif.SarifResponse
370+ err = json .Unmarshal (bodyBytes , & sarifResponse )
371+ if err != nil {
372+ return nil , err
373+ }
374+
375+ return & sarifResponse , nil
323376}
324377
325378func (a * analysisOrchestrator ) host (isHidden bool ) string {
0 commit comments