Skip to content

Commit fe7363e

Browse files
committed
chore: fix breaking changes from api version update
1 parent a1c0754 commit fe7363e

File tree

9 files changed

+293
-49
lines changed

9 files changed

+293
-49
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ scripts/__pycache__/
5353
internal/workspace/**/**/*.yaml
5454
!internal/workspace/**/**/*.config.yaml
5555
internal/orchestration/**/**/*.yaml
56-
!internal/orchestration/**/**/*.config.yaml
56+
!internal/orchestration/**/**/*.config.yaml
57+
.cursor

internal/analysis/analysis.go

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type analysisOrchestrator struct {
6666
logger *zerolog.Logger
6767
trackerFactory scan.TrackerFactory
6868
config config.Config
69-
testType testModels.Scan
69+
testType testModels.ResultType
7070
}
7171

7272
var _ AnalysisOrchestrator = (*analysisOrchestrator)(nil)
@@ -97,7 +97,7 @@ func WithTrackerFactory(factory scan.TrackerFactory) func(*analysisOrchestrator)
9797
}
9898
}
9999

100-
func WithResultType(t testModels.Scan) func(*analysisOrchestrator) {
100+
func WithResultType(t testModels.ResultType) func(*analysisOrchestrator) {
101101
return func(a *analysisOrchestrator) {
102102
a.testType = t
103103
}
@@ -237,8 +237,9 @@ func (a *analysisOrchestrator) RunTest(ctx context.Context, orgId string, b bund
237237
repoUrl = &tmp
238238
}
239239

240+
commitId := target.GetCommitId()
240241
body := testApi.NewCreateTestApplicationBody(
241-
testApi.WithInputBundle(b.GetBundleHash(), target.GetPath(), repoUrl, b.GetLimitToFiles()),
242+
testApi.WithInputBundle(b.GetBundleHash(), target.GetPath(), repoUrl, b.GetLimitToFiles(), &commitId),
242243
testApi.WithScanType(a.testType),
243244
testApi.WithProjectName(reportingConfig.ProjectName),
244245
testApi.WithTargetName(reportingConfig.TargetName),
@@ -300,11 +301,11 @@ func (a *analysisOrchestrator) retrieveTestURL(ctx context.Context, client *test
300301
logger := a.logger.With().Str("method", method).Logger()
301302
logger.Debug().Msg("retrieving Test URL")
302303

303-
httpResponse, err := client.GetTestResult(
304+
httpResponse, err := client.GetComponents(
304305
ctx,
305306
org,
306307
testId,
307-
&testApi.GetTestResultParams{Version: testApi.ApiVersion},
308+
&testApi.GetComponentsParams{Version: testApi.ApiVersion},
308309
)
309310
if err != nil {
310311
logger.Err(err).Str("testId", testId.String()).Msg("error requesting the ScanJobResult")
@@ -317,50 +318,51 @@ func (a *analysisOrchestrator) retrieveTestURL(ctx context.Context, client *test
317318
}
318319
}()
319320

320-
parsedResponse, err := testApi.ParseGetTestResultResponse(httpResponse)
321+
parsedResponse, err := testApi.ParseGetComponentsResponse(httpResponse)
321322
if err != nil {
322323
return nil, false, err
323324
}
324325

325326
switch parsedResponse.StatusCode() {
326327
case 200:
327-
stateDiscriminator, stateError := parsedResponse.ApplicationvndApiJSON200.Data.Attributes.Discriminator()
328-
if stateError != nil {
329-
return nil, false, stateError
328+
data := parsedResponse.ApplicationvndApiJSON200.Data
329+
var sastComponent *testModels.GetComponentsResponseItem
330+
for _, component := range data {
331+
if component.Attributes.Type == "sast" {
332+
a.logger.Debug().Msgf("inner component: %+v", component)
333+
sastComponent = &component
334+
break
335+
}
330336
}
331-
332-
switch stateDiscriminator {
333-
case string(testModels.TestAcceptedStateStatusAccepted):
334-
fallthrough
335-
case string(testModels.TestInProgressStateStatusInProgress):
337+
if sastComponent == nil {
338+
a.logger.Debug().Msg("no sast component found")
336339
return nil, false, nil
337-
case string(testModels.TestCompletedStateStatusCompleted):
338-
testCompleted, stateCompleteError := parsedResponse.ApplicationvndApiJSON200.Data.Attributes.AsTestCompletedState()
339-
if stateCompleteError != nil {
340-
return nil, false, stateCompleteError
341-
}
340+
}
342341

343-
findingsUrl := a.host(true) + testCompleted.Documents.EnrichedSarif + "?version=" + testApi.DocumentApiVersion
344-
result := &scan.ResultMetaData{
345-
FindingsUrl: findingsUrl,
346-
}
342+
result := &scan.ResultMetaData{}
343+
attributes := sastComponent.Attributes
344+
345+
if attributes.FindingsDocumentType != nil && *attributes.FindingsDocumentType == testModels.Sarif {
346+
// TODO: adjustedPath is a workaround for the fact that a breaking change was introduced to the findings document path
347+
// see https://github.com/snyk/test-service/pull/683
348+
adjustedPath := strings.Split(*attributes.FindingsDocumentPath, "v2")[0]
349+
adjustedPath = adjustedPath + "documents/enriched-findings/blob"
350+
findingsUrl := a.host(true) + adjustedPath + "?version=" + testApi.DocumentApiVersion
351+
result.FindingsUrl = findingsUrl
347352

348-
if testCompleted.Results.Webui != nil {
349-
if testCompleted.Results.Webui.Link != nil {
350-
result.WebUiUrl = *testCompleted.Results.Webui.Link
353+
if attributes.Webui != nil {
354+
if attributes.Webui.Link != nil {
355+
result.WebUiUrl = *attributes.Webui.Link
351356
}
352-
if testCompleted.Results.Webui.ProjectId != nil {
353-
result.ProjectId = testCompleted.Results.Webui.ProjectId.String()
357+
if attributes.Webui.ProjectId != nil {
358+
result.ProjectId = attributes.Webui.ProjectId.String()
354359
}
355-
if testCompleted.Results.Webui.SnapshotId != nil {
356-
result.SnapshotId = testCompleted.Results.Webui.SnapshotId.String()
360+
if attributes.Webui.SnapshotId != nil {
361+
result.SnapshotId = attributes.Webui.SnapshotId.String()
357362
}
358363
}
359-
360-
return result, true, nil
361-
default:
362-
return nil, false, fmt.Errorf("unexpected test status \"%s\"", stateDiscriminator)
363364
}
365+
return result, true, nil
364366
default:
365367
return nil, false, fmt.Errorf("unexpected response status \"%d\"", parsedResponse.StatusCode())
366368
}

internal/analysis/analysis_test.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
httpmocks "github.com/snyk/code-client-go/http/mocks"
3838
"github.com/snyk/code-client-go/internal/analysis"
3939
v20250407 "github.com/snyk/code-client-go/internal/api/test/2025-04-07"
40+
v20250407Models "github.com/snyk/code-client-go/internal/api/test/2025-04-07/models"
4041
"github.com/snyk/code-client-go/observability/mocks"
4142
"github.com/snyk/code-client-go/sarif"
4243
"github.com/snyk/code-client-go/scan"
@@ -55,7 +56,10 @@ func mockGetDocumentResponse(t *testing.T, sarifResponse sarif.SarifDocument, ex
5556
t.Helper()
5657
responseBodyBytes, err := json.Marshal(sarifResponse)
5758
assert.NoError(t, err)
58-
expectedDocumentUrl := fmt.Sprintf("http://localhost/hidden%s?version=%s", expectedDocumentPath, v20250407.DocumentApiVersion)
59+
// TODO: adjustedUrl is a workaround for the fact that a breaking change was introduced to the findings document path
60+
// see https://github.com/snyk/test-service/pull/683
61+
adjustedUrl := "http://localhost/hidden%sdocuments/enriched-findings/blob?version=%s"
62+
expectedDocumentUrl := fmt.Sprintf(adjustedUrl, expectedDocumentPath, v20250407.DocumentApiVersion)
5963
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
6064
req := i.(*http.Request)
6165
return req.URL.String() == expectedDocumentUrl
@@ -70,18 +74,20 @@ func mockGetDocumentResponse(t *testing.T, sarifResponse sarif.SarifDocument, ex
7074

7175
func mockResultCompletedResponse(t *testing.T, mockHTTPClient *httpmocks.MockHTTPClient, expectedWebuilink string, projectId uuid.UUID, snapshotId uuid.UUID, orgId string, testId uuid.UUID, documentPath string, responseCode int) {
7276
t.Helper()
73-
response := v20250407.NewTestResponse()
74-
state := v20250407.NewTestCompleteState()
75-
state.Documents.EnrichedSarif = documentPath
76-
state.Results.Webui.Link = &expectedWebuilink
77-
state.Results.Webui.ProjectId = &projectId
78-
state.Results.Webui.SnapshotId = &snapshotId
79-
stateBytes, err := json.Marshal(state)
80-
assert.NoError(t, err)
81-
response.Data.Attributes.UnmarshalJSON(stateBytes)
82-
responseBodyBytes, err := json.Marshal(response)
77+
state := v20250407.NewGetComponentsState()
78+
state.Data[0].Attributes.Type = "sast"
79+
state.Data[0].Attributes.FindingsDocumentPath = &documentPath
80+
findingsDocumentType := v20250407Models.Sarif
81+
state.Data[0].Attributes.FindingsDocumentType = &findingsDocumentType
82+
state.Data[0].Attributes.Success = true
83+
state.Data[0].Attributes.Webui = &v20250407Models.WebUI{
84+
Link: &expectedWebuilink,
85+
ProjectId: &projectId,
86+
SnapshotId: &snapshotId,
87+
}
88+
responseBodyBytes, err := json.Marshal(state)
8389
assert.NoError(t, err)
84-
expectedRetrieveTestUrl := fmt.Sprintf("http://localhost/hidden/orgs/%s/tests/%s?version=%s", orgId, testId, v20250407.ApiVersion)
90+
expectedRetrieveTestUrl := fmt.Sprintf("http://localhost/hidden/orgs/%s/tests/%s/components?version=%s", orgId, testId, v20250407.ApiVersion)
8591
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
8692
req := i.(*http.Request)
8793
return req.URL.String() == expectedRetrieveTestUrl
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package v20250407
2+
3+
import (
4+
openapi_types "github.com/oapi-codegen/runtime/types"
5+
6+
externalRef0 "github.com/snyk/code-client-go/internal/api/test/2025-04-07/common"
7+
v20250407 "github.com/snyk/code-client-go/internal/api/test/2025-04-07/models"
8+
)
9+
10+
const ApiVersion = "2025-04-07"
11+
const DocumentApiVersion = "2024-10-15~experimental"
12+
13+
type CreateTestOption func(*CreateTestApplicationVndAPIPlusJSONRequestBody)
14+
15+
func WithInputBundle(id string, localFilePath string, repoUrl *string, limitTestToFiles []string, commitId *string) CreateTestOption {
16+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
17+
bundleInput := v20250407.TestInputSourceBundle{
18+
BundleId: id,
19+
Type: v20250407.SourceBundle,
20+
Metadata: struct {
21+
CommitId *string `json:"commit_id,omitempty"`
22+
LimitTestToFiles *[]string `json:"limit_test_to_files,omitempty"`
23+
LocalFilePath string `json:"local_file_path"`
24+
RepoUrl *string `json:"repo_url,omitempty"`
25+
}{LocalFilePath: localFilePath, RepoUrl: repoUrl, CommitId: commitId},
26+
}
27+
28+
if len(limitTestToFiles) > 0 {
29+
bundleInput.Metadata.LimitTestToFiles = &limitTestToFiles
30+
}
31+
32+
body.Data.Attributes.Input.FromTestInputSourceBundle(bundleInput)
33+
}
34+
}
35+
36+
func WithInputLegacyScmProject(project v20250407.TestInputLegacyScmProject) CreateTestOption {
37+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
38+
body.Data.Attributes.Input.FromTestInputLegacyScmProject(project)
39+
}
40+
}
41+
42+
func WithScanType(t v20250407.ResultType) CreateTestOption {
43+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
44+
body.Data.Attributes.Configuration.Scan = &v20250407.ScanConfig{
45+
ResultType: &t,
46+
}
47+
}
48+
}
49+
50+
func ensureOutput(body *CreateTestApplicationVndAPIPlusJSONRequestBody) *v20250407.OutputConfig {
51+
if body.Data.Attributes.Configuration.Output == nil {
52+
body.Data.Attributes.Configuration.Output = &v20250407.OutputConfig{}
53+
}
54+
return body.Data.Attributes.Configuration.Output
55+
}
56+
57+
func WithProjectName(name *string) CreateTestOption {
58+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
59+
if name == nil {
60+
return
61+
}
62+
out := ensureOutput(body)
63+
out.ProjectName = name
64+
}
65+
}
66+
67+
func WithProjectId(id openapi_types.UUID) CreateTestOption {
68+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
69+
out := ensureOutput(body)
70+
out.ProjectId = &id
71+
}
72+
}
73+
74+
func WithTargetName(name *string) CreateTestOption {
75+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
76+
if name == nil || len(*name) == 0 {
77+
return
78+
}
79+
out := ensureOutput(body)
80+
out.TargetName = name
81+
}
82+
}
83+
84+
func WithTargetReference(targetRef *string) CreateTestOption {
85+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
86+
if targetRef == nil || len(*targetRef) == 0 {
87+
return
88+
}
89+
out := ensureOutput(body)
90+
out.TargetReference = targetRef
91+
}
92+
}
93+
94+
func WithReporting(report *bool) CreateTestOption {
95+
return func(body *CreateTestApplicationVndAPIPlusJSONRequestBody) {
96+
if report == nil {
97+
return
98+
}
99+
out := ensureOutput(body)
100+
out.Report = report
101+
}
102+
}
103+
104+
func NewCreateTestApplicationBody(options ...CreateTestOption) *CreateTestApplicationVndAPIPlusJSONRequestBody {
105+
result := &CreateTestApplicationVndAPIPlusJSONRequestBody{}
106+
result.Data.Type = v20250407.CreateTestRequestBodyDataTypeTest
107+
result.Data.Attributes.Input = &v20250407.TestAttributes_Input{}
108+
result.Data.Attributes.Configuration = &v20250407.TestConfiguration{}
109+
110+
for _, option := range options {
111+
option(result)
112+
}
113+
114+
return result
115+
}
116+
117+
func NewTestInputLegacyScmProject(projectId openapi_types.UUID, commitId string) v20250407.TestInputLegacyScmProject {
118+
return v20250407.TestInputLegacyScmProject{
119+
ProjectId: projectId,
120+
CommitId: commitId,
121+
Type: v20250407.LegacyScmProject,
122+
}
123+
}
124+
125+
func NewTestResponse() *v20250407.TestResult {
126+
return &v20250407.TestResult{
127+
Data: struct {
128+
Attributes v20250407.TestState `json:"attributes"`
129+
Id openapi_types.UUID `json:"id"`
130+
Type v20250407.TestResultDataType `json:"type"`
131+
}{},
132+
}
133+
}
134+
135+
func NewGetComponentsState() *v20250407.GetComponentsResponse {
136+
return &v20250407.GetComponentsResponse{
137+
Data: []v20250407.GetComponentsResponseItem{
138+
{
139+
Attributes: v20250407.ComponentAttributes{},
140+
Id: "1",
141+
Type: v20250407.Component,
142+
},
143+
},
144+
Jsonapi: externalRef0.JsonApi{
145+
Version: ApiVersion,
146+
},
147+
Links: struct {
148+
Next *externalRef0.LinkProperty `json:"next,omitempty"`
149+
Prev *externalRef0.LinkProperty `json:"prev,omitempty"`
150+
Self *externalRef0.LinkProperty `json:"self,omitempty"`
151+
}{},
152+
}
153+
}

internal/util/repository.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ func GetRepositoryUrl(path string) (string, error) {
4646
return repoUrl, err
4747
}
4848

49+
func GetCommitId(path string) (string, error) {
50+
repo, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{
51+
DetectDotGit: true,
52+
})
53+
if err != nil {
54+
return "", fmt.Errorf("open local repository: %w", err)
55+
}
56+
57+
commitId, err := repo.Head()
58+
if err != nil {
59+
return "", fmt.Errorf("get commit id: %w", err)
60+
}
61+
62+
return commitId.Hash().String(), nil
63+
}
64+
4965
func SanitiseCredentials(rawUrl string) (string, error) {
5066
parsedURL, err := url.Parse(rawUrl)
5167
if err != nil {

0 commit comments

Comments
 (0)