From 8cb907fbaf59e1a006134550032122ed050ef98c Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Fri, 15 May 2026 17:00:38 +0800 Subject: [PATCH 1/8] feat: integrate Atlas Cloud provider --- .env.example | 5 +++ .gitignore | 4 +- ATLAS_CLOUD_REVIEW.md | 42 +++++++++++++++++++++ README.md | 21 +++++++++++ autofix/ai.go | 13 ++++++- autofix/ai_test.go | 4 +- autofix/atlas.go | 68 ++++++++++++++++++++++++++++++++++ autofix/atlas_test.go | 85 +++++++++++++++++++++++++++++++++++++++++++ cmd/gosec/main.go | 9 ++++- 9 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 .env.example create mode 100644 ATLAS_CLOUD_REVIEW.md create mode 100644 autofix/atlas.go create mode 100644 autofix/atlas_test.go diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..b393ec20d8 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +GOSEC_AI_API_KEY=your_atlas_cloud_api_key +ATLASCLOUD_API_KEY=your_atlas_cloud_api_key +GOSEC_AI_PROVIDER=atlas +GOSEC_AI_MODEL=atlas +GOSEC_AI_BASE_URL=https://api.atlascloud.ai/v1 diff --git a/.gitignore b/.gitignore index d9f5c1fc99..eac8f99dcb 100644 --- a/.gitignore +++ b/.gitignore @@ -33,10 +33,12 @@ coverage.out *.prof .DS_Store +.env.local +.env.*.local .vscode .idea # SBOMs generated during CI /bom.json -1 \ No newline at end of file +1 diff --git a/ATLAS_CLOUD_REVIEW.md b/ATLAS_CLOUD_REVIEW.md new file mode 100644 index 0000000000..b25ead6534 --- /dev/null +++ b/ATLAS_CLOUD_REVIEW.md @@ -0,0 +1,42 @@ +# Atlas Cloud Provider Review + +## What Changed + +- Added a first-class `atlas` AI provider preset in `autofix`. +- Defaulted Atlas Cloud traffic to `https://api.atlascloud.ai/v1`. +- Added Atlas model aliases: + - `atlas` -> `deepseek-ai/deepseek-v4-flash` + - `atlas-deepseek-v4-flash` -> `deepseek-ai/deepseek-v4-flash` + - `atlas-qwen3-coder-next` -> `qwen/qwen3-coder-next` + - `atlas-kimi-k2.6` -> `moonshotai/kimi-k2.6` + - `atlas/` and `atlas:` for direct model pass-through +- Added `ATLASCLOUD_API_KEY` fallback support in the CLI when `-ai-api-provider` starts with `atlas`. +- Updated README with Atlas Cloud usage, examples, and the official link: + `https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=gosec` +- Added `.env.example` for local setup and ignored `.env.local` files. + +## Files Changed + +- `autofix/ai.go` +- `autofix/atlas.go` +- `autofix/ai_test.go` +- `autofix/atlas_test.go` +- `cmd/gosec/main.go` +- `README.md` +- `.gitignore` +- `.env.example` + +## Local Validation Plan + +- Unit test the `autofix` package. +- Build and run `gosec` against a temporary vulnerable sample with `-ai-api-provider=atlas`. +- Validate direct Atlas Cloud non-stream and stream responses with the provided API key. + +## Validation Results + +- `go test ./...` passed. +- Atlas Cloud `/v1/models` responded successfully and returned account-accessible model IDs. +- Atlas Cloud non-stream chat completion succeeded with `deepseek-ai/deepseek-v4-flash`. +- Atlas Cloud stream chat completion succeeded with `deepseek-ai/deepseek-v4-flash`. +- `gosec` binary integration succeeded: + `-ai-api-provider=atlas` generated a live Autofix for a temporary `G402` sample. diff --git a/README.md b/README.md index 589727b812..c38c793a39 100644 --- a/README.md +++ b/README.md @@ -398,6 +398,14 @@ line arguments: - `ai-api-provider`: the name of the AI API provider. Supported providers: + - **Atlas Cloud**: `atlas` (default model + `deepseek-ai/deepseek-v4-flash`), + `atlas-deepseek-v4-flash`, + `atlas-qwen3-coder-next`, `atlas-kimi-k2.6`, or + `atlas/` / `atlas:` for any Atlas Cloud + hosted chat model. + Atlas Cloud is an OpenAI-compatible provider available at + [atlascloud.ai](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=gosec) - **Gemini**: `gemini-3-pro-preview` (default), `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.5-flash-lite` @@ -411,6 +419,8 @@ line arguments: (requires `ai-base-url`) - `ai-api-key` or set the environment variable `GOSEC_AI_API_KEY`: the key to access the AI API + - For Atlas Cloud, you can also set `ATLASCLOUD_API_KEY` + and use the default base URL `https://api.atlascloud.ai/v1` - For Gemini, you can create an API key following [these instructions](https://ai.google.dev/gemini-api/docs/api-key) - For Claude, get your API key from @@ -420,12 +430,23 @@ line arguments: - `ai-base-url`: (optional) custom base URL for OpenAI-compatible APIs (e.g., Azure OpenAI, LocalAI, Ollama) + - Atlas Cloud uses `https://api.atlascloud.ai/v1` by default, + so `ai-base-url` is optional for the built-in `atlas` + provider - `ai-skip-ssl`: (optional) skip SSL certificate verification for AI API (useful for self-signed certificates) **Examples:** ```bash +# Using Atlas Cloud with the default DeepSeek V4 Flash model +export ATLASCLOUD_API_KEY="your_key" +gosec -ai-api-provider="atlas" ./... + +# Using Atlas Cloud with an explicit hosted model +gosec -ai-api-provider="atlas:qwen/qwen3-coder-next" \ + -ai-api-key="your_key" ./... + # Using Gemini gosec -ai-api-provider="gemini-3-pro-preview" \ -ai-api-key="your_key" ./... diff --git a/autofix/ai.go b/autofix/ai.go index f8d0690a5c..0c7a6bc3e0 100644 --- a/autofix/ai.go +++ b/autofix/ai.go @@ -12,6 +12,7 @@ import ( const ( AIProviderFlagHelp = `AI API provider to generate auto fixes to issues. Valid options are: + - atlas (Atlas Cloud default), atlas-deepseek-v4-flash, atlas-qwen3-coder-next, atlas-kimi-k2.6, atlas/, atlas:; - gemini-3-pro-preview (gemini, default), gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite; - claude-sonnet-4-6 (claude, default), claude-opus-4-7, claude-opus-4-6, claude-sonnet-4-5, claude-opus-4-5, claude-haiku-4-5; - gpt-5.4 (openai, default), gpt-5.4-mini, gpt-5.4-nano` @@ -32,6 +33,14 @@ func GenerateSolution(model, aiAPIKey, baseURL string, skipSSL bool, issues []*i var client GenAIClient switch { + case model == "atlas" || strings.HasPrefix(model, "atlas-") || strings.HasPrefix(model, "atlas/") || strings.HasPrefix(model, "atlas:"): + config := AtlasConfig{ + Model: model, + APIKey: aiAPIKey, + BaseURL: baseURL, + SkipSSL: skipSSL, + } + client, err = NewAtlasClient(config) case strings.HasPrefix(model, "claude"): client, err = NewClaudeClient(model, aiAPIKey) case strings.HasPrefix(model, "gemini"): @@ -76,11 +85,11 @@ func generateSolution(client GenAIClient, issues []*issue.Issue) error { prompt := fmt.Sprintf(AIPrompt, issue.What) resp, err := client.GenerateSolution(ctx, prompt) if err != nil { - return fmt.Errorf("generating autofix with gemini: %w", err) + return fmt.Errorf("generating autofix with AI provider: %w", err) } if resp == "" { - return errors.New("no autofix returned by gemini") + return errors.New("no autofix returned by AI provider") } issue.Autofix = resp diff --git a/autofix/ai_test.go b/autofix/ai_test.go index ea012f5bad..3a6c14a292 100644 --- a/autofix/ai_test.go +++ b/autofix/ai_test.go @@ -53,7 +53,7 @@ func TestGenerateSolutionByGemini_NoCandidates(t *testing.T) { err := generateSolution(mockClient, issues) // Assert - require.EqualError(t, err, "no autofix returned by gemini") + require.EqualError(t, err, "no autofix returned by AI provider") mock.AssertExpectationsForObjects(t, mockClient) } @@ -70,7 +70,7 @@ func TestGenerateSolutionByGemini_APIError(t *testing.T) { err := generateSolution(mockClient, issues) // Assert - require.EqualError(t, err, "generating autofix with gemini: API error") + require.EqualError(t, err, "generating autofix with AI provider: API error") mock.AssertExpectationsForObjects(t, mockClient) } diff --git a/autofix/atlas.go b/autofix/atlas.go new file mode 100644 index 0000000000..9f987707a8 --- /dev/null +++ b/autofix/atlas.go @@ -0,0 +1,68 @@ +package autofix + +import "strings" + +const ( + ModelAtlasDefault = "deepseek-ai/deepseek-v4-flash" + ModelAtlasDeepSeekV4Flash = "deepseek-ai/deepseek-v4-flash" + ModelAtlasQwenCoderNext = "qwen/qwen3-coder-next" + ModelAtlasKimiK26 = "moonshotai/kimi-k2.6" + + DefaultAtlasBaseURL = "https://api.atlascloud.ai/v1" +) + +type AtlasConfig struct { + Model string + APIKey string `json:"-"` + BaseURL string + MaxTokens int + Temperature float64 + SkipSSL bool +} + +func NewAtlasClient(config AtlasConfig) (GenAIClient, error) { + baseURL := config.BaseURL + if baseURL == "" { + baseURL = DefaultAtlasBaseURL + } + + return NewOpenAIClient(OpenAIConfig{ + Model: parseAtlasModel(config.Model), + APIKey: config.APIKey, + BaseURL: baseURL, + MaxTokens: config.MaxTokens, + Temperature: config.Temperature, + SkipSSL: config.SkipSSL, + }) +} + +func parseAtlasModel(model string) string { + switch model { + case "", "atlas", "atlas-deepseek-v4-flash": + return ModelAtlasDefault + case "atlas-qwen3-coder-next", "atlas-qwen-turbo": + return ModelAtlasQwenCoderNext + case "atlas-kimi-k2.6", "atlas-kimi-k2": + return ModelAtlasKimiK26 + } + + for _, prefix := range []string{"atlas/", "atlas:"} { + if strings.HasPrefix(model, prefix) { + trimmed := strings.TrimPrefix(model, prefix) + if trimmed != "" { + return trimmed + } + return ModelAtlasDefault + } + } + + if strings.HasPrefix(model, "atlas-") { + trimmed := strings.TrimPrefix(model, "atlas-") + if trimmed != "" { + return trimmed + } + return ModelAtlasDefault + } + + return model +} diff --git a/autofix/atlas_test.go b/autofix/atlas_test.go new file mode 100644 index 0000000000..f6286fc008 --- /dev/null +++ b/autofix/atlas_test.go @@ -0,0 +1,85 @@ +package autofix + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParseAtlasModel(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "atlas defaults to deepseek v3", + input: "atlas", + expected: ModelAtlasDefault, + }, + { + name: "atlas deepseek alias", + input: "atlas-deepseek-v4-flash", + expected: ModelAtlasDeepSeekV4Flash, + }, + { + name: "atlas qwen alias", + input: "atlas-qwen3-coder-next", + expected: ModelAtlasQwenCoderNext, + }, + { + name: "atlas kimi alias", + input: "atlas-kimi-k2.6", + expected: ModelAtlasKimiK26, + }, + { + name: "atlas slash syntax", + input: "atlas/deepseek-v3", + expected: "deepseek-v3", + }, + { + name: "atlas colon syntax", + input: "atlas:qwen-plus", + expected: "qwen-plus", + }, + { + name: "unknown non atlas model passes through", + input: "custom-model", + expected: "custom-model", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, parseAtlasModel(tt.input)) + }) + } +} + +func TestNewAtlasClient_Defaults(t *testing.T) { + client, err := NewAtlasClient(AtlasConfig{ + Model: "atlas", + APIKey: "test-key", + }) + require.NoError(t, err) + require.NotNil(t, client) + + wrapper, ok := client.(*openaiWrapper) + require.True(t, ok) + assert.Equal(t, ModelAtlasDefault, string(wrapper.model)) + assert.Equal(t, 1024, wrapper.maxTokens) + assert.InEpsilon(t, 0.7, wrapper.temperature, 0.001) +} + +func TestNewAtlasClient_CustomModelSyntax(t *testing.T) { + client, err := NewAtlasClient(AtlasConfig{ + Model: "atlas/moonshot-v1-8k", + APIKey: "test-key", + BaseURL: DefaultAtlasBaseURL, + }) + require.NoError(t, err) + + wrapper := client.(*openaiWrapper) + assert.Equal(t, "moonshot-v1-8k", string(wrapper.model)) +} diff --git a/cmd/gosec/main.go b/cmd/gosec/main.go index 50df79af4e..e52a012db3 100644 --- a/cmd/gosec/main.go +++ b/cmd/gosec/main.go @@ -66,7 +66,9 @@ USAGE: $ gosec --exclude-rules="scripts/.*:*" ./... ` // Environment variable for AI API key. - aiAPIKeyEnv = "GOSEC_AI_API_KEY" // #nosec G101 + aiAPIKeyEnv = "GOSEC_AI_API_KEY" // #nosec G101 + atlasAPIKeyEnv = "ATLASCLOUD_API_KEY" + atlasProviderEnv = "atlas" // Exit codes exitSuccess = 0 @@ -181,7 +183,7 @@ Use "*" to exclude all rules for a path: "scripts/.*:*"`) flagAiAPIKey = flag.String("ai-api-key", "", "Key to access the AI API") // base URL for AI API (optional, for OpenAI-compatible APIs) - flagAiBaseURL = flag.String("ai-base-url", "", "Base URL for AI API (e.g., for OpenAI-compatible services)") + flagAiBaseURL = flag.String("ai-base-url", "", "Base URL for AI API (e.g., for Atlas Cloud or other OpenAI-compatible services)") // skip SSL verification for AI API flagAiSkipSSL = flag.Bool("ai-skip-ssl", false, "Skip SSL certificate verification for AI API") @@ -589,6 +591,9 @@ func run() int { // Call AI request to solve the issues aiAPIKey := os.Getenv(aiAPIKeyEnv) + if aiAPIKey == "" && strings.HasPrefix(*flagAiAPIProvider, atlasProviderEnv) { + aiAPIKey = os.Getenv(atlasAPIKeyEnv) + } if aiAPIKey == "" { aiAPIKey = *flagAiAPIKey } From 12553fa1873e11ace9593c34b439cf4f730dce99 Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:22:23 +0800 Subject: [PATCH 2/8] Update .env.example for review feedback --- .env.example | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.env.example b/.env.example index b393ec20d8..0a7ec71e54 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,3 @@ -GOSEC_AI_API_KEY=your_atlas_cloud_api_key -ATLASCLOUD_API_KEY=your_atlas_cloud_api_key +GOSEC_AI_API_KEY=your_ai_api_key GOSEC_AI_PROVIDER=atlas -GOSEC_AI_MODEL=atlas GOSEC_AI_BASE_URL=https://api.atlascloud.ai/v1 From 91425c286a2bed89f23973832b3c691e2b924243 Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:23:00 +0800 Subject: [PATCH 3/8] Update README.md for review feedback --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c38c793a39..c3b3659ef7 100644 --- a/README.md +++ b/README.md @@ -402,8 +402,7 @@ line arguments: `deepseek-ai/deepseek-v4-flash`), `atlas-deepseek-v4-flash`, `atlas-qwen3-coder-next`, `atlas-kimi-k2.6`, or - `atlas/` / `atlas:` for any Atlas Cloud - hosted chat model. + `atlas:` for any Atlas Cloud hosted chat model. Atlas Cloud is an OpenAI-compatible provider available at [atlascloud.ai](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=gosec) - **Gemini**: `gemini-3-pro-preview` (default), @@ -419,8 +418,6 @@ line arguments: (requires `ai-base-url`) - `ai-api-key` or set the environment variable `GOSEC_AI_API_KEY`: the key to access the AI API - - For Atlas Cloud, you can also set `ATLASCLOUD_API_KEY` - and use the default base URL `https://api.atlascloud.ai/v1` - For Gemini, you can create an API key following [these instructions](https://ai.google.dev/gemini-api/docs/api-key) - For Claude, get your API key from @@ -433,6 +430,10 @@ line arguments: - Atlas Cloud uses `https://api.atlascloud.ai/v1` by default, so `ai-base-url` is optional for the built-in `atlas` provider +- `GOSEC_AI_PROVIDER`: (optional) environment variable + alternative to `ai-api-provider` +- `GOSEC_AI_BASE_URL`: (optional) environment variable + alternative to `ai-base-url` - `ai-skip-ssl`: (optional) skip SSL certificate verification for AI API (useful for self-signed certificates) @@ -440,12 +441,13 @@ line arguments: ```bash # Using Atlas Cloud with the default DeepSeek V4 Flash model -export ATLASCLOUD_API_KEY="your_key" -gosec -ai-api-provider="atlas" ./... +export GOSEC_AI_API_KEY="your_key" +export GOSEC_AI_PROVIDER="atlas" +gosec ./... # Using Atlas Cloud with an explicit hosted model -gosec -ai-api-provider="atlas:qwen/qwen3-coder-next" \ - -ai-api-key="your_key" ./... +GOSEC_AI_API_KEY="your_key" \ + gosec -ai-api-provider="atlas:qwen/qwen3-coder-next" ./... # Using Gemini gosec -ai-api-provider="gemini-3-pro-preview" \ From eeccf71bb130fb9f5254b00c5ca135b47e95c199 Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:23:13 +0800 Subject: [PATCH 4/8] Update autofix/ai.go for review feedback --- autofix/ai.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/autofix/ai.go b/autofix/ai.go index 0c7a6bc3e0..f1a208ea2d 100644 --- a/autofix/ai.go +++ b/autofix/ai.go @@ -12,7 +12,7 @@ import ( const ( AIProviderFlagHelp = `AI API provider to generate auto fixes to issues. Valid options are: - - atlas (Atlas Cloud default), atlas-deepseek-v4-flash, atlas-qwen3-coder-next, atlas-kimi-k2.6, atlas/, atlas:; + - atlas (Atlas Cloud default), atlas-deepseek-v4-flash, atlas-qwen3-coder-next, atlas-kimi-k2.6, atlas:; - gemini-3-pro-preview (gemini, default), gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite; - claude-sonnet-4-6 (claude, default), claude-opus-4-7, claude-opus-4-6, claude-sonnet-4-5, claude-opus-4-5, claude-haiku-4-5; - gpt-5.4 (openai, default), gpt-5.4-mini, gpt-5.4-nano` @@ -34,13 +34,13 @@ func GenerateSolution(model, aiAPIKey, baseURL string, skipSSL bool, issues []*i switch { case model == "atlas" || strings.HasPrefix(model, "atlas-") || strings.HasPrefix(model, "atlas/") || strings.HasPrefix(model, "atlas:"): - config := AtlasConfig{ + config := atlasConfig{ Model: model, APIKey: aiAPIKey, BaseURL: baseURL, SkipSSL: skipSSL, } - client, err = NewAtlasClient(config) + client, err = newAtlasClient(config) case strings.HasPrefix(model, "claude"): client, err = NewClaudeClient(model, aiAPIKey) case strings.HasPrefix(model, "gemini"): From 2a6ed6f9d844d43b4b9161a0f738ae04a2a3682a Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:23:32 +0800 Subject: [PATCH 5/8] Update autofix/atlas.go for review feedback --- autofix/atlas.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/autofix/atlas.go b/autofix/atlas.go index 9f987707a8..e09aad089a 100644 --- a/autofix/atlas.go +++ b/autofix/atlas.go @@ -3,15 +3,15 @@ package autofix import "strings" const ( - ModelAtlasDefault = "deepseek-ai/deepseek-v4-flash" - ModelAtlasDeepSeekV4Flash = "deepseek-ai/deepseek-v4-flash" - ModelAtlasQwenCoderNext = "qwen/qwen3-coder-next" - ModelAtlasKimiK26 = "moonshotai/kimi-k2.6" + modelAtlasDefault = "deepseek-ai/deepseek-v4-flash" + modelAtlasDeepSeekV4Flash = "deepseek-ai/deepseek-v4-flash" + modelAtlasQwenCoderNext = "qwen/qwen3-coder-next" + modelAtlasKimiK26 = "moonshotai/kimi-k2.6" - DefaultAtlasBaseURL = "https://api.atlascloud.ai/v1" + defaultAtlasBaseURL = "https://api.atlascloud.ai/v1" ) -type AtlasConfig struct { +type atlasConfig struct { Model string APIKey string `json:"-"` BaseURL string @@ -20,10 +20,10 @@ type AtlasConfig struct { SkipSSL bool } -func NewAtlasClient(config AtlasConfig) (GenAIClient, error) { +func newAtlasClient(config atlasConfig) (GenAIClient, error) { baseURL := config.BaseURL if baseURL == "" { - baseURL = DefaultAtlasBaseURL + baseURL = defaultAtlasBaseURL } return NewOpenAIClient(OpenAIConfig{ @@ -39,11 +39,11 @@ func NewAtlasClient(config AtlasConfig) (GenAIClient, error) { func parseAtlasModel(model string) string { switch model { case "", "atlas", "atlas-deepseek-v4-flash": - return ModelAtlasDefault + return modelAtlasDefault case "atlas-qwen3-coder-next", "atlas-qwen-turbo": - return ModelAtlasQwenCoderNext + return modelAtlasQwenCoderNext case "atlas-kimi-k2.6", "atlas-kimi-k2": - return ModelAtlasKimiK26 + return modelAtlasKimiK26 } for _, prefix := range []string{"atlas/", "atlas:"} { @@ -52,7 +52,7 @@ func parseAtlasModel(model string) string { if trimmed != "" { return trimmed } - return ModelAtlasDefault + return modelAtlasDefault } } @@ -61,7 +61,7 @@ func parseAtlasModel(model string) string { if trimmed != "" { return trimmed } - return ModelAtlasDefault + return modelAtlasDefault } return model From 0f3853a93db87d61ee3dc4ce38968bf1f7afef9f Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:23:51 +0800 Subject: [PATCH 6/8] Update autofix/atlas_test.go for review feedback --- autofix/atlas_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/autofix/atlas_test.go b/autofix/atlas_test.go index f6286fc008..987374d2a8 100644 --- a/autofix/atlas_test.go +++ b/autofix/atlas_test.go @@ -16,22 +16,22 @@ func TestParseAtlasModel(t *testing.T) { { name: "atlas defaults to deepseek v3", input: "atlas", - expected: ModelAtlasDefault, + expected: modelAtlasDefault, }, { name: "atlas deepseek alias", input: "atlas-deepseek-v4-flash", - expected: ModelAtlasDeepSeekV4Flash, + expected: modelAtlasDeepSeekV4Flash, }, { name: "atlas qwen alias", input: "atlas-qwen3-coder-next", - expected: ModelAtlasQwenCoderNext, + expected: modelAtlasQwenCoderNext, }, { name: "atlas kimi alias", input: "atlas-kimi-k2.6", - expected: ModelAtlasKimiK26, + expected: modelAtlasKimiK26, }, { name: "atlas slash syntax", @@ -58,7 +58,7 @@ func TestParseAtlasModel(t *testing.T) { } func TestNewAtlasClient_Defaults(t *testing.T) { - client, err := NewAtlasClient(AtlasConfig{ + client, err := newAtlasClient(atlasConfig{ Model: "atlas", APIKey: "test-key", }) @@ -67,16 +67,16 @@ func TestNewAtlasClient_Defaults(t *testing.T) { wrapper, ok := client.(*openaiWrapper) require.True(t, ok) - assert.Equal(t, ModelAtlasDefault, string(wrapper.model)) + assert.Equal(t, modelAtlasDefault, string(wrapper.model)) assert.Equal(t, 1024, wrapper.maxTokens) assert.InEpsilon(t, 0.7, wrapper.temperature, 0.001) } func TestNewAtlasClient_CustomModelSyntax(t *testing.T) { - client, err := NewAtlasClient(AtlasConfig{ + client, err := newAtlasClient(atlasConfig{ Model: "atlas/moonshot-v1-8k", APIKey: "test-key", - BaseURL: DefaultAtlasBaseURL, + BaseURL: defaultAtlasBaseURL, }) require.NoError(t, err) From 810a27f42342b283676754ef75c3eb72333ae479 Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:24:07 +0800 Subject: [PATCH 7/8] Update cmd/gosec/main.go for review feedback --- cmd/gosec/main.go | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/cmd/gosec/main.go b/cmd/gosec/main.go index e52a012db3..386a45eee1 100644 --- a/cmd/gosec/main.go +++ b/cmd/gosec/main.go @@ -66,9 +66,9 @@ USAGE: $ gosec --exclude-rules="scripts/.*:*" ./... ` // Environment variable for AI API key. - aiAPIKeyEnv = "GOSEC_AI_API_KEY" // #nosec G101 - atlasAPIKeyEnv = "ATLASCLOUD_API_KEY" - atlasProviderEnv = "atlas" + aiAPIKeyEnv = "GOSEC_AI_API_KEY" // #nosec G101 + aiProviderEnv = "GOSEC_AI_PROVIDER" + aiBaseURLEnv = "GOSEC_AI_BASE_URL" // Exit codes exitSuccess = 0 @@ -183,7 +183,7 @@ Use "*" to exclude all rules for a path: "scripts/.*:*"`) flagAiAPIKey = flag.String("ai-api-key", "", "Key to access the AI API") // base URL for AI API (optional, for OpenAI-compatible APIs) - flagAiBaseURL = flag.String("ai-base-url", "", "Base URL for AI API (e.g., for Atlas Cloud or other OpenAI-compatible services)") + flagAiBaseURL = flag.String("ai-base-url", "", "Base URL for AI API (e.g., for OpenAI-compatible services)") // skip SSL verification for AI API flagAiSkipSSL = flag.Bool("ai-skip-ssl", false, "Skip SSL certificate verification for AI API") @@ -590,18 +590,25 @@ func run() int { reportInfo := gosec.NewReportInfo(issues, metrics, errors).WithVersion(Version) // Call AI request to solve the issues - aiAPIKey := os.Getenv(aiAPIKeyEnv) - if aiAPIKey == "" && strings.HasPrefix(*flagAiAPIProvider, atlasProviderEnv) { - aiAPIKey = os.Getenv(atlasAPIKeyEnv) + aiProvider := *flagAiAPIProvider + if aiProvider == "" { + aiProvider = os.Getenv(aiProviderEnv) } + + aiAPIKey := os.Getenv(aiAPIKeyEnv) if aiAPIKey == "" { aiAPIKey = *flagAiAPIKey } - aiEnabled := *flagAiAPIProvider != "" + aiBaseURL := *flagAiBaseURL + if aiBaseURL == "" { + aiBaseURL = os.Getenv(aiBaseURLEnv) + } + + aiEnabled := aiProvider != "" if len(issues) > 0 && aiEnabled { - err := autofix.GenerateSolution(*flagAiAPIProvider, aiAPIKey, *flagAiBaseURL, *flagAiSkipSSL, issues) + err := autofix.GenerateSolution(aiProvider, aiAPIKey, aiBaseURL, *flagAiSkipSSL, issues) if err != nil { logger.Print(err) } From c959ad5cff50039984b5723d707f42ceaa606fab Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Thu, 21 May 2026 20:24:20 +0800 Subject: [PATCH 8/8] Remove temporary Atlas review document --- ATLAS_CLOUD_REVIEW.md | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 ATLAS_CLOUD_REVIEW.md diff --git a/ATLAS_CLOUD_REVIEW.md b/ATLAS_CLOUD_REVIEW.md deleted file mode 100644 index b25ead6534..0000000000 --- a/ATLAS_CLOUD_REVIEW.md +++ /dev/null @@ -1,42 +0,0 @@ -# Atlas Cloud Provider Review - -## What Changed - -- Added a first-class `atlas` AI provider preset in `autofix`. -- Defaulted Atlas Cloud traffic to `https://api.atlascloud.ai/v1`. -- Added Atlas model aliases: - - `atlas` -> `deepseek-ai/deepseek-v4-flash` - - `atlas-deepseek-v4-flash` -> `deepseek-ai/deepseek-v4-flash` - - `atlas-qwen3-coder-next` -> `qwen/qwen3-coder-next` - - `atlas-kimi-k2.6` -> `moonshotai/kimi-k2.6` - - `atlas/` and `atlas:` for direct model pass-through -- Added `ATLASCLOUD_API_KEY` fallback support in the CLI when `-ai-api-provider` starts with `atlas`. -- Updated README with Atlas Cloud usage, examples, and the official link: - `https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=gosec` -- Added `.env.example` for local setup and ignored `.env.local` files. - -## Files Changed - -- `autofix/ai.go` -- `autofix/atlas.go` -- `autofix/ai_test.go` -- `autofix/atlas_test.go` -- `cmd/gosec/main.go` -- `README.md` -- `.gitignore` -- `.env.example` - -## Local Validation Plan - -- Unit test the `autofix` package. -- Build and run `gosec` against a temporary vulnerable sample with `-ai-api-provider=atlas`. -- Validate direct Atlas Cloud non-stream and stream responses with the provided API key. - -## Validation Results - -- `go test ./...` passed. -- Atlas Cloud `/v1/models` responded successfully and returned account-accessible model IDs. -- Atlas Cloud non-stream chat completion succeeded with `deepseek-ai/deepseek-v4-flash`. -- Atlas Cloud stream chat completion succeeded with `deepseek-ai/deepseek-v4-flash`. -- `gosec` binary integration succeeded: - `-ai-api-provider=atlas` generated a live Autofix for a temporary `G402` sample.