Skip to main content

Function Signature

func Scan(ctx context.Context, path string, opts ...Option) (*ScanResult, error)
Source: aguara.go:81

Description

Scans a file or directory on disk for security issues using all registered analyzers:
  • Pattern Matcher: Regex/contains matching against YAML rules
  • NLP Injection: Markdown-specific instruction injection detection
  • Toxic Flow: Taint tracking for dangerous data flows
  • Rug-Pull: File change detection (when used with --monitor)

Parameters

ParameterTypeDescription
ctxcontext.ContextContext for cancellation and timeout
pathstringFile or directory path to scan
opts...OptionFunctional options (see Options)

Return Values

TypeDescription
*ScanResultScan results containing findings, file count, and metadata
errorNon-nil if path doesn’t exist, permission denied, or rule compilation fails

Examples

Basic Usage

package main

import (
    "context"
    "fmt"
    "log"
    
    "github.com/garagon/aguara"
)

func main() {
    ctx := context.Background()
    result, err := aguara.Scan(ctx, "./skills/")
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Scanned %d files, found %d issues\n",
        result.FilesScanned, len(result.Findings))
}

With Minimum Severity Filter

// Only report MEDIUM and above
result, err := aguara.Scan(ctx, "./skills/",
    aguara.WithMinSeverity(aguara.SeverityMedium),
)

With Disabled Rules

// Skip specific rules
result, err := aguara.Scan(ctx, "./skills/",
    aguara.WithDisabledRules("EXFIL_005", "CRED_001"),
)

With Custom Rules

// Load additional rules from a directory
result, err := aguara.Scan(ctx, "./skills/",
    aguara.WithCustomRules("./custom-rules/"),
)

With Multiple Options

result, err := aguara.Scan(ctx, "./skills/",
    aguara.WithMinSeverity(aguara.SeverityHigh),
    aguara.WithWorkers(8),
    aguara.WithDisabledRules("UNICODE_001"),
    aguara.WithIgnorePatterns([]string{"vendor/", "*.log"}),
)

With Timeout

import "time"

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

result, err := aguara.Scan(ctx, "./large-directory/")
if err != nil {
    if ctx.Err() == context.DeadlineExceeded {
        log.Fatal("Scan timed out")
    }
    log.Fatal(err)
}

Processing Results

result, err := aguara.Scan(ctx, "./skills/")
if err != nil {
    log.Fatal(err)
}

// Count findings by severity
counts := make(map[aguara.Severity]int)
for _, f := range result.Findings {
    counts[f.Severity]++
}

fmt.Printf("Critical: %d\n", counts[aguara.SeverityCritical])
fmt.Printf("High:     %d\n", counts[aguara.SeverityHigh])
fmt.Printf("Medium:   %d\n", counts[aguara.SeverityMedium])

Exit on Critical Findings

result, err := aguara.Scan(ctx, "./skills/")
if err != nil {
    log.Fatal(err)
}

for _, f := range result.Findings {
    if f.Severity == aguara.SeverityCritical {
        fmt.Fprintf(os.Stderr, "CRITICAL: %s at %s:%d\n",
            f.RuleName, f.FilePath, f.Line)
    }
}

if hasCritical(result) {
    os.Exit(1)
}

func hasCritical(r *aguara.ScanResult) bool {
    for _, f := range r.Findings {
        if f.Severity == aguara.SeverityCritical {
            return true
        }
    }
    return false
}

File Discovery

When scanning a directory, Aguara:
  1. Recursively walks the directory tree
  2. Skips ignored patterns (.git/, node_modules/, etc.)
  3. Skips binary file extensions (.exe, .dll, .so, .png, .jpg, .zip, .pdf)
  4. Respects .aguaraignore files (gitignore-style patterns)
  5. Applies WithIgnorePatterns() if specified
  6. Filters by WithMaxFileSize() if set (default: 50 MB)

Concurrency

Scanning is parallelized using a worker pool:
  • Default worker count: runtime.NumCPU()
  • Override with WithWorkers(n)
  • Each worker processes one file at a time
  • Results are collected concurrently

Build docs developers (and LLMs) love