config

package
v0.2.9 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package config models and loads .codefit.yaml, the per-project configuration committed to the repository. It is a leaf package (no codefit dependencies) so that both the core context and the language providers can reference its types without creating import cycles.

Status: BUILT. The struct shape mirrors the PRD's .codefit.yaml and Load validates it, reporting errors located to the offending line. There is no global config to merge with, by design: codefit manages no models and no credentials, so .codefit.yaml is the only configuration there is.

Index

Constants

View Source
const (
	TestSeverityInfo      = "info"
	TestSeverityDowngrade = "downgrade"
	TestSeverityKeep      = "keep"
)

Test-path severity modes (RF-10). They govern what happens to a security finding whose file is classified "test" by path_criticality:

  • TestSeverityInfo forces it to info. It is the DEFAULT, and the mode the PRD chose: a secret in a test does not weigh what a secret in production weighs, so it costs the security score nothing (severity penalty 0).
  • TestSeverityDowngrade lowers it exactly one level (critical→high, …). It was codefit's hardcoded behaviour before this key existed.
  • TestSeverityKeep applies NO adjustment at all: the natural severity survives. It is the only one of the three that can leave a critical security finding standing on a test path, which means it is also the only one that can make scoring.IsBlocked true from a test file. That is a deliberate, PRD-named choice, not an accident — see SecuritySensor.
View Source
const (
	CriticalityProduction = "production"
	CriticalityTest       = "test"
	CriticalityExample    = "example"
)

Path-criticality classes (RF-10).

View Source
const LanguageUndetected = "undetected"

LanguageUndetected is the value `codefit init` writes into project.language when no marker file under the project root resolved an auditable language provider.

It is a statement about codefit's DETECTION, never about the project. A Java or Rust repository has a language; codefit simply registers no provider that can audit its code, so it says so in the one place every later reader looks instead of refusing to write a config at all. Rendering it as "this project has no language" would be a lie.

It lives here, beside allowedLanguages, for two reasons. internal/scaffold already imports internal/config, so housing it there would invert the dependency; and internal/providers/registry is the wrong home because the sentinel is precisely the ABSENCE of a registered entry — a constant there invites someone to add a matching fake table row.

Every consumer of Project.Language must read it as "resolve no provider", not as a language name. No production sensor or handler reads the field today (validation is its only consumer), so the sentinel resolves nothing anywhere by construction — internal/mcp's Lock A asserts exactly that.

Variables

This section is empty.

Functions

func ExpandGlobs

func ExpandGlobs(root string, patterns []string) ([]string, error)

ExpandGlobs resolves glob patterns (with ** support) to the set of existing files under root, project-relative and de-duplicated. It is used to turn schema_paths, test_dirs and ignore.paths into concrete file lists.

Types

type Baseline

type Baseline struct {
	Enabled bool   `yaml:"enabled"`
	File    string `yaml:"file"`
}

Baseline configures the adoption baseline (RF-08): when enabled only new findings are reported.

type Cache

type Cache struct {
	Enabled bool   `yaml:"enabled"`
	Dir     string `yaml:"dir"`
}

Cache configures the content-hash finding cache.

type Config

type Config struct {
	Version  string   `yaml:"version"`
	Project  Project  `yaml:"project"`
	Database Database `yaml:"database"`
	Sensors  Sensors  `yaml:"sensors"`
	Report   Report   `yaml:"report"`
	Cache    Cache    `yaml:"cache"`
	Baseline Baseline `yaml:"baseline"`
	MCP      MCP      `yaml:"mcp"`
	Ignore   Ignore   `yaml:"ignore"`
}

Config is the parsed representation of .codefit.yaml. Fields mirror the PRD schema. Zero values are acceptable throughout: .codefit.yaml is optional and every consumer defaults, so an absent key is a real state, not an unfinished one. Load validates what IS present.

func Load

func Load(path string) (*Config, error)

Load reads, parses and validates a .codefit.yaml file from path. Validation errors are located (path:line) so the user can jump to the offending line.

It does not yet apply defaulting or merge with the global user config; those are layered on by the caller.

func LoadOptional

func LoadOptional(path string) (*Config, error)

LoadOptional loads a .codefit.yaml only when it exists, distinguishing the three states callers must not conflate:

  • ABSENT → (nil, nil): no config is fine, the caller uses defaults.
  • PRESENT but INVALID → (nil, error): codefit must REFUSE to run silently with a broken config. Swallowing this is the very anti-pattern codefit exists to catch — a false "all good" that hides a real problem (e.g. an invalid framework silently disabling path_criticality).
  • VALID → (cfg, nil): loaded normally.

The returned error is the located, field-level message from Load/validate (e.g. `invalid framework "nextjs" (allowed: …)`), useful enough to fix.

func (*Config) PathCriticalityFor

func (c *Config) PathCriticalityFor(file string) string

PathCriticalityFor classifies a project-relative file path as "production", "test" or "example" by matching it against the configured path_criticality globs, or returns "" when nothing matches.

Test and example take precedence over production so that, e.g., a *_test.go living under a production directory is correctly treated as test (lower severity), not production.

func (*Config) TestSeverityMode added in v0.2.9

func (c *Config) TestSeverityMode() string

TestSeverityMode resolves sensors.security.test_severity into the mode the security sensor must apply to a test-classified path (RF-10).

It is the SINGLE place the default is decided. Unset ("") means TestSeverityInfo — the PRD's default — and so does a nil Config, which is the ordinary state of a project with no .codefit.yaml. A value outside the enum cannot survive Load (validate rejects it with a located error), so reaching this function it can only come from a hand-built Config; the resolver refuses to invent a fourth mode and falls back to the default rather than silently leaving severities unweighted.

Callers ask for the mode; they never read Sensors.Security.TestSeverity raw. A sensor that re-implemented the "" → info rule locally is exactly how two defaults drift apart, which is the same reason PathCriticalityFor lives here.

type Database

type Database struct {
	Paradigm    string   `yaml:"paradigm"` // oltp | olap | mixed | auto (default)
	Type        string   `yaml:"type"`
	SchemaPaths []string `yaml:"schema_paths"`
	ORM         string   `yaml:"orm"`
}

Database declares the DB paradigm and schema sources for the DB sensor.

type Ignore

type Ignore struct {
	Paths    []string        `yaml:"paths"`
	Findings []IgnoreFinding `yaml:"findings"`
}

Ignore holds path globs and finding suppressions. Critical security suppressions require an embedded ConsentRecord (validated later).

type IgnoreFinding

type IgnoreFinding struct {
	ID         string `yaml:"id"`
	Reason     string `yaml:"reason"`
	AcceptedBy string `yaml:"accepted_by"`
	AcceptedAt string `yaml:"accepted_at"`
}

IgnoreFinding suppresses a finding by ID. For critical security findings the consent fields are mandatory.

type MCP

type MCP struct {
	Enabled     bool     `yaml:"enabled"`
	ExposeTools []string `yaml:"expose_tools"`
}

MCP configures the MCP server and which tools it exposes.

type PathCriticality

type PathCriticality struct {
	Production []string `yaml:"production"`
	Test       []string `yaml:"test"`
	Example    []string `yaml:"example"`
}

PathCriticality classifies directories so the engine can raise or lower a finding's severity by where it lives. A secret in a test is noise; in production it is critical (RF-10). Language providers supply sensible defaults via LanguageProvider.DefaultPathCriticality.

type Project

type Project struct {
	Name            string          `yaml:"name"`
	Language        string          `yaml:"language"`
	Framework       string          `yaml:"framework"`
	Description     string          `yaml:"description"`
	PathCriticality PathCriticality `yaml:"path_criticality"`
}

Project holds project identity and the path-criticality classification that weights finding severity by location (RF-10).

type Report

type Report struct {
	Output       string         `yaml:"output"`
	OutFile      string         `yaml:"out_file"`
	IncludeInfo  bool           `yaml:"include_info"`
	ScoreWeights map[string]int `yaml:"score_weights"`
}

Report configures output format and the per-dimension score weights (which must sum to 100).

type SecuritySensor added in v0.2.9

type SecuritySensor struct {
	SensorToggle `yaml:",inline"`
	TestSeverity string `yaml:"test_severity,omitempty"`
}

SecuritySensor is the security sensor's config: the shared toggle plus the knobs only this sensor honours.

SensorToggle is embedded with `yaml:",inline"` so `enabled` and `test_severity` sit at the same level in .codefit.yaml while `enabled` keeps ONE definition (and its three-state *bool) shared with every other sensor.

TestSeverity selects how a test-classified path re-weights a security finding: "" (unset) means TestSeverityInfo — resolve it through (*Config).TestSeverityMode(), never by reading this field raw.

CONSEQUENCE OF "keep", stated where the key is declared: under TestSeverityKeep a critical security finding in a test file stays critical, so it keeps RequiresConsent and scoring.IsBlocked reports the project as blocked. codefit does not refuse the mode — it is one of the three the PRD names, and the developer decides — but the consequence is not hidden either: the security sensor emits one warning per run when keep actually leaves a finding at critical on a test path.

type SensorToggle

type SensorToggle struct {
	Enabled *bool `yaml:"enabled,omitempty"`
}

SensorToggle is the minimal per-sensor config common to every sensor. Enabled is a *bool to carry a THREE-STATE meaning: nil (unset in .codefit.yaml) lets a sensor apply its own default (the DB sensor treats unset as on — opt-out); an explicit true/false overrides it. A plain bool could not tell "unset" from "explicitly false".

It carries ONLY what every sensor honours. Adding a sensor-specific knob here is the tempting one-line edit that makes five other sensors silently ACCEPT a key none of them reads — dead config that parses, validates and does nothing, exactly the class of defect codefit audits for. TestSeverity therefore lives on SecuritySensor, and sensortoggle_lock_test.go fails the build if that ever stops being true.

type Sensors

type Sensors struct {
	Security   SecuritySensor `yaml:"security"`
	Review     SensorToggle   `yaml:"review"`
	DB         SensorToggle   `yaml:"db"`
	Complexity SensorToggle   `yaml:"complexity"`
	Practices  SensorToggle   `yaml:"practices"`
	Tests      SensorToggle   `yaml:"tests"`
}

Sensors toggles and tunes each sensor. Only the enable flags and a couple of representative knobs are modeled — the tuning surface grows with the sensors that need it, rather than being declared ahead of them.

Jump to

Keyboard shortcuts

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