Compare commits

...

29 Commits

Author SHA1 Message Date
Cosmin Cojocar
15d5c61e86 Update cosign to v2.6.0 and go in the CI to latest version
Change-Id: I1754871a875f82fa1177793e74a41cc88ef4059f
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-09-22 08:42:03 +00:00
Matteo Calabrò
7b8713e2c9 fix(autofix): unnecessary conversion 2025-09-22 08:24:39 +00:00
Matteo Calabrò
64ebfc0106 feat(autofix): update gemini sdk and add anthropic claude
* upgrade gemini sdk to google.golang.org/genai v1.25.0
* support newer gemini models
* add anthropic claude
2025-09-22 08:24:39 +00:00
Eshani Parulekar
506407e7df feat(G304): add os.Root remediation hint (Autofix) when Go >= 1.24 2025-09-16 14:37:06 +00:00
renovate[bot]
3ead143f0a chore(deps): update all dependencies 2025-09-15 07:25:27 +00:00
Eshani Parulekar
e81fba3c3a refactor(G304): remove unused trackJoin helper; no functional change 2025-09-12 13:52:23 +00:00
Eshani Parulekar
ab078db7b0 style: gofmt rules/readfile.go 2025-09-12 13:52:23 +00:00
Eshani Parulekar
e6218c83ec test(g304): add samples for var perm and var flag with cleaned path\n\n- Ensure G304 does not fire when only non-path args (flag/perm) are variables\n- Both samples use filepath.Clean on the path arg\n- Rules suite remains green (42 passed) 2025-09-12 13:52:23 +00:00
Eshani Parulekar
79f835d9c7 rules(G304): analyze only path arg; ignore flag/perm vars; track Clean and safe Join; fix nil-context panic\n\n- Limit G304 checks to first arg (path) for os.Open/OpenFile/ReadFile, avoiding false positives when flag/perm are variables\n- Track filepath.Clean so cleaned identifiers are treated as safe\n- Consider safe joins: filepath.Join(const|resolvedBase, Clean(var)|cleanedIdent)\n- Record Join(...) assigned to identifiers and allow if later cleaned\n- Fix panic by passing non-nil context in trackJoinAssignStmt\n- All rules tests: 42 passed 2025-09-12 13:52:23 +00:00
Eshani Parulekar
40ac53017b rules(G202): detect SQL concat in ValueSpec declarations; add test sample\n\n- Handle var query string = 'SELECT ...' + user style declarations\n- Reuse existing binary expr detection on ValueSpec.Values\n- Add postgres sample mirroring issue #1309 report\n- Rules tests: 42 passed 2025-09-12 13:27:02 +00:00
renovate[bot]
4be6b11bbc chore(deps): update all dependencies 2025-09-08 11:06:08 +00:00
renovate[bot]
5af1117217 chore(deps): update all dependencies 2025-08-25 08:18:38 +00:00
renovate[bot]
287b46c018 chore(deps): update all dependencies 2025-08-18 07:59:10 +00:00
Cosmin Cojocar
cee0aeae8a Update gosec version to v2.22.8 in the Github action
Change-Id: Ifc3c472f6c6aa08bda00ab57298fd7d383ab8325
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-08-14 13:16:42 +00:00
Cosmin Cojocar
c9453023c4 Add support for go version 1.25.0
Change-Id: Ia694411be7e861177970485cc6185af5a6944686
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-08-14 12:38:12 +00:00
Cosmin Cojocar
ef7adab98c Update go version in CI to 1.24.6 and 1.23.12
Change-Id: I940b6382282fa2609736a62491c22b3e9319f430
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-08-11 13:42:46 +00:00
renovate[bot]
e201bb86c2 chore(deps): update all dependencies 2025-08-11 08:54:42 +00:00
renovate[bot]
ba592afef6 chore(deps): update all dependencies 2025-07-28 09:33:21 +00:00
Cosmin Cojocar
2ef6017991 Update github action to release v2.22.7
Change-Id: I827d332eb4ad80fbddbabccc4d501d2968449aab
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-07-21 15:54:30 +00:00
Cosmin Cojocar
32975f4bab Fix crash in hardcoded_nonce analyzer
Change-Id: If5ed3709d6e1ddced1be555477dd0f5451aab901
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-07-21 15:19:49 +00:00
Cosmin Cojocar
6ea6b35e61 Update go action to use release v2.22.6
Change-Id: I9081035b07d8b254034468af77d65d48c7c06ecb
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-07-21 10:49:17 +00:00
Cosmin Cojocar
bc3f2145b5 Update go version to 1.24.5 and 1.23.11 in the CI
Change-Id: I56c3576fbda7cc2633dac335c29b2494985978e9
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-07-21 09:38:01 +00:00
renovate[bot]
925741b7ef chore(deps): update module google.golang.org/api to v0.242.0 2025-07-21 08:06:50 +00:00
renovate[bot]
59ae7e9e27 chore(deps): update all dependencies 2025-07-14 08:59:55 +00:00
renovate[bot]
e7abd9e348 chore(deps): update all dependencies 2025-07-07 10:04:42 +02:00
renovate[bot]
35e7bc1a94 chore(deps): update all dependencies 2025-06-30 10:33:36 +02:00
renovate[bot]
2d1ed95a0b chore(deps): update all dependencies 2025-06-23 11:35:00 +02:00
Oleksandr Redko
4a8cb4609f Do not allow dashes in file names 2025-06-16 14:34:38 +02:00
Cosmin Cojocar
bcc8afbe30 Update gosec to version 2.22.5 in Github action
Change-Id: Ide774b7157678f54e17bd7decad22d0712ff1b40
Signed-off-by: Cosmin Cojocar <ccojocar@google.com>
2025-06-16 12:57:45 +02:00
21 changed files with 587 additions and 276 deletions

View File

@@ -10,17 +10,21 @@ jobs:
test:
strategy:
matrix:
version: [{go: '1.23.10', golangci: 'latest'}, {go: '1.24.4', golangci: 'latest'}]
version:
- go-version: "1.24.7"
golangci: "latest"
- go-version: "1.25.1"
golangci: "latest"
runs-on: ubuntu-latest
env:
GO111MODULE: on
steps:
- name: Setup go ${{ matrix.version.go }}
uses: actions/setup-go@v5
- name: Setup go ${{ matrix.version.go-version }}
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.version.go }}
go-version: ${{ matrix.version.go-version }}
- name: Checkout Source
uses: actions/checkout@v4
uses: actions/checkout@v5
- uses: actions/cache@v4
with:
path: ~/go/pkg/mod
@@ -30,7 +34,7 @@ jobs:
- name: lint
uses: golangci/golangci-lint-action@v8
with:
version: ${{ matrix.version.golangci }}
version: ${{ matrix.version.golangci }}
- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
@@ -46,11 +50,11 @@ jobs:
GO111MODULE: on
steps:
- name: Setup go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.24.4'
go-version: "1.25.1"
- name: Checkout Source
uses: actions/checkout@v4
uses: actions/checkout@v5
- uses: actions/cache@v4
with:
path: ~/go/pkg/mod

View File

@@ -2,7 +2,7 @@ name: Release
on:
push:
tags:
- 'v*'
- "v*"
jobs:
build:
runs-on: ubuntu-latest
@@ -11,17 +11,17 @@ jobs:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
steps:
- name: Checkout Source
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Unshallow
run: git fetch --prune --unshallow
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.24.4'
go-version: "1.25.1"
- name: Install Cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: 'v2.5.0'
cosign-release: "v2.6.0"
- name: Store Cosign private key in a file
run: 'echo "$COSIGN_KEY" > /tmp/cosign.key'
shell: bash
@@ -67,7 +67,7 @@ jobs:
tags: ${{steps.meta.outputs.tags}}
labels: ${{steps.meta.outputs.labels}}
push: true
build-args: GO_VERSION=1.24
build-args: GO_VERSION=1.25
- name: Sign Docker Image
run: cosign sign --yes --key /tmp/cosign.key ${DIGEST} --registry-username="$secrets.DOCKER_USERNAME" --registry-password="::add-mask::$secrets.DOCKER_PASSWORD"
env:

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Security Scan
uses: securego/gosec@master
with:

View File

@@ -24,6 +24,9 @@ linters:
rules:
- name: dot-imports
disabled: true
- name: filename-format
arguments:
- ^[a-z][_a-z0-9]*.go$
- name: redefines-builtin-id
staticcheck:
checks:

View File

@@ -17,7 +17,7 @@ GOSEC ?= $(GOBIN)/gosec
GINKGO ?= $(GOBIN)/ginkgo
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
GOVULN_MIN_VERSION = 17
GO_VERSION = 1.24
GO_VERSION = 1.25
LDFLAGS = -ldflags "\
-X 'main.Version=$(shell git describe --tags --always)' \
-X 'main.GitTag=$(shell git describe --tags --abbrev=0)' \

View File

@@ -10,7 +10,7 @@ inputs:
runs:
using: 'docker'
image: 'docker://securego/gosec:2.22.3'
image: 'docker://securego/gosec:2.22.8'
args:
- ${{ inputs.args }}

View File

@@ -197,12 +197,20 @@ func isFuncContainsCryptoRand(funcCall *ssa.Function) (bool, error) {
}
func addToVarsMap(value ssa.Value, mapToAddTo map[string]*ssa.Value) {
key := value.Name() + value.Type().String() + value.String() + value.Parent().String()
var parent string
if value.Parent() != nil {
parent = value.Parent().String()
}
key := value.Name() + value.Type().String() + value.String() + parent
mapToAddTo[key] = &value
}
func isContainedInMap(value ssa.Value, mapToCheck map[string]*ssa.Value) bool {
key := value.Name() + value.Type().String() + value.String() + value.Parent().String()
var parent string
if value.Parent() != nil {
parent = value.Parent().String()
}
key := value.Name() + value.Type().String() + value.String() + parent
_, contained := mapToCheck[key]
return contained
}

View File

@@ -4,97 +4,53 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/google/generative-ai-go/genai"
"google.golang.org/api/option"
"github.com/securego/gosec/v2/issue"
)
const (
GeminiModel = "gemini-1.5-flash"
AIPrompt = `Provide a brief explanation and a solution to fix this security issue
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-opus-4-0, claude-opus-4-1, claude-sonnet-3-7`
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.`
GeminiProvider = "gemini"
timeout = 30 * time.Second
)
// GenAIClient defines the interface for the GenAI client.
type GenAIClient interface {
// Close clean up and close the client.
Close() error
// GenerativeModel build the generative mode.
GenerativeModel(name string) GenAIGenerativeModel
GenerateSolution(ctx context.Context, prompt string) (string, error)
}
// GenAIGenerativeModel defines the interface for the Generative Model.
type GenAIGenerativeModel interface {
// GenerateContent generates an response for given prompt.
GenerateContent(ctx context.Context, prompt string) (string, error)
}
// GenerateSolution generates a solution for the given issues using the specified AI provider
func GenerateSolution(model, aiAPIKey string, issues []*issue.Issue) (err error) {
var client GenAIClient
// genAIClientWrapper wraps the genai.Client to implement GenAIClient.
type genAIClientWrapper struct {
client *genai.Client
}
// Close closes the gen AI client.
func (w *genAIClientWrapper) Close() error {
return w.client.Close()
}
// GenerativeModel builds the generative Model.
func (w *genAIClientWrapper) GenerativeModel(name string) GenAIGenerativeModel {
return &genAIGenerativeModelWrapper{model: w.client.GenerativeModel(name)}
}
// genAIGenerativeModelWrapper wraps the genai.GenerativeModel to implement GenAIGenerativeModel
type genAIGenerativeModelWrapper struct {
// model is the underlying generative model
model *genai.GenerativeModel
}
// GenerateContent generates a response for the given prompt using gemini API.
func (w *genAIGenerativeModelWrapper) GenerateContent(ctx context.Context, prompt string) (string, error) {
resp, err := w.model.GenerateContent(ctx, genai.Text(prompt))
if err != nil {
return "", fmt.Errorf("generating autofix: %w", err)
}
if len(resp.Candidates) == 0 {
return "", errors.New("no autofix returned by gemini")
switch {
case strings.HasPrefix(model, "claude"):
client, err = NewClaudeClient(model, aiAPIKey)
case strings.HasPrefix(model, "gemini"):
client, err = NewGeminiClient(model, aiAPIKey)
}
if len(resp.Candidates[0].Content.Parts) == 0 {
return "", errors.New("nothing found in the first autofix returned by gemini")
switch {
case err != nil:
return fmt.Errorf("initializing AI client: %w", err)
case client == nil:
return fmt.Errorf("unsupported AI backend: %s", model)
}
// Return the first candidate
return fmt.Sprintf("%+v", resp.Candidates[0].Content.Parts[0]), nil
return generateSolution(client, issues)
}
// NewGenAIClient creates a new gemini API client.
func NewGenAIClient(ctx context.Context, aiAPIKey, endpoint string) (GenAIClient, error) {
clientOptions := []option.ClientOption{option.WithAPIKey(aiAPIKey)}
if endpoint != "" {
clientOptions = append(clientOptions, option.WithEndpoint(endpoint))
}
client, err := genai.NewClient(ctx, clientOptions...)
if err != nil {
return nil, fmt.Errorf("calling gemini API: %w", err)
}
return &genAIClientWrapper{client: client}, nil
}
func generateSolutionByGemini(client GenAIClient, issues []*issue.Issue) error {
func generateSolution(client GenAIClient, issues []*issue.Issue) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
model := client.GenerativeModel(GeminiModel)
cachedAutofix := make(map[string]string)
for _, issue := range issues {
if val, ok := cachedAutofix[issue.What]; ok {
@@ -103,7 +59,7 @@ func generateSolutionByGemini(client GenAIClient, issues []*issue.Issue) error {
}
prompt := fmt.Sprintf(AIPrompt, issue.What)
resp, err := model.GenerateContent(ctx, prompt)
resp, err := client.GenerateSolution(ctx, prompt)
if err != nil {
return fmt.Errorf("generating autofix with gemini: %w", err)
}
@@ -117,26 +73,3 @@ func generateSolutionByGemini(client GenAIClient, issues []*issue.Issue) error {
}
return nil
}
// GenerateSolution generates a solution for the given issues using the specified AI provider
func GenerateSolution(aiAPIProvider, aiAPIKey, endpoint string, issues []*issue.Issue) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
var client GenAIClient
switch aiAPIProvider {
case GeminiProvider:
var err error
client, err = NewGenAIClient(ctx, aiAPIKey, endpoint)
if err != nil {
return fmt.Errorf("generating autofix: %w", err)
}
default:
return errors.New("ai provider not supported")
}
defer client.Close()
return generateSolutionByGemini(client, issues)
}

View File

@@ -17,22 +17,7 @@ type MockGenAIClient struct {
mock.Mock
}
func (m *MockGenAIClient) Close() error {
args := m.Called()
return args.Error(0)
}
func (m *MockGenAIClient) GenerativeModel(name string) GenAIGenerativeModel {
args := m.Called(name)
return args.Get(0).(GenAIGenerativeModel)
}
// MockGenAIGenerativeModel is a mock of the GenAIGenerativeModel interface
type MockGenAIGenerativeModel struct {
mock.Mock
}
func (m *MockGenAIGenerativeModel) GenerateContent(ctx context.Context, prompt string) (string, error) {
func (m *MockGenAIClient) GenerateSolution(ctx context.Context, prompt string) (string, error) {
args := m.Called(ctx, prompt)
return args.String(0), args.Error(1)
}
@@ -44,17 +29,15 @@ func TestGenerateSolutionByGemini_Success(t *testing.T) {
}
mockClient := new(MockGenAIClient)
mockModel := new(MockGenAIGenerativeModel)
mockClient.On("GenerativeModel", GeminiModel).Return(mockModel).Once()
mockModel.On("GenerateContent", mock.Anything, mock.Anything).Return("Autofix for issue 1", nil).Once()
mockClient.On("GenerateSolution", mock.Anything, mock.Anything).Return("Autofix for issue 1", nil).Once()
// Act
err := generateSolutionByGemini(mockClient, issues)
err := generateSolution(mockClient, issues)
// Assert
require.NoError(t, err)
assert.Equal(t, []*issue.Issue{{What: "Example issue 1", Autofix: "Autofix for issue 1"}}, issues)
mock.AssertExpectationsForObjects(t, mockClient, mockModel)
mock.AssertExpectationsForObjects(t, mockClient)
}
func TestGenerateSolutionByGemini_NoCandidates(t *testing.T) {
@@ -64,16 +47,14 @@ func TestGenerateSolutionByGemini_NoCandidates(t *testing.T) {
}
mockClient := new(MockGenAIClient)
mockModel := new(MockGenAIGenerativeModel)
mockClient.On("GenerativeModel", GeminiModel).Return(mockModel).Once()
mockModel.On("GenerateContent", mock.Anything, mock.Anything).Return("", nil).Once()
mockClient.On("GenerateSolution", mock.Anything, mock.Anything).Return("", nil).Once()
// Act
err := generateSolutionByGemini(mockClient, issues)
err := generateSolution(mockClient, issues)
// Assert
require.EqualError(t, err, "no autofix returned by gemini")
mock.AssertExpectationsForObjects(t, mockClient, mockModel)
mock.AssertExpectationsForObjects(t, mockClient)
}
func TestGenerateSolutionByGemini_APIError(t *testing.T) {
@@ -83,16 +64,14 @@ func TestGenerateSolutionByGemini_APIError(t *testing.T) {
}
mockClient := new(MockGenAIClient)
mockModel := new(MockGenAIGenerativeModel)
mockClient.On("GenerativeModel", GeminiModel).Return(mockModel).Once()
mockModel.On("GenerateContent", mock.Anything, mock.Anything).Return("", errors.New("API error")).Once()
mockClient.On("GenerateSolution", mock.Anything, mock.Anything).Return("", errors.New("API error")).Once()
// Act
err := generateSolutionByGemini(mockClient, issues)
err := generateSolution(mockClient, issues)
// Assert
require.EqualError(t, err, "generating autofix with gemini: API error")
mock.AssertExpectationsForObjects(t, mockClient, mockModel)
mock.AssertExpectationsForObjects(t, mockClient)
}
func TestGenerateSolution_UnsupportedProvider(t *testing.T) {
@@ -102,8 +81,8 @@ func TestGenerateSolution_UnsupportedProvider(t *testing.T) {
}
// Act
err := GenerateSolution("unsupported-provider", "test-api-key", "", issues)
err := GenerateSolution("unsupported-provider", "test-api-key", issues)
// Assert
require.EqualError(t, err, "ai provider not supported")
require.EqualError(t, err, "unsupported AI backend: unsupported-provider")
}

74
autofix/claude.go Normal file
View File

@@ -0,0 +1,74 @@
package autofix
import (
"context"
"errors"
"fmt"
"github.com/anthropics/anthropic-sdk-go"
"github.com/anthropics/anthropic-sdk-go/option"
)
const (
ModelClaudeOpus4_0 = anthropic.ModelClaudeOpus4_0
ModelClaudeOpus4_1 = anthropic.ModelClaudeOpus4_1_20250805
ModelClaudeSonnet4_0 = anthropic.ModelClaudeSonnet4_0
)
var _ GenAIClient = (*claudeWrapper)(nil)
type claudeWrapper struct {
client anthropic.Client
model anthropic.Model
}
func NewClaudeClient(model, apiKey string) (GenAIClient, error) {
var options []option.RequestOption
if apiKey != "" {
options = append(options, option.WithAPIKey(apiKey))
}
anthropicModel := parseAnthropicModel(model)
return &claudeWrapper{
client: anthropic.NewClient(options...),
model: anthropicModel,
}, nil
}
func (c *claudeWrapper) GenerateSolution(ctx context.Context, prompt string) (string, error) {
resp, err := c.client.Messages.New(ctx, anthropic.MessageNewParams{
Model: c.model,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock(prompt)),
},
})
if err != nil {
return "", fmt.Errorf("generating autofix: %w", err)
}
if resp == nil || len(resp.Content) == 0 {
return "", errors.New("no autofix returned by claude")
}
if len(resp.Content[0].Text) == 0 {
return "", errors.New("nothing found in the first autofix returned by claude")
}
return resp.Content[0].Text, nil
}
func parseAnthropicModel(model string) anthropic.Model {
switch model {
case "claude-sonnet-3-7":
return anthropic.ModelClaude3_7SonnetLatest
case "claude-opus", "claude-opus-4-0":
return anthropic.ModelClaudeOpus4_0
case "claude-opus-4-1":
return anthropic.ModelClaudeOpus4_1_20250805
}
return anthropic.ModelClaudeSonnet4_0
}

91
autofix/gemini.go Normal file
View File

@@ -0,0 +1,91 @@
package autofix
import (
"context"
"errors"
"fmt"
"google.golang.org/genai"
)
// https://ai.google.dev/gemini-api/docs/models
type GenAIModel string
const (
ModelGeminiPro2_5 GenAIModel = "gemini-2.5-pro"
ModelGeminiFlash2_5 GenAIModel = "gemini-2.5-flash"
ModelGeminiFlash2_5Lite GenAIModel = "gemini-2.5-flash-lite"
ModelGeminiFlash2_0 GenAIModel = "gemini-2.0-flash"
ModelGeminiFlash2_0Lite GenAIModel = "gemini-2.0-flash-lite"
// Deprecated: Use Gemini 2.x models.
ModelGeminiFlash1_5 GenAIModel = "gemini-1.5-flash"
)
var _ GenAIClient = (*geminiWrapper)(nil)
type geminiWrapper struct {
client *genai.Client
model GenAIModel
}
func NewGeminiClient(model, apiKey string) (GenAIClient, error) {
ctx := context.Background()
genaiModel, err := parseGeminiModel(model)
if err != nil {
return nil, err
}
config := genai.ClientConfig{
APIKey: apiKey,
Backend: genai.BackendUnspecified,
}
client, err := genai.NewClient(ctx, &config)
if err != nil {
return nil, fmt.Errorf("creating gemini client: %w", err)
}
return &geminiWrapper{
client: client,
model: genaiModel,
}, nil
}
func (g *geminiWrapper) GenerateSolution(ctx context.Context, prompt string) (string, error) {
var config genai.GenerateContentConfig
resp, err := g.client.Models.GenerateContent(ctx, string(g.model), genai.Text(prompt), &config)
if err != nil {
return "", fmt.Errorf("generating autofix: %w", err)
}
if resp == nil || len(resp.Candidates) == 0 {
return "", errors.New("no autofix returned by gemini")
}
if len(resp.Candidates[0].Content.Parts) == 0 {
return "", errors.New("nothing found in the first autofix returned by gemini")
}
return resp.Text(), nil
}
func parseGeminiModel(model string) (GenAIModel, error) {
switch model {
case "gemini-2.5-pro":
return ModelGeminiPro2_5, nil
case "gemini-2.5-flash":
return ModelGeminiFlash2_5, nil
case "gemini-2.5-flash-lite":
return ModelGeminiFlash2_5Lite, nil
case "gemini-2.0-flash":
return ModelGeminiFlash2_0, nil
case "gemini-2.0-flash-lite", "gemini": // Default
return ModelGeminiFlash2_0Lite, nil
case "gemini-1.5-flash":
return ModelGeminiFlash1_5, nil
}
return "", fmt.Errorf("unsupported gemini model: %s", model)
}

View File

@@ -154,14 +154,11 @@ var (
flagTerse = flag.Bool("terse", false, "Shows only the results and summary")
// AI platform provider to generate solutions to issues
flagAiAPIProvider = flag.String("ai-api-provider", "", "AI API provider to generate auto fixes to issues.\nValid options are: gemini")
flagAiAPIProvider = flag.String("ai-api-provider", "", autofix.AIProviderFlagHelp)
// key to implementing AI provider services
flagAiAPIKey = flag.String("ai-api-key", "", "Key to access the AI API")
// endpoint to the AI provider
flagAiEndpoint = flag.String("ai-endpoint", "", "Endpoint AI API.\nThis is optional, the default API endpoint will be used when not provided.")
// exclude the folders from scan
flagDirsExclude arrayFlags
@@ -508,8 +505,11 @@ func main() {
if aiAPIKey == "" {
aiAPIKey = *flagAiAPIKey
}
if *flagAiAPIProvider != "" && aiAPIKey != "" {
err := autofix.GenerateSolution(*flagAiAPIProvider, aiAPIKey, *flagAiEndpoint, issues)
aiEnabled := *flagAiAPIProvider != ""
if len(issues) > 0 && aiEnabled {
err := autofix.GenerateSolution(*flagAiAPIProvider, aiAPIKey, issues)
if err != nil {
logger.Print(err)
}

62
go.mod
View File

@@ -1,59 +1,59 @@
module github.com/securego/gosec/v2
require (
github.com/anthropics/anthropic-sdk-go v1.12.0
github.com/ccojocar/zxcvbn-go v1.0.4
github.com/google/generative-ai-go v0.20.1
github.com/google/uuid v1.6.0
github.com/gookit/color v1.5.4
github.com/gookit/color v1.6.0
github.com/lib/pq v1.10.9
github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.37.0
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.39.0
golang.org/x/text v0.26.0
golang.org/x/tools v0.34.0
google.golang.org/api v0.237.0
github.com/onsi/ginkgo/v2 v2.25.3
github.com/onsi/gomega v1.38.2
github.com/stretchr/testify v1.11.1
golang.org/x/crypto v0.42.0
golang.org/x/text v0.29.0
golang.org/x/tools v0.37.0
google.golang.org/genai v1.25.0
gopkg.in/yaml.v3 v3.0.1
)
require (
cloud.google.com/go v0.121.2 // indirect
cloud.google.com/go/ai v0.12.1 // indirect
cloud.google.com/go/auth v0.16.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/longrunning v0.6.7 // indirect
cloud.google.com/go/auth v0.16.5 // indirect
cloud.google.com/go/compute/metadata v0.8.0 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/time v0.12.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.28.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/grpc v1.75.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)
go 1.23.0
go 1.24.0

140
go.sum
View File

@@ -15,24 +15,18 @@ cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZ
cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU=
cloud.google.com/go v0.121.2 h1:v2qQpN6Dx9x2NmwrqlesOt3Ys4ol5/lFZ6Mg1B7OJCg=
cloud.google.com/go v0.121.2/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw=
cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0=
cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4=
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -50,12 +44,16 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anthropics/anthropic-sdk-go v1.12.0 h1:xPqlGnq7rWrTiHazIvCiumA0u7mGQnwDQtvA1M82h9U=
github.com/anthropics/anthropic-sdk-go v1.12.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -160,8 +158,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs=
github.com/google/generative-ai-go v0.20.1 h1:6dEIujpgN2V0PgLhr6c/M1ynRdc7ARtiIDPFzj45uNQ=
github.com/google/generative-ai-go v0.20.1/go.mod h1:TjOnZJmZKzarWbjUJgy+r3Ee7HGBRVLhOIgupnwR4Bg=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -179,8 +175,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
@@ -194,15 +190,19 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=
github.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E=
github.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA=
github.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
@@ -290,11 +290,11 @@ github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXW
github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -352,8 +352,18 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -383,20 +393,18 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -408,6 +416,8 @@ go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -417,8 +427,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -452,8 +462,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -486,15 +496,13 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -504,8 +512,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -546,25 +554,23 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -611,11 +617,13 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -632,8 +640,6 @@ google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.237.0 h1:MP7XVsGZesOsx3Q8WVa4sUdbrsTvDSOERd3Vh4xj/wc=
google.golang.org/api v0.237.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -641,6 +647,8 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genai v1.25.0 h1:Cpyh2nmEoOS1eM3mT9XKuA/qWTEDoktfP2gsN3EduPE=
google.golang.org/genai v1.25.0/go.mod h1:OClfdf+r5aaD+sCd4aUSkPzJItmg2wD/WON9lQnRPaY=
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -672,12 +680,8 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -692,8 +696,8 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -704,8 +708,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -4,13 +4,13 @@
<meta charset="utf-8">
<title>Golang Security Checker</title>
<link rel="shortcut icon" type="image/png" href="https://securego.io/img/favicon.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/1.0.3/css/bulma.min.css" integrity="sha512-4EnjWdm80dyWrJ7rh/tlhNt6fJL52dSDSHNEqfdVmBLpJLPrRYnFa+Kn4ZZL+FRkDL5/7lAXuHylzJkpzkSM2A==" crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/1.0.4/css/bulma.min.css" integrity="sha512-yh2RE0wZCVZeysGiqTwDTO/dKelCbS9bP2L94UvOFtl/FKXcNAje3Y2oBg/ZMZ3LS1sicYk4dYVGtDex75fvvA==" crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js" integrity="sha512-EBLzUL8XLl+va/zAsmXwS7Z2B1F9HUHkZwyS/VKwh3S7T/U0nF4BaU29EP/ZSf6zgiIxYAnKLu6bJ8dqpmX5uw==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js" integrity="sha512-weC0VNVf2qQR6OY675qO0AEL92gt3h5f2VGjhMUvi/UqFHaWzIEL5S/8Dt763fWfKftchzb7GryvEj/2HC9Exw==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.7.0/react.min.js" integrity="sha512-+TFn1Gqbwx/qgwW3NU1/YtFYTfHGeD1e/8YfJZzkb6TFEZP4SUwp1Az9DMeWh3qC0F+YPKXbV3YclMUwBTvO3g==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js" integrity="sha512-8C49ZG/SaQnWaUgCHTU1o8uIQNYE6R8me38SwF26g2Q0byEXF4Jlvm+T/JAMHMeTBiEVPslSZRv9Xt4AV0pfmw==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js" integrity="sha512-Y37Caenc5CZqwSMwWZj+5uxkB3Loc9yJNHvb+eSwEsT6nhURSrPZo39vTnb5g8UvOGCNXRbQ+xQvnqr2rR9nRw==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.28.4/babel.min.js" integrity="sha512-BCw4VuBF2HKIgxDP8K7DRHcHzazAAND+5+2E7GgX3CC1u1pteJ415mMJlQfUORjkFT64irzu1jIV93Vfvzkevw==" crossorigin="anonymous"></script>
<style>
.field-label {
min-width: 80px;

View File

@@ -25,9 +25,12 @@ import (
type readfile struct {
issue.MetaData
gosec.CallList
pathJoin gosec.CallList
clean gosec.CallList
pathJoin gosec.CallList
clean gosec.CallList
// cleanedVar maps the declaration node of an identifier to the Clean() call node
cleanedVar map[any]ast.Node
// joinedVar maps the declaration node of an identifier to the Join() call node
joinedVar map[any]ast.Node
}
// ID returns the identifier for this rule
@@ -61,6 +64,7 @@ func (r *readfile) isJoinFunc(n ast.Node, c *gosec.Context) bool {
// isFilepathClean checks if there is a filepath.Clean for given variable
func (r *readfile) isFilepathClean(n *ast.Ident, c *gosec.Context) bool {
// quick lookup: was this var's declaration recorded as a Clean() call?
if _, ok := r.cleanedVar[n.Obj.Decl]; ok {
return true
}
@@ -90,37 +94,172 @@ func (r *readfile) trackFilepathClean(n ast.Node) {
}
}
// Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile`
// trackJoinAssignStmt tracks assignments where RHS is a Join(...) call and LHS is an identifier
func (r *readfile) trackJoinAssignStmt(node *ast.AssignStmt, c *gosec.Context) {
if len(node.Rhs) == 0 {
return
}
if call, ok := node.Rhs[0].(*ast.CallExpr); ok {
if r.pathJoin.ContainsPkgCallExpr(call, c, false) != nil {
// LHS must be an identifier (simple case)
if len(node.Lhs) > 0 {
if ident, ok := node.Lhs[0].(*ast.Ident); ok && ident.Obj != nil {
r.joinedVar[ident.Obj.Decl] = call
}
}
}
}
}
// osRootSuggestion returns an Autofix suggesting the use of os.Root where supported
// to constrain file access under a fixed directory and mitigate traversal risks.
func (r *readfile) osRootSuggestion() string {
major, minor, _ := gosec.GoVersion()
if major == 1 && minor >= 24 {
return "Consider using os.Root to scope file access under a fixed root (Go >=1.24). Prefer root.Open/root.Stat over os.Open/os.Stat to prevent directory traversal."
}
return ""
}
// isSafeJoin checks if path is baseDir + filepath.Clean(fn) joined.
// improvements over earlier naive version:
// - allow baseDir as a BasicLit or as an identifier that resolves to a string constant
// - accept Clean(...) being either a CallExpr or an identifier previously recorded as Clean result
func (r *readfile) isSafeJoin(call *ast.CallExpr, c *gosec.Context) bool {
join := r.pathJoin.ContainsPkgCallExpr(call, c, false)
if join == nil {
return false
}
// We expect join.Args to include a baseDir-like arg and a cleaned path arg.
var foundBaseDir bool
var foundCleanArg bool
for _, arg := range join.Args {
switch a := arg.(type) {
case *ast.BasicLit:
// literal string or similar — treat as possible baseDir
foundBaseDir = true
case *ast.Ident:
// If ident is resolvable to a constant string (TryResolve true), treat as baseDir.
// Or if ident refers to a variable that was itself assigned from a constant BasicLit,
// it's considered safe as baseDir.
if gosec.TryResolve(a, c) {
foundBaseDir = true
} else {
// It might be a cleaned variable: e.g. cleanPath := filepath.Clean(fn)
if r.isFilepathClean(a, c) {
foundCleanArg = true
}
}
case *ast.CallExpr:
// If an argument is a Clean() call directly, mark clean arg found.
if r.clean.ContainsPkgCallExpr(a, c, false) != nil {
foundCleanArg = true
}
default:
// ignore other types
}
}
return foundBaseDir && foundCleanArg
}
func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
// Track filepath.Clean usages so identifiers assigned from Clean() are known.
if node := r.clean.ContainsPkgCallExpr(n, c, false); node != nil {
r.trackFilepathClean(n)
return nil, nil
} else if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
for _, arg := range node.Args {
// handles path joining functions in Arg
// eg. os.Open(filepath.Join("/tmp/", file))
if callExpr, ok := arg.(*ast.CallExpr); ok {
if r.isJoinFunc(callExpr, c) {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
if binExp, ok := arg.(*ast.BinaryExpr); ok {
// resolve all found identities from the BinaryExpr
if _, ok := gosec.FindVarIdentities(binExp, c); ok {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
if ident, ok := arg.(*ast.Ident); ok {
obj := c.Info.ObjectOf(ident)
if _, ok := obj.(*types.Var); ok &&
!gosec.TryResolve(ident, c) &&
!r.isFilepathClean(ident, c) {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
// Track Join assignments if we see an AssignStmt whose RHS is a Join call.
if assign, ok := n.(*ast.AssignStmt); ok {
// track join result assigned to a variable, e.g., fullPath := filepath.Join(baseDir, cleanPath)
r.trackJoinAssignStmt(assign, c)
// also track Clean assignment if present on RHS
if len(assign.Rhs) > 0 {
if call, ok := assign.Rhs[0].(*ast.CallExpr); ok {
if r.clean.ContainsPkgCallExpr(call, c, false) != nil {
r.trackFilepathClean(call)
}
}
}
// continue, don't return here — other checks may apply
}
// Now check for file-reading calls (os.Open, os.OpenFile, ioutil.ReadFile etc.)
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
if len(node.Args) == 0 {
return nil, nil
}
arg := node.Args[0]
// If argument is a call expression, check for Join/Clean patterns.
if callExpr, ok := arg.(*ast.CallExpr); ok {
// If this call matches a safe Join(baseDir, Clean(...)) pattern, treat as safe.
if r.isSafeJoin(callExpr, c) {
// safe pattern detected; do not raise an issue
return nil, nil
}
// If the argument is a Join call but not safe per above, flag it (as before)
if r.isJoinFunc(callExpr, c) {
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
if s := r.osRootSuggestion(); s != "" {
iss.Autofix = s
}
return iss, nil
}
}
// If arg is an identifier that was assigned from a Join(...) call, check that recorded Join call.
if ident, ok := arg.(*ast.Ident); ok {
if ident.Obj != nil {
if joinCall, ok := r.joinedVar[ident.Obj.Decl]; ok {
// If the identifier itself was later cleaned, treat as safe regardless of original Join args
if r.isFilepathClean(ident, c) {
return nil, nil
}
// joinCall is a *ast.CallExpr; check if that join is a safe join
if jc, ok := joinCall.(*ast.CallExpr); ok {
if r.isSafeJoin(jc, c) {
return nil, nil
}
// join exists but is not safe: flag it
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
if s := r.osRootSuggestion(); s != "" {
iss.Autofix = s
}
return iss, nil
}
}
}
}
// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
if binExp, ok := arg.(*ast.BinaryExpr); ok {
// resolve all found identities from the BinaryExpr
if _, ok := gosec.FindVarIdentities(binExp, c); ok {
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
if s := r.osRootSuggestion(); s != "" {
iss.Autofix = s
}
return iss, nil
}
}
// if it's a plain identifier, and not resolved and not cleaned, flag it
if ident, ok := arg.(*ast.Ident); ok {
obj := c.Info.ObjectOf(ident)
if _, ok := obj.(*types.Var); ok &&
!gosec.TryResolve(ident, c) &&
!r.isFilepathClean(ident, c) {
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
if s := r.osRootSuggestion(); s != "" {
iss.Autofix = s
}
return iss, nil
}
}
}
return nil, nil
}
@@ -138,6 +277,7 @@ func NewReadFile(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
Confidence: issue.High,
},
cleanedVar: map[any]ast.Node{},
joinedVar: map[any]ast.Node{},
}
rule.pathJoin.Add("path/filepath", "Join")
rule.pathJoin.Add("path", "Join")
@@ -149,5 +289,5 @@ func NewReadFile(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
rule.Add("os", "Open")
rule.Add("os", "OpenFile")
rule.Add("os", "Create")
return rule, []ast.Node{(*ast.CallExpr)(nil)}
return rule, []ast.Node{(*ast.CallExpr)(nil), (*ast.AssignStmt)(nil)}
}

View File

@@ -191,6 +191,11 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issu
if injection := s.findInjectionInBranch(ctx, decl.Rhs); injection != nil {
return ctx.NewIssue(injection, s.ID(), s.What, s.Severity, s.Confidence), nil
}
case *ast.ValueSpec:
// handle: var query string = "SELECT ...'" + user
if injection := s.findInjectionInBranch(ctx, decl.Values); injection != nil {
return ctx.NewIssue(injection, s.ID(), s.What, s.Severity, s.Confidence), nil
}
}
}

View File

@@ -308,4 +308,32 @@ func main() {
fmt.Println(result)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func main() {
db, err := sql.Open("postgres", "user=postgres password=password dbname=mydb sslmode=disable")
if err!= nil {
panic(err)
}
defer db.Close()
var username string
fmt.Println("请输入用户名:")
fmt.Scanln(&username)
var query string = "SELECT * FROM users WHERE username = '" + username + "'"
rows, err := db.Query(query)
if err!= nil {
panic(err)
}
defer rows.Close()
}
`}, 1, gosec.NewConfig()},
}

View File

@@ -301,5 +301,47 @@ func main() {
package main
var THEWD string
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"path/filepath"
)
func open(fn string, perm os.FileMode) {
fh, err := os.OpenFile(filepath.Clean(fn), os.O_RDONLY, perm)
if err != nil {
panic(err)
}
defer fh.Close()
}
func main() {
fn := "filename"
open(fn, 0o600)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"path/filepath"
)
func open(fn string, flag int) {
fh, err := os.OpenFile(filepath.Clean(fn), flag, 0o600)
if err != nil {
panic(err)
}
defer fh.Close()
}
func main() {
fn := "filename"
open(fn, os.O_RDONLY)
}
`}, 0, gosec.NewConfig()},
}