From 6d6552320c86330787a8c9e78a2a1cb3baa64726 Mon Sep 17 00:00:00 2001 From: Teodora Sandu Date: Mon, 25 Mar 2024 15:49:25 +0000 Subject: [PATCH] refactor: configuration is injected --- README.md | 15 +++---- bundle/bundle.go | 10 ++--- bundle/bundle_manager.go | 14 +++---- bundle/bundle_manager_test.go | 54 ++++++++++-------------- bundle/bundle_test.go | 14 +++---- bundle/mocks/bundle.go | 8 ++-- bundle/mocks/bundle_manager.go | 16 +++---- deepcode/client.go | 56 +++---------------------- deepcode/client_pact_test.go | 35 +++++++--------- deepcode/client_test.go | 57 ++++--------------------- deepcode/mocks/client.go | 24 +++++------ http/config.go | 6 +++ http/http.go | 38 +++++++++++++++-- http/http_test.go | 48 ++++++++++++++++++++- http/mocks/config.go | 76 ++++++++++++++++++++++++++++++++++ http/mocks/http.go | 60 ++++++--------------------- scan.go | 9 ++-- scan_test.go | 12 +++--- 18 files changed, 284 insertions(+), 268 deletions(-) create mode 100644 http/mocks/config.go diff --git a/README.md b/README.md index 762ef102..cc909dd7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # code-client-go A library that exposes scanning capabilities for Snyk Code that can be used in the [Snyk CLI](https://github.com/snyk/cli) as well as Snyk IDE plugins using the [Snyk Language Server](https://github.com/snyk/snyk-ls). @@ -35,13 +36,12 @@ The HTTP client exposes a `DoCall` function. ### Configuration -Implement the http.Config interface and to configure the Snyk Code API client from applications. +Implement the `http.Config` interface to configure the Snyk Code API client from applications. ### Snyk Code Client Use the Snyk Code Client to make calls to the DeepCode API using the `httpClient` HTTP client created above. - ```go snykCode := deepcode.NewSnykCodeClient(logger, httpClient, testutil.NewTestInstrumentor()) ``` @@ -56,7 +56,7 @@ The Snyk Code Client exposes the following functions: Use the Bundle Manager to create bundles using the `snykCode` Snyk Code Client created above and then to extend it by uploading more files to it. ```go -bundleManager := bundle.NewBundleManager(snykCode, testutil.NewTestInstrumentor(), testutil.NewTestCodeInstrumentor()) +bundleManager := bundle.NewBundleManager(logger, snykCode, testutil.NewTestInstrumentor(), testutil.NewTestCodeInstrumentor()) ``` The Bundle Manager exposes the following functions: @@ -65,18 +65,19 @@ The Bundle Manager exposes the following functions: ### Code Scanner -Use the Code Scanner to trigger a scan for a Snyk Code workspace using the Bundle Manager created above: +Use the Code Scanner to trigger a scan for a Snyk Code workspace using the Bundle Manager created above. +The Code Scanner exposes a `UploadAndAnalyze` function, which can be used like this: ```go codeScanner := codeclient.NewCodeScanner( bundleManager, testutil.NewTestInstrumentor(), - testutil.NewTestCodeInstrumentor(), - testutils.NewTestAnalytics(), + testutil.NewTestErrorReporter(), + logger, ) +codeScanner.UploadAndAnalyze(context.Background(), "path/to/workspace", channelForWalkingFiles, changedFiles) ``` -The Code Scanner exposes a `UploadAndAnalyze` function. ### Observability diff --git a/bundle/bundle.go b/bundle/bundle.go index 953bffd9..ebff8c2a 100644 --- a/bundle/bundle.go +++ b/bundle/bundle.go @@ -26,7 +26,7 @@ import ( //go:generate mockgen -destination=mocks/bundle.go -source=bundle.go -package mocks type Bundle interface { - UploadBatch(ctx context.Context, host string, batch *Batch) error + UploadBatch(ctx context.Context, batch *Batch) error GetBundleHash() string GetRootPath() string GetRequestId() string @@ -95,8 +95,8 @@ func (b *deepCodeBundle) GetMissingFiles() []string { return b.missingFiles } -func (b *deepCodeBundle) UploadBatch(ctx context.Context, host string, batch *Batch) error { - err := b.extendBundle(ctx, host, batch) +func (b *deepCodeBundle) UploadBatch(ctx context.Context, batch *Batch) error { + err := b.extendBundle(ctx, batch) if err != nil { return err } @@ -104,10 +104,10 @@ func (b *deepCodeBundle) UploadBatch(ctx context.Context, host string, batch *Ba return nil } -func (b *deepCodeBundle) extendBundle(ctx context.Context, host string, uploadBatch *Batch) error { +func (b *deepCodeBundle) extendBundle(ctx context.Context, uploadBatch *Batch) error { var err error if uploadBatch.hasContent() { - b.bundleHash, b.missingFiles, err = b.SnykCode.ExtendBundle(ctx, host, b.bundleHash, uploadBatch.documents, []string{}) + b.bundleHash, b.missingFiles, err = b.SnykCode.ExtendBundle(ctx, b.bundleHash, uploadBatch.documents, []string{}) b.logger.Debug().Str("requestId", b.requestId).Interface("MissingFiles", b.missingFiles).Msg("extended deepCodeBundle on backend") } diff --git a/bundle/bundle_manager.go b/bundle/bundle_manager.go index a65868cb..45f54196 100644 --- a/bundle/bundle_manager.go +++ b/bundle/bundle_manager.go @@ -42,7 +42,6 @@ type bundleManager struct { //go:generate mockgen -destination=mocks/bundle_manager.go -source=bundle_manager.go -package mocks type BundleManager interface { Create(ctx context.Context, - host string, requestId string, rootPath string, filePaths <-chan string, @@ -51,7 +50,6 @@ type BundleManager interface { Upload( ctx context.Context, - host string, originalBundle Bundle, files map[string]deepcode.BundleFile, ) (Bundle, error) @@ -74,7 +72,6 @@ func NewBundleManager( } func (b *bundleManager) Create(ctx context.Context, - host string, requestId string, rootPath string, filePaths <-chan string, @@ -93,7 +90,7 @@ func (b *bundleManager) Create(ctx context.Context, return bundle, err // The cancellation error should be handled by the calling function } var supported bool - supported, err = b.IsSupported(span.Context(), host, absoluteFilePath) + supported, err = b.IsSupported(span.Context(), absoluteFilePath) if err != nil { return bundle, err } @@ -134,7 +131,7 @@ func (b *bundleManager) Create(ctx context.Context, var bundleHash string var missingFiles []string if len(fileHashes) > 0 { - bundleHash, missingFiles, err = b.SnykCode.CreateBundle(span.Context(), host, fileHashes) + bundleHash, missingFiles, err = b.SnykCode.CreateBundle(span.Context(), fileHashes) } bundle = NewBundle( b.SnykCode, @@ -153,7 +150,6 @@ func (b *bundleManager) Create(ctx context.Context, func (b *bundleManager) Upload( ctx context.Context, - host string, bundle Bundle, files map[string]deepcode.BundleFile, ) (Bundle, error) { @@ -172,7 +168,7 @@ func (b *bundleManager) Upload( if err := ctx.Err(); err != nil { return bundle, err } - err := bundle.UploadBatch(s.Context(), host, batch) + err := bundle.UploadBatch(s.Context(), batch) if err != nil { return bundle, err } @@ -214,9 +210,9 @@ func (b *bundleManager) groupInBatches( return batches } -func (b *bundleManager) IsSupported(ctx context.Context, host string, file string) (bool, error) { +func (b *bundleManager) IsSupported(ctx context.Context, file string) (bool, error) { if b.supportedExtensions.Size() == 0 && b.supportedConfigFiles.Size() == 0 { - filters, err := b.SnykCode.GetFilters(ctx, host) + filters, err := b.SnykCode.GetFilters(ctx) if err != nil { b.logger.Error().Err(err).Msg("could not get filters") return false, err diff --git a/bundle/bundle_manager_test.go b/bundle/bundle_manager_test.go index d34f3e66..c7d21564 100644 --- a/bundle/bundle_manager_test.go +++ b/bundle/bundle_manager_test.go @@ -43,11 +43,11 @@ func Test_Create(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{}, Extensions: []string{".java"}, }, nil) - mockSnykCodeClient.EXPECT().CreateBundle(gomock.Any(), "testHost", map[string]string{ + mockSnykCodeClient.EXPECT().CreateBundle(gomock.Any(), map[string]string{ "file.java": "386f1997f6da5133a0f75c347d5cdff15a428b817231278e2509832c1a80b3ea", }).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) @@ -63,7 +63,6 @@ func Test_Create(t *testing.T) { var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) bundle, err := bundleManager.Create(context.Background(), - "testHost", "testRequestId", dir, sliceToChannel([]string{file}), @@ -79,7 +78,7 @@ func Test_Create(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{}, Extensions: []string{".java"}, }, nil) @@ -96,7 +95,6 @@ func Test_Create(t *testing.T) { var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) bundle, err := bundleManager.Create(context.Background(), - "testHost", "testRequestId", dir, sliceToChannel([]string{file}), @@ -113,7 +111,7 @@ func Test_Create(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{}, Extensions: []string{".java"}, }, nil) @@ -134,7 +132,6 @@ func Test_Create(t *testing.T) { var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) bundle, err := bundleManager.Create(context.Background(), - "testHost", "testRequestId", dir, sliceToChannel([]string{file}), @@ -151,7 +148,7 @@ func Test_Create(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{}, Extensions: []string{".java"}, }, nil) @@ -171,7 +168,6 @@ func Test_Create(t *testing.T) { require.NoError(t, err) var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) bundle, err := bundleManager.Create(context.Background(), - "testHost", "testRequestId", dir, sliceToChannel([]string{file}), @@ -186,11 +182,11 @@ func Test_Create(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{".test"}, Extensions: []string{}, }, nil) - mockSnykCodeClient.EXPECT().CreateBundle(gomock.Any(), "testHost", map[string]string{ + mockSnykCodeClient.EXPECT().CreateBundle(gomock.Any(), map[string]string{ ".test": "9c05690c5b8e22df259431c95df33d01267f799de6810382ada1a9ff1b89710e", }).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) @@ -205,7 +201,6 @@ func Test_Create(t *testing.T) { var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) bundle, err := bundleManager.Create(context.Background(), - "testHost", "testRequestId", tempDir, sliceToChannel([]string{file}), @@ -220,11 +215,11 @@ func Test_Create(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{}, Extensions: []string{".java"}, }, nil) - mockSnykCodeClient.EXPECT().CreateBundle(gomock.Any(), "testHost", map[string]string{ + mockSnykCodeClient.EXPECT().CreateBundle(gomock.Any(), map[string]string{ "path/to/file1.java": "9c05690c5b8e22df259431c95df33d01267f799de6810382ada1a9ff1b89710e", "path/with%20spaces/file2.java": "9c05690c5b8e22df259431c95df33d01267f799de6810382ada1a9ff1b89710e", }).Times(1) @@ -254,7 +249,6 @@ func Test_Create(t *testing.T) { var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) bundle, err := bundleManager.Create(context.Background(), - "testHost", "testRequestId", tempDir, sliceToChannel(filesFullPaths), @@ -279,7 +273,7 @@ func Test_Upload(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testHost", "bundleHash", gomock.Len(1), []string{}).Times(1) + mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "bundleHash", gomock.Len(1), []string{}).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) mockInstrumentor.EXPECT().StartSpan(gomock.Any(), gomock.Any()).Return(mockSpan).Times(2) mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(2) @@ -291,7 +285,6 @@ func Test_Upload(t *testing.T) { bundleFileMap[documentURI] = bundleFile _, err := bundleManager.Upload(context.Background(), - "testHost", bundle.NewBundle(mockSnykCodeClient, mockInstrumentor, mockErrorReporter, &logger, "bundleHash", "testRequestId", "", bundleFileMap, []string{}, []string{documentURI}), bundleFileMap) assert.NoError(t, err) @@ -302,8 +295,8 @@ func Test_Upload(t *testing.T) { mockSpan := mocks.NewMockSpan(ctrl) mockSpan.EXPECT().Context().AnyTimes() mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testHost", "bundleHash", gomock.Len(3), []string{}).Return("newBundleHash", []string{}, nil).Times(1) - mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testHost", "newBundleHash", gomock.Len(2), []string{}).Return("newerBundleHash", []string{}, nil).Times(1) + mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "bundleHash", gomock.Len(3), []string{}).Return("newBundleHash", []string{}, nil).Times(1) + mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "newBundleHash", gomock.Len(2), []string{}).Return("newerBundleHash", []string{}, nil).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) mockInstrumentor.EXPECT().StartSpan(gomock.Any(), gomock.Any()).Return(mockSpan).Times(2) mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(2) @@ -329,7 +322,6 @@ func Test_Upload(t *testing.T) { missingFiles = append(missingFiles, path) _, err := bundleManager.Upload(context.Background(), - "testHost", bundle.NewBundle(mockSnykCodeClient, mockInstrumentor, mockErrorReporter, &logger, "bundleHash", "testRequestId", "", bundleFileMap, []string{}, missingFiles), bundleFileMap) assert.Nil(t, err) @@ -346,7 +338,7 @@ func createTempFileInDir(t *testing.T, name string, size int, temporaryDir strin func Test_IsSupported_Extensions(t *testing.T) { ctrl := gomock.NewController(t) mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: []string{}, Extensions: []string{".java"}, }, nil) @@ -355,19 +347,19 @@ func Test_IsSupported_Extensions(t *testing.T) { bundler := bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter) t.Run("should return true for supported languages", func(t *testing.T) { - supported, _ := bundler.IsSupported(context.Background(), "testHost", "C:\\some\\path\\Test.java") + supported, _ := bundler.IsSupported(context.Background(), "C:\\some\\path\\Test.java") assert.True(t, supported) }) t.Run("should return false for unsupported languages", func(t *testing.T) { - supported, _ := bundler.IsSupported(context.Background(), "testHost", "C:\\some\\path\\Test.rs") + supported, _ := bundler.IsSupported(context.Background(), "C:\\some\\path\\Test.rs") assert.False(t, supported) }) t.Run("should cache supported extensions", func(t *testing.T) { path := "C:\\some\\path\\Test.rs" - _, _ = bundler.IsSupported(context.Background(), "testHost", path) - _, _ = bundler.IsSupported(context.Background(), "testHost", path) + _, _ = bundler.IsSupported(context.Background(), path) + _, _ = bundler.IsSupported(context.Background(), path) }) } @@ -385,7 +377,7 @@ func Test_IsSupported_ConfigFiles(t *testing.T) { ctrl := gomock.NewController(t) mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().GetFilters(gomock.Any(), "testHost").Return(deepcode2.FiltersResponse{ + mockSnykCodeClient.EXPECT().GetFilters(gomock.Any()).Return(deepcode2.FiltersResponse{ ConfigFiles: configFilesFromFiltersEndpoint, Extensions: []string{}, }, nil) @@ -397,27 +389,27 @@ func Test_IsSupported_ConfigFiles(t *testing.T) { t.Run("should return true for supported config files", func(t *testing.T) { for _, file := range expectedConfigFiles { path := filepath.Join(dir, file) - supported, _ := bundler.IsSupported(context.Background(), "testHost", path) + supported, _ := bundler.IsSupported(context.Background(), path) assert.True(t, supported) } }) t.Run("should exclude .gitignore and .dcignore", func(t *testing.T) { for _, file := range []string{".gitignore", ".dcignore"} { path := filepath.Join(dir, file) - supported, _ := bundler.IsSupported(context.Background(), "testHost", path) + supported, _ := bundler.IsSupported(context.Background(), path) assert.False(t, supported) } }) t.Run("should return false for unsupported config files", func(t *testing.T) { path := "C:\\some\\path\\.unsupported" - supported, _ := bundler.IsSupported(context.Background(), "testHost", path) + supported, _ := bundler.IsSupported(context.Background(), path) assert.False(t, supported) }) t.Run("should cache supported extensions", func(t *testing.T) { path := "C:\\some\\path\\Test.rs" - _, _ = bundler.IsSupported(context.Background(), "testHost", path) - _, _ = bundler.IsSupported(context.Background(), "testHost", path) + _, _ = bundler.IsSupported(context.Background(), path) + _, _ = bundler.IsSupported(context.Background(), path) }) } diff --git a/bundle/bundle_test.go b/bundle/bundle_test.go index 8a60a2ee..91687a5c 100644 --- a/bundle/bundle_test.go +++ b/bundle/bundle_test.go @@ -53,14 +53,14 @@ func Test_UploadBatch(t *testing.T) { b := bundle.NewBundle(mockSnykCodeClient, mockInstrumentor, mockErrorReporter, &testLogger, "testBundleHash", "testRequestId", "", map[string]deepcode.BundleFile{}, []string{}, []string{}) emptyBundle := &bundle.Batch{} - err := b.UploadBatch(context.Background(), "testHost", emptyBundle) + err := b.UploadBatch(context.Background(), emptyBundle) assert.NoError(t, err) }) t.Run("when no bundles - creates new deepCodeBundle and sets hash", func(t *testing.T) { ctrl := gomock.NewController(t) mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testHost", "testBundleHash", map[string]deepcode.BundleFile{ + mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testBundleHash", map[string]deepcode.BundleFile{ "file": {}, }, []string{}).Return("testBundleHash", []string{}, nil) @@ -72,18 +72,18 @@ func Test_UploadBatch(t *testing.T) { mockErrorReporter := mocks.NewMockErrorReporter(ctrl) b := bundle.NewBundle(mockSnykCodeClient, mockInstrumentor, mockErrorReporter, &testLogger, "testBundleHash", "testRequestId", "", map[string]deepcode.BundleFile{}, []string{}, []string{}) - err := b.UploadBatch(context.Background(), "testHost", bundleWithFiles) + err := b.UploadBatch(context.Background(), bundleWithFiles) assert.NoError(t, err) }) t.Run("when existing bundles - extends deepCodeBundle and updates hash", func(t *testing.T) { ctrl := gomock.NewController(t) mockSnykCodeClient := mocks2.NewMockSnykCodeClient(ctrl) - mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testHost", "testBundleHash", map[string]deepcode.BundleFile{ + mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testBundleHash", map[string]deepcode.BundleFile{ "another": {}, "file": {}, }, []string{}).Return("bundleWithMultipleFilesHash", []string{}, nil).Times(1) - mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testHost", "testBundleHash", map[string]deepcode.BundleFile{ + mockSnykCodeClient.EXPECT().ExtendBundle(gomock.Any(), "testBundleHash", map[string]deepcode.BundleFile{ "file": {}, }, []string{}).Return("testBundleHash", []string{}, nil).Times(1) @@ -95,10 +95,10 @@ func Test_UploadBatch(t *testing.T) { mockErrorReporter := mocks.NewMockErrorReporter(ctrl) b := bundle.NewBundle(mockSnykCodeClient, mockInstrumentor, mockErrorReporter, &testLogger, "testBundleHash", "testRequestId", "", map[string]deepcode.BundleFile{}, []string{}, []string{}) - err := b.UploadBatch(context.Background(), "testHost", bundleWithFiles) + err := b.UploadBatch(context.Background(), bundleWithFiles) require.NoError(t, err) oldHash := b.GetBundleHash() - err = b.UploadBatch(context.Background(), "testHost", bundleWithMultipleFiles) + err = b.UploadBatch(context.Background(), bundleWithMultipleFiles) require.NoError(t, err) newHash := b.GetBundleHash() assert.NotEqual(t, oldHash, newHash) diff --git a/bundle/mocks/bundle.go b/bundle/mocks/bundle.go index 3f36d9ae..cd49881b 100644 --- a/bundle/mocks/bundle.go +++ b/bundle/mocks/bundle.go @@ -107,15 +107,15 @@ func (mr *MockBundleMockRecorder) GetRootPath() *gomock.Call { } // UploadBatch mocks base method. -func (m *MockBundle) UploadBatch(ctx context.Context, host string, batch *bundle.Batch) error { +func (m *MockBundle) UploadBatch(ctx context.Context, batch *bundle.Batch) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UploadBatch", ctx, host, batch) + ret := m.ctrl.Call(m, "UploadBatch", ctx, batch) ret0, _ := ret[0].(error) return ret0 } // UploadBatch indicates an expected call of UploadBatch. -func (mr *MockBundleMockRecorder) UploadBatch(ctx, host, batch interface{}) *gomock.Call { +func (mr *MockBundleMockRecorder) UploadBatch(ctx, batch interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBatch", reflect.TypeOf((*MockBundle)(nil).UploadBatch), ctx, host, batch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBatch", reflect.TypeOf((*MockBundle)(nil).UploadBatch), ctx, batch) } diff --git a/bundle/mocks/bundle_manager.go b/bundle/mocks/bundle_manager.go index 36db9d69..bdd82031 100644 --- a/bundle/mocks/bundle_manager.go +++ b/bundle/mocks/bundle_manager.go @@ -37,31 +37,31 @@ func (m *MockBundleManager) EXPECT() *MockBundleManagerMockRecorder { } // Create mocks base method. -func (m *MockBundleManager) Create(ctx context.Context, host, requestId, rootPath string, filePaths <-chan string, changedFiles map[string]bool) (bundle.Bundle, error) { +func (m *MockBundleManager) Create(ctx context.Context, requestId, rootPath string, filePaths <-chan string, changedFiles map[string]bool) (bundle.Bundle, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", ctx, host, requestId, rootPath, filePaths, changedFiles) + ret := m.ctrl.Call(m, "Create", ctx, requestId, rootPath, filePaths, changedFiles) ret0, _ := ret[0].(bundle.Bundle) ret1, _ := ret[1].(error) return ret0, ret1 } // Create indicates an expected call of Create. -func (mr *MockBundleManagerMockRecorder) Create(ctx, host, requestId, rootPath, filePaths, changedFiles interface{}) *gomock.Call { +func (mr *MockBundleManagerMockRecorder) Create(ctx, requestId, rootPath, filePaths, changedFiles interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockBundleManager)(nil).Create), ctx, host, requestId, rootPath, filePaths, changedFiles) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockBundleManager)(nil).Create), ctx, requestId, rootPath, filePaths, changedFiles) } // Upload mocks base method. -func (m *MockBundleManager) Upload(ctx context.Context, host string, originalBundle bundle.Bundle, files map[string]deepcode.BundleFile) (bundle.Bundle, error) { +func (m *MockBundleManager) Upload(ctx context.Context, originalBundle bundle.Bundle, files map[string]deepcode.BundleFile) (bundle.Bundle, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Upload", ctx, host, originalBundle, files) + ret := m.ctrl.Call(m, "Upload", ctx, originalBundle, files) ret0, _ := ret[0].(bundle.Bundle) ret1, _ := ret[1].(error) return ret0, ret1 } // Upload indicates an expected call of Upload. -func (mr *MockBundleManagerMockRecorder) Upload(ctx, host, originalBundle, files interface{}) *gomock.Call { +func (mr *MockBundleManagerMockRecorder) Upload(ctx, originalBundle, files interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upload", reflect.TypeOf((*MockBundleManager)(nil).Upload), ctx, host, originalBundle, files) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upload", reflect.TypeOf((*MockBundleManager)(nil).Upload), ctx, originalBundle, files) } diff --git a/deepcode/client.go b/deepcode/client.go index 0fc6f86f..0442764b 100644 --- a/deepcode/client.go +++ b/deepcode/client.go @@ -19,9 +19,6 @@ package deepcode import ( "context" "encoding/json" - "errors" - "net/url" - "regexp" "strconv" "github.com/rs/zerolog" @@ -32,19 +29,17 @@ import ( //go:generate mockgen -destination=mocks/client.go -source=client.go -package mocks type SnykCodeClient interface { - GetFilters(ctx context.Context, host string) ( + GetFilters(ctx context.Context) ( filters FiltersResponse, err error) CreateBundle( ctx context.Context, - host string, files map[string]string, ) (newBundleHash string, missingFiles []string, err error) ExtendBundle( ctx context.Context, - host string, bundleHash string, files map[string]BundleFile, removedFiles []string, @@ -80,7 +75,7 @@ func NewSnykCodeClient( return &snykCodeClient{httpClient, instrumentor, logger} } -func (s *snykCodeClient) GetFilters(ctx context.Context, snykCodeApiUrl string) ( +func (s *snykCodeClient) GetFilters(ctx context.Context) ( filters FiltersResponse, err error, ) { @@ -91,12 +86,7 @@ func (s *snykCodeClient) GetFilters(ctx context.Context, snykCodeApiUrl string) span := s.instrumentor.StartSpan(ctx, method) defer s.instrumentor.Finish(span) - host, err := s.FormatCodeApiURL(snykCodeApiUrl) - if err != nil { - return FiltersResponse{ConfigFiles: nil, Extensions: nil}, err - } - - responseBody, err := s.httpClient.DoCall(span.Context(), host, "GET", "/filters", nil) + responseBody, err := s.httpClient.DoCall(span.Context(), "GET", "/filters", nil) if err != nil { return FiltersResponse{ConfigFiles: nil, Extensions: nil}, err } @@ -111,7 +101,6 @@ func (s *snykCodeClient) GetFilters(ctx context.Context, snykCodeApiUrl string) func (s *snykCodeClient) CreateBundle( ctx context.Context, - snykCodeApiUrl string, filesToFilehashes map[string]string, ) (string, []string, error) { method := "code.CreateBundle" @@ -126,12 +115,7 @@ func (s *snykCodeClient) CreateBundle( return "", nil, err } - host, err := s.FormatCodeApiURL(snykCodeApiUrl) - if err != nil { - return "", nil, err - } - - responseBody, err := s.httpClient.DoCall(span.Context(), host, "POST", "/bundle", requestBody) + responseBody, err := s.httpClient.DoCall(span.Context(), "POST", "/bundle", requestBody) if err != nil { return "", nil, err } @@ -147,7 +131,6 @@ func (s *snykCodeClient) CreateBundle( func (s *snykCodeClient) ExtendBundle( ctx context.Context, - snykCodeApiUrl string, bundleHash string, files map[string]BundleFile, removedFiles []string, @@ -168,12 +151,7 @@ func (s *snykCodeClient) ExtendBundle( return "", nil, err } - host, err := s.FormatCodeApiURL(snykCodeApiUrl) - if err != nil { - return "", nil, err - } - - responseBody, err := s.httpClient.DoCall(span.Context(), host, "PUT", "/bundle/"+bundleHash, requestBody) + responseBody, err := s.httpClient.DoCall(span.Context(), "PUT", "/bundle/"+bundleHash, requestBody) if err != nil { return "", nil, err } @@ -181,27 +159,3 @@ func (s *snykCodeClient) ExtendBundle( err = json.Unmarshal(responseBody, &bundleResponse) return bundleResponse.BundleHash, bundleResponse.MissingFiles, err } - -var codeApiRegex = regexp.MustCompile(`^(deeproxy\.)?`) - -// This is only exported for tests. -func (s *snykCodeClient) FormatCodeApiURL(snykCodeApiUrl string) (string, error) { - if !s.httpClient.Config().IsFedramp() { - return snykCodeApiUrl, nil - } - u, err := url.Parse(snykCodeApiUrl) - if err != nil { - return "", err - } - - u.Host = codeApiRegex.ReplaceAllString(u.Host, "api.") - - organization := s.httpClient.Config().Organization() - if organization == "" { - return "", errors.New("Organization is required in a fedramp environment") - } - - u.Path = "/hidden/orgs/" + organization + "/code" - - return u.String(), nil -} diff --git a/deepcode/client_pact_test.go b/deepcode/client_pact_test.go index 193f5111..805358eb 100644 --- a/deepcode/client_pact_test.go +++ b/deepcode/client_pact_test.go @@ -38,9 +38,8 @@ const ( pactDir = "./pacts" pactProvider = "SnykCodeApi" - orgUUID = "00000000-0000-0000-0000-000000000023" - sessionTokenMatcher = "^token [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - uuidMatcher = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + orgUUID = "00000000-0000-0000-0000-000000000023" + uuidMatcher = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" ) // Common test data @@ -48,7 +47,7 @@ var pact dsl.Pact var client deepcode.SnykCodeClient func TestSnykCodeBackendServicePact(t *testing.T) { - snykCodeApiUrl := setupPact(t) + setupPact(t) defer pact.Teardown() defer func() { @@ -74,7 +73,7 @@ func TestSnykCodeBackendServicePact(t *testing.T) { test := func() error { files := make(map[string]string) files[path1] = util.Hash([]byte(content)) - bundleHash, missingFiles, err := client.CreateBundle(context.Background(), snykCodeApiUrl, files) + bundleHash, missingFiles, err := client.CreateBundle(context.Background(), files) if err != nil { return err @@ -115,7 +114,7 @@ func TestSnykCodeBackendServicePact(t *testing.T) { test := func() error { files := make(map[string]string) files[path1] = util.Hash([]byte(content)) - _, _, err := client.CreateBundle(context.Background(), snykCodeApiUrl, files) + _, _, err := client.CreateBundle(context.Background(), files) if err != nil { return nil @@ -151,7 +150,7 @@ func TestSnykCodeBackendServicePact(t *testing.T) { filesExtend := createTestExtendMap() var removedFiles []string - extendedBundleHash, missingFiles, err := client.ExtendBundle(context.Background(), snykCodeApiUrl, bundleHash, filesExtend, removedFiles) + extendedBundleHash, missingFiles, err := client.ExtendBundle(context.Background(), bundleHash, filesExtend, removedFiles) if err != nil { return err @@ -190,7 +189,7 @@ func TestSnykCodeBackendServicePact(t *testing.T) { }) test := func() error { - if _, err := client.GetFilters(context.Background(), snykCodeApiUrl); err != nil { + if _, err := client.GetFilters(context.Background()); err != nil { return err } @@ -203,23 +202,23 @@ func TestSnykCodeBackendServicePact(t *testing.T) { }) } -func setupPact(t *testing.T) string { +func setupPact(t *testing.T) { t.Helper() - ctrl := gomock.NewController(t) - config := httpmocks.NewMockConfig(ctrl) - config.EXPECT().IsFedramp().AnyTimes().Return(false) - config.EXPECT().Organization().AnyTimes().Return(orgUUID) - + // Proactively start service to get access to the port pact = dsl.Pact{ Consumer: consumer, Provider: pactProvider, PactDir: pactDir, } - // Proactively start service to get access to the port pact.Setup(true) + ctrl := gomock.NewController(t) + config := httpmocks.NewMockConfig(ctrl) + config.EXPECT().IsFedramp().AnyTimes().Return(false) + config.EXPECT().Organization().AnyTimes().Return(orgUUID) snykCodeApiUrl := fmt.Sprintf("http://localhost:%d", pact.Server.Port) + config.EXPECT().SnykCodeApi().AnyTimes().Return(snykCodeApiUrl) instrumentor := testutil.NewTestInstrumentor() errorReporter := testutil.NewTestErrorReporter() @@ -227,8 +226,6 @@ func setupPact(t *testing.T) string { return http.DefaultClient }, instrumentor, errorReporter) client = deepcode.NewSnykCodeClient(newLogger(t), httpClient, instrumentor) - - return snykCodeApiUrl } func getPutPostHeaderMatcher() dsl.MapMatcher { @@ -249,7 +246,7 @@ func getSnykRequestIdMatcher() dsl.Matcher { } func TestSnykCodeBackendServicePact_LocalCodeEngine(t *testing.T) { - snykCodeApiUrl := setupPact(t) + setupPact(t) defer pact.Teardown() @@ -269,7 +266,7 @@ func TestSnykCodeBackendServicePact_LocalCodeEngine(t *testing.T) { }) test := func() error { - if _, err := client.GetFilters(context.Background(), snykCodeApiUrl); err != nil { + if _, err := client.GetFilters(context.Background()); err != nil { return err } return nil diff --git a/deepcode/client_test.go b/deepcode/client_test.go index 4b9b31e7..054fb09b 100644 --- a/deepcode/client_test.go +++ b/deepcode/client_test.go @@ -64,14 +64,14 @@ func TestSnykCodeBackendService_GetFilters(t *testing.T) { mockConfig.EXPECT().IsFedramp().AnyTimes().Return(false) mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) mockHTTPClient.EXPECT().Config().AnyTimes().Return(mockConfig) - mockHTTPClient.EXPECT().DoCall(gomock.Any(), "http://fake-host", "GET", "/filters", gomock.Any()).Return([]byte(`{"configFiles": ["test"], "extensions": ["test"]}`), nil).Times(1) + mockHTTPClient.EXPECT().DoCall(gomock.Any(), "GET", "/filters", gomock.Any()).Return([]byte(`{"configFiles": ["test"], "extensions": ["test"]}`), nil).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) mockInstrumentor.EXPECT().StartSpan(gomock.Any(), gomock.Any()).Return(mockSpan).Times(1) mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(1) s := deepcode.NewSnykCodeClient(newLogger(t), mockHTTPClient, mockInstrumentor) - filters, err := s.GetFilters(context.Background(), "http://fake-host") + filters, err := s.GetFilters(context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(filters.ConfigFiles)) assert.Equal(t, 1, len(filters.ConfigFiles)) @@ -87,7 +87,7 @@ func TestSnykCodeBackendService_CreateBundle(t *testing.T) { mockConfig.EXPECT().IsFedramp().AnyTimes().Return(false) mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) mockHTTPClient.EXPECT().Config().AnyTimes().Return(mockConfig) - mockHTTPClient.EXPECT().DoCall(gomock.Any(), "http://fake-host", "POST", "/bundle", gomock.Any()).Return([]byte(`{"bundleHash": "bundleHash", "missingFiles": ["test"]}`), nil).Times(1) + mockHTTPClient.EXPECT().DoCall(gomock.Any(), "POST", "/bundle", gomock.Any()).Return([]byte(`{"bundleHash": "bundleHash", "missingFiles": ["test"]}`), nil).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) mockInstrumentor.EXPECT().StartSpan(gomock.Any(), gomock.Any()).Return(mockSpan).Times(1) mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(1) @@ -96,7 +96,7 @@ func TestSnykCodeBackendService_CreateBundle(t *testing.T) { files := map[string]string{} randomAddition := fmt.Sprintf("\n public void random() { System.out.println(\"%d\") }", time.Now().UnixMicro()) files[path1] = util.Hash([]byte(content + randomAddition)) - bundleHash, missingFiles, err := s.CreateBundle(context.Background(), "http://fake-host", files) + bundleHash, missingFiles, err := s.CreateBundle(context.Background(), files) assert.Nil(t, err) assert.NotNil(t, bundleHash) assert.Equal(t, "bundleHash", bundleHash) @@ -113,8 +113,8 @@ func TestSnykCodeBackendService_ExtendBundle(t *testing.T) { mockConfig.EXPECT().IsFedramp().AnyTimes().Return(false) mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) mockHTTPClient.EXPECT().Config().AnyTimes().Return(mockConfig) - mockHTTPClient.EXPECT().DoCall(gomock.Any(), "http://fake-host", "POST", "/bundle", gomock.Any()).Return([]byte(`{"bundleHash": "bundleHash", "missingFiles": []}`), nil).Times(1) - mockHTTPClient.EXPECT().DoCall(gomock.Any(), "http://fake-host", "PUT", "/bundle/bundleHash", gomock.Any()).Return([]byte(`{"bundleHash": "bundleHash", "missingFiles": []}`), nil).Times(1) + mockHTTPClient.EXPECT().DoCall(gomock.Any(), "POST", "/bundle", gomock.Any()).Return([]byte(`{"bundleHash": "bundleHash", "missingFiles": []}`), nil).Times(1) + mockHTTPClient.EXPECT().DoCall(gomock.Any(), "PUT", "/bundle/bundleHash", gomock.Any()).Return([]byte(`{"bundleHash": "bundleHash", "missingFiles": []}`), nil).Times(1) mockInstrumentor := mocks.NewMockInstrumentor(ctrl) mockInstrumentor.EXPECT().StartSpan(gomock.Any(), gomock.Any()).Return(mockSpan).Times(2) mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(2) @@ -123,10 +123,10 @@ func TestSnykCodeBackendService_ExtendBundle(t *testing.T) { var removedFiles []string files := map[string]string{} files[path1] = util.Hash([]byte(content)) - bundleHash, _, _ := s.CreateBundle(context.Background(), "http://fake-host", files) + bundleHash, _, _ := s.CreateBundle(context.Background(), files) filesExtend := createTestExtendMap() - bundleHash, missingFiles, err := s.ExtendBundle(context.Background(), "http://fake-host", bundleHash, filesExtend, removedFiles) + bundleHash, missingFiles, err := s.ExtendBundle(context.Background(), bundleHash, filesExtend, removedFiles) assert.Nil(t, err) assert.Equal(t, 0, len(missingFiles)) assert.NotEmpty(t, bundleHash) @@ -146,47 +146,6 @@ func createTestExtendMap() map[string]deepcode.BundleFile { return filesExtend } -func Test_getCodeApiUrl(t *testing.T) { - ctrl := gomock.NewController(t) - mockInstrumentor := mocks.NewMockInstrumentor(ctrl) - logger := newLogger(t) - - t.Run("Changes the URL if FedRAMP", func(t *testing.T) { - mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) - config := httpmocks.NewMockConfig(ctrl) - config.EXPECT().IsFedramp().AnyTimes().Return(true) - config.EXPECT().Organization().AnyTimes().Return(orgUUID) - mockHTTPClient.EXPECT().Config().AnyTimes().Return(config) - - s := deepcode.NewSnykCodeClient(logger, mockHTTPClient, mockInstrumentor) - - input := "https://snyk.io/api/v1" - expected := "https://api.snyk.io/hidden/orgs/" + orgUUID + "/code" - - actual, err := s.FormatCodeApiURL(input) - assert.Nil(t, err) - assert.Contains(t, actual, expected) - }) - - t.Run("Does not change the URL if it's not FedRAMP", func(t *testing.T) { - mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) - config := httpmocks.NewMockConfig(ctrl) - config.EXPECT().IsFedramp().AnyTimes().Return(false) - config.EXPECT().Organization().AnyTimes().Return("") - mockHTTPClient.EXPECT().Config().AnyTimes().Return(config) - - s := deepcode.NewSnykCodeClient(logger, mockHTTPClient, mockInstrumentor) - - input := "https://snyk.io/api/v1" - expected := "https://snyk.io/api/v1" - - actual, err := s.FormatCodeApiURL(input) - t.Log(input, actual) - assert.Nil(t, err) - assert.Contains(t, actual, expected) - }) -} - func newLogger(t *testing.T) *zerolog.Logger { t.Helper() logger := zerolog.New(zerolog.NewTestWriter(t)) diff --git a/deepcode/mocks/client.go b/deepcode/mocks/client.go index 382b2201..2ea33e80 100644 --- a/deepcode/mocks/client.go +++ b/deepcode/mocks/client.go @@ -36,9 +36,9 @@ func (m *MockSnykCodeClient) EXPECT() *MockSnykCodeClientMockRecorder { } // CreateBundle mocks base method. -func (m *MockSnykCodeClient) CreateBundle(ctx context.Context, host string, files map[string]string) (string, []string, error) { +func (m *MockSnykCodeClient) CreateBundle(ctx context.Context, files map[string]string) (string, []string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateBundle", ctx, host, files) + ret := m.ctrl.Call(m, "CreateBundle", ctx, files) ret0, _ := ret[0].(string) ret1, _ := ret[1].([]string) ret2, _ := ret[2].(error) @@ -46,15 +46,15 @@ func (m *MockSnykCodeClient) CreateBundle(ctx context.Context, host string, file } // CreateBundle indicates an expected call of CreateBundle. -func (mr *MockSnykCodeClientMockRecorder) CreateBundle(ctx, host, files interface{}) *gomock.Call { +func (mr *MockSnykCodeClientMockRecorder) CreateBundle(ctx, files interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBundle", reflect.TypeOf((*MockSnykCodeClient)(nil).CreateBundle), ctx, host, files) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBundle", reflect.TypeOf((*MockSnykCodeClient)(nil).CreateBundle), ctx, files) } // ExtendBundle mocks base method. -func (m *MockSnykCodeClient) ExtendBundle(ctx context.Context, host, bundleHash string, files map[string]deepcode.BundleFile, removedFiles []string) (string, []string, error) { +func (m *MockSnykCodeClient) ExtendBundle(ctx context.Context, bundleHash string, files map[string]deepcode.BundleFile, removedFiles []string) (string, []string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExtendBundle", ctx, host, bundleHash, files, removedFiles) + ret := m.ctrl.Call(m, "ExtendBundle", ctx, bundleHash, files, removedFiles) ret0, _ := ret[0].(string) ret1, _ := ret[1].([]string) ret2, _ := ret[2].(error) @@ -62,22 +62,22 @@ func (m *MockSnykCodeClient) ExtendBundle(ctx context.Context, host, bundleHash } // ExtendBundle indicates an expected call of ExtendBundle. -func (mr *MockSnykCodeClientMockRecorder) ExtendBundle(ctx, host, bundleHash, files, removedFiles interface{}) *gomock.Call { +func (mr *MockSnykCodeClientMockRecorder) ExtendBundle(ctx, bundleHash, files, removedFiles interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExtendBundle", reflect.TypeOf((*MockSnykCodeClient)(nil).ExtendBundle), ctx, host, bundleHash, files, removedFiles) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExtendBundle", reflect.TypeOf((*MockSnykCodeClient)(nil).ExtendBundle), ctx, bundleHash, files, removedFiles) } // GetFilters mocks base method. -func (m *MockSnykCodeClient) GetFilters(ctx context.Context, host string) (deepcode.FiltersResponse, error) { +func (m *MockSnykCodeClient) GetFilters(ctx context.Context) (deepcode.FiltersResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFilters", ctx, host) + ret := m.ctrl.Call(m, "GetFilters", ctx) ret0, _ := ret[0].(deepcode.FiltersResponse) ret1, _ := ret[1].(error) return ret0, ret1 } // GetFilters indicates an expected call of GetFilters. -func (mr *MockSnykCodeClientMockRecorder) GetFilters(ctx, host interface{}) *gomock.Call { +func (mr *MockSnykCodeClientMockRecorder) GetFilters(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilters", reflect.TypeOf((*MockSnykCodeClient)(nil).GetFilters), ctx, host) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilters", reflect.TypeOf((*MockSnykCodeClient)(nil).GetFilters), ctx) } diff --git a/http/config.go b/http/config.go index ec193ae4..dc4ca527 100644 --- a/http/config.go +++ b/http/config.go @@ -1,6 +1,8 @@ package http // Config defines the configurable options for the HTTP client. +// +//go:generate mockgen -destination=mocks/config.go -source=config.go -package mocks type Config interface { // Organization is the Snyk organization in which code SAST is being run. @@ -10,4 +12,8 @@ type Config interface { // IsFedramp indicates whether the code SAST is being run in the context of FedRAMP. IsFedramp() bool + + // SnykCodeApi returns the Snyk Code API URL configured to run against, which could be + // the one used by the Local Code Engine. + SnykCodeApi() string } diff --git a/http/http.go b/http/http.go index 7d42a917..21a97dec 100644 --- a/http/http.go +++ b/http/http.go @@ -23,6 +23,8 @@ import ( "errors" "io" "net/http" + "net/url" + "regexp" "time" "github.com/rs/zerolog" @@ -35,11 +37,11 @@ import ( type HTTPClient interface { Config() Config DoCall(ctx context.Context, - host string, method string, path string, requestBody []byte, ) (responseBody []byte, err error) + FormatCodeApiURL() (string, error) } type httpClient struct { @@ -72,7 +74,6 @@ func (s *httpClient) Config() Config { } func (s *httpClient) DoCall(ctx context.Context, - host string, method string, path string, requestBody []byte, @@ -91,7 +92,7 @@ func (s *httpClient) DoCall(ctx context.Context, } var req *http.Request - req, err = s.newRequest(host, method, path, bodyBuffer, requestId) + req, err = s.newRequest(method, path, bodyBuffer, requestId) if err != nil { return nil, err } @@ -131,12 +132,16 @@ func (s *httpClient) DoCall(ctx context.Context, } func (s *httpClient) newRequest( - host string, method string, path string, body *bytes.Buffer, requestId string, ) (*http.Request, error) { + host, err := s.FormatCodeApiURL() + if err != nil { + return nil, err + } + req, err := http.NewRequest(method, host+path, body) if err != nil { return nil, err @@ -217,3 +222,28 @@ func (s *httpClient) checkResponseCode(r *http.Response) error { } return errors.New("Unexpected response code: " + r.Status) } + +var codeApiRegex = regexp.MustCompile(`^(deeproxy\.)?`) + +// This is only exported for tests. +func (s *httpClient) FormatCodeApiURL() (string, error) { + snykCodeApiUrl := s.config.SnykCodeApi() + if !s.Config().IsFedramp() { + return snykCodeApiUrl, nil + } + u, err := url.Parse(snykCodeApiUrl) + if err != nil { + return "", err + } + + u.Host = codeApiRegex.ReplaceAllString(u.Host, "api.") + + organization := s.Config().Organization() + if organization == "" { + return "", errors.New("Organization is required in a fedramp environment") + } + + u.Path = "/hidden/orgs/" + organization + "/code" + + return u.String(), nil +} diff --git a/http/http_test.go b/http/http_test.go index 72d15d69..243eb9df 100644 --- a/http/http_test.go +++ b/http/http_test.go @@ -63,9 +63,10 @@ func TestSnykCodeBackendService_DoCall_shouldRetry(t *testing.T) { config := httpmocks.NewMockConfig(ctrl) config.EXPECT().IsFedramp().AnyTimes().Return(false) config.EXPECT().Organization().AnyTimes().Return("") + config.EXPECT().SnykCodeApi().AnyTimes().Return("") s := codeClientHTTP.NewHTTPClient(newLogger(t), config, dummyClientFactory, mockInstrumentor, mockErrorReporter) - _, err := s.DoCall(context.Background(), "", "GET", "https: //httpstat.us/500", nil) + _, err := s.DoCall(context.Background(), "GET", "https: //httpstat.us/500", nil) assert.Error(t, err) assert.Equal(t, 3, d.calls) } @@ -86,12 +87,55 @@ func TestSnykCodeBackendService_doCall_rejected(t *testing.T) { config := httpmocks.NewMockConfig(ctrl) config.EXPECT().IsFedramp().AnyTimes().Return(false) config.EXPECT().Organization().AnyTimes().Return("") + config.EXPECT().SnykCodeApi().AnyTimes().Return("") s := codeClientHTTP.NewHTTPClient(newLogger(t), config, dummyClientFactory, mockInstrumentor, mockErrorReporter) - _, err := s.DoCall(context.Background(), "", "GET", "https://127.0.0.1", nil) + _, err := s.DoCall(context.Background(), "GET", "https://127.0.0.1", nil) assert.Error(t, err) } +func Test_FormatCodeApiURL(t *testing.T) { + ctrl := gomock.NewController(t) + mockInstrumentor := mocks.NewMockInstrumentor(ctrl) + mockErrorReporter := mocks.NewMockErrorReporter(ctrl) + logger := newLogger(t) + dummyClientFactory := func() *http.Client { + return &http.Client{} + } + + orgUUID := "00000000-0000-0000-0000-000000000023" + + t.Run("Changes the URL if FedRAMP", func(t *testing.T) { + mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) + config := httpmocks.NewMockConfig(ctrl) + config.EXPECT().IsFedramp().AnyTimes().Return(true) + config.EXPECT().Organization().AnyTimes().Return(orgUUID) + config.EXPECT().SnykCodeApi().AnyTimes().Return("https://snyk.io/api/v1") + mockHTTPClient.EXPECT().Config().AnyTimes().Return(config) + + s := codeClientHTTP.NewHTTPClient(logger, config, dummyClientFactory, mockInstrumentor, mockErrorReporter) + + actual, err := s.FormatCodeApiURL() + assert.Nil(t, err) + assert.Contains(t, actual, "https://api.snyk.io/hidden/orgs/00000000-0000-0000-0000-000000000023/code") + }) + + t.Run("Does not change the URL if it's not FedRAMP", func(t *testing.T) { + mockHTTPClient := httpmocks.NewMockHTTPClient(ctrl) + config := httpmocks.NewMockConfig(ctrl) + config.EXPECT().IsFedramp().AnyTimes().Return(false) + config.EXPECT().Organization().AnyTimes().Return("") + config.EXPECT().SnykCodeApi().AnyTimes().Return("https://snyk.io/api/v1") + mockHTTPClient.EXPECT().Config().AnyTimes().Return(config) + + s := codeClientHTTP.NewHTTPClient(logger, config, dummyClientFactory, mockInstrumentor, mockErrorReporter) + + actual, err := s.FormatCodeApiURL() + assert.Nil(t, err) + assert.Contains(t, actual, "https://snyk.io/api/v1") + }) +} + func newLogger(t *testing.T) *zerolog.Logger { t.Helper() logger := zerolog.New(zerolog.NewTestWriter(t)) diff --git a/http/mocks/config.go b/http/mocks/config.go new file mode 100644 index 00000000..428d2ca6 --- /dev/null +++ b/http/mocks/config.go @@ -0,0 +1,76 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: config.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockConfig is a mock of Config interface. +type MockConfig struct { + ctrl *gomock.Controller + recorder *MockConfigMockRecorder +} + +// MockConfigMockRecorder is the mock recorder for MockConfig. +type MockConfigMockRecorder struct { + mock *MockConfig +} + +// NewMockConfig creates a new mock instance. +func NewMockConfig(ctrl *gomock.Controller) *MockConfig { + mock := &MockConfig{ctrl: ctrl} + mock.recorder = &MockConfigMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConfig) EXPECT() *MockConfigMockRecorder { + return m.recorder +} + +// IsFedramp mocks base method. +func (m *MockConfig) IsFedramp() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsFedramp") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsFedramp indicates an expected call of IsFedramp. +func (mr *MockConfigMockRecorder) IsFedramp() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFedramp", reflect.TypeOf((*MockConfig)(nil).IsFedramp)) +} + +// Organization mocks base method. +func (m *MockConfig) Organization() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Organization") + ret0, _ := ret[0].(string) + return ret0 +} + +// Organization indicates an expected call of Organization. +func (mr *MockConfigMockRecorder) Organization() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Organization", reflect.TypeOf((*MockConfig)(nil).Organization)) +} + +// SnykCodeApi mocks base method. +func (m *MockConfig) SnykCodeApi() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SnykCodeApi") + ret0, _ := ret[0].(string) + return ret0 +} + +// SnykCodeApi indicates an expected call of SnykCodeApi. +func (mr *MockConfigMockRecorder) SnykCodeApi() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnykCodeApi", reflect.TypeOf((*MockConfig)(nil).SnykCodeApi)) +} diff --git a/http/mocks/http.go b/http/mocks/http.go index 0a7142bb..876647e7 100644 --- a/http/mocks/http.go +++ b/http/mocks/http.go @@ -50,67 +50,31 @@ func (mr *MockHTTPClientMockRecorder) Config() *gomock.Call { } // DoCall mocks base method. -func (m *MockHTTPClient) DoCall(ctx context.Context, host, method, path string, requestBody []byte) ([]byte, error) { +func (m *MockHTTPClient) DoCall(ctx context.Context, method, path string, requestBody []byte) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DoCall", ctx, host, method, path, requestBody) + ret := m.ctrl.Call(m, "DoCall", ctx, method, path, requestBody) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // DoCall indicates an expected call of DoCall. -func (mr *MockHTTPClientMockRecorder) DoCall(ctx, host, method, path, requestBody interface{}) *gomock.Call { +func (mr *MockHTTPClientMockRecorder) DoCall(ctx, method, path, requestBody interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DoCall", reflect.TypeOf((*MockHTTPClient)(nil).DoCall), ctx, host, method, path, requestBody) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DoCall", reflect.TypeOf((*MockHTTPClient)(nil).DoCall), ctx, method, path, requestBody) } -// MockConfig is a mock of Config interface. -type MockConfig struct { - ctrl *gomock.Controller - recorder *MockConfigMockRecorder -} - -// MockConfigMockRecorder is the mock recorder for MockConfig. -type MockConfigMockRecorder struct { - mock *MockConfig -} - -// NewMockConfig creates a new mock instance. -func NewMockConfig(ctrl *gomock.Controller) *MockConfig { - mock := &MockConfig{ctrl: ctrl} - mock.recorder = &MockConfigMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockConfig) EXPECT() *MockConfigMockRecorder { - return m.recorder -} - -// IsFedramp mocks base method. -func (m *MockConfig) IsFedramp() bool { +// FormatCodeApiURL mocks base method. +func (m *MockHTTPClient) FormatCodeApiURL() (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsFedramp") - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsFedramp indicates an expected call of IsFedramp. -func (mr *MockConfigMockRecorder) IsFedramp() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFedramp", reflect.TypeOf((*MockConfig)(nil).IsFedramp)) -} - -// Organization mocks base method. -func (m *MockConfig) Organization() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Organization") + ret := m.ctrl.Call(m, "FormatCodeApiURL") ret0, _ := ret[0].(string) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } -// Organization indicates an expected call of Organization. -func (mr *MockConfigMockRecorder) Organization() *gomock.Call { +// FormatCodeApiURL indicates an expected call of FormatCodeApiURL. +func (mr *MockHTTPClientMockRecorder) FormatCodeApiURL() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Organization", reflect.TypeOf((*MockConfig)(nil).Organization)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FormatCodeApiURL", reflect.TypeOf((*MockHTTPClient)(nil).FormatCodeApiURL)) } diff --git a/scan.go b/scan.go index 8ce49522..db7841bf 100644 --- a/scan.go +++ b/scan.go @@ -19,9 +19,8 @@ package codeclient import ( "context" - "github.com/rs/zerolog" - "github.com/pkg/errors" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/snyk/code-client-go/bundle" @@ -40,7 +39,6 @@ type codeScanner struct { type CodeScanner interface { UploadAndAnalyze( ctx context.Context, - host string, path string, files <-chan string, changedFiles map[string]bool, @@ -65,7 +63,6 @@ func NewCodeScanner( // UploadAndAnalyze returns a fake SARIF response for testing. Use target-service to run analysis on. func (c *codeScanner) UploadAndAnalyze( ctx context.Context, - host string, path string, files <-chan string, changedFiles map[string]bool, @@ -81,7 +78,7 @@ func (c *codeScanner) UploadAndAnalyze( requestId := span.GetTraceId() // use span trace id as code-request-id c.logger.Info().Str("requestId", requestId).Msg("Starting Code analysis.") - b, err := c.bundleManager.Create(span.Context(), host, requestId, path, files, changedFiles) + b, err := c.bundleManager.Create(span.Context(), requestId, path, files, changedFiles) if err != nil { if bundle.IsNoFilesError(err) { return nil, nil, nil @@ -98,7 +95,7 @@ func (c *codeScanner) UploadAndAnalyze( uploadedFiles := b.GetFiles() - b, err = c.bundleManager.Upload(span.Context(), host, b, uploadedFiles) + b, err = c.bundleManager.Upload(span.Context(), b, uploadedFiles) if err != nil { if ctx.Err() != nil { // Only handle errors that are not intentional cancellations msg := "error uploading files..." diff --git a/scan_test.go b/scan_test.go index a335675e..47dfdde2 100644 --- a/scan_test.go +++ b/scan_test.go @@ -56,12 +56,12 @@ func Test_UploadAndAnalyze(t *testing.T) { mockErrorReporter := mocks.NewMockErrorReporter(ctrl) mockBundle := bundle.NewBundle(mocks3.NewMockSnykCodeClient(ctrl), mockInstrumentor, mockErrorReporter, &logger, "", "testRequestId", baseDir, files, []string{}, []string{}) mockBundleManager := mocks2.NewMockBundleManager(ctrl) - mockBundleManager.EXPECT().Create(gomock.Any(), "testHost", "testRequestId", baseDir, gomock.Any(), map[string]bool{}).Return(mockBundle, nil) - mockBundleManager.EXPECT().Upload(gomock.Any(), "testHost", mockBundle, files).Return(mockBundle, nil) + mockBundleManager.EXPECT().Create(gomock.Any(), "testRequestId", baseDir, gomock.Any(), map[string]bool{}).Return(mockBundle, nil) + mockBundleManager.EXPECT().Upload(gomock.Any(), mockBundle, files).Return(mockBundle, nil) codeScanner := codeclient.NewCodeScanner(mockBundleManager, mockInstrumentor, mockErrorReporter, &logger) - response, bundle, err := codeScanner.UploadAndAnalyze(context.Background(), "testHost", baseDir, docs, map[string]bool{}) + response, bundle, err := codeScanner.UploadAndAnalyze(context.Background(), baseDir, docs, map[string]bool{}) require.NoError(t, err) assert.Equal(t, "", bundle.GetBundleHash()) assert.Equal(t, files, bundle.GetFiles()) @@ -81,12 +81,12 @@ func Test_UploadAndAnalyze(t *testing.T) { mockErrorReporter := mocks.NewMockErrorReporter(ctrl) mockBundle := bundle.NewBundle(mocks3.NewMockSnykCodeClient(ctrl), mockInstrumentor, mockErrorReporter, &logger, "testBundleHash", "testRequestId", baseDir, files, []string{}, []string{}) mockBundleManager := mocks2.NewMockBundleManager(ctrl) - mockBundleManager.EXPECT().Create(gomock.Any(), "testHost", "testRequestId", baseDir, gomock.Any(), map[string]bool{}).Return(mockBundle, nil) - mockBundleManager.EXPECT().Upload(gomock.Any(), "testHost", mockBundle, files).Return(mockBundle, nil) + mockBundleManager.EXPECT().Create(gomock.Any(), "testRequestId", baseDir, gomock.Any(), map[string]bool{}).Return(mockBundle, nil) + mockBundleManager.EXPECT().Upload(gomock.Any(), mockBundle, files).Return(mockBundle, nil) codeScanner := codeclient.NewCodeScanner(mockBundleManager, mockInstrumentor, mockErrorReporter, &logger) - response, bundle, err := codeScanner.UploadAndAnalyze(context.Background(), "testHost", baseDir, docs, map[string]bool{}) + response, bundle, err := codeScanner.UploadAndAnalyze(context.Background(), baseDir, docs, map[string]bool{}) require.NoError(t, err) assert.Equal(t, "COMPLETE", response.Status) assert.Equal(t, "testBundleHash", bundle.GetBundleHash())