Skip to content

Lint

StageFreight's built-in linters — content hygiene, dependency freshness, secret detection, merge-conflict markers, Unicode/bidi defenses, file size, and more — run as a pipeline gate. They are cache-aware and parallel, and by default scan only what changed.

lint:
  level: changed              # "changed" (delta-only) or "full"
  exclude:
    - "vendor/**"
    - "*.generated.go"
  modules:
    secrets: { enabled: true }
    freshness:
      enabled: true
      options:
        cache_ttl: 300

--level (or --all for full) overrides lint.level, which overrides the changed default. Individual modules can be toggled in config or with --module / --no-module.

Modules

Content-only modules produce deterministic output and are cached forever by content hash. The freshness and vulnerabilities modules depend on external state (registries, the OSV database) and use TTL-based caching.

Module Default Detects
tabs enabled Tab characters
secrets enabled Committed secrets (gitleaks)
conflicts enabled Unresolved merge-conflict markers
filesize enabled Files over a size threshold (default 500 KB)
linecount disabled Files over a line-count threshold (default 1000)
unicode enabled Dangerous Unicode (see below)
yaml enabled YAML syntax errors
lineendings enabled Inconsistent line endings
freshness enabled Out-of-date dependencies + correlated CVEs (TTL-cached)
vulnerabilities enabled Advisories against lockfiles (TTL-cached; osv is a deprecated alias)

Unicode — supply-chain defense

The unicode module defends against trojan-source attacks, invisible-text obfuscation, and control-byte smuggling. BiDi overrides, zero-width characters, tag characters, confusable whitespace, and invalid UTF-8 are flagged; ASCII control bytes are gated by a path-scoped allowlist.

    unicode:
      options:
        detect_control_ascii: true
        allow_control_ascii_in_paths: ["src/output/banner_art.go"]
        allow_control_ascii: [27]      # ESC only

Freshness & vulnerabilities

freshness checks dependency versions against upstream registries and correlates them against the OSV database. vulnerabilities emits one finding per canonical advisory (RuleID = the advisory ID, e.g. GHSA-…/CVE-…), unifying the OSV-API correlation and a per-lockfile osv-scanner pass so the same CVE never surfaces twice — even when an ecosystem splits its manifest and lockfile into separate files (e.g. npm's package.json vs package-lock.json). Vulnerability options are shared with freshness unless placed directly under vulnerabilities.options.

A pinned osv-scanner that fails to resolve hard-fails the gate; an unpinned/unavailable scanner silently skips the osv-scanner leg (the OSV-API leg still runs).

Cache TTL contract

Each module declares its caching behavior, which the engine honors uniformly:

CacheTTL() Engine behavior Expiry
> 0 Cache with TTL Expires when now - CachedAt > TTL
== 0 Cache forever No expiry check
< 0 Never cache Skips Get + Put
not implemented Cache forever No expiry check

Reference

lint

Linting configuration. Controls scan mode, module toggles, and per-module options. 9 modules: tabs, secrets, conflicts, filesize, linecount, unicode, yaml, lineendings, freshness.

lint:
  preset: <string>
  level: <string>   # one of: changed, full · required
  cache_dir: <string>   # required
  target_branch: <string>   # required
  exclude: [<string>]   # required
  modules: {}   # required
  provenance:
    generated: [<string>]
    vendored: [<string>]
  remediation:
    trailing_whitespace: false   # default ON under --fix-safe
    final_newline: false   # default ON under --fix-safe
  cache:
    max_age: <string>   # evict entries not hit in this duration (e.g. "7d")
    max_size: <string>   # evict oldest entries when cache exceeds this (e.g. "100MB")
  fail_on: <string>   # FailOn is the DIAGNOSTIC-IMPORTANCE threshold at or above which a lint finding blocks the build…