Skip to content
Open
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
4 changes: 4 additions & 0 deletions cliv2/cmd/cliv2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import (
ignoreworkflow "github.com/snyk/go-application-framework/pkg/local_workflows/ignore_workflow"
"github.com/snyk/go-application-framework/pkg/local_workflows/output_workflow"
"github.com/snyk/go-application-framework/pkg/networking"
"github.com/snyk/go-application-framework/pkg/networking/middleware"
"github.com/snyk/go-application-framework/pkg/runtimeinfo"
"github.com/snyk/go-application-framework/pkg/ui"
"github.com/snyk/go-application-framework/pkg/utils"
Expand Down Expand Up @@ -81,6 +82,7 @@ const (
disable_analytics_flag string = "DISABLE_ANALYTICS"
debug_level_flag string = "log-level"
integrationNameFlag string = "integration-name"
retryAttemptsFlag string = "retry-attempts"
)

type JsonErrorStruct struct {
Expand Down Expand Up @@ -113,6 +115,7 @@ func initApplicationConfiguration(config configuration.Configuration) {
config.AddAlternativeKeys(configuration.PREVIEW_FEATURES_ENABLED, []string{"snyk_preview"})
config.AddAlternativeKeys(configuration.LOG_LEVEL, []string{debug_level_flag})
config.AddAlternativeKeys(configuration.INTEGRATION_NAME, []string{integrationNameFlag})
config.AddAlternativeKeys(middleware.ConfigurationKeyRetryAttempts, []string{"snyk_retry_attempts", retryAttemptsFlag})
}

func getFullCommandString(cmd *cobra.Command) string {
Expand Down Expand Up @@ -338,6 +341,7 @@ func getGlobalFLags() *pflag.FlagSet {
globalFLags.Bool(disable_analytics_flag, false, "")
globalFLags.String(debug_level_flag, "debug", "")
globalFLags.String(integrationNameFlag, "", "")
globalFLags.Int(retryAttemptsFlag, -1, "")
return globalFLags
}

Expand Down
2 changes: 1 addition & 1 deletion cliv2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/snyk/code-client-go v1.26.1
github.com/snyk/container-cli v0.0.0-20260213211631-cd2b2cf8f3ea
github.com/snyk/error-catalog-golang-public v0.0.0-20260205094614-116c03822905
github.com/snyk/go-application-framework v0.0.0-20260219121502-ba9cecc54f7d
github.com/snyk/go-application-framework v0.0.0-20260224120801-752ad9103b28
github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65
github.com/snyk/snyk-iac-capture v0.6.5
github.com/snyk/snyk-ls v0.0.0-20260224142246-0af54371c7aa
Expand Down
4 changes: 2 additions & 2 deletions cliv2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,8 @@ github.com/snyk/dep-graph/go v0.0.0-20251219134535-fcb262dc6d25 h1:dwJ4Kdp4c5aaW
github.com/snyk/dep-graph/go v0.0.0-20251219134535-fcb262dc6d25/go.mod h1:hTr91da/4ze2nk9q6ZW1BmfM2Z8rLUZSEZ3kK+6WGpc=
github.com/snyk/error-catalog-golang-public v0.0.0-20260205094614-116c03822905 h1:pUe6iOWHEOFY0t4u4ssXeTqpMmZBu1xq06VBFI9zUik=
github.com/snyk/error-catalog-golang-public v0.0.0-20260205094614-116c03822905/go.mod h1:Ytttq7Pw4vOCu9NtRQaOeDU2dhBYUyNBe6kX4+nIIQ4=
github.com/snyk/go-application-framework v0.0.0-20260219121502-ba9cecc54f7d h1:BKf/UnLaPnLlM/hrsuk28AJv6KqxGQUrz7bkrkvpm8o=
github.com/snyk/go-application-framework v0.0.0-20260219121502-ba9cecc54f7d/go.mod h1:6MuCxSVGYNY3gfNKPZc5oMuy5/Q+yxbLxKnVtOMSB8Y=
github.com/snyk/go-application-framework v0.0.0-20260224120801-752ad9103b28 h1:oiM8WdWfIVJb8Al+lFMnJRiRHhgd1Vsjf1dF1eB0F6Y=
github.com/snyk/go-application-framework v0.0.0-20260224120801-752ad9103b28/go.mod h1:6MuCxSVGYNY3gfNKPZc5oMuy5/Q+yxbLxKnVtOMSB8Y=
github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65 h1:CEQuYv0Go6MEyRCD3YjLYM2u3Oxkx8GpCpFBd4rUTUk=
github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65/go.mod h1:88KbbvGYlmLgee4OcQ19yr0bNpXpOr2kciOthaSzCAg=
github.com/snyk/policy-engine v1.1.3 h1:MU+K8pxbN6VZ9P5wALUt8BwTjrPDpoEtmTtQqj7sKfY=
Expand Down
94 changes: 94 additions & 0 deletions test/jest/acceptance/retry-attempts.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { runSnykCLI } from '../util/runSnykCLI';
import { fakeServer, getFirstIPv4Address } from '../../acceptance/fake-server';
import { getAvailableServerPort } from '../util/getServerPort';

jest.setTimeout(1000 * 60);

describe('retry-attempts configuration', () => {
let server: ReturnType<typeof fakeServer>;
let env: Record<string, string>;
let port: string;
const baseApi = '/api/v1';
const ipAddress = getFirstIPv4Address();

beforeAll(async () => {
port = await getAvailableServerPort(process);
env = {
...process.env,
SNYK_API: `http://${ipAddress}:${port}${baseApi}`,
SNYK_HOST: `http://${ipAddress}:${port}`,
SNYK_TOKEN: '123456789',
SNYK_DISABLE_ANALYTICS: '1',
};
server = fakeServer(baseApi, env.SNYK_TOKEN);
await new Promise<void>((resolve) => server.listen(Number(port), resolve));
});

afterEach(() => {
server.restore();
});

afterAll((done) => {
server.close(() => {
done();
});
});

it('retries on 500 error and succeeds when server recovers', async () => {
// First request returns 500, second returns 200
server.setStatusCodes([500, 200]);

const { code } = await runSnykCLI(
`whoami --experimental --retry-attempts=3`,
{
env,
},
);

expect(code).toBe(0);
expect(server.getRequests().length).toBeGreaterThanOrEqual(2);
});

it('retries multiple times on repeated 500 errors', async () => {
// First two requests return 500, third returns 200
server.setStatusCodes([500, 500, 200]);

const { code } = await runSnykCLI(
`whoami --experimental --retry-attempts=3`,
{
env,
},
);

expect(code).toBe(0);
expect(server.getRequests().length).toBeGreaterThanOrEqual(3);
});

it('fails after exhausting retry attempts', async () => {
// All requests return 500
server.setStatusCode(500);

const { code } = await runSnykCLI(
`whoami --experimental --retry-attempts=2`,
{
env,
},
);

expect(code).not.toBe(0);
});

it('accepts SNYK_RETRY_ATTEMPTS env var', async () => {
server.setStatusCodes([500, 200]);

const { code } = await runSnykCLI(`whoami --experimental`, {
env: {
...env,
SNYK_RETRY_ATTEMPTS: '3',
},
});

expect(code).toBe(0);
expect(server.getRequests().length).toBeGreaterThanOrEqual(2);
});
});