From 5b95d6295f2b5fca6d146730342ac814143fa01f Mon Sep 17 00:00:00 2001 From: Abdelrahman Shawki Hassan Date: Thu, 6 Nov 2025 17:36:04 +0100 Subject: [PATCH 1/5] fix: explain requests shouldnt be encoded --- http/http.go | 12 ++++++------ internal/analysis/analysis_legacy.go | 4 ++-- internal/deepcode/client.go | 4 ++-- llm/api_client.go | 12 ++++++------ llm/api_client_test.go | 25 ++++++++++++++++++++++++- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/http/http.go b/http/http.go index 4b9a6ec..70de40e 100644 --- a/http/http.go +++ b/http/http.go @@ -163,7 +163,7 @@ func NewDefaultClientFactory() HTTPClientFactory { return clientFunc } -func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method string) { +func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method string, skipEncoding bool) { // if requestId is empty it will be enriched from the Gateway if len(requestId) > 0 { req.Header.Set("snyk-request-id", requestId) @@ -175,7 +175,7 @@ func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method // https://www.keycdn.com/blog/http-cache-headers req.Header.Set("Cache-Control", "private, max-age=0, no-cache") - if mustBeEncoded(method) { + if mustBeEncoded(method, skipEncoding) { req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Encoding", "gzip") } else { @@ -185,9 +185,9 @@ func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method // EncodeIfNeeded returns a byte buffer for the requestBody. Depending on the request method, it may encode the buffer. // (See http.mustBeEncoded for the list of methods which require encoding the request body.) -func EncodeIfNeeded(method string, requestBody []byte) (*bytes.Buffer, error) { +func EncodeIfNeeded(method string, requestBody []byte, skipEncoding bool) (*bytes.Buffer, error) { b := new(bytes.Buffer) - if mustBeEncoded(method) { + if mustBeEncoded(method, skipEncoding) { enc := encoding.NewEncoder(b) _, err := enc.Write(requestBody) if err != nil { @@ -200,6 +200,6 @@ func EncodeIfNeeded(method string, requestBody []byte) (*bytes.Buffer, error) { } // mustBeEncoded returns true if the request method requires the request body to be encoded. -func mustBeEncoded(method string) bool { - return method == http.MethodPost || method == http.MethodPut +func mustBeEncoded(method string, skipEncoding bool) bool { + return !skipEncoding && (method == http.MethodPost || method == http.MethodPut) } diff --git a/internal/analysis/analysis_legacy.go b/internal/analysis/analysis_legacy.go index 4e39e32..bdeb7c1 100644 --- a/internal/analysis/analysis_legacy.go +++ b/internal/analysis/analysis_legacy.go @@ -165,7 +165,7 @@ func (a *analysisOrchestrator) RunLegacyTest(ctx context.Context, bundleHash str httpMethod := http.MethodPost // Encode the request body - bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(http.MethodPost, requestBody) + bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(http.MethodPost, requestBody, false) if err != nil { a.logger.Err(err).Str("requestBody", string(requestBody)).Msg("error encoding request body") return nil, scan.LegacyScanStatus{}, err @@ -176,7 +176,7 @@ func (a *analysisOrchestrator) RunLegacyTest(ctx context.Context, bundleHash str a.logger.Err(err).Str("method", method).Msg("error creating HTTP request") return nil, scan.LegacyScanStatus{}, err } - codeClientHTTP.AddDefaultHeaders(req, span.GetTraceId(), a.config.Organization(), httpMethod) + codeClientHTTP.AddDefaultHeaders(req, span.GetTraceId(), a.config.Organization(), httpMethod, false) // Make HTTP call resp, err := a.httpClient.Do(req) diff --git a/internal/deepcode/client.go b/internal/deepcode/client.go index 8a5ff5b..78d841c 100644 --- a/internal/deepcode/client.go +++ b/internal/deepcode/client.go @@ -215,7 +215,7 @@ func (s *deepcodeClient) Request( return nil, err } - bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(method, requestBody) + bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(method, requestBody, false) if err != nil { return nil, err } @@ -225,7 +225,7 @@ func (s *deepcodeClient) Request( return nil, err } - codeClientHTTP.AddDefaultHeaders(req, codeClientHTTP.NoRequestId, s.config.Organization(), method) + codeClientHTTP.AddDefaultHeaders(req, codeClientHTTP.NoRequestId, s.config.Organization(), method, false) response, err := s.httpClient.Do(req) if err != nil { diff --git a/llm/api_client.go b/llm/api_client.go index 57e3204..739fc6a 100644 --- a/llm/api_client.go +++ b/llm/api_client.go @@ -44,7 +44,7 @@ func (d *DeepCodeLLMBindingImpl) runExplain(ctx context.Context, options Explain } } - responseBody, err := d.submitRequest(span.Context(), u, requestBody, "") + responseBody, err := d.submitRequest(span.Context(), u, requestBody, "", true) if err != nil { return Explanations{}, err } @@ -63,14 +63,14 @@ func (d *DeepCodeLLMBindingImpl) runExplain(ctx context.Context, options Explain return explains, nil } -func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL, requestBody []byte, orgId string) ([]byte, error) { +func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL, requestBody []byte, orgId string, skipEncoding bool) ([]byte, error) { logger := d.logger.With().Str("method", "submitRequest").Logger() logger.Trace().Str("payload body: %s\n", string(requestBody)).Msg("Marshaled payload") span := d.instrumentor.StartSpan(ctx, "code.SubmitRequest") defer span.Finish() // Encode the request body - bodyBuffer, err := http2.EncodeIfNeeded(http.MethodPost, requestBody) + bodyBuffer, err := http2.EncodeIfNeeded(http.MethodPost, requestBody, skipEncoding) if err != nil { logger.Err(err).Str("requestBody", string(requestBody)).Msg("error encoding request body") return nil, err @@ -82,7 +82,7 @@ func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL return nil, err } - http2.AddDefaultHeaders(req, http2.NoRequestId, orgId, http.MethodPost) + http2.AddDefaultHeaders(req, http2.NoRequestId, orgId, http.MethodPost, skipEncoding) resp, err := d.httpClientFunc().Do(req) //nolint:bodyclose // this seems to be a false positive if err != nil { @@ -152,7 +152,7 @@ func (d *DeepCodeLLMBindingImpl) runAutofix(ctx context.Context, options Autofix } logger.Info().Msg("Started obtaining autofix Response") - responseBody, err := d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId) + responseBody, err := d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId, false) logger.Info().Msg("Finished obtaining autofix Response") if err != nil { @@ -228,7 +228,7 @@ func (d *DeepCodeLLMBindingImpl) submitAutofixFeedback(ctx context.Context, opti } logger.Info().Msg("Started obtaining autofix Response") - _, err = d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId) + _, err = d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId, false) logger.Info().Msg("Finished obtaining autofix Response") return err diff --git a/llm/api_client_test.go b/llm/api_client_test.go index 512a512..bf1ec1e 100644 --- a/llm/api_client_test.go +++ b/llm/api_client_test.go @@ -264,7 +264,30 @@ func testLogger(t *testing.T) *zerolog.Logger { func TestAddDefaultHeadersWithExistingHeaders(t *testing.T) { req := &http.Request{Header: http.Header{"Existing-Header": {"existing-value"}}} - http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodGet) + http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodGet, false) + + cacheControl := req.Header.Get("Cache-Control") + contentType := req.Header.Get("Content-Type") + existingHeader := req.Header.Get("Existing-Header") + + if cacheControl != "private, max-age=0, no-cache" { + t.Errorf("Expected Cache-Control header to be 'private, max-age=0, no-cache', got %s", cacheControl) + } + + if contentType != "application/json" { + t.Errorf("Expected Content-Type header to be 'application/json', got %s", contentType) + } + + if existingHeader != "existing-value" { + t.Errorf("Expected Existing-Header to be 'existing-value', got %s", existingHeader) + } +} + +// Test with existing headers +func TestAddDefaultHeadersWithSkipEncodingEnabled(t *testing.T) { + req := &http.Request{Header: http.Header{"Existing-Header": {"existing-value"}}} + + http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodPost, true) cacheControl := req.Header.Get("Cache-Control") contentType := req.Header.Get("Content-Type") From 66dc61c90e3a5ad282cf8de95e3f99ac410085fc Mon Sep 17 00:00:00 2001 From: Abdelrahman Shawki Hassan Date: Thu, 6 Nov 2025 19:21:51 +0100 Subject: [PATCH 2/5] refactor: revert boolean --- http/http.go | 12 ++++++------ internal/analysis/analysis_legacy.go | 2 +- internal/deepcode/client.go | 2 +- llm/api_client.go | 12 ++++++------ llm/api_client_test.go | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/http/http.go b/http/http.go index 70de40e..6e5afbc 100644 --- a/http/http.go +++ b/http/http.go @@ -163,7 +163,7 @@ func NewDefaultClientFactory() HTTPClientFactory { return clientFunc } -func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method string, skipEncoding bool) { +func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method string, needsEncoding bool) { // if requestId is empty it will be enriched from the Gateway if len(requestId) > 0 { req.Header.Set("snyk-request-id", requestId) @@ -175,7 +175,7 @@ func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method // https://www.keycdn.com/blog/http-cache-headers req.Header.Set("Cache-Control", "private, max-age=0, no-cache") - if mustBeEncoded(method, skipEncoding) { + if mustBeEncoded(method, needsEncoding) { req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Encoding", "gzip") } else { @@ -185,9 +185,9 @@ func AddDefaultHeaders(req *http.Request, requestId string, orgId string, method // EncodeIfNeeded returns a byte buffer for the requestBody. Depending on the request method, it may encode the buffer. // (See http.mustBeEncoded for the list of methods which require encoding the request body.) -func EncodeIfNeeded(method string, requestBody []byte, skipEncoding bool) (*bytes.Buffer, error) { +func EncodeIfNeeded(method string, requestBody []byte, needsEncoding bool) (*bytes.Buffer, error) { b := new(bytes.Buffer) - if mustBeEncoded(method, skipEncoding) { + if mustBeEncoded(method, needsEncoding) { enc := encoding.NewEncoder(b) _, err := enc.Write(requestBody) if err != nil { @@ -200,6 +200,6 @@ func EncodeIfNeeded(method string, requestBody []byte, skipEncoding bool) (*byte } // mustBeEncoded returns true if the request method requires the request body to be encoded. -func mustBeEncoded(method string, skipEncoding bool) bool { - return !skipEncoding && (method == http.MethodPost || method == http.MethodPut) +func mustBeEncoded(method string, needsEncoding bool) bool { + return needsEncoding && (method == http.MethodPost || method == http.MethodPut) } diff --git a/internal/analysis/analysis_legacy.go b/internal/analysis/analysis_legacy.go index bdeb7c1..f29b174 100644 --- a/internal/analysis/analysis_legacy.go +++ b/internal/analysis/analysis_legacy.go @@ -176,7 +176,7 @@ func (a *analysisOrchestrator) RunLegacyTest(ctx context.Context, bundleHash str a.logger.Err(err).Str("method", method).Msg("error creating HTTP request") return nil, scan.LegacyScanStatus{}, err } - codeClientHTTP.AddDefaultHeaders(req, span.GetTraceId(), a.config.Organization(), httpMethod, false) + codeClientHTTP.AddDefaultHeaders(req, span.GetTraceId(), a.config.Organization(), httpMethod, true) // Make HTTP call resp, err := a.httpClient.Do(req) diff --git a/internal/deepcode/client.go b/internal/deepcode/client.go index 78d841c..53235c0 100644 --- a/internal/deepcode/client.go +++ b/internal/deepcode/client.go @@ -225,7 +225,7 @@ func (s *deepcodeClient) Request( return nil, err } - codeClientHTTP.AddDefaultHeaders(req, codeClientHTTP.NoRequestId, s.config.Organization(), method, false) + codeClientHTTP.AddDefaultHeaders(req, codeClientHTTP.NoRequestId, s.config.Organization(), method, true) response, err := s.httpClient.Do(req) if err != nil { diff --git a/llm/api_client.go b/llm/api_client.go index 739fc6a..ddbba2c 100644 --- a/llm/api_client.go +++ b/llm/api_client.go @@ -44,7 +44,7 @@ func (d *DeepCodeLLMBindingImpl) runExplain(ctx context.Context, options Explain } } - responseBody, err := d.submitRequest(span.Context(), u, requestBody, "", true) + responseBody, err := d.submitRequest(span.Context(), u, requestBody, "", false) if err != nil { return Explanations{}, err } @@ -63,14 +63,14 @@ func (d *DeepCodeLLMBindingImpl) runExplain(ctx context.Context, options Explain return explains, nil } -func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL, requestBody []byte, orgId string, skipEncoding bool) ([]byte, error) { +func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL, requestBody []byte, orgId string, needsEncoding bool) ([]byte, error) { logger := d.logger.With().Str("method", "submitRequest").Logger() logger.Trace().Str("payload body: %s\n", string(requestBody)).Msg("Marshaled payload") span := d.instrumentor.StartSpan(ctx, "code.SubmitRequest") defer span.Finish() // Encode the request body - bodyBuffer, err := http2.EncodeIfNeeded(http.MethodPost, requestBody, skipEncoding) + bodyBuffer, err := http2.EncodeIfNeeded(http.MethodPost, requestBody, needsEncoding) if err != nil { logger.Err(err).Str("requestBody", string(requestBody)).Msg("error encoding request body") return nil, err @@ -82,7 +82,7 @@ func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL return nil, err } - http2.AddDefaultHeaders(req, http2.NoRequestId, orgId, http.MethodPost, skipEncoding) + http2.AddDefaultHeaders(req, http2.NoRequestId, orgId, http.MethodPost, needsEncoding) resp, err := d.httpClientFunc().Do(req) //nolint:bodyclose // this seems to be a false positive if err != nil { @@ -152,7 +152,7 @@ func (d *DeepCodeLLMBindingImpl) runAutofix(ctx context.Context, options Autofix } logger.Info().Msg("Started obtaining autofix Response") - responseBody, err := d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId, false) + responseBody, err := d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId, true) logger.Info().Msg("Finished obtaining autofix Response") if err != nil { @@ -228,7 +228,7 @@ func (d *DeepCodeLLMBindingImpl) submitAutofixFeedback(ctx context.Context, opti } logger.Info().Msg("Started obtaining autofix Response") - _, err = d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId, false) + _, err = d.submitRequest(span.Context(), endpoint, requestBody, options.CodeRequestContext.Org.PublicId, true) logger.Info().Msg("Finished obtaining autofix Response") return err diff --git a/llm/api_client_test.go b/llm/api_client_test.go index bf1ec1e..d49b22d 100644 --- a/llm/api_client_test.go +++ b/llm/api_client_test.go @@ -264,7 +264,7 @@ func testLogger(t *testing.T) *zerolog.Logger { func TestAddDefaultHeadersWithExistingHeaders(t *testing.T) { req := &http.Request{Header: http.Header{"Existing-Header": {"existing-value"}}} - http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodGet, false) + http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodPost, true) cacheControl := req.Header.Get("Cache-Control") contentType := req.Header.Get("Content-Type") @@ -274,7 +274,7 @@ func TestAddDefaultHeadersWithExistingHeaders(t *testing.T) { t.Errorf("Expected Cache-Control header to be 'private, max-age=0, no-cache', got %s", cacheControl) } - if contentType != "application/json" { + if contentType != "application/octet-stream" { t.Errorf("Expected Content-Type header to be 'application/json', got %s", contentType) } @@ -287,7 +287,7 @@ func TestAddDefaultHeadersWithExistingHeaders(t *testing.T) { func TestAddDefaultHeadersWithSkipEncodingEnabled(t *testing.T) { req := &http.Request{Header: http.Header{"Existing-Header": {"existing-value"}}} - http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodPost, true) + http2.AddDefaultHeaders(req, http2.NoRequestId, "", http.MethodPost, false) cacheControl := req.Header.Get("Cache-Control") contentType := req.Header.Get("Content-Type") From b539b37eaf68f919531f78194ec54eb1304f3c7f Mon Sep 17 00:00:00 2001 From: Abdelrahman Shawki Hassan Date: Thu, 6 Nov 2025 19:28:56 +0100 Subject: [PATCH 3/5] fix: encode for legacy tests --- internal/analysis/analysis_legacy.go | 2 +- internal/deepcode/client.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/analysis/analysis_legacy.go b/internal/analysis/analysis_legacy.go index f29b174..993c3e3 100644 --- a/internal/analysis/analysis_legacy.go +++ b/internal/analysis/analysis_legacy.go @@ -165,7 +165,7 @@ func (a *analysisOrchestrator) RunLegacyTest(ctx context.Context, bundleHash str httpMethod := http.MethodPost // Encode the request body - bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(http.MethodPost, requestBody, false) + bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(http.MethodPost, requestBody, true) if err != nil { a.logger.Err(err).Str("requestBody", string(requestBody)).Msg("error encoding request body") return nil, scan.LegacyScanStatus{}, err diff --git a/internal/deepcode/client.go b/internal/deepcode/client.go index 53235c0..4000c03 100644 --- a/internal/deepcode/client.go +++ b/internal/deepcode/client.go @@ -215,7 +215,7 @@ func (s *deepcodeClient) Request( return nil, err } - bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(method, requestBody, false) + bodyBuffer, err := codeClientHTTP.EncodeIfNeeded(method, requestBody, true) if err != nil { return nil, err } From 40b7c82d128f4c5fdda6f2607c806da015996988 Mon Sep 17 00:00:00 2001 From: Abdelrahman Shawki Hassan Date: Thu, 6 Nov 2025 20:08:07 +0100 Subject: [PATCH 4/5] chore: add tests --- llm/api_client_test.go | 150 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/llm/api_client_test.go b/llm/api_client_test.go index d49b22d..142817c 100644 --- a/llm/api_client_test.go +++ b/llm/api_client_test.go @@ -373,3 +373,153 @@ func TestAutofixRequestBody(t *testing.T) { assert.Equal(t, expectedBody, body) } + +func TestRunExplain_WithHeaderValidation(t *testing.T) { + t.Run("vulnerability explanation with headers", func(t *testing.T) { + ruleKey := "test-rule-key" + derivation := "test-derivation" + ruleMessage := "test-rule-message" + + expectedResponse := Explanations{ + "explanation1": "This is the first explanation", + "explanation2": "This is the second explanation", + } + + explainResponse := explainResponse{ + Status: completeStatus, + Explanation: expectedResponse, + } + + responseBodyBytes, err := json.Marshal(explainResponse) + require.NoError(t, err) + + // Create a test server that validates headers + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Verify headers + assert.Equal(t, "private, max-age=0, no-cache", r.Header.Get("Cache-Control")) + assert.Equal(t, "application/json", r.Header.Get("Content-Type")) + assert.Equal(t, http.MethodPost, r.Method) + + // Verify request body + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + + var requestData explainVulnerabilityRequest + err = json.Unmarshal(body, &requestData) + require.NoError(t, err) + + assert.Equal(t, ruleKey, requestData.RuleId) + assert.Equal(t, derivation, requestData.Derivation) + assert.Equal(t, ruleMessage, requestData.RuleMessage) + assert.Equal(t, SHORT, requestData.ExplanationLength) + + // Send response + w.WriteHeader(http.StatusOK) + _, _ = w.Write(responseBodyBytes) + })) + defer server.Close() + + // Parse server URL + u, err := url.Parse(server.URL) + require.NoError(t, err) + + // Create options + options := ExplainOptions{ + RuleKey: ruleKey, + Derivation: derivation, + RuleMessage: ruleMessage, + Endpoint: u, + } + + // Create DeepCodeLLMBinding + d := NewDeepcodeLLMBinding() + + // Run the test + ctx := t.Context() + ctx = observability.GetContextWithTraceId(ctx, "test-trace-id") + + result, err := d.runExplain(ctx, options) + + // Verify results + require.NoError(t, err) + assert.Equal(t, expectedResponse, result) + }) + + t.Run("fix explanation with base64 encoded diffs and headers", func(t *testing.T) { + ruleKey := "test-rule-key" + testDiffs := []string{ + "--- a/file.txt\n+++ b/file.txt\n@@ -1,1 +1,1 @@\n-old line\n+new line\n", + } + + expectedResponse := Explanations{ + "explanation1": "This explains the fix", + } + + explainResponse := explainResponse{ + Status: completeStatus, + Explanation: expectedResponse, + } + + responseBodyBytes, err := json.Marshal(explainResponse) + require.NoError(t, err) + + // Create a test server that validates headers and base64 encoded diffs + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Verify headers + assert.Equal(t, "private, max-age=0, no-cache", r.Header.Get("Cache-Control")) + assert.Equal(t, "application/json", r.Header.Get("Content-Type")) + assert.Equal(t, http.MethodPost, r.Method) + + // Verify request body + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + + var requestData explainFixRequest + err = json.Unmarshal(body, &requestData) + require.NoError(t, err) + + assert.Equal(t, ruleKey, requestData.RuleId) + assert.Equal(t, SHORT, requestData.ExplanationLength) + + // Verify diffs are base64 encoded + require.Len(t, requestData.Diffs, 1) + + // Decode the base64 diff to verify it was encoded properly + decodedDiff, err := base64.StdEncoding.DecodeString(requestData.Diffs[0]) + require.NoError(t, err) + + // The prepareDiffs function strips --- and +++ headers and adds a newline + expectedDecodedDiff := "@@ -1,1 +1,1 @@\n-old line\n+new line\n\n" + assert.Equal(t, expectedDecodedDiff, string(decodedDiff)) + + // Send response + w.WriteHeader(http.StatusOK) + _, _ = w.Write(responseBodyBytes) + })) + defer server.Close() + + // Parse server URL + u, err := url.Parse(server.URL) + require.NoError(t, err) + + // Create options + options := ExplainOptions{ + RuleKey: ruleKey, + Diffs: testDiffs, + Endpoint: u, + } + + // Create DeepCodeLLMBinding + d := NewDeepcodeLLMBinding() + + // Run the test + ctx := t.Context() + ctx = observability.GetContextWithTraceId(ctx, "test-trace-id") + + result, err := d.runExplain(ctx, options) + + // Verify results + require.NoError(t, err) + assert.Equal(t, expectedResponse, result) + }) +} From 3d866c0f5b92be6b32c555a8bf1f9d5fdbe648a1 Mon Sep 17 00:00:00 2001 From: Abdelrahman Shawki Hassan Date: Thu, 6 Nov 2025 20:14:00 +0100 Subject: [PATCH 5/5] chore: lint --- llm/api_client_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/llm/api_client_test.go b/llm/api_client_test.go index 142817c..5bd9165 100644 --- a/llm/api_client_test.go +++ b/llm/api_client_test.go @@ -385,12 +385,12 @@ func TestRunExplain_WithHeaderValidation(t *testing.T) { "explanation2": "This is the second explanation", } - explainResponse := explainResponse{ + response := explainResponse{ Status: completeStatus, Explanation: expectedResponse, } - responseBodyBytes, err := json.Marshal(explainResponse) + responseBodyBytes, err := json.Marshal(response) require.NoError(t, err) // Create a test server that validates headers @@ -401,8 +401,8 @@ func TestRunExplain_WithHeaderValidation(t *testing.T) { assert.Equal(t, http.MethodPost, r.Method) // Verify request body - body, err := io.ReadAll(r.Body) - require.NoError(t, err) + body, readErr := io.ReadAll(r.Body) + require.NoError(t, readErr) var requestData explainVulnerabilityRequest err = json.Unmarshal(body, &requestData) @@ -455,12 +455,12 @@ func TestRunExplain_WithHeaderValidation(t *testing.T) { "explanation1": "This explains the fix", } - explainResponse := explainResponse{ + response := explainResponse{ Status: completeStatus, Explanation: expectedResponse, } - responseBodyBytes, err := json.Marshal(explainResponse) + responseBodyBytes, err := json.Marshal(response) require.NoError(t, err) // Create a test server that validates headers and base64 encoded diffs @@ -471,8 +471,8 @@ func TestRunExplain_WithHeaderValidation(t *testing.T) { assert.Equal(t, http.MethodPost, r.Method) // Verify request body - body, err := io.ReadAll(r.Body) - require.NoError(t, err) + body, readErr := io.ReadAll(r.Body) + require.NoError(t, readErr) var requestData explainFixRequest err = json.Unmarshal(body, &requestData) @@ -485,8 +485,8 @@ func TestRunExplain_WithHeaderValidation(t *testing.T) { require.Len(t, requestData.Diffs, 1) // Decode the base64 diff to verify it was encoded properly - decodedDiff, err := base64.StdEncoding.DecodeString(requestData.Diffs[0]) - require.NoError(t, err) + decodedDiff, decodeErr := base64.StdEncoding.DecodeString(requestData.Diffs[0]) + require.NoError(t, decodeErr) // The prepareDiffs function strips --- and +++ headers and adds a newline expectedDecodedDiff := "@@ -1,1 +1,1 @@\n-old line\n+new line\n\n"