mirror of
https://github.com/securego/gosec.git
synced 2026-06-20 00:15:59 +02:00
* feat(ai): add OpenAI and custom API provider support - Expand AI provider support to include OpenAI (gpt-4o, gpt-4o-mini) and custom OpenAI-compatible APIs - Add support for configuring AI API base URL and skipping SSL verification - Update documentation to list all supported AI providers and clarify configuration options with examples - Refactor AI client initialization to fallback on OpenAI-compatible API for unknown models - Add OpenAI client implementation using openai-go library - Update tests to validate OpenAI-compatible fallback behavior - Add openai-go dependency to go.mod Signed-off-by: appleboy <appleboy.tw@gmail.com> * Fix info message after merge Change-Id: I1cb556a42e2bd9e9b2051d6db99889c6c9f7ccdb Signed-off-by: Cosmin Cojocar <ccojocar@google.com> * Fix lint warning Change-Id: I3689b96205f494920dbbd03344e8f132a30f40b3 Signed-off-by: Cosmin Cojocar <ccojocar@google.com> --------- Signed-off-by: appleboy <appleboy.tw@gmail.com> Signed-off-by: Cosmin Cojocar <ccojocar@google.com> Co-authored-by: Cosmin Cojocar <cosmin@cojocar.ch> Co-authored-by: Cosmin Cojocar <ccojocar@google.com>
91 lines
2.4 KiB
Go
91 lines
2.4 KiB
Go
package autofix
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/securego/gosec/v2/issue"
|
|
)
|
|
|
|
const (
|
|
AIProviderFlagHelp = `AI API provider to generate auto fixes to issues. Valid options are:
|
|
- gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-2.0-flash, gemini-2.0-flash-lite (gemini, default);
|
|
- claude-sonnet-4-0 (claude, default), claude-sonnet-4-5, claude-opus-4-0, claude-opus-4-1, claude-haiku-4-5, claude-sonnet-3-7
|
|
- gpt-4o (openai, default), gpt-4o-mini`
|
|
|
|
AIPrompt = `Provide a brief explanation and a solution to fix this security issue
|
|
in Go programming language: %q.
|
|
Answer in markdown format and keep the response limited to 200 words.`
|
|
|
|
timeout = 30 * time.Second
|
|
)
|
|
|
|
type GenAIClient interface {
|
|
GenerateSolution(ctx context.Context, prompt string) (string, error)
|
|
}
|
|
|
|
// GenerateSolution generates a solution for the given issues using the specified AI provider
|
|
func GenerateSolution(model, aiAPIKey, baseURL string, skipSSL bool, issues []*issue.Issue) (err error) {
|
|
var client GenAIClient
|
|
|
|
switch {
|
|
case strings.HasPrefix(model, "claude"):
|
|
client, err = NewClaudeClient(model, aiAPIKey)
|
|
case strings.HasPrefix(model, "gemini"):
|
|
client, err = NewGeminiClient(model, aiAPIKey)
|
|
case strings.HasPrefix(model, "gpt"):
|
|
config := OpenAIConfig{
|
|
Model: model,
|
|
APIKey: aiAPIKey,
|
|
BaseURL: baseURL,
|
|
SkipSSL: skipSSL,
|
|
}
|
|
client, err = NewOpenAIClient(config)
|
|
default:
|
|
// Default to OpenAI-compatible API for custom models
|
|
config := OpenAIConfig{
|
|
Model: model,
|
|
APIKey: aiAPIKey,
|
|
BaseURL: baseURL,
|
|
SkipSSL: skipSSL,
|
|
}
|
|
client, err = NewOpenAIClient(config)
|
|
}
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("initializing AI client: %w", err)
|
|
}
|
|
|
|
return generateSolution(client, issues)
|
|
}
|
|
|
|
func generateSolution(client GenAIClient, issues []*issue.Issue) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
defer cancel()
|
|
|
|
cachedAutofix := make(map[string]string)
|
|
for _, issue := range issues {
|
|
if val, ok := cachedAutofix[issue.What]; ok {
|
|
issue.Autofix = val
|
|
continue
|
|
}
|
|
|
|
prompt := fmt.Sprintf(AIPrompt, issue.What)
|
|
resp, err := client.GenerateSolution(ctx, prompt)
|
|
if err != nil {
|
|
return fmt.Errorf("generating autofix with gemini: %w", err)
|
|
}
|
|
|
|
if resp == "" {
|
|
return errors.New("no autofix returned by gemini")
|
|
}
|
|
|
|
issue.Autofix = resp
|
|
cachedAutofix[issue.What] = issue.Autofix
|
|
}
|
|
return nil
|
|
}
|