Skip to content

Commit ef273f4

Browse files
committed
Merge develop into main: ShellAI test fixes
2 parents 65f565c + 89b292b commit ef273f4

File tree

5 files changed

+47
-3
lines changed

5 files changed

+47
-3
lines changed

internal/query/review_bugpatterns.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,11 @@ func checkDiscardedError(root *sitter.Node, source []byte, file string) []Review
499499
}
500500

501501
// Build a map of variable names to their declared types within this function.
502+
// For closures (func_literal), also include vars from enclosing scopes.
502503
varTypes := buildVarTypeMap(body, source)
504+
if fn.Type() == "func_literal" {
505+
mergeEnclosingVarTypes(fn, source, varTypes)
506+
}
503507

504508
// Find discarded calls in this function body.
505509
exprStmts := complexity.FindNodes(body, []string{"expression_statement"})
@@ -623,6 +627,30 @@ func buildVarTypeMap(body *sitter.Node, source []byte) map[string]string {
623627
return result
624628
}
625629

630+
// mergeEnclosingVarTypes walks up from a func_literal to find the enclosing
631+
// function's variable declarations. This catches cases like:
632+
//
633+
// var rawContent strings.Builder
634+
// provider.GenerateStream(ctx, prompt, func(chunk string) {
635+
// rawContent.WriteString(chunk) // closure captures outer var
636+
// })
637+
func mergeEnclosingVarTypes(closureNode *sitter.Node, source []byte, varTypes map[string]string) {
638+
for n := closureNode.Parent(); n != nil; n = n.Parent() {
639+
if n.Type() == "function_declaration" || n.Type() == "method_declaration" {
640+
body := n.ChildByFieldName("body")
641+
if body != nil {
642+
enclosing := buildVarTypeMap(body, source)
643+
for k, v := range enclosing {
644+
if _, exists := varTypes[k]; !exists {
645+
varTypes[k] = v
646+
}
647+
}
648+
}
649+
return
650+
}
651+
}
652+
}
653+
626654
// splitSelector splits "b.WriteString" into ("b", "WriteString").
627655
func splitSelector(fullName string) (receiver, method string) {
628656
idx := strings.LastIndex(fullName, ".")

internal/query/review_deadcode.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,14 @@ func (e *Engine) checkDeadCode(ctx context.Context, changedFiles []string, opts
111111

112112
// findDeadConstants scans changed Go files for exported constants and checks
113113
// if they have any references outside their declaration file.
114+
// Requires SCIP index for reference counting — skips if unavailable to avoid
115+
// tree-sitter fallback which isn't thread-safe for concurrent use.
114116
func (e *Engine) findDeadConstants(ctx context.Context, changedFiles []string, alreadyReported map[string]bool) []ReviewFinding {
117+
// Skip constant scanning when SCIP is unavailable — the tree-sitter
118+
// fallback search path is not thread-safe for concurrent goroutine use.
119+
if e.scipAdapter == nil {
120+
return nil
121+
}
115122
var findings []ReviewFinding
116123

117124
for _, file := range changedFiles {

internal/query/symbols.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ func sortReferences(refs []ReferenceInfo) {
818818
}
819819

820820
// searchWithTreesitter performs symbol search using tree-sitter as fallback.
821+
// Acquires tsMu because tree-sitter cgo is not thread-safe.
821822
func (e *Engine) searchWithTreesitter(ctx context.Context, opts SearchSymbolsOptions) ([]SearchResultItem, error) {
822823
if e.treesitterExtractor == nil {
823824
return nil, nil
@@ -829,8 +830,10 @@ func (e *Engine) searchWithTreesitter(ctx context.Context, opts SearchSymbolsOpt
829830
searchRoot = filepath.Join(e.repoRoot, opts.Scope)
830831
}
831832

832-
// Extract all symbols from the directory
833+
// Extract all symbols from the directory — tree-sitter cgo requires mutex
834+
e.tsMu.Lock()
833835
allSymbols, err := e.treesitterExtractor.ExtractDirectory(ctx, searchRoot, nil)
836+
e.tsMu.Unlock()
834837
if err != nil {
835838
e.logger.Warn("Tree-sitter extraction failed",
836839
"error", err.Error(),

internal/secrets/patterns.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ var BuiltinPatterns = []Pattern{
212212
Name: "generic_secret",
213213
Type: SecretTypeGenericSecret,
214214
Severity: SeverityMedium,
215-
Regex: regexp.MustCompile(`(?i)(?:secret|password|passwd|pwd|token)['":\s=]+['"]?([A-Za-z0-9!@#$%^&*()_+\-=]{8,64})['"]?`),
215+
Regex: regexp.MustCompile(`(?i)(?:secret|password|passwd|pwd|token)\s*[=:]\s*['"]([A-Za-z0-9!@#$%^&*()_+\-=]{8,64})['"]`),
216216
MinEntropy: 3.0,
217217
Description: "Generic Secret or Password",
218218
},

internal/secrets/scanner.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ func isLikelyFalsePositive(line, secret string) bool {
409409
return true
410410
}
411411

412-
// Check for test/example indicators
412+
// Check for test/example/dev indicators
413413
falsePositiveIndicators := []string{
414414
"example",
415415
"sample",
@@ -426,6 +426,12 @@ func isLikelyFalsePositive(line, secret string) bool {
426426
"insert",
427427
"fixme",
428428
"todo",
429+
"local-dev",
430+
"dev-token",
431+
"dev-secret",
432+
"default",
433+
"template",
434+
"demo",
429435
}
430436

431437
for _, indicator := range falsePositiveIndicators {

0 commit comments

Comments
 (0)