allowlist

package
v1.2.9 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package allowlist is the one reader and the one writer of the exception lists the class tests in internal/ci keep under internal/ci/testdata.

A list is a text file: `#` comment lines, blank lines, and rows. Each row has a key (by default its first field) and whatever reason follows it for a reader. A class test Loads its list, walks the tree, and hands Check the set of keys it measured: every offender it found, listed or not. Check returns the rows nobody needs any more (stale) and the keys the list does not hold (unlisted); the test prints both with its own remedy.

Under NOVA_CI_UPDATE=1, Check rewrites the file to the measured set instead: the stale rows go, every comment and every kept row stays byte for byte, and the test fails once with "updated, rerun". A ceiling-only list -- one whose count only falls, which is every list in internal/ci today -- refuses to grow under the update and says so for each key it will not add: an update never writes a reason on anyone's behalf. A `# ceiling: N` line caps a list's row count; the update lowers N to the new count and never raises it.

A counted list carries a site count after the key (`key 3 reason`): the number of sites the row covers. A row that covers sites alone is not a shrink-only list, because a new site under an existing key reads as already listed; the count closes that. The measured count of a key must equal its row's count, a higher one is a new site (red), a lower one is a count to lower (red, and NOVA_CI_UPDATE=1 lowers it), and an update never raises one.

No script edits a list file: a removal regenerates every list with one env var.

Index

Constants

View Source
const UpdateEnv = diffcheck.UpdateEnv

UpdateEnv is the variable that turns Check into a rewrite. Only the value "1" does. It is defined once, beside the lander that runs the update (pkg/diffcheck).

View Source
const UpdatedRerun = diffcheck.UpdatedRerun

UpdatedRerun is the sentence the one failure of an update run carries.

Variables

This section is empty.

Functions

func Fields

func Fields(n int) func(string) string

Fields returns a key of the row's first n fields joined by one blank, for a list whose identity is more than one field (`file:line kind`, `file spell`).

func FirstField

func FirstField(row string) string

FirstField is the default key: the row's first whitespace-separated field.

func Updating

func Updating() bool

Updating reports whether this run rewrites the lists (NOVA_CI_UPDATE=1).

func WholeRow

func WholeRow(row string) string

WholeRow keys a row by its whole trimmed text.

Types

type CountRow

type CountRow struct {
	Key      string
	Listed   int
	Measured int
}

CountRow is one counted key: the sites its row lists and the sites measured.

type List

type List struct {
	Path string
	// contains filtered or unexported fields
}

List is a loaded allowlist.

func Load

func Load(path string, opt Options) (*List, error)

Load reads the list at path.

func Parse

func Parse(path, raw string, opt Options) (*List, error)

Parse reads a list from its text; path is where Check writes it back.

func (*List) Ceiling

func (l *List) Ceiling() (int, bool)

Ceiling returns the `# ceiling: N` cap, and false when the list carries none.

func (*List) Count

func (l *List) Count(key string) int

Count is a counted row's site count, 0 for a key no row carries.

func (*List) Has

func (l *List) Has(key string) bool

Has reports whether a row carries this key.

func (*List) Len

func (l *List) Len() int

Len is the number of rows.

func (*List) Rows

func (l *List) Rows() []Row

Rows returns the rows in file order.

func (*List) Text

func (l *List) Text() string

Text is the file as it was loaded.

type Options

type Options struct {
	// Key derives a row's key from its trimmed text. Nil is FirstField.
	Key func(row string) string
	// Ceiling marks a list whose count only falls: an update drops stale rows and
	// refuses to add a row for an unlisted key.
	Ceiling bool
	// NewRow is the text an update appends for an unlisted key on a list that may
	// grow. Nil appends the key alone. Unused on a ceiling list.
	NewRow func(key string) string
	// MissingIsEmpty loads a missing file as an empty list instead of an error: a
	// tree with nothing parked in it is the goal.
	MissingIsEmpty bool
	// Counted marks a list whose rows carry a site count as the second field
	// (`key N reason`, N a positive integer); use CheckCountedMode with it.
	Counted bool
	// PackageKeys makes LoadPackages interpret a counted key as
	// `<repo-relative-package>:<kind>` instead of a file-qualified key.
	// The row key itself remains unchanged; this only selects its shard.
	PackageKeys bool
	// RepeatedKeys permits rows with duplicate keys; by default Parse rejects
	// a repeated key.
	RepeatedKeys bool
}

Options says how a list's rows are keyed and whether it may grow.

type Packages

type Packages struct {
	Path string
	// contains filtered or unexported fields
}

Packages is a counted ledger split by source directory or explicit package. Its rows retain their full keys and original reasons.

func LoadPackages

func LoadPackages(dir string, opt Options) (*Packages, error)

LoadPackages reads every shard below dir. A missing directory is an empty ledger; an offender in it is still unlisted and cannot be added by UPDATE. Shards use <dir>/<owner>.txt, where owner is a source directory by default or a package with Options.PackageKeys. @root.txt represents the repository root. A real path component beginning with @ gains one @, so the mapping is reversible even for a directory literally named @root.

func (*Packages) Ceiling

func (p *Packages) Ceiling() (int, bool)

Ceiling is the sum of the shards' row ceilings, including zero for an empty ledger. LoadPackages requires a ceiling in every existing shard.

func (*Packages) Count

func (p *Packages) Count(key string) int

func (*Packages) Has

func (p *Packages) Has(key string) bool

Has and Count read the merged ledger by its unchanged full row key.

func (*Packages) Lists

func (p *Packages) Lists() []*List

func (*Packages) Rows

func (p *Packages) Rows() []Row

Rows returns all shards' rows sorted by their full keys. Lists returns the underlying lists in package-name order when a caller needs shard provenance.

type Reporter

type Reporter interface {
	Helper()
	Errorf(format string, args ...any)
}

Reporter is the part of testing.TB Check writes to. It is an interface here so the package does not link the testing package into a binary that imports internal/ci.

type Result

type Result struct {
	// Stale are the rows whose key was not measured. Each is a red run; an update
	// drops them and returns none.
	Stale []Row
	// Unlisted are the measured keys no row carries, sorted. Each is a red run; an
	// update on a list that may grow adds them and returns none, and a ceiling list
	// keeps them (it refuses to grow).
	Unlisted []string
	// Over are the keys of a counted list measured at more sites than their row
	// allows: a new site under an existing row. Each is a red run, and an update
	// refuses to raise the count.
	Over []CountRow
	// Lowered are the keys of a counted list measured at fewer sites than their
	// row says. Each is a red run outside an update; an update lowers the count and
	// returns none.
	Lowered []CountRow
	// Updated is true when this run rewrote the file.
	Updated bool
}

Result is what Check found.

func Check

func Check(r Reporter, l *List, measured map[string]bool) Result

Check compares the measured keys with the list. Outside an update it only reports: a list over its ceiling is refused here, and the stale rows and unlisted keys come back for the caller to print with its own remedy. Under NOVA_CI_UPDATE=1 it rewrites the file to the measured set and fails once with "updated, rerun"; a ceiling list refuses each key it would have to add, one line per key.

func CheckCountedMode

func CheckCountedMode(r Reporter, l *List, measured map[string]int, update bool) Result

CheckCountedMode compares the measured site counts with a counted list. Stale rows (a key measured at none) and Unlisted keys are as in CheckMode; Over holds the keys measured above their row's count and Lowered those below it. Outside an update it only reports. Under an update it drops the stale rows, lowers the lowered counts and refuses, one line per key, to add a row or raise a count: the list only shrinks.

func CheckMode

func CheckMode(r Reporter, l *List, measured map[string]bool, update bool) Result

CheckMode is Check with the update mode given, not read from the environment, so a test of this package does not depend on how its own run was started.

func CheckPackagesCounted

func CheckPackagesCounted(r Reporter, p *Packages, measured map[string]int) Result

CheckPackagesCounted compares measured site counts and honors NOVA_CI_UPDATE.

func CheckPackagesCountedMode

func CheckPackagesCountedMode(r Reporter, p *Packages, measured map[string]int, update bool) Result

CheckPackagesCountedMode performs a whole-ledger preflight before any update write. An unlisted key, raised count, invalid key, or raised ceiling in any shard refuses all writes; a permitted update replaces only changed shards. Each replacement is atomic through atomicfile. Multiple replacements are not a single crash-atomic transaction.

type Row

type Row struct {
	Line int    // 1-based line in the file
	Text string // the row, trimmed
	Key  string
}

Row is one row of a list.

Jump to

Keyboard shortcuts

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