config

package
v0.2.1 Latest Latest
Warning

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

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

Documentation

Overview

Package config decodes, normalizes, and validates the versioned soapbox.yaml extraction profile.

Decoding is strict. Unknown fields, duplicate keys, and multiple YAML documents are rejected so a profile can never silently lose meaning between engine versions. Normalization is deterministic because later phases hash the output affecting subset of a profile to detect control plane changes.

Index

Constants

View Source
const (
	TypePolicyPreferExternal = "prefer-external"
	TypePolicyKeepInternal   = "keep-internal"

	DependencyPolicyExternal     = "external"
	DependencyPolicyCopyApproved = "copy-approved"

	AuthorPolicyPreserveUpstream = "preserve-upstream"

	// PublicationModeManual requires an explicit workflow dispatch to publish.
	PublicationModeManual = "manual"
	// PublicationModeAutomatic adds -unattended to the scheduled sync so
	// publication proceeds without further human intervention.
	PublicationModeAutomatic = "automatic"

	// CompatibilityApiserverExternal means the generated module depends only on
	// published staging modules.
	CompatibilityApiserverExternal = "external"
	// CompatibilityApiserverLocal means the module may use in-tree apiserver
	// helpers that are not published as staging modules.
	CompatibilityApiserverLocal = "local"
)

Supported policy values. Unknown values are rejected rather than ignored so a profile written for a newer engine cannot silently lose meaning.

View Source
const DefaultFileName = "soapbox.yaml"

DefaultFileName is the conventional profile file name in a repository root.

View Source
const PriorSchemaVersion = 1

PriorSchemaVersion is the schema version this engine can migrate from.

View Source
const ReleasePolicyV1ToV0 = "v1-to-v0"

ReleasePolicyV1ToV0 maps upstream v1.X.Y tags onto generated v0.X.Y tags, which is how Kubernetes staging repositories are versioned.

View Source
const SchemaVersion = 2

SchemaVersion is the only soapbox.yaml schema version this engine accepts.

Variables

View Source
var (
	// ErrAbsolutePath reports a configured path that is not repository relative.
	ErrAbsolutePath = errors.New("path must be relative")
	// ErrPathTraversal reports a configured path with a parent directory element.
	ErrPathTraversal = errors.New("path must not traverse parent directories")
	// ErrPathNotClean reports a configured path that is not in canonical form.
	ErrPathNotClean = errors.New("path must be in clean slash form")
	// ErrPathEscape reports a path that leaves its permitted root once symbolic
	// links are resolved.
	ErrPathEscape = errors.New("path escapes its permitted root")
	// ErrDanglingSymlink reports a symbolic link whose target does not exist.
	// Such a link cannot be proved to stay inside its root, so it is refused
	// rather than treated as a component that simply does not exist yet.
	ErrDanglingSymlink = errors.New("path resolves through a dangling symbolic link")
)

Path validation sentinels. Callers use errors.Is to distinguish the failure.

Functions

func CorrectnessGateNames

func CorrectnessGateNames() []string

CorrectnessGateNames returns the gate names no override may relax.

func CostGateNames

func CostGateNames() []string

CostGateNames returns the gate names an override may relax.

It is exported so the package that evaluates these gates can be tested against the profile schema's actual vocabulary rather than against a copy of it. The two lists live in different packages on purpose, and a copied literal in a test would keep passing while they drifted apart.

func LicenseIdentifiers

func LicenseIdentifiers() []string

LicenseIdentifiers returns the SPDX identifiers a profile may name.

It is exported so the package that verifies licence text can be tested against the profile schema's actual vocabulary rather than against a literal copied into a test, which would keep passing while the two drifted apart.

func MapReleaseTag

func MapReleaseTag(policy, sourceTag string) (string, error)

MapReleaseTag maps an upstream release tag onto the generated module tag.

func MigrateV1ToV2 added in v0.2.0

func MigrateV1ToV2(data []byte) ([]byte, error)

MigrateV1ToV2 reads a schema v1 profile, validates it strictly, and returns migrated v2 bytes. The migration sets publication.mode=manual, compatibility.apiserver=external, and forbiddenModules=[].

The migration is deliberate and explicit: an operator upgrades by running "soapbox upgrade", which calls this function, reviews the manifest, and approves it. No silent migration happens during a normal load.

func ParseMinorSeries

func ParseMinorSeries(value string) (major, minor int, err error)

ParseMinorSeries parses a vMAJOR.MINOR release series such as v1.37.

func ParseSymbolRef

func ParseSymbolRef(ref string) (pkgPath, name string, err error)

ParseSymbolRef splits a fully qualified symbol reference such as k8s.io/kubernetes/pkg/registry/rbac/validation.RoleGetter into its package path and symbol name.

func SafeJoin

func SafeJoin(ctx context.Context, root, rel string) (string, error)

SafeJoin resolves rel below root and fails when the result leaves root, both before and after symbolic link resolution. Missing trailing elements are allowed so callers can resolve outputs that do not exist yet.

func ValidateEmail

func ValidateEmail(value string) error

ValidateEmail checks that value is a single conservative addr-spec.

func ValidateEnvName

func ValidateEnvName(name string) error

ValidateEnvName checks that name is a conventional environment variable name. Only names are configurable. Secret values never appear in configuration.

func ValidateExportedIdent

func ValidateExportedIdent(name string) error

ValidateExportedIdent checks that name is an exported Go identifier.

func ValidateGlob

func ValidateGlob(p string) error

ValidateGlob checks that p is a repository relative match pattern.

Recursive patterns are rejected. path.Match reads ** as two ordinary stars that still stop at a slash, so accepting the syntax would silently match far less than an operator expects. One shared recursive matcher can be introduced when the extraction phase needs it.

func ValidateHexSHA

func ValidateHexSHA(value string) error

ValidateHexSHA checks that value is a lower case Git object name.

func ValidateIdent

func ValidateIdent(name string) error

ValidateIdent checks that name is a Go identifier.

func ValidateIdentityName

func ValidateIdentityName(name string) error

ValidateIdentityName checks a Git author or committer name. Git trims surrounding whitespace and treats angle brackets and newlines as identity syntax, so a name that Git would rewrite is rejected rather than silently changed on the way into a commit object.

func ValidateImportPath

func ValidateImportPath(p string) error

ValidateImportPath checks that p is a syntactically valid Go import path.

func ValidateModulePath

func ValidateModulePath(p string) error

ValidateModulePath checks that p is a valid module path with a domain like first element.

func ValidatePackagePath

func ValidatePackagePath(p string) error

ValidatePackagePath checks that p is a repository relative Go package directory path.

func ValidateRelPath

func ValidateRelPath(p string) error

ValidateRelPath checks that p is a clean, relative, traversal free slash path.

func ValidateRepositorySlug

func ValidateRepositorySlug(value string) error

ValidateRepositorySlug checks that value is an owner/name repository slug.

Types

type Alias

type Alias struct {
	Name   string `yaml:"name"`
	Kind   string `yaml:"kind"`
	Source string `yaml:"source"`
}

Alias republishes an internal symbol under a different name, which is how upstream name collisions are resolved in a single facade package.

type Closure

type Closure struct {
	IncludeTests bool          `yaml:"includeTests"`
	Limits       ClosureLimits `yaml:"limits"`
	Golden       string        `yaml:"golden"`
}

Closure bounds the materialized package set.

type ClosureLimits

type ClosureLimits struct {
	MaxPackages      int `yaml:"maxPackages"`
	MaxFiles         int `yaml:"maxFiles"`
	MaxNonTestLines  int `yaml:"maxNonTestLines"`
	MaxPackageGrowth int `yaml:"maxPackageGrowth"`
}

ClosureLimits are observational publication gates. They never change output bytes, so they stay out of the replay profile hash.

type Commit

type Commit struct {
	AuthorPolicy string   `yaml:"authorPolicy"`
	Committer    Identity `yaml:"committer"`
	TrailerKey   string   `yaml:"trailerKey"`
	Sign         bool     `yaml:"sign"`
}

Commit describes generated commit identity. Generated commits preserve the upstream author and are never signed.

type Compatibility added in v0.2.0

type Compatibility struct {
	// Apiserver is either external or local. External means the generated module
	// depends only on published staging modules (the default for consumers that
	// run out of tree). Local means the module may use in-tree apiserver helpers
	// that are not published as staging modules (for testing against a locally
	// built apiserver).
	Apiserver string `yaml:"apiserver"`
}

Compatibility selects which apiserver environments the generated module targets.

type Config

type Config struct {
	Version       int           `yaml:"version"`
	Source        Source        `yaml:"source"`
	Destination   Destination   `yaml:"destination"`
	Packages      Packages      `yaml:"packages"`
	Prune         Prune         `yaml:"prune"`
	Deny          Deny          `yaml:"deny"`
	Closure       Closure       `yaml:"closure"`
	Types         Types         `yaml:"types"`
	Dependencies  Dependencies  `yaml:"dependencies"`
	Patches       []Patch       `yaml:"patches"`
	Facade        Facade        `yaml:"facade"`
	Release       Release       `yaml:"release"`
	Commit        Commit        `yaml:"commit"`
	Vanity        Vanity        `yaml:"vanity"`
	Publication   Publication   `yaml:"publication"`
	Compatibility Compatibility `yaml:"compatibility"`
	Determinism   Determinism   `yaml:"determinism"`
}

Config is a complete extraction profile.

func Decode

func Decode(data []byte) (*Config, error)

Decode parses, normalizes, and validates profile bytes. Content problems are reported as *DecodeError or *ValidationError so callers can separate them from input and output failures.

func DecodeWithMigration added in v0.2.0

func DecodeWithMigration(data []byte) (*Config, []byte, error)

DecodeWithMigration decodes profile bytes, applying v1→v2 migration if needed. It returns the migrated bytes alongside the config so the caller can write them back.

func Load

func Load(ctx context.Context, path string) (*Config, error)

Load reads, decodes, normalizes, and validates the profile stored at path.

func (*Config) Canonical

func (c *Config) Canonical() ([]byte, error)

Canonical renders the normalized profile as deterministic YAML bytes.

func (*Config) ProfileBytes

func (c *Config) ProfileBytes() ([]byte, error)

ProfileBytes renders the output affecting subset of the profile. Later phases hash these bytes to decide when a control plane change starts a new epoch.

type CostGates

type CostGates struct {
	MaxCopiedPackages   int   `yaml:"maxCopiedPackages"`
	MaxCopiedLines      int   `yaml:"maxCopiedLines"`
	MaxGeneratedFiles   int   `yaml:"maxGeneratedFiles"`
	MaxDistinctLicenses int   `yaml:"maxDistinctLicenses"`
	MaxModuleZipBytes   int64 `yaml:"maxModuleZipBytes"`
	// MaxReleasesPerMinor bounds how fast the copied code moves upstream. A
	// dependency that ships nine times in one minor series is nine merges the
	// generated module performs itself once it owns the code, and that cost
	// recurs for as long as the copy exists.
	MaxReleasesPerMinor int `yaml:"maxReleasesPerMinor"`
	// MinModulesRemoved, MinPackagesRemoved, and MinLinesRemoved are the benefit
	// a copy has to deliver to be worth owning.
	//
	// They are minima rather than maxima because they are the gate that asks
	// what the copy is for. The usual outcome of copying some packages of a
	// module that stays in the build for the others is that nothing leaves at
	// all: the consumer downloads the same module, compiles the same packages,
	// and now compiles the copy as well. A profile states the benefit it expects
	// and a copy that does not deliver it is refused however cheap it looks.
	MinModulesRemoved  int `yaml:"minModulesRemoved"`
	MinPackagesRemoved int `yaml:"minPackagesRemoved"`
	MinLinesRemoved    int `yaml:"minLinesRemoved"`
}

CostGates bound the size of an approved staging copy and the benefit it must deliver in exchange.

type DecodeError

type DecodeError struct {
	Reason string
	Err    error
}

DecodeError reports profile content that could not be decoded: unknown or duplicated fields, malformed YAML, an empty document, or more than one document. It is distinct from a filesystem failure, because a profile the operator can see and fix is a policy problem rather than a runtime one.

func (*DecodeError) Error

func (e *DecodeError) Error() string

Error renders the decode failure.

func (*DecodeError) Unwrap

func (e *DecodeError) Unwrap() error

Unwrap exposes the underlying YAML error.

type Deny

type Deny struct {
	Imports []string `yaml:"imports"`
}

Deny lists exact import paths that may never reenter the closure.

type Dependencies

type Dependencies struct {
	Policy           string               `yaml:"policy"`
	CopyPackages     []string             `yaml:"copyPackages"`
	ForbiddenModules []string             `yaml:"forbiddenModules"`
	Gates            DependencyGates      `yaml:"gates"`
	Overrides        []DependencyOverride `yaml:"overrides"`
}

Dependencies decides whether staging packages may be copied.

type DependencyGates

type DependencyGates struct {
	Interoperability bool      `yaml:"interoperability"`
	GlobalState      bool      `yaml:"globalState"`
	Diamond          bool      `yaml:"diamond"`
	Cost             CostGates `yaml:"cost"`
}

DependencyGates holds the non-overridable correctness gates and the cost gates an override may relax.

type DependencyOverride

type DependencyOverride struct {
	Package       string `yaml:"package"`
	Gate          string `yaml:"gate"`
	Justification string `yaml:"justification"`
	Approver      string `yaml:"approver"`
	ExpiresAfter  string `yaml:"expiresAfter"`
}

DependencyOverride relaxes exactly one cost gate for one candidate package.

type Destination

type Destination struct {
	Module            string `yaml:"module"`
	Repository        string `yaml:"repository"`
	Remote            string `yaml:"remote"`
	Branch            string `yaml:"branch"`
	StateRef          string `yaml:"stateRef"`
	ProgressRefPrefix string `yaml:"progressRefPrefix"`
	RootPackage       string `yaml:"rootPackage"`
	InternalPrefix    string `yaml:"internalPrefix"`
	// Summary states what the module provides. It is a noun phrase completing
	// "Package <rootPackage> provides ...", because the generated root doc
	// comment reads exactly that way and the same words stand alone as the
	// opening paragraph of the README and the NOTICE. No analysis of the code
	// can say what the code is for, so a human writes it here.
	Summary string `yaml:"summary"`
}

Destination describes the generated module and the repository that holds it.

type Determinism

type Determinism struct {
	Toolchain string `yaml:"toolchain"`
	ChunkSize int    `yaml:"chunkSize"`
}

Determinism pins the formatting toolchain and the gated backfill chunk size.

type Export

type Export struct {
	Name   string `yaml:"name"`
	Kind   string `yaml:"kind"`
	Source string `yaml:"source"`
	// Direct is engine-derived and never decoded. It marks a generated
	// module-local declaration that needs no source-to-internal relocation.
	Direct bool `yaml:"-"`
}

Export republishes an internal symbol under its upstream name.

type Facade

type Facade struct {
	Package             string               `yaml:"package"`
	File                string               `yaml:"file"`
	AssertionsFile      string               `yaml:"assertionsFile"`
	Exports             []Export             `yaml:"exports"`
	Aliases             []Alias              `yaml:"aliases"`
	InterfaceAssertions []InterfaceAssertion `yaml:"interfaceAssertions"`
}

Facade describes the curated public API of the generated module.

type Identity

type Identity struct {
	Name  string `yaml:"name"`
	Email string `yaml:"email"`
}

Identity is a Git author or committer identity.

type InterfaceAssertion

type InterfaceAssertion struct {
	Type      string `yaml:"type"`
	Pointer   bool   `yaml:"pointer"`
	Interface string `yaml:"interface"`
	// Local is engine-derived and permits an assertion against a generated
	// module-local interface in an intentionally breaking compatibility mode.
	Local bool `yaml:"-"`
}

InterfaceAssertion generates a compile-time implementation assertion.

type Packages

type Packages struct {
	Roots      []string `yaml:"roots"`
	Recursive  bool     `yaml:"recursive"`
	AssetGlobs []string `yaml:"assetGlobs"`
}

Packages selects the upstream package roots that seed the closure.

type Patch

type Patch struct {
	File     string   `yaml:"file"`
	Since    string   `yaml:"since"`
	Until    string   `yaml:"until"`
	Branches []string `yaml:"branches"`
}

Patch is one ordered unified diff with ancestry and branch selectors.

type Prune

type Prune struct {
	Files    []string `yaml:"files"`
	Required []string `yaml:"required"`
}

Prune lists the exact files removed from, and required to remain in, the materialized closure. Entries are files, never directories or globs.

type Publication added in v0.2.0

type Publication struct {
	// Mode is either manual or automatic. Manual mode requires an explicit
	// workflow dispatch to publish; automatic mode adds -unattended to the sync
	// command so a scheduled run publishes without further intervention.
	Mode string `yaml:"mode"`
}

Publication describes how the generated module is published.

type Refs

type Refs struct {
	MinimumRelease     string   `yaml:"minimumRelease"`
	IncludePrereleases bool     `yaml:"includePrereleases"`
	Branches           []string `yaml:"branches"`
	AnchorCommit       string   `yaml:"anchorCommit"`
}

Refs selects the upstream history the engine replays.

type Release

type Release struct {
	Policy   string `yaml:"policy"`
	FirstTag string `yaml:"firstTag"`
}

Release maps upstream release tags onto generated module tags.

type Semver

type Semver struct {
	Major      int
	Minor      int
	Patch      int
	Prerelease string
}

Semver is a parsed v prefixed semantic version without build metadata.

func ParseSemver

func ParseSemver(value string) (Semver, error)

ParseSemver parses a v prefixed semantic version. Build metadata is rejected because module tags may not carry it.

func (Semver) String

func (v Semver) String() string

String renders the version in its original v prefixed form.

type Source

type Source struct {
	Repository   string `yaml:"repository"`
	ImportPrefix string `yaml:"importPrefix"`
	// Project is the upstream project's display name, such as Kubernetes. The
	// generated evidence uses it only to say where the code came from and to
	// state that this module is not a release of that project, so it is written
	// by the profile rather than derived from a module path that spells the
	// name in whatever form a domain happens to use.
	Project string `yaml:"project"`
	// License is the SPDX identifier of the upstream grant, such as Apache-2.0.
	// The generated files quote the obligations of a particular licence, so the
	// identifier is stated here and checked against the licence text before
	// anything is published.
	License string `yaml:"license"`
	Refs    Refs   `yaml:"refs"`
}

Source describes the upstream repository and the refs the engine tracks.

type TypePair

type TypePair struct {
	Internal string `yaml:"internal"`
	External string `yaml:"external"`
}

TypePair records a verified internal to external API package pairing.

type Types

type Types struct {
	Policy string     `yaml:"policy"`
	Pairs  []TypePair `yaml:"pairs"`
}

Types selects the internal to public API substitution policy.

type ValidationError

type ValidationError struct {
	Problems []string
}

ValidationError reports every problem found in one profile.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error renders each problem on its own line.

type Vanity

type Vanity struct {
	Repository    string `yaml:"repository"`
	Path          string `yaml:"path"`
	ImportPath    string `yaml:"importPath"`
	RepositoryURL string `yaml:"repositoryURL"`
	ProbeURL      string `yaml:"probeURL"`
}

Vanity describes the go-import metadata page for the generated module.

Jump to

Keyboard shortcuts

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