Skip to content

Commit e847ea7

Browse files
author
Test User
committed
fix(lineutil): prevent false positives in API key detection
Add isPlaceholderSecret() to filter out documentation examples, placeholder values, and common test patterns from secret detection. Prevents flagging legitimate example code like "API_KEY=your-key-here" in documentation. Updated all internal/cli/*_test.go files to use placeholder patterns that won't trigger false positives.
1 parent c903ec7 commit e847ea7

7 files changed

Lines changed: 1394 additions & 0 deletions

File tree

internal/cli/agents_test.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package cli
33
import (
44
"strings"
55
"testing"
6+
7+
"github.com/dotcommander/cclint/internal/cue"
8+
"github.com/dotcommander/cclint/internal/discovery"
69
)
710

811
func TestValidateAgentSpecific(t *testing.T) {
@@ -248,3 +251,135 @@ func TestKnownAgentFields(t *testing.T) {
248251
}
249252
}
250253
}
254+
255+
func TestAgentLinterPostProcessBatch(t *testing.T) {
256+
linter := NewAgentLinter()
257+
258+
tests := []struct {
259+
name string
260+
files []discovery.File
261+
noCycleCheck bool
262+
wantCycleErrors int
263+
wantTotalErrors int
264+
wantFailedFiles int
265+
wantSuccessFiles int
266+
}{
267+
{
268+
name: "no cycles detected",
269+
files: []discovery.File{
270+
{
271+
RelPath: "agents/agent-a.md",
272+
Type: discovery.FileTypeAgent,
273+
Contents: "Skill: skill-a",
274+
},
275+
{
276+
RelPath: "skills/skill-a/SKILL.md",
277+
Type: discovery.FileTypeSkill,
278+
Contents: "Skill content",
279+
},
280+
},
281+
noCycleCheck: false,
282+
wantCycleErrors: 0,
283+
wantTotalErrors: 0,
284+
wantFailedFiles: 0,
285+
wantSuccessFiles: 2,
286+
},
287+
{
288+
name: "cycle detected",
289+
files: []discovery.File{
290+
{
291+
RelPath: "agents/agent-a.md",
292+
Type: discovery.FileTypeAgent,
293+
Contents: "Task(agent-b)",
294+
},
295+
{
296+
RelPath: "agents/agent-b.md",
297+
Type: discovery.FileTypeAgent,
298+
Contents: "Task(agent-a)",
299+
},
300+
},
301+
noCycleCheck: false,
302+
wantCycleErrors: 2, // One error per agent in cycle
303+
wantTotalErrors: 2,
304+
wantFailedFiles: 2,
305+
wantSuccessFiles: 0,
306+
},
307+
{
308+
name: "cycle check disabled",
309+
files: []discovery.File{
310+
{
311+
RelPath: "agents/agent-a.md",
312+
Type: discovery.FileTypeAgent,
313+
Contents: "Task(agent-b)",
314+
},
315+
{
316+
RelPath: "agents/agent-b.md",
317+
Type: discovery.FileTypeAgent,
318+
Contents: "Task(agent-a)",
319+
},
320+
},
321+
noCycleCheck: true,
322+
wantCycleErrors: 0, // Cycle check disabled
323+
wantTotalErrors: 0,
324+
wantFailedFiles: 0,
325+
wantSuccessFiles: 2,
326+
},
327+
}
328+
329+
for _, tt := range tests {
330+
t.Run(tt.name, func(t *testing.T) {
331+
crossValidator := NewCrossFileValidator(tt.files)
332+
ctx := &LinterContext{
333+
CrossValidator: crossValidator,
334+
NoCycleCheck: tt.noCycleCheck,
335+
}
336+
337+
// Create initial summary with all files successful
338+
summary := &LintSummary{
339+
TotalFiles: len(tt.files),
340+
SuccessfulFiles: len(tt.files),
341+
FailedFiles: 0,
342+
TotalErrors: 0,
343+
Results: make([]LintResult, len(tt.files)),
344+
}
345+
346+
for i, file := range tt.files {
347+
summary.Results[i] = LintResult{
348+
File: file.RelPath,
349+
Type: "agent",
350+
Success: true,
351+
Errors: []cue.ValidationError{},
352+
}
353+
}
354+
355+
// Run post-processing
356+
linter.PostProcessBatch(ctx, summary)
357+
358+
// Count cycle errors
359+
cycleErrors := 0
360+
for _, result := range summary.Results {
361+
for _, err := range result.Errors {
362+
if strings.Contains(err.Message, "Circular dependency") {
363+
cycleErrors++
364+
}
365+
}
366+
}
367+
368+
if cycleErrors != tt.wantCycleErrors {
369+
t.Errorf("PostProcessBatch() cycle errors = %d, want %d", cycleErrors, tt.wantCycleErrors)
370+
}
371+
372+
if summary.TotalErrors != tt.wantTotalErrors {
373+
t.Errorf("PostProcessBatch() TotalErrors = %d, want %d", summary.TotalErrors, tt.wantTotalErrors)
374+
}
375+
376+
if summary.FailedFiles != tt.wantFailedFiles {
377+
t.Errorf("PostProcessBatch() FailedFiles = %d, want %d", summary.FailedFiles, tt.wantFailedFiles)
378+
}
379+
380+
if summary.SuccessfulFiles != tt.wantSuccessFiles {
381+
t.Errorf("PostProcessBatch() SuccessfulFiles = %d, want %d", summary.SuccessfulFiles, tt.wantSuccessFiles)
382+
}
383+
})
384+
}
385+
}

0 commit comments

Comments
 (0)