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
- Variables
- func CorrectnessGateNames() []string
- func CostGateNames() []string
- func LicenseIdentifiers() []string
- func MapReleaseTag(policy, sourceTag string) (string, error)
- func MigrateV1ToV2(data []byte) ([]byte, error)
- func ParseMinorSeries(value string) (major, minor int, err error)
- func ParseSymbolRef(ref string) (pkgPath, name string, err error)
- func SafeJoin(ctx context.Context, root, rel string) (string, error)
- func ValidateEmail(value string) error
- func ValidateEnvName(name string) error
- func ValidateExportedIdent(name string) error
- func ValidateGlob(p string) error
- func ValidateHexSHA(value string) error
- func ValidateIdent(name string) error
- func ValidateIdentityName(name string) error
- func ValidateImportPath(p string) error
- func ValidateModulePath(p string) error
- func ValidatePackagePath(p string) error
- func ValidateRelPath(p string) error
- func ValidateRepositorySlug(value string) error
- type Alias
- type Closure
- type ClosureLimits
- type Commit
- type Compatibility
- type Config
- type CostGates
- type DecodeError
- type Deny
- type Dependencies
- type DependencyGates
- type DependencyOverride
- type Destination
- type Determinism
- type Export
- type Facade
- type Identity
- type InterfaceAssertion
- type Packages
- type Patch
- type Prune
- type Publication
- type Refs
- type Release
- type Semver
- type Source
- type TypePair
- type Types
- type ValidationError
- type Vanity
Constants ¶
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.
const DefaultFileName = "soapbox.yaml"
DefaultFileName is the conventional profile file name in a repository root.
const PriorSchemaVersion = 1
PriorSchemaVersion is the schema version this engine can migrate from.
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.
const SchemaVersion = 2
SchemaVersion is the only soapbox.yaml schema version this engine accepts.
Variables ¶
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 ¶
MapReleaseTag maps an upstream release tag onto the generated module tag.
func MigrateV1ToV2 ¶ added in v0.2.0
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 ¶
ParseMinorSeries parses a vMAJOR.MINOR release series such as v1.37.
func ParseSymbolRef ¶
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 ¶
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 ¶
ValidateEmail checks that value is a single conservative addr-spec.
func ValidateEnvName ¶
ValidateEnvName checks that name is a conventional environment variable name. Only names are configurable. Secret values never appear in configuration.
func ValidateExportedIdent ¶
ValidateExportedIdent checks that name is an exported Go identifier.
func ValidateGlob ¶
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 ¶
ValidateHexSHA checks that value is a lower case Git object name.
func ValidateIdent ¶
ValidateIdent checks that name is a Go identifier.
func ValidateIdentityName ¶
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 ¶
ValidateImportPath checks that p is a syntactically valid Go import path.
func ValidateModulePath ¶
ValidateModulePath checks that p is a valid module path with a domain like first element.
func ValidatePackagePath ¶
ValidatePackagePath checks that p is a repository relative Go package directory path.
func ValidateRelPath ¶
ValidateRelPath checks that p is a clean, relative, traversal free slash path.
func ValidateRepositorySlug ¶
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 ¶
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
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 (*Config) ProfileBytes ¶
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 ¶
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) 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 ¶
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 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 ¶
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 Semver ¶
Semver is a parsed v prefixed semantic version without build metadata.
func ParseSemver ¶
ParseSemver parses a v prefixed semantic version. Build metadata is rejected because module tags may not carry it.
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 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.