policy

package
v0.56.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// RuleImport is a dependency this kind of repository may not have.
	RuleImport = "import"
	// RuleLayer is an import travelling the wrong way inside one repository.
	RuleLayer = "layer"
	// RuleRole is a package whose name matches no declared role, reported
	// only where the policy asks for it.
	RuleRole = "role"
)

Rule names the family a finding belongs to.

View Source
const (
	ScopeSource = "source"
	ScopeTests  = "tests"
	// ScopeMain is a composition root — a file in package main. Wiring a
	// concrete database driver or bot framework is what a composition root is
	// for, and forbidding it there would either flag every daemon in the fleet
	// or force the wiring somewhere worse.
	ScopeMain = "main"
)

Scope names the body of code a rule applies to. Test files legitimately reach for dependencies production code must not — an in-memory or emulator database driver being the usual case — so the two are separate rule sets declared centrally, rather than an exception filed per repository.

View Source
const ConfigFileName = ".wb-deps-policy.yaml"

ConfigFileName is the per-repository policy declaration. It is deliberately tiny: which policy governs this repository, and — only where the module path cannot say — what kind of repository it is.

View Source
const GroupStdlib = "stdlib"

GroupStdlib is assigned to imports of the Go standard library. The standard library is never an architecture boundary, so it is always permitted and cannot be named in an allow list.

View Source
const GroupUnclassified = "unclassified"

GroupUnclassified is assigned to an import no declared group matches. Rules are allow lists, so an unclassified import is denied: a policy that gains a new kind of dependency fails closed instead of quietly permitting it. A policy that wants a catch-all declares one, with the pattern "...".

Variables

This section is empty.

Functions

func IsStdlib

func IsStdlib(importPath string) bool

IsStdlib reports whether an import path names the Go standard library. Standard-library paths are the ones whose first segment carries no dot, which is the same rule the go command uses.

func Scopes

func Scopes() []string

Scopes lists every scope in a stable order.

func WriteResult

func WriteResult(out io.Writer, result Result, format Format) error

WriteResult renders a check result.

Types

type Classification

type Classification struct {
	Import string
	Group  string

	// Pattern is the winning pattern as the policy author wrote it, and
	// PatternNumber its position in declaration order across the whole policy.
	Pattern       string
	PatternNumber int

	// AlsoMatched lists patterns declared after the winner that would also
	// have matched. Under first-match-wins these are shadowed, and being able
	// to see them is what makes an ordering mistake findable.
	AlsoMatched []PatternMatch
}

Classification is the full account of how one import path was classified. It carries more than the answer because the answer alone is not reviewable: when a verdict surprises someone, what they need is which pattern won and what else would have matched.

type Diagnostic

type Diagnostic struct {
	Message string
}

Diagnostic is a non-fatal finding about a policy document itself.

func Validate

func Validate(policy Policy) []Diagnostic

Validate reports quality problems in a policy that do not stop it running but do stop it meaning what its author thinks it means.

The one that matters most is an unreachable group pattern. Classification is first-match-wins, so a broad pattern placed above a narrow one silently takes every path the narrow one was written for, and nothing anywhere errors.

type Effective

type Effective struct {
	PolicySource string
	Module       string
	RepoType     string
	TypeDetected bool
	ConfigPath   string
	Strict       bool

	Scopes      []ScopeVerdict
	LayerMode   Mode
	LayerOrder  string
	LayerForbid []ForbidEdge
}

Effective is the resolved rule set one repository is actually held to.

func Describe

func Describe(policy Policy, modulePath, declaredType, configPath string, strict bool) (Effective, error)

Describe resolves what a repository is bound by. Central policy is opaque unless a repository can print its own rules back.

type Expectation

type Expectation struct {
	Import string
	Module string
	Group  string
	Type   string
}

Expectation is one assertion a policy makes about itself, exercised by `wb deps policy test`. Classification is the part of a policy that breaks quietly, so a policy is expected to carry examples of its own intent.

type ExpectationResult

type ExpectationResult struct {
	Expectation Expectation
	Subject     string
	Want        string
	Got         string
	Passed      bool
	Err         string
}

ExpectationResult is the outcome of one policy self-assertion.

func RunExpectations

func RunExpectations(policy Policy) []ExpectationResult

RunExpectations exercises the assertions a policy makes about itself.

Classification is the part of a policy that breaks quietly — reorder two group patterns and every verdict downstream changes with nothing to show for it — so a policy is expected to carry examples of what it means.

type Explanation

type Explanation struct {
	Import         string
	Module         string
	RepoType       string
	TypeDetected   bool
	Classification Classification

	// Scopes reports the verdict in each scope, because the same import can
	// be legitimate in a test and forbidden in production code.
	Scopes []ScopeVerdict
}

Explanation is the full account of one classification decision, which is what someone needs when a verdict surprises them.

func Explain

func Explain(policy Policy, modulePath, declaredType, importPath string) (Explanation, error)

Explain answers "why is this import allowed or forbidden here".

type Finding

type Finding struct {
	Rule string
	Mode Mode

	File     string
	Line     int
	Package  string
	Scope    string
	Import   string
	Manifest bool

	// Group is set for import findings.
	Group string
	// FromRole and ToRole are set for layer findings.
	FromRole string
	ToRole   string

	Message string
	// Fix names the shape of the remedy where one can be stated honestly.
	Fix string
}

Finding is one violation.

type ForbidEdge

type ForbidEdge struct {
	From   string
	To     string
	Reason string
}

ForbidEdge is one explicitly refused role-to-role import.

type Format

type Format string

Format is an output rendering.

const (
	// FormatText is for a person reading a terminal.
	FormatText Format = "text"
	// FormatJSON is for another program, including fleet aggregation.
	FormatJSON Format = "json"
	// FormatGitHub emits workflow commands so findings land as annotations on
	// the changed lines of a pull request.
	FormatGitHub Format = "github"
)

func ParseFormat

func ParseFormat(raw string) (Format, error)

ParseFormat validates a format name.

type Group

type Group struct {
	Name     string
	Patterns []Pattern
}

Group classifies import paths. Order is significant and first match wins, so a narrow group must be declared above a broad one.

type Layers

type Layers struct {
	Mode Mode
	// UnknownRole says what to do with a package whose name matches no role.
	// "ignore" is the sane default while a fleet still has packages that
	// predate the convention.
	UnknownRole string
	Roles       []RoleRule
	// Order runs from the outermost layer to the innermost. A package may
	// import its own layer and any layer below it, never above.
	Order [][]string
	// Forbid names individual role edges that are refused even though the
	// layer order permits them. The depth rule alone cannot express "delivery
	// must go through the facade", because api → dal does travel downward;
	// stating such edges explicitly keeps the exception visible in the policy
	// rather than hidden in the tool.
	Forbid []ForbidEdge
}

Layers describes permitted direction between packages inside one repository.

type Mode

type Mode string

Mode says whether a rule family blocks or merely reports. It is declared in the central policy and cannot be set by a repository, so a new rule can be rolled out fleet-wide without any repository being able to opt itself out.

const (
	// ModeEnforce fails the check.
	ModeEnforce Mode = "enforce"
	// ModeReport prints and counts findings without affecting the exit code.
	ModeReport Mode = "report"
)

func ParseMode

func ParseMode(raw string) (Mode, error)

ParseMode validates a mode string.

type Module

type Module struct {
	Path string
	Dir  string

	References []Reference

	// Unparseable lists files that could not be parsed. They are reported
	// rather than swallowed: a file the scanner cannot read is a hole in the
	// check, and a hole that stays quiet is worse than one that does not.
	Unparseable []string
}

Module is the lexical evidence gathered from one Go module.

Nothing here is resolved or type-checked: the scan reads import blocks and go.mod, and never downloads a dependency. That is deliberate — it means the check still reports when the build itself cannot start, which is exactly when an architecture boundary is most likely to be under discussion.

func ScanModule

func ScanModule(dir string) (Module, error)

ScanModule reads the module rooted at dir.

type Pattern

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

Pattern matches Go import paths and module paths.

The syntax is deliberately the one Go developers already read:

github.com/acme/thing        exactly that path
github.com/acme/thing/...    that path and everything beneath it
github.com/acme/ext-*/...    "*" matches within one path segment
github.com/acme/{a,b}/...    brace alternation
<self>/...                   the module being scanned

Braces are expanded at compile time, so a pattern is held as one or more flat alternatives.

func CompilePattern

func CompilePattern(raw string) (Pattern, error)

CompilePattern parses one pattern. It reports an error rather than silently accepting a pattern that cannot match anything, because an unmatchable pattern in a policy is invisible at check time.

func (Pattern) Covers

func (p Pattern) Covers(other Pattern) bool

Covers reports whether every path described by other is also described by p — the check behind the "unreachable pattern" diagnostic in validate.

It is a deliberately conservative approximation: for each of other's alternatives it builds one representative concrete path and asks whether p matches it. That catches the ordering mistake this exists for (a broad pattern placed above a narrow one), and errs towards staying quiet rather than reporting a shadow that is not real.

func (Pattern) Match

func (p Pattern) Match(importPath, self string) bool

Match reports whether importPath is described by this pattern. self is the module path substituted for <self>; an empty self makes <self> patterns match nothing rather than match everything.

func (Pattern) String

func (p Pattern) String() string

String returns the pattern as written in the policy, so diagnostics quote what the author typed rather than an expanded form.

type PatternMatch

type PatternMatch struct {
	Group   string
	Pattern string
	Number  int
}

PatternMatch names one pattern that matched.

type Policy

type Policy struct {
	// Source records where the document was loaded from, so `show` can tell a
	// repository what it is actually being held to.
	Source string

	Groups []Group
	Types  []RepoType
	Layers Layers

	Expectations []Expectation
}

Policy is a complete, compiled rule set. It carries no knowledge of any particular fleet: every name in it comes from the policy document.

func Load

func Load(path string) (Policy, error)

Load reads and compiles a policy document.

It fails on anything that would make the policy unusable or silently wrong: a malformed pattern, a duplicate name, an allow list naming a group that does not exist, a type with nothing to detect it by. Softer quality findings — a pattern another pattern already shadows, a role nobody placed in the layer order — are reported by Validate instead, so that they can be surfaced without refusing to run.

func Parse

func Parse(contents []byte, source string) (Policy, error)

Parse compiles a policy from bytes. source is used only for diagnostics.

func (Policy) Classify

func (p Policy) Classify(importPath, self string) Classification

Classify assigns an import path to a group. self is the module path being scanned, substituted for <self> patterns.

func (Policy) Detect

func (p Policy) Detect(modulePath string) (string, error)

Detect resolves a module path to a repository type.

Types are declared in order and the first match wins — the same rule groups follow, so a policy document has one ordering principle rather than two. Overlap is expected and useful: "github.com/acme/ext-*/backend" above "github.com/acme/*/backend" reads as "contracts, then everything else", which is what the author means. Validate reports a detect pattern that an earlier type has already claimed entirely.

func (Policy) GroupNames

func (p Policy) GroupNames() []string

GroupNames lists declared group names in declaration order.

func (Policy) HasGroup

func (p Policy) HasGroup(name string) bool

HasGroup reports whether a group of that name is declared.

func (Policy) Type

func (p Policy) Type(name string) (RepoType, bool)

Type returns the named repository type.

func (Policy) TypeNames

func (p Policy) TypeNames() []string

TypeNames lists declared type names in declaration order.

type Reference

type Reference struct {
	// Import is the imported path, or the required module path for a manifest
	// requirement.
	Import string
	// File is slash-separated and relative to the module directory.
	File string
	// Line is 1-indexed; 0 for a manifest requirement with no useful position.
	Line int
	// Package is the directory the importing file lives in, relative to the
	// module directory. Empty means the module root.
	Package string
	// Scope is source or tests.
	Scope string
	// Manifest marks a go.mod requirement rather than a source import.
	Manifest bool
}

Reference is one dependency edge found in a module: an import in a source file, or a requirement in go.mod.

type RepoConfig

type RepoConfig struct {
	// Found is false when the repository has no config file at all.
	Found bool
	// Path is where the config was read from.
	Path string

	Policy string
	Type   string
	// Strict promotes report-mode rules to errors for this repository only.
	// It is the single permitted local change, and it can only tighten.
	Strict bool
}

RepoConfig is a repository's declaration.

func LoadRepoConfig

func LoadRepoConfig(root string) (RepoConfig, error)

LoadRepoConfig reads the config file in root. A missing file is not an error: detection from the module path is the normal case, and a repository with nothing to say should not need to say it.

type RepoType

type RepoType struct {
	Name   string
	Detect []Pattern
	Scopes map[string]Scope
}

RepoType is a kind of repository. Detect patterns are matched against the module path, which is why most repositories need no configuration at all.

type Result

type Result struct {
	Module Module
	Policy Policy
	// Type is the repository type the rules were taken from.
	Type string
	// TypeDetected records whether Type came from detection or was declared.
	TypeDetected bool

	Findings []Finding
}

Result is the outcome of checking one module.

func Check

func Check(policy Policy, module Module, declaredType string) (Result, error)

Check applies a policy to a scanned module.

declaredType overrides detection. It exists because a module path cannot always say what a repository is; it is not an escape hatch, since the rules it selects are still the central policy's.

func (*Result) ApplyStrict

func (r *Result) ApplyStrict()

ApplyStrict promotes report-mode findings to blocking ones. A repository may hold itself to more than the fleet requires; it may never hold itself to less.

func (Result) Blocking

func (r Result) Blocking() int

Blocking counts findings that must fail the command. Report-mode findings are excluded: they are visible and counted, and they do not gate.

func (Result) Reported

func (r Result) Reported() int

Reported counts findings that are visible but do not gate.

func (Result) Summary

func (r Result) Summary() string

Summary counts findings by rule for a one-line report.

type RoleRule

type RoleRule struct {
	Role     string
	Patterns []Pattern
}

RoleRule maps package directory names onto a role such as "facade".

type Scope

type Scope struct {
	Allow []string
}

Scope is the allow list for one body of code. There is deliberately no deny list: anything not allowed is forbidden, which leaves nothing to widen.

func (Scope) Allows

func (s Scope) Allows(group string) bool

Allows reports whether this scope permits the named group.

type ScopeVerdict

type ScopeVerdict struct {
	Scope   string
	Allowed bool
	Allow   []string
}

ScopeVerdict is the outcome for one scope.

type Source

type Source struct {
	Raw  string
	Kind SourceKind

	Owner string
	Repo  string
	Path  string
	URL   string
}

Source is a parsed policy reference.

func ParseSource

func ParseSource(raw string) (Source, error)

ParseSource reads a policy reference.

A reference names which policy applies and never which release of it. A repository frozen on an old policy would be carrying an exception without anyone having written one down, so a pinned version is refused here rather than honoured.

func (Source) Locate

func (s Source) Locate(repoRoot string, searchRoots []string) (string, error)

Locate resolves a path or fleet reference to a file on disk. URL references are the caller's to fetch, because caching and network policy belong to the command layer rather than to the rule engine.

type SourceKind

type SourceKind string

SourceKind is how a policy reference is resolved.

const (
	// SourcePath is a file beside the repository.
	SourcePath SourceKind = "path"
	// SourceFleet is owner/repo//path, resolved against local checkouts.
	SourceFleet SourceKind = "fleet"
	// SourceURL is an https document.
	SourceURL SourceKind = "url"
)

Jump to

Keyboard shortcuts

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