scan

package
v0.5.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 5, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package scan implements the local detectors that ship with the CLI.

Right now: a port of workers/src/security/secrets.ts. Two-pass — provider regex (high confidence) + keyword-proximity + Shannon entropy fallback — kept independent from the server-side TS so `npx getdebug analyze . --ci` works offline with no account.

Behavioral parity with the TS implementation is enforced by secrets_test.go. When updating either, update both.

Index

Constants

View Source
const (
	SeverityCritical = "critical"
	SeverityHigh     = "high"
	SeverityMedium   = "medium"
	SeverityLow      = "low"
	SeverityInfo     = "info"
)

Severity levels. Mirrors api/src/db/schema.ts severityEnum.

Variables

This section is empty.

Functions

func BuiltInIgnorePatterns added in v0.4.0

func BuiltInIgnorePatterns() []string

BuiltInIgnorePatterns returns the conservative default exclusions every scan applies unless the user passes --no-default-ignores. Limited to patterns that are UNAMBIGUOUSLY test-scaffolding so the defaults never silently drop real source code:

  • **/*.test.{ts,tsx,js,jsx,mjs,cjs} — Jest / Vitest convention
  • **/*.spec.{ts,tsx,js,jsx,mjs,cjs} — Jest convention
  • **/*_test.go — Go convention (enforced by the toolchain)
  • **/test_*.py — pytest convention
  • **/*_test.py — pytest convention (alternative form)
  • **/__tests__/**, **/__fixtures__/**, **/__snapshots__/**, **/__mocks__/** — Jest's double-underscore convention is specifically reserved for test scaffolding
  • **/testdata/** — Go convention; `go build` itself ignores it

Deliberately NOT included (too ambiguous):

  • fixtures/, bench/, examples/ — common legitimate directory names in user code
  • **/__init__.py, conftest.py — Python markers that could be legit

The user can always override with a `!` line in .getdebug-ignore.

Types

type AiAppRegexResult added in v0.2.0

type AiAppRegexResult struct {
	Findings        []Finding
	FilesConsidered int
	FilesScanned    int
	FilesSkipped    int
	Errors          int
}

AiAppRegexResult mirrors the existing scan-pass return shapes so the CLI's analyze command can emit honest coverage numbers (files considered, scanned, errors, etc.) the same way as secrets + sastlocal.

func ScanAiAppRegex added in v0.2.0

func ScanAiAppRegex(workdir string, rules *IgnoreRuleset, logf func(format string, args ...any)) (*AiAppRegexResult, error)

ScanAiAppRegex walks workdir for JS/TS/JSX/TSX files and applies both regex prefilters. Mirrors the file-walk shape secrets.go uses, with the same vendor + lockfile skips, so a clean analyze run never double-walks. Best-effort: read errors are logged via logf and the walk continues.

type Finding

type Finding struct {
	FilePath    string `json:"filePath"`
	LineStart   int    `json:"lineStart"`
	LineEnd     int    `json:"lineEnd"`
	Category    string `json:"category"`
	Severity    string `json:"severity"`
	Title       string `json:"title"`
	Explanation string `json:"explanation"`
	ContentHash string `json:"contentHash"`
	Pattern     string `json:"pattern,omitempty"`
	Detection   string `json:"detection,omitempty"` // "regex" | "entropy"
	Snippet     string `json:"snippet,omitempty"`
	CWE         string `json:"cwe,omitempty"`
	OWASP       string `json:"owasp,omitempty"`
}

Finding is the CLI-local shape of a security finding. Maps onto the SecurityFinding type in workers/src/security/types.ts.

type IgnoreRuleset added in v0.3.0

type IgnoreRuleset struct {
	// contains filtered or unexported fields
}

IgnoreRuleset holds the parsed ignore matchers for a scan workdir. Zero value is safe to use: every IsIgnored call returns false.

Nested .gitignore files are honored: each .gitignore found during a pre-walk gets its own matcher scoped to the directory the file lives in. A path is checked against every matcher whose scope is an ancestor of the path (workdir-relative). This matches git's semantics for nested .gitignore files like `bench/.gitignore` excluding `results/`.

func LoadIgnoreRules added in v0.3.0

func LoadIgnoreRules(workdir string, respectGitignore, respectDefaults bool, logf func(format string, args ...any)) *IgnoreRuleset

LoadIgnoreRules reads every .gitignore under workdir + a single .getdebug-ignore at the workdir root, plus the built-in default patterns when respectDefaults=true.

respectGitignore=false skips the .gitignore traversal entirely (the --no-gitignore code path). respectDefaults=false skips the built-in test-scaffolding exclusions (the --no-default-ignores code path). .getdebug-ignore always applies regardless of either flag — it's the user's scanner-specific config.

The traversal honors `skipDirs` (no descending into node_modules, .next, etc.) so we don't pay the cost of reading thousands of vendored .gitignores. Errors are non-fatal: a malformed file is reported via logf and the scan continues with no rules from that file. Honest degradation.

func (*IgnoreRuleset) IsDirIgnored added in v0.3.0

func (r *IgnoreRuleset) IsDirIgnored(relDir string) bool

IsDirIgnored is the same as IsIgnored but for a directory path. Callers can use filepath.WalkDir's `if d.IsDir() { ... }` branch to skip whole subtrees. Internally we check both the bare path and the trailing-slash form so directory-only patterns (`foo/`) match.

func (*IgnoreRuleset) IsIgnored added in v0.3.0

func (r *IgnoreRuleset) IsIgnored(relPath string) bool

IsIgnored returns true when relPath matches either layer's rules. `relPath` must be relative to the workdir LoadIgnoreRules was called with, using forward slashes (filepath.ToSlash).

Empty path returns false — the workdir itself is never ignored.

type Result

type Result struct {
	Findings     []Finding
	ScannedFiles int
	ScannedBytes int64
	Truncated    bool // hit MAX_TOTAL_BYTES before finishing the walk
}

Result is what ScanSecrets returns.

func ScanSecrets

func ScanSecrets(opts ScanOptions) (*Result, error)

ScanSecrets runs the two-pass secret detector across Workdir. Manually recurses with os.ReadDir per directory (rather than filepath.WalkDir) because we need the full directory listing in hand to check the database-data-dir sentinels (PG_VERSION etc.) before descending — WalkDir delivers entries individually.

type SastLocalOptions added in v0.2.0

type SastLocalOptions struct {
	Workdir string
	Client  *localllm.Client
	Model   string
	// IgnoreRules applies .gitignore + .getdebug-ignore patterns. Same
	// semantic as the secrets + ai-app passes — nil means "no rules."
	IgnoreRules *IgnoreRuleset
	// MaxFiles caps the per-scan call count. Local 7B models on CPU run
	// 30s–5min per file; without this, a 500-file repo could pin the
	// laptop for hours. Default 50.
	MaxFiles int
	// MaxFileBytes skips oversize files (generated, vendored, lockfiles).
	// Default 96 KiB — large enough for almost every hand-written source
	// file, small enough that the model's context window isn't a problem.
	MaxFileBytes int
	// Logf is an optional progress logger (printed to stderr by the CLI).
	Logf func(format string, args ...any)
}

SastLocalOptions configures one local-SAST pass.

type SastLocalResult added in v0.2.0

type SastLocalResult struct {
	Findings        []Finding
	FilesConsidered int
	FilesScanned    int
	FilesSkipped    int // oversize / unreadable
	Malformed       int // model responses we couldn't parse
	Errors          int // transport / model errors
}

SastLocalResult summarises what the pass covered + emitted.

func ScanSastLocal added in v0.2.0

func ScanSastLocal(ctx context.Context, opts SastLocalOptions) (*SastLocalResult, error)

ScanSastLocal runs the local SAST pass over Workdir. Returns the findings alongside the coverage counters so the CLI can render an honest "scanned N of M, dropped K malformed" footer (mirroring how the hosted dashboard surfaces SAST coverage).

type ScanOptions

type ScanOptions struct {
	// Workdir is the root to walk. Required.
	Workdir string
	// Ignore is a set of relative paths to skip (forward-slash form).
	Ignore map[string]struct{}
	// IgnoreRules applies .gitignore + .getdebug-ignore patterns.
	// Nil means "no additional rules" — only the built-in skipDirs +
	// the per-path Ignore set above are honored. Loaded by
	// LoadIgnoreRules at the analyze command level.
	IgnoreRules *IgnoreRuleset
}

ScanOptions controls the secrets walk.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL