config

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package config loads and validates sqletch.yaml. Strict decoding: unknown keys are errors, required fields are named in messages. See docs/design/07-cli-config.md.

Index

Constants

View Source
const (
	OracleServer = "server"
	OracleNative = "native"
)

Oracle backend names.

View Source
const DefaultVerificationMaxShapes = 4096

DefaultVerificationMaxShapes is the shape budget `check --exhaustive` gets when the config says nothing.

Variables

This section is empty.

Functions

func SQLiteFileURIString

func SQLiteFileURIString(absPath, rawQuery string) string

SQLiteFileURIString rebuilds a `file:` URI for an absolute path, preserving a raw query string verbatim. It is how cli.sqliteDSNPath re-roots a relative `file:` DSN against the config directory. url.URL escapes the path (spaces, `#`, …) so the emitted URI round-trips through SQLite's decoder.

Types

type Cache

type Cache struct {
	Path string `yaml:"path"`
}

type Config

type Config struct {
	Version       int          `yaml:"version"`
	Dialect       string       `yaml:"dialect"`
	ServerVersion string       `yaml:"server_version"`
	Database      Database     `yaml:"database"`
	Schema        Schema       `yaml:"schema"`
	Targets       []Target     `yaml:"targets"`
	Cache         Cache        `yaml:"cache"`
	Overrides     []Override   `yaml:"overrides"`
	Expansion     Expansion    `yaml:"static_expansion"`
	Verification  Verification `yaml:"verification"`
	TreeCaps      TreeCaps     `yaml:"filter_tree_caps"`
	Policies      []Policy     `yaml:"policies"`

	// Dir is the directory containing sqletch.yaml; all relative paths
	// resolve against it. Not part of the YAML.
	Dir string `yaml:"-"`
	// Path is the config file itself, so later phases can attach
	// diagnostics to it (e.g. SQLETCH200). Not part of the YAML.
	Path string `yaml:"-"`

	// LegacyQueries and LegacyOutput decode the pre-`targets` spelling
	// (one config, one output package) for ONE purpose: to answer it
	// with the rewrite (SQLETCH301) instead of goccy's generic
	// "unknown field". Neither is ever consumed — the presence of
	// either is an error, so there is no ambiguity about which
	// spelling won. See docs/design/19-multi-target-output.md §7.
	LegacyQueries []string `yaml:"queries"`
	LegacyOutput  *Output  `yaml:"output"`
}

func Load

func Load(path string) (Config, []diagnostics.Diagnostic)

Load reads and validates the configuration. Config values are literal: there is deliberately no ${VAR} environment-variable expansion (removed as a secret-exfiltration / SSRF vector — a cloned repo could otherwise splice the caller's environment, including secrets, into database.dsn and point it at an attacker host). An operator who wants the dev-database DSN to come from the environment should leave database.dsn empty and let the driver's own libpq/DSN environment variables (PGHOST, MYSQL_DSN, …) take effect, or template the config outside sqletch.

func (Config) Abs

func (c Config) Abs(p string) string

Abs resolves a config-relative path.

func (Config) ExpandGlobs

func (c Config) ExpandGlobs(patterns []string) ([]string, error)

ExpandGlobs resolves config-relative globs into a sorted, duplicate- free path list; a pattern matching nothing is an error (a typoed glob silently matching zero files is the classic footgun).

Every match is path-escape-checked (SQLETCH306): the read paths (cli/commands.go, pipeline.go via os.ReadFile) consume this list unchecked, so a committed `queries: ["../../etc/*.conf"]` or a symlinked-directory glob would otherwise read arbitrary host-readable files on a clone-and-run `check`/`generate` and disclose them through catalog/scan and diagnostic excerpts. The check mirrors Load's write-path policy (lexical `..` plus symlinked-component resolution) against the project directory.

func (Config) Expanded

func (c Config) Expanded(query string) bool

func (Config) NativeOracle

func (c Config) NativeOracle() bool

NativeOracle reports whether the native-inference backend is selected.

func (Config) NullOverridesFor

func (c Config) NullOverridesFor(query string) map[string]bool

NullOverridesFor collects the per-column nullability overrides of one query.

func (Config) ResolveTargets added in v0.0.2

func (c Config) ResolveTargets() (Resolution, []diagnostics.Diagnostic)

ResolveTargets expands every target's patterns against the project directory. It is the single resolution seam: pipeline.Run and the LSP's OfflineChecker both call it, so the two can never disagree about which file belongs to which generated package.

A pattern matching nothing is a WARNING, not an error (design 19 §4): in a monorepo a captured directory may not exist yet, and a target with no files simply emits nothing. `schema.files` keeps the stricter rule — an empty schema silently fingerprints nothing.

type Database

type Database struct {
	DSN string `yaml:"dsn"`
	// Oracle selects the type-oracle backend: "server" (default; a
	// dev database serves cache misses) or "native" (sqletch's own
	// corpus-validated inference — MySQL only, design 15). Strict by
	// decision D1: no fallback, and no DSN to fall back to.
	Oracle string `yaml:"oracle"`
}

type Expansion

type Expansion struct {
	Queries   []string `yaml:"queries"`
	MaxShapes int      `yaml:"max_shapes"`
}

Expansion configures strict static expansion: listed queries are materialized shape-by-shape into .sql files and dispatch to precomposed SQL instead of composing at runtime.

type Output

type Output struct {
	Package string `yaml:"package"`
	Path    string `yaml:"path"`
}

func (Output) HasCaptureRefs added in v0.0.2

func (o Output) HasCaptureRefs() bool

HasCaptureRefs reports whether the output spells a `$n` capture reference, i.e. whether it can only be validated once patterns have been expanded against the filesystem.

type Override

type Override struct {
	Query    string `yaml:"query"`
	Column   string `yaml:"column"`
	Nullable *bool  `yaml:"nullable"`
}

type Policy

type Policy struct {
	Name      string      `yaml:"name"`
	Tables    []string    `yaml:"tables"`
	Predicate string      `yaml:"predicate"`
	Param     PolicyParam `yaml:"param"`
	// AppliesTo restricts the statement kinds the policy covers;
	// empty means select, update, and delete. INSERT … VALUES is
	// never a policy target (no rows are filtered).
	AppliesTo []string `yaml:"applies_to"`
}

Policy declares one cross-query policy (spec §"Cross-Query Policies"): a predicate woven at compile time into every query that touches a designated table, plus the enforcement that no reachable shape goes unscoped. Shape checks that need the dialect (predicate probing, identifier rules) live in policy.Validate; Load checks only the config-level vocabulary.

type PolicyParam

type PolicyParam struct {
	Name string `yaml:"name"`
	Type string `yaml:"type"`
}

PolicyParam declares the policy predicate's parameter. Type is required on Tier 2 dialects (their oracles cannot type parameter slots) and asserted like a `-- @param` hint on Tier 1.

type Resolution added in v0.0.2

type Resolution struct {
	// Targets are ordered by output path, and each target's Files are
	// sorted: determinism is never conditional on directory order.
	Targets []ResolvedTarget
	// Files is the union of every target's files, sorted. It is what
	// the whole-workspace commands (fmt, explain) and the LSP iterate.
	Files []string
	// Dirs are the directories the expansion consulted, absolute. A
	// directory's mtime moves when an entry is added or removed, so
	// re-stating these is a sound memo signature for the LSP (§6).
	Dirs []string
}

Resolution is one expansion of `targets` against the project directory.

type ResolvedTarget added in v0.0.2

type ResolvedTarget struct {
	// Package is the generated package name (captures substituted).
	Package string
	// Path is the output directory as written in the config (captures
	// substituted): project-relative and slash-separated unless the
	// user spelled an absolute path. Use Config.Abs for filesystem
	// access and Slug for a derived-output namespace.
	Path string
	// Files are the template files, absolute and sorted.
	Files []string
}

ResolvedTarget is one generated Go package: the files that feed it and where it is written. It is what `targets` resolves to once patterns are expanded and captures substituted (docs/design/19-multi-target-output.md §4).

func (ResolvedTarget) Abs added in v0.0.2

func (t ResolvedTarget) Abs(c Config) string

Abs is the target's output directory as a filesystem path.

func (ResolvedTarget) Slug added in v0.0.2

func (t ResolvedTarget) Slug() string

Slug is the target's identity inside the derived-output trees (.sqletch/explain/<slug>/…, .sqletch/expanded/<slug>/…). It mirrors the output path so the tree is readable, with the escapes a path component cannot carry folded away — an absolute or climbing path (only reachable via the absolute-output warning) must not send a derived write out of .sqletch/.

type SQLiteFileURI

type SQLiteFileURI struct {
	// InMemory is true for an in-memory / private-temp database — an empty
	// or ":memory:" path component. It is not a filesystem path, so it is
	// exempt from the escape check and passes through resolution untouched.
	InMemory bool
	// Abs is true when the path component is absolute. An absolute dev-DB
	// path is a normal operator choice (allowed like the plain absolute
	// spelling) and is never re-rooted against the config dir.
	Abs bool
	// Safe is false when the URI cannot be proven to stay inside the project
	// — a non-local authority (`file://host/…` with host other than
	// localhost) or an undecodable percent-escape. A trusted config never
	// produces one; callers refuse it (SQLETCH306) rather than guess.
	Safe bool
	// Path is the DECODED path component: relative to the config dir when
	// !Abs, absolute when Abs, empty when InMemory.
	Path string
	// Query is the raw query string after '?' (without the '?'), preserved
	// verbatim by SQLiteFileURIString.
	Query string
}

SQLiteFileURI is the classified result of parsing a SQLite `file:` DSN. A `file:` URI is a real filesystem reference (ncruces opens SQLite with OPEN_URI|OPEN_CREATE), so its path component must go through the same SQLETCH306 escape check as a plain path. Both the config validator (Load → the SQLETCH306 refusal) and the DSN resolver (cli.sqliteDSNPath) classify with this type, so the parse lives in one place and they cannot drift.

func ParseSQLiteFileURI

func ParseSQLiteFileURI(dsn string) SQLiteFileURI

ParseSQLiteFileURI classifies a DSN the caller already knows begins with "file:". net/url does the heavy lifting: a relative path component lands in Opaque (kept percent-encoded), an absolute one in Path (already decoded), and any authority in Host. Only an empty or "localhost" authority is provably safe — SQLite rejects the rest — so anything else is refused conservatively (a false-reject on trusted config is a LOW annoyance; a false-accept is the vulnerability).

type Schema

type Schema struct {
	Files []string `yaml:"files"`
}

type Target added in v0.0.2

type Target struct {
	Queries []string `yaml:"queries"`
	Output  Output   `yaml:"output"`
}

Target pairs a set of query-file patterns with the Go package they generate into (docs/design/19-multi-target-output.md). Patterns may carry capture groups whose text substitutes into Output, so ONE target can fan out into one package per matched directory; the grouping key is the SUBSTITUTED output, not the config entry, so several patterns landing on the same output merge into one package.

type TreeCaps

type TreeCaps struct {
	MaxNodes int `yaml:"max_nodes"`
	MaxDepth int `yaml:"max_depth"`
}

TreeCaps bounds @filter-tree values at runtime; the values are baked into generated code.

type Verification

type Verification struct {
	MaxShapes int `yaml:"max_shapes"`
}

Verification bounds the work `check --exhaustive` will do. It is a config key rather than a flag because it decides whether a CI gate passes: a project's verification budget must be the same on every machine that runs the check, not a property of who typed the command.

Jump to

Keyboard shortcuts

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