Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,36 @@ $ go get github.com/snyk/code-client-go

Use the HTTP client to make HTTP requests with configured retriable codes and authorisation headers for Snyk Rest APIs.

Implement the `github.com/snyk/code-client-go/http.Config` interface to configure the Snyk Code API client from applications.

Provide a net/http.Client factory to customize the underlying HTTP protocol behavior (timeouts, etc).

```go
engine := workflow.NewDefaultWorkFlowEngine()
httpClient := http.NewHTTPClient(engine, engine.GetNetworkAccess().GetHttpClient, codeInstrumentor, codeErrorReporter)
import (
"net/http"

"github.com/rs/zerolog"
codehttp "github.com/snyk/code-client-go/http"
)

logger := zerlog.NewLogger(...)
config := newConfigForMyApp()
httpClient := codehttp.NewHTTPClient(logger, config, func() *http.Client { return http.DefaultClient }, codeInstrumentor, codeErrorReporter)
```

The HTTP client exposes a `DoCall` function.

### Configuration

Implement the http.Config interface and 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
engine := workflow.NewDefaultWorkFlowEngine()
snykCode := deepcode.NewSnykCodeClient(engine, httpClient, testutil.NewTestInstrumentor())
snykCode := deepcode.NewSnykCodeClient(logger, httpClient, testutil.NewTestInstrumentor())
```

The Snyk Code Client exposes the following functions:
Expand Down Expand Up @@ -66,4 +80,4 @@ The Code Scanner exposes a `UploadAndAnalyze` function.

### Observability

Under [./observability](./observability) we have defined some observability interfaces which allows consumers of the library to inject their own observability implementations as long as they follow the defined interfaces.
Under [./observability](./observability) we have defined some observability interfaces which allows consumers of the library to inject their own observability implementations as long as they follow the defined interfaces.
8 changes: 4 additions & 4 deletions bundle/bundle_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ package bundle

import (
"context"
"github.com/rs/zerolog"
"github.com/snyk/go-application-framework/pkg/workflow"
"os"
"path/filepath"

"github.com/puzpuzpuz/xsync"
"github.com/rs/zerolog"

"github.com/snyk/code-client-go/deepcode"
"github.com/snyk/code-client-go/internal/util"
"github.com/snyk/code-client-go/observability"
Expand Down Expand Up @@ -58,7 +58,7 @@ type BundleManager interface {
}

func NewBundleManager(
engine workflow.Engine,
logger *zerolog.Logger,
SnykCode deepcode.SnykCodeClient,
instrumentor observability.Instrumentor,
errorReporter observability.ErrorReporter,
Expand All @@ -67,7 +67,7 @@ func NewBundleManager(
SnykCode: SnykCode,
instrumentor: instrumentor,
errorReporter: errorReporter,
logger: engine.GetLogger(),
logger: logger,
supportedExtensions: xsync.NewMapOf[bool](),
supportedConfigFiles: xsync.NewMapOf[bool](),
}
Expand Down
29 changes: 17 additions & 12 deletions bundle/bundle_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ package bundle_test
import (
"bytes"
"context"
"github.com/rs/zerolog"
"os"
"path/filepath"
"strings"
"testing"

"github.com/golang/mock/gomock"
"github.com/snyk/go-application-framework/pkg/workflow"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -62,7 +61,7 @@ func Test_Create(t *testing.T) {
err := os.WriteFile(file, []byte(data), 0600)
require.NoError(t, err)

var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundle, err := bundleManager.Create(context.Background(),
"testHost",
"testRequestId",
Expand Down Expand Up @@ -95,7 +94,7 @@ func Test_Create(t *testing.T) {
err := os.WriteFile(file, []byte(data), 0600)
require.NoError(t, err)

var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundle, err := bundleManager.Create(context.Background(),
"testHost",
"testRequestId",
Expand Down Expand Up @@ -133,7 +132,7 @@ func Test_Create(t *testing.T) {
)
require.NoError(t, err)

var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundle, err := bundleManager.Create(context.Background(),
"testHost",
"testRequestId",
Expand Down Expand Up @@ -170,7 +169,7 @@ func Test_Create(t *testing.T) {
},
)
require.NoError(t, err)
var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundle, err := bundleManager.Create(context.Background(),
"testHost",
"testRequestId",
Expand Down Expand Up @@ -204,7 +203,7 @@ func Test_Create(t *testing.T) {
err := os.WriteFile(file, []byte("some content so the file won't be skipped"), 0600)
assert.Nil(t, err)

var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundle, err := bundleManager.Create(context.Background(),
"testHost",
"testRequestId",
Expand Down Expand Up @@ -253,7 +252,7 @@ func Test_Create(t *testing.T) {
require.NoError(t, err)
}

var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundle, err := bundleManager.Create(context.Background(),
"testHost",
"testRequestId",
Expand Down Expand Up @@ -286,7 +285,7 @@ func Test_Upload(t *testing.T) {
mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(2)
mockErrorReporter := mocks.NewMockErrorReporter(ctrl)

var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
documentURI, bundleFile := createTempFileInDir(t, "bundleDoc.java", 10, temporaryDir)
bundleFileMap := map[string]deepcode2.BundleFile{}
bundleFileMap[documentURI] = bundleFile
Expand All @@ -309,7 +308,7 @@ func Test_Upload(t *testing.T) {
mockInstrumentor.EXPECT().StartSpan(gomock.Any(), gomock.Any()).Return(mockSpan).Times(2)
mockInstrumentor.EXPECT().Finish(gomock.Any()).Times(2)
mockErrorReporter := mocks.NewMockErrorReporter(ctrl)
var bundleManager = bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
var bundleManager = bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)

bundleFileMap := map[string]deepcode2.BundleFile{}
var missingFiles []string
Expand Down Expand Up @@ -353,7 +352,7 @@ func Test_IsSupported_Extensions(t *testing.T) {
}, nil)
mockInstrumentor := mocks.NewMockInstrumentor(ctrl)
mockErrorReporter := mocks.NewMockErrorReporter(ctrl)
bundler := bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
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")
Expand Down Expand Up @@ -392,7 +391,7 @@ func Test_IsSupported_ConfigFiles(t *testing.T) {
}, nil)
mockInstrumentor := mocks.NewMockInstrumentor(ctrl)
mockErrorReporter := mocks.NewMockErrorReporter(ctrl)
bundler := bundle.NewBundleManager(workflow.NewDefaultWorkFlowEngine(), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
bundler := bundle.NewBundleManager(newLogger(t), mockSnykCodeClient, mockInstrumentor, mockErrorReporter)
dir, _ := os.Getwd()

t.Run("should return true for supported config files", func(t *testing.T) {
Expand Down Expand Up @@ -457,3 +456,9 @@ func sliceToChannel(slice []string) <-chan string {

return ch
}

func newLogger(t *testing.T) *zerolog.Logger {
t.Helper()
logger := zerolog.New(zerolog.NewTestWriter(t))
return &logger
}
26 changes: 7 additions & 19 deletions deepcode/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import (
"strconv"

"github.com/rs/zerolog"
"github.com/snyk/go-application-framework/pkg/configuration"
"github.com/snyk/go-application-framework/pkg/workflow"

codeClientHTTP "github.com/snyk/code-client-go/http"
"github.com/snyk/code-client-go/observability"
Expand Down Expand Up @@ -71,17 +69,15 @@ type BundleResponse struct {
type snykCodeClient struct {
httpClient codeClientHTTP.HTTPClient
instrumentor observability.Instrumentor
engine workflow.Engine
logger *zerolog.Logger
}

func NewSnykCodeClient(
engine workflow.Engine,
logger *zerolog.Logger,
httpClient codeClientHTTP.HTTPClient,
instrumentor observability.Instrumentor,
) *snykCodeClient {
logger := engine.GetLogger()
return &snykCodeClient{httpClient, instrumentor, engine, logger}
return &snykCodeClient{httpClient, instrumentor, logger}
}

func (s *snykCodeClient) GetFilters(ctx context.Context, snykCodeApiUrl string) (
Expand All @@ -95,14 +91,12 @@ func (s *snykCodeClient) GetFilters(ctx context.Context, snykCodeApiUrl string)
span := s.instrumentor.StartSpan(ctx, method)
defer s.instrumentor.Finish(span)

c := s.engine.GetConfiguration()

host, err := s.FormatCodeApiURL(snykCodeApiUrl)
if err != nil {
return FiltersResponse{ConfigFiles: nil, Extensions: nil}, err
}

responseBody, err := s.httpClient.DoCall(span.Context(), c, host, "GET", "/filters", nil)
responseBody, err := s.httpClient.DoCall(span.Context(), host, "GET", "/filters", nil)
if err != nil {
return FiltersResponse{ConfigFiles: nil, Extensions: nil}, err
}
Expand Down Expand Up @@ -132,14 +126,12 @@ func (s *snykCodeClient) CreateBundle(
return "", nil, err
}

c := s.engine.GetConfiguration()

host, err := s.FormatCodeApiURL(snykCodeApiUrl)
if err != nil {
return "", nil, err
}

responseBody, err := s.httpClient.DoCall(span.Context(), c, host, "POST", "/bundle", requestBody)
responseBody, err := s.httpClient.DoCall(span.Context(), host, "POST", "/bundle", requestBody)
if err != nil {
return "", nil, err
}
Expand Down Expand Up @@ -176,14 +168,12 @@ func (s *snykCodeClient) ExtendBundle(
return "", nil, err
}

c := s.engine.GetConfiguration()

host, err := s.FormatCodeApiURL(snykCodeApiUrl)
if err != nil {
return "", nil, err
}

responseBody, err := s.httpClient.DoCall(span.Context(), c, host, "PUT", "/bundle/"+bundleHash, requestBody)
responseBody, err := s.httpClient.DoCall(span.Context(), host, "PUT", "/bundle/"+bundleHash, requestBody)
if err != nil {
return "", nil, err
}
Expand All @@ -196,9 +186,7 @@ var codeApiRegex = regexp.MustCompile(`^(deeproxy\.)?`)

// This is only exported for tests.
func (s *snykCodeClient) FormatCodeApiURL(snykCodeApiUrl string) (string, error) {
config := s.engine.GetConfiguration()

if !config.GetBool(configuration.IS_FEDRAMP) {
if !s.httpClient.Config().IsFedramp() {
return snykCodeApiUrl, nil
}
u, err := url.Parse(snykCodeApiUrl)
Expand All @@ -208,7 +196,7 @@ func (s *snykCodeClient) FormatCodeApiURL(snykCodeApiUrl string) (string, error)

u.Host = codeApiRegex.ReplaceAllString(u.Host, "api.")

organization := config.GetString(configuration.ORGANIZATION)
organization := s.httpClient.Config().Organization()
if organization == "" {
return "", errors.New("Organization is required in a fedramp environment")
}
Expand Down
25 changes: 9 additions & 16 deletions deepcode/client_pact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import (
"net/http"
"testing"

"github.com/golang/mock/gomock"
"github.com/pact-foundation/pact-go/dsl"
"github.com/snyk/go-application-framework/pkg/configuration"
"github.com/snyk/go-application-framework/pkg/workflow"
"github.com/stretchr/testify/assert"

"github.com/snyk/code-client-go/deepcode"
codeClientHTTP "github.com/snyk/code-client-go/http"
httpmocks "github.com/snyk/code-client-go/http/mocks"
"github.com/snyk/code-client-go/internal/util"
"github.com/snyk/code-client-go/internal/util/testutil"
)
Expand Down Expand Up @@ -206,11 +206,10 @@ func TestSnykCodeBackendServicePact(t *testing.T) {
func setupPact(t *testing.T) string {
t.Helper()

config := configuration.NewInMemory()
config.Set(configuration.ORGANIZATION, orgUUID)
config.Set(configuration.AUTHENTICATION_TOKEN, "00000000-0000-0000-0000-000000000001")

engine := workflow.NewWorkFlowEngine(config)
ctrl := gomock.NewController(t)
config := httpmocks.NewMockConfig(ctrl)
config.EXPECT().IsFedramp().AnyTimes().Return(false)
config.EXPECT().Organization().AnyTimes().Return(orgUUID)

pact = dsl.Pact{
Consumer: consumer,
Expand All @@ -221,16 +220,13 @@ func setupPact(t *testing.T) string {
// Proactively start service to get access to the port
pact.Setup(true)
snykCodeApiUrl := fmt.Sprintf("http://localhost:%d", pact.Server.Port)
additionalURLs := config.GetStringSlice(configuration.AUTHENTICATION_ADDITIONAL_URLS)
additionalURLs = append(additionalURLs, snykCodeApiUrl)
config.Set(configuration.AUTHENTICATION_ADDITIONAL_URLS, additionalURLs)

instrumentor := testutil.NewTestInstrumentor()
errorReporter := testutil.NewTestErrorReporter()
httpClient := codeClientHTTP.NewHTTPClient(engine, func() *http.Client {
return engine.GetNetworkAccess().GetHttpClient()
httpClient := codeClientHTTP.NewHTTPClient(newLogger(t), config, func() *http.Client {
return http.DefaultClient
}, instrumentor, errorReporter)
client = deepcode.NewSnykCodeClient(engine, httpClient, instrumentor)
client = deepcode.NewSnykCodeClient(newLogger(t), httpClient, instrumentor)

return snykCodeApiUrl
}
Expand All @@ -239,7 +235,6 @@ func getPutPostHeaderMatcher() dsl.MapMatcher {
return dsl.MapMatcher{
"Content-Type": dsl.String("application/octet-stream"),
"Content-Encoding": dsl.String("gzip"),
"Session-Token": dsl.Regex("token fc763eba-0905-41c5-a27f-3934ab26786c", sessionTokenMatcher),
"snyk-org-name": dsl.Regex(orgUUID, uuidMatcher),
"snyk-request-id": getSnykRequestIdMatcher(),
}
Expand All @@ -264,8 +259,6 @@ func TestSnykCodeBackendServicePact_LocalCodeEngine(t *testing.T) {
Headers: dsl.MapMatcher{
"Content-Type": dsl.String("application/json"),
"snyk-request-id": getSnykRequestIdMatcher(),
"Session-Token": dsl.Regex("token fc763eba-0905-41c5-a27f-3934ab26786c", sessionTokenMatcher),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes happened because we stopped setting up the configuration with the authentication token, which behind-the-scenes is used to configure these headers for the local code engine mode. I wanted to keep them so that we can make sure the local code engine mode continues to work during this refactoring but I think I can add a test in snyk/snyk-ls#455 instead to make sure these headers are set

"Authorization": dsl.Regex("token fc763eba-0905-41c5-a27f-3934ab26786c", sessionTokenMatcher),
},
}).WillRespondWith(dsl.Response{
Status: 200,
Expand Down
Loading