Skip to content

Commit 2c806e5

Browse files
feat: retrieve real findings [IDE-245] (#36)
1 parent 4efdd02 commit 2c806e5

File tree

6 files changed

+674
-102
lines changed

6 files changed

+674
-102
lines changed

internal/analysis/analysis.go

Lines changed: 91 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
176176
func (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

325378
func (a *analysisOrchestrator) host(isHidden bool) string {

0 commit comments

Comments
 (0)